Skip to content

Commit 63f8b73

Browse files
committed
Fix missing target features when using xforms
1 parent 9b37613 commit 63f8b73

File tree

7 files changed

+83
-2
lines changed

7 files changed

+83
-2
lines changed

Diff for: CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,12 @@
4545
* Fix MSRV compilation.
4646
[#3927](https://github.com/rustwasm/wasm-bindgen/pull/3927)
4747

48-
* Fixed `clippy::empty_docs` lint.
48+
* Fix `clippy::empty_docs` lint.
4949
[#3946](https://github.com/rustwasm/wasm-bindgen/pull/3946)
5050

51+
* Fix missing target features in module when enabling reference types or multi-value transformation.
52+
[#3967](https://github.com/rustwasm/wasm-bindgen/pull/3967)
53+
5154
--------------------------------------------------------------------------------
5255

5356
## [0.2.92](https://github.com/rustwasm/wasm-bindgen/compare/0.2.91...0.2.92)

Diff for: crates/externref-xform/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ rust-version = "1.57"
1515
[dependencies]
1616
anyhow = "1.0"
1717
walrus = "0.20.2"
18+
wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "=0.2.92" }
1819

1920
[dev-dependencies]
2021
rayon = "1.0"

Diff for: crates/externref-xform/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ impl Context {
101101
/// large the function table is so we know what indexes to hand out when
102102
/// we're appending entries.
103103
pub fn prepare(&mut self, module: &mut Module) -> Result<(), Error> {
104+
// Insert reference types to the target features section.
105+
wasm_bindgen_wasm_conventions::insert_target_feature(module, "reference-types");
106+
104107
// Figure out what the maximum index of functions pointers are. We'll
105108
// be adding new entries to the function table later (maybe) so
106109
// precalculate this ahead of time.

Diff for: crates/multi-value-xform/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ rust-version = "1.57"
1515
[dependencies]
1616
anyhow = "1.0"
1717
walrus = "0.20.2"
18+
wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "=0.2.92" }
1819

1920
[dev-dependencies]
2021
rayon = "1.0"

Diff for: crates/multi-value-xform/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ pub fn run(
117117
shadow_stack_pointer: walrus::GlobalId,
118118
to_xform: &[(walrus::FunctionId, usize, Vec<walrus::ValType>)],
119119
) -> Result<Vec<walrus::FunctionId>, anyhow::Error> {
120+
// Insert multi-value to the target features section.
121+
wasm_bindgen_wasm_conventions::insert_target_feature(module, "multivalue");
122+
120123
let mut wrappers = Vec::new();
121124
for (func, return_pointer_index, results) in to_xform {
122125
wrappers.push(xform_one(

Diff for: crates/wasm-conventions/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,8 @@ edition = "2018"
1111
rust-version = "1.57"
1212

1313
[dependencies]
14+
leb128 = "0.2"
1415
walrus = "0.20.2"
16+
# Matching the version `walrus` depends on.
17+
wasmparser = "0.80"
1518
anyhow = "1.0"

Diff for: crates/wasm-conventions/src/lib.rs

+68-1
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
//! * The shadow stack pointer
77
//! * The canonical linear memory that contains the shadow stack
88
9+
use std::io::Cursor;
10+
911
use anyhow::{anyhow, bail, Result};
1012
use walrus::{
1113
ir::Value, ElementId, FunctionBuilder, FunctionId, FunctionKind, GlobalId, GlobalKind,
12-
InitExpr, MemoryId, Module, ValType,
14+
InitExpr, MemoryId, Module, RawCustomSection, ValType,
1315
};
16+
use wasmparser::BinaryReader;
1417

1518
/// Get a Wasm module's canonical linear memory.
1619
pub fn get_memory(module: &Module) -> Result<MemoryId> {
@@ -148,3 +151,67 @@ pub fn get_or_insert_start_builder(module: &mut Module) -> &mut FunctionBuilder
148151
.unwrap_local_mut()
149152
.builder_mut()
150153
}
154+
155+
pub fn insert_target_feature(module: &mut Module, new_feature: &str) {
156+
// Taken from <https://github.com/bytecodealliance/wasm-tools/blob/f1898f46bb9d96f0f09682415cb6ccfd6a4dca79/crates/wasmparser/src/limits.rs#L27>.
157+
assert!(new_feature.len() <= 100_000);
158+
159+
// Try to find an existing section.
160+
let section = module
161+
.customs
162+
.iter_mut()
163+
.find(|(_, custom)| custom.name() == "target_features");
164+
165+
// If one exists, check if the target feature is already present.
166+
let section = if let Some((_, section)) = section {
167+
let section: &mut RawCustomSection = section.as_any_mut().downcast_mut().unwrap();
168+
let mut reader = BinaryReader::new(&section.data);
169+
// The first integer contains the target feature count.
170+
let count = reader.read_var_u32().unwrap();
171+
172+
// Try to find if the target feature is already present.
173+
for _ in 0..count {
174+
// First byte is the prefix.
175+
let prefix_index = reader.current_position();
176+
let prefix = reader.read_u8().unwrap() as u8;
177+
// Read the feature.
178+
let length = reader.read_var_u32().unwrap();
179+
let feature = reader.read_bytes(length as usize).unwrap();
180+
181+
// If we found the target feature, we are done here.
182+
if feature == new_feature.as_bytes() {
183+
// Make sure we set any existing prefix to "enabled".
184+
if prefix == b'-' {
185+
section.data[prefix_index] = b'+';
186+
}
187+
188+
return;
189+
}
190+
}
191+
192+
section
193+
} else {
194+
let mut data = Vec::new();
195+
leb128::write::unsigned(&mut data, 0).unwrap();
196+
let id = module.customs.add(RawCustomSection {
197+
name: String::from("target_features"),
198+
data,
199+
});
200+
module.customs.get_mut(id).unwrap()
201+
};
202+
203+
// If we couldn't find the target feature, insert it.
204+
205+
// The first byte contains an integer describing the target feature count, which we increase by one.
206+
let mut data = Cursor::new(&section.data);
207+
let count = leb128::read::unsigned(&mut data).unwrap();
208+
let mut new_count = Vec::new();
209+
leb128::write::unsigned(&mut new_count, count + 1).unwrap();
210+
section.data.splice(0..data.position() as usize, new_count);
211+
// Then we insert the "enabled" prefix at the end.
212+
section.data.push(b'+');
213+
// The next byte contains the length of the target feature string.
214+
leb128::write::unsigned(&mut section.data, new_feature.len() as u64).unwrap();
215+
// Lastly the target feature string is inserted.
216+
section.data.extend(new_feature.as_bytes());
217+
}

0 commit comments

Comments
 (0)