Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable transformations when detecting target features #4133

Merged
merged 1 commit into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
* Added bindings for the draft [WebRTC Encoded Transform](https://www.w3.org/TR/webrtc-encoded-transform) spec.
[#4125](https://github.com/rustwasm/wasm-bindgen/pull/4125)

### Changed

* Implicitly enable reference type and multivalue transformations if the module already makes use of the corresponding target features.
[#4133](https://github.com/rustwasm/wasm-bindgen/pull/4133)

### Fixed

* Fixed linked modules emitting snippet files when not using `--split-linked-modules`.
Expand Down
11 changes: 11 additions & 0 deletions crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,17 @@ impl Bindgen {
.context("failed getting Wasm module")?,
};

// Enable reference type transformations if the module is already using it.
if let Ok(true) = wasm_bindgen_wasm_conventions::target_feature(&module, "reference-types")
{
self.externref = true;
}

// Enable multivalue transformations if the module is already using it.
if let Ok(true) = wasm_bindgen_wasm_conventions::target_feature(&module, "multivalue") {
self.multi_value = true;
}

// Check that no exported symbol is called "default" if we target web.
if matches!(self.mode, OutputMode::Web)
&& module.exports.iter().any(|export| export.name == "default")
Expand Down
44 changes: 44 additions & 0 deletions crates/wasm-conventions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,50 @@ pub fn get_or_insert_start_builder(module: &mut Module) -> &mut FunctionBuilder
.builder_mut()
}

pub fn target_feature(module: &Module, feature: &str) -> Result<bool> {
// Taken from <https://github.com/bytecodealliance/wasm-tools/blob/f1898f46bb9d96f0f09682415cb6ccfd6a4dca79/crates/wasmparser/src/limits.rs#L27>.
anyhow::ensure!(feature.len() <= 100_000, "feature name too long");

// Try to find an existing section.
let section = module
.customs
.iter()
.find(|(_, custom)| custom.name() == "target_features");

if let Some((_, section)) = section {
let section: &RawCustomSection = section
.as_any()
.downcast_ref()
.context("failed to read section")?;
let mut reader = BinaryReader::new(&section.data, 0, WasmFeatures::default());
// The first integer contains the target feature count.
let count = reader.read_var_u32()?;

// Try to find if the target feature is already present.
for _ in 0..count {
// First byte is the prefix.
let prefix = reader.read_u8()?;
// Read the feature.
let length = reader.read_var_u32()?;
let this_feature = reader.read_bytes(length as usize)?;

// If we found the target feature, we are done here.
if this_feature == feature.as_bytes() {
// Make sure we set any existing prefix to "enabled".
if prefix == b'-' {
return Ok(false);
}

return Ok(true);
}
}

Ok(false)
} else {
Ok(false)
}
}

pub fn insert_target_feature(module: &mut Module, new_feature: &str) -> Result<()> {
// Taken from <https://github.com/bytecodealliance/wasm-tools/blob/f1898f46bb9d96f0f09682415cb6ccfd6a4dca79/crates/wasmparser/src/limits.rs#L27>.
anyhow::ensure!(new_feature.len() <= 100_000, "feature name too long");
Expand Down