Skip to content

Commit

Permalink
Fix missing target features when using xforms
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed May 22, 2024
1 parent 9b37613 commit 7ae0b53
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 2 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@
* Fix MSRV compilation.
[#3927](https://github.com/rustwasm/wasm-bindgen/pull/3927)

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

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

--------------------------------------------------------------------------------

## [0.2.92](https://github.com/rustwasm/wasm-bindgen/compare/0.2.91...0.2.92)
Expand Down
1 change: 1 addition & 0 deletions crates/externref-xform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rust-version = "1.57"
[dependencies]
anyhow = "1.0"
walrus = "0.20.2"
wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "=0.2.92" }

[dev-dependencies]
rayon = "1.0"
Expand Down
3 changes: 3 additions & 0 deletions crates/externref-xform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ impl Context {
/// large the function table is so we know what indexes to hand out when
/// we're appending entries.
pub fn prepare(&mut self, module: &mut Module) -> Result<(), Error> {
// Insert reference types to the target features section.
wasm_bindgen_wasm_conventions::insert_target_feature(module, "reference-types");

// Figure out what the maximum index of functions pointers are. We'll
// be adding new entries to the function table later (maybe) so
// precalculate this ahead of time.
Expand Down
1 change: 1 addition & 0 deletions crates/multi-value-xform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rust-version = "1.57"
[dependencies]
anyhow = "1.0"
walrus = "0.20.2"
wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "=0.2.92" }

[dev-dependencies]
rayon = "1.0"
Expand Down
3 changes: 3 additions & 0 deletions crates/multi-value-xform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ pub fn run(
shadow_stack_pointer: walrus::GlobalId,
to_xform: &[(walrus::FunctionId, usize, Vec<walrus::ValType>)],
) -> Result<Vec<walrus::FunctionId>, anyhow::Error> {
// Insert multi-value to the target features section.
wasm_bindgen_wasm_conventions::insert_target_feature(module, "multivalue");

let mut wrappers = Vec::new();
for (func, return_pointer_index, results) in to_xform {
wrappers.push(xform_one(
Expand Down
65 changes: 64 additions & 1 deletion crates/wasm-conventions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
//! * The shadow stack pointer
//! * The canonical linear memory that contains the shadow stack
use std::cmp::Ordering;

use anyhow::{anyhow, bail, Result};
use walrus::{
ir::Value, ElementId, FunctionBuilder, FunctionId, FunctionKind, GlobalId, GlobalKind,
InitExpr, MemoryId, Module, ValType,
InitExpr, MemoryId, Module, RawCustomSection, ValType,
};

/// Get a Wasm module's canonical linear memory.
Expand Down Expand Up @@ -148,3 +150,64 @@ pub fn get_or_insert_start_builder(module: &mut Module) -> &mut FunctionBuilder
.unwrap_local_mut()
.builder_mut()
}

pub fn insert_target_feature(module: &mut Module, new_feature: &str) {
// Try to find an existing section.
let section = module
.customs
.iter_mut()
.find(|(_, custom)| custom.name() == "target_features");

// If one exists, check if the target feature is already present.
let section = if let Some((_, section)) = section {
let section: &mut RawCustomSection = section.as_any_mut().downcast_mut().unwrap();
// The first byte contains the target feature count.
let count = section.data[0];

// Try to find if the target feature is already present.
if count != 0 {
let mut bytes = section.data[1..].iter_mut();

for _ in 0..count {
// First byte is the prefix.
let prefix = bytes.next().unwrap();
// Read the length of the target feature.
let length = *bytes.next().unwrap();
// Read the feature.
let mut feature = bytes.by_ref().take(length.into());

// If we found the target feature, we are done here.
if let Ordering::Equal = feature.by_ref().map(|b| &*b).cmp(new_feature.as_bytes()) {
// Make sure we set any existing prefix to "enabled".
if *prefix == b'-' {
*prefix = b'+';
}

return;
}

// If we couldn't find it, consume it so we can advance.
feature.for_each(|_| ());
}
}

section
} else {
let id = module.customs.add(RawCustomSection {
name: String::from("target_features"),
data: vec![0],
});
module.customs.get_mut(id).unwrap()
};

// If we couldn't find the target feature, insert it.

// The first byte contains the target feature count, which we increase by one.
section.data[0] += 1;
// Then we insert the "enabled" prefix at the end.
section.data.push(b'+');
// The next byte contains the length of the target feature string.
section.data.push(new_feature.len() as u8);
// Lastly the target feature string is inserted.
section.data.extend(new_feature.as_bytes());
}

0 comments on commit 7ae0b53

Please sign in to comment.