Skip to content

Commit 7ae0b53

Browse files
committed
Fix missing target features when using xforms
1 parent 9b37613 commit 7ae0b53

File tree

6 files changed

+76
-2
lines changed

6 files changed

+76
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
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)

crates/externref-xform/Cargo.toml

Lines changed: 1 addition & 0 deletions
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"

crates/externref-xform/src/lib.rs

Lines changed: 3 additions & 0 deletions
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.

crates/multi-value-xform/Cargo.toml

Lines changed: 1 addition & 0 deletions
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"

crates/multi-value-xform/src/lib.rs

Lines changed: 3 additions & 0 deletions
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(

crates/wasm-conventions/src/lib.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
//! * The shadow stack pointer
77
//! * The canonical linear memory that contains the shadow stack
88
9+
use std::cmp::Ordering;
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
};
1416

1517
/// Get a Wasm module's canonical linear memory.
@@ -148,3 +150,64 @@ pub fn get_or_insert_start_builder(module: &mut Module) -> &mut FunctionBuilder
148150
.unwrap_local_mut()
149151
.builder_mut()
150152
}
153+
154+
pub fn insert_target_feature(module: &mut Module, new_feature: &str) {
155+
// Try to find an existing section.
156+
let section = module
157+
.customs
158+
.iter_mut()
159+
.find(|(_, custom)| custom.name() == "target_features");
160+
161+
// If one exists, check if the target feature is already present.
162+
let section = if let Some((_, section)) = section {
163+
let section: &mut RawCustomSection = section.as_any_mut().downcast_mut().unwrap();
164+
// The first byte contains the target feature count.
165+
let count = section.data[0];
166+
167+
// Try to find if the target feature is already present.
168+
if count != 0 {
169+
let mut bytes = section.data[1..].iter_mut();
170+
171+
for _ in 0..count {
172+
// First byte is the prefix.
173+
let prefix = bytes.next().unwrap();
174+
// Read the length of the target feature.
175+
let length = *bytes.next().unwrap();
176+
// Read the feature.
177+
let mut feature = bytes.by_ref().take(length.into());
178+
179+
// If we found the target feature, we are done here.
180+
if let Ordering::Equal = feature.by_ref().map(|b| &*b).cmp(new_feature.as_bytes()) {
181+
// Make sure we set any existing prefix to "enabled".
182+
if *prefix == b'-' {
183+
*prefix = b'+';
184+
}
185+
186+
return;
187+
}
188+
189+
// If we couldn't find it, consume it so we can advance.
190+
feature.for_each(|_| ());
191+
}
192+
}
193+
194+
section
195+
} else {
196+
let id = module.customs.add(RawCustomSection {
197+
name: String::from("target_features"),
198+
data: vec![0],
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 the target feature count, which we increase by one.
206+
section.data[0] += 1;
207+
// Then we insert the "enabled" prefix at the end.
208+
section.data.push(b'+');
209+
// The next byte contains the length of the target feature string.
210+
section.data.push(new_feature.len() as u8);
211+
// Lastly the target feature string is inserted.
212+
section.data.extend(new_feature.as_bytes());
213+
}

0 commit comments

Comments
 (0)