Skip to content

Commit 13c24b3

Browse files
committed
Fix missing target features when using xforms
1 parent 9b37613 commit 13c24b3

File tree

6 files changed

+57
-2
lines changed

6 files changed

+57
-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/src/lib.rs

+45-1
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,45 @@ 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+
// Insert reference types to the target features section.
156+
let (_, section) = module
157+
.customs
158+
.iter_mut()
159+
.find(|(_, custom)| custom.name() == "target_features")
160+
.expect("`target_features` section could not be found");
161+
let section: &mut RawCustomSection = section.as_any_mut().downcast_mut().unwrap();
162+
163+
// Try to find if the target feature is already present.
164+
let mut bytes = section.data[1..].iter();
165+
166+
// The first byte contains the target feature count.
167+
for _ in 0..section.data[0] {
168+
// Skip the prefix.
169+
bytes.next().unwrap();
170+
// Read the length of the target feature.
171+
let length = *bytes.next().unwrap();
172+
// Read the feature.
173+
let mut feature = bytes.by_ref().take(length.into());
174+
175+
// If we found the target feature, we are done here.
176+
if let Ordering::Equal = feature.by_ref().cmp(new_feature.as_bytes()) {
177+
return;
178+
}
179+
180+
// If we couldn't find it, consume it so we can advance.
181+
feature.for_each(|_| ());
182+
}
183+
184+
// If we couldn't find the target feature, insert it.
185+
186+
// The first byte contains the target feature count, which we increase by one.
187+
section.data[0] += 1;
188+
// Then we insert the "enabled" prefix at the end.
189+
section.data.push(b'+');
190+
// The next byte contains the length of the target feature string.
191+
section.data.push(new_feature.len() as u8);
192+
// Lastly the target feature string is inserted.
193+
section.data.extend(new_feature.as_bytes());
194+
}

0 commit comments

Comments
 (0)