mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-26 14:32:12 +00:00
Fix the anyref xform working on empty modules (#1861)
If there's no need for a transformation then there's no need to inject anything, so make sure that wasm-bindgen with anyref passes enabled works on non-wasm-bindgen blobs as well. Closes bytecodealliance/cargo-wasi#16
This commit is contained in:
parent
a8882dc3a6
commit
aca49e1a6e
@ -58,9 +58,9 @@ struct Transform<'a> {
|
|||||||
// Indices of items that we have injected or found. This state is maintained
|
// Indices of items that we have injected or found. This state is maintained
|
||||||
// during the pass execution.
|
// during the pass execution.
|
||||||
table: TableId,
|
table: TableId,
|
||||||
clone_ref: FunctionId,
|
clone_ref: Option<FunctionId>,
|
||||||
heap_alloc: FunctionId,
|
heap_alloc: Option<FunctionId>,
|
||||||
heap_dealloc: FunctionId,
|
heap_dealloc: Option<FunctionId>,
|
||||||
stack_pointer: GlobalId,
|
stack_pointer: GlobalId,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,9 +185,8 @@ impl Context {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let heap_alloc = heap_alloc.ok_or_else(|| anyhow!("failed to find heap alloc"))?;
|
let mut clone_ref = None;
|
||||||
let heap_dealloc = heap_dealloc.ok_or_else(|| anyhow!("failed to find heap dealloc"))?;
|
if let Some(heap_alloc) = heap_alloc {
|
||||||
|
|
||||||
// Create a shim function that looks like:
|
// Create a shim function that looks like:
|
||||||
//
|
//
|
||||||
// (func __wbindgen_object_clone_ref (param i32) (result i32)
|
// (func __wbindgen_object_clone_ref (param i32) (result i32)
|
||||||
@ -209,9 +208,11 @@ impl Context {
|
|||||||
.table_set(table)
|
.table_set(table)
|
||||||
.local_get(local);
|
.local_get(local);
|
||||||
|
|
||||||
let clone_ref = builder.finish(vec![arg], &mut module.funcs);
|
let func = builder.finish(vec![arg], &mut module.funcs);
|
||||||
let name = "__wbindgen_object_clone_ref".to_string();
|
let name = "__wbindgen_object_clone_ref".to_string();
|
||||||
module.funcs.get_mut(clone_ref).name = Some(name);
|
module.funcs.get_mut(func).name = Some(name);
|
||||||
|
clone_ref = Some(func);
|
||||||
|
}
|
||||||
|
|
||||||
// And run the transformation!
|
// And run the transformation!
|
||||||
Transform {
|
Transform {
|
||||||
@ -236,9 +237,9 @@ impl Transform<'_> {
|
|||||||
self.find_intrinsics(module)?;
|
self.find_intrinsics(module)?;
|
||||||
|
|
||||||
// Perform transformations of imports, exports, and function pointers.
|
// Perform transformations of imports, exports, and function pointers.
|
||||||
self.process_imports(module);
|
self.process_imports(module)?;
|
||||||
assert!(self.cx.imports.is_empty());
|
assert!(self.cx.imports.is_empty());
|
||||||
self.process_exports(module);
|
self.process_exports(module)?;
|
||||||
assert!(self.cx.exports.is_empty());
|
assert!(self.cx.exports.is_empty());
|
||||||
self.process_elements(module)?;
|
self.process_elements(module)?;
|
||||||
assert!(self.cx.elements.is_empty());
|
assert!(self.cx.elements.is_empty());
|
||||||
@ -251,7 +252,7 @@ impl Transform<'_> {
|
|||||||
|
|
||||||
// Perform all instruction transformations to rewrite calls between
|
// Perform all instruction transformations to rewrite calls between
|
||||||
// functions and make sure everything is still hooked up right.
|
// functions and make sure everything is still hooked up right.
|
||||||
self.rewrite_calls(module);
|
self.rewrite_calls(module)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -297,7 +298,22 @@ impl Transform<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_imports(&mut self, module: &mut Module) {
|
fn heap_alloc(&self) -> Result<FunctionId, Error> {
|
||||||
|
self.heap_alloc
|
||||||
|
.ok_or_else(|| anyhow!("failed to find the `__wbindgen_anyref_table_alloc` function"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_ref(&self) -> Result<FunctionId, Error> {
|
||||||
|
self.clone_ref
|
||||||
|
.ok_or_else(|| anyhow!("failed to find intrinsics to enable `clone_ref` function"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn heap_dealloc(&self) -> Result<FunctionId, Error> {
|
||||||
|
self.heap_dealloc
|
||||||
|
.ok_or_else(|| anyhow!("failed to find the `__wbindgen_anyref_table_dealloc` function"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_imports(&mut self, module: &mut Module) -> Result<(), Error> {
|
||||||
for import in module.imports.iter_mut() {
|
for import in module.imports.iter_mut() {
|
||||||
let f = match import.kind {
|
let f = match import.kind {
|
||||||
walrus::ImportKind::Function(f) => f,
|
walrus::ImportKind::Function(f) => f,
|
||||||
@ -315,16 +331,17 @@ impl Transform<'_> {
|
|||||||
&mut module.types,
|
&mut module.types,
|
||||||
&mut module.funcs,
|
&mut module.funcs,
|
||||||
&mut module.locals,
|
&mut module.locals,
|
||||||
);
|
)?;
|
||||||
self.import_map.insert(f, shim);
|
self.import_map.insert(f, shim);
|
||||||
match &mut module.funcs.get_mut(f).kind {
|
match &mut module.funcs.get_mut(f).kind {
|
||||||
walrus::FunctionKind::Import(f) => f.ty = anyref_ty,
|
walrus::FunctionKind::Import(f) => f.ty = anyref_ty,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_exports(&mut self, module: &mut Module) {
|
fn process_exports(&mut self, module: &mut Module) -> Result<(), Error> {
|
||||||
// let mut new_exports = Vec::new();
|
// let mut new_exports = Vec::new();
|
||||||
for export in module.exports.iter_mut() {
|
for export in module.exports.iter_mut() {
|
||||||
let f = match export.item {
|
let f = match export.item {
|
||||||
@ -342,9 +359,10 @@ impl Transform<'_> {
|
|||||||
&mut module.types,
|
&mut module.types,
|
||||||
&mut module.funcs,
|
&mut module.funcs,
|
||||||
&mut module.locals,
|
&mut module.locals,
|
||||||
);
|
)?;
|
||||||
export.item = shim.into();
|
export.item = shim.into();
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_elements(&mut self, module: &mut Module) -> Result<(), Error> {
|
fn process_elements(&mut self, module: &mut Module) -> Result<(), Error> {
|
||||||
@ -372,7 +390,7 @@ impl Transform<'_> {
|
|||||||
&mut module.types,
|
&mut module.types,
|
||||||
&mut module.funcs,
|
&mut module.funcs,
|
||||||
&mut module.locals,
|
&mut module.locals,
|
||||||
);
|
)?;
|
||||||
kind.elements.push(Some(shim));
|
kind.elements.push(Some(shim));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +411,7 @@ impl Transform<'_> {
|
|||||||
types: &mut walrus::ModuleTypes,
|
types: &mut walrus::ModuleTypes,
|
||||||
funcs: &mut walrus::ModuleFunctions,
|
funcs: &mut walrus::ModuleFunctions,
|
||||||
locals: &mut walrus::ModuleLocals,
|
locals: &mut walrus::ModuleLocals,
|
||||||
) -> (FunctionId, TypeId) {
|
) -> Result<(FunctionId, TypeId), Error> {
|
||||||
let target = funcs.get_mut(shim_target);
|
let target = funcs.get_mut(shim_target);
|
||||||
let (is_export, ty) = match &target.kind {
|
let (is_export, ty) = match &target.kind {
|
||||||
walrus::FunctionKind::Import(f) => (false, f.ty),
|
walrus::FunctionKind::Import(f) => (false, f.ty),
|
||||||
@ -508,7 +526,7 @@ impl Transform<'_> {
|
|||||||
body.local_get(params[i])
|
body.local_get(params[i])
|
||||||
.table_get(self.table)
|
.table_get(self.table)
|
||||||
.local_get(params[i])
|
.local_get(params[i])
|
||||||
.call(self.heap_dealloc);
|
.call(self.heap_dealloc()?);
|
||||||
}
|
}
|
||||||
Convert::Load { owned: false } => {
|
Convert::Load { owned: false } => {
|
||||||
body.local_get(params[i]).table_get(self.table);
|
body.local_get(params[i]).table_get(self.table);
|
||||||
@ -516,7 +534,7 @@ impl Transform<'_> {
|
|||||||
Convert::Store { owned: true } => {
|
Convert::Store { owned: true } => {
|
||||||
// Allocate space for the anyref, store it, and then leave
|
// Allocate space for the anyref, store it, and then leave
|
||||||
// the index of the allocated anyref on the stack.
|
// the index of the allocated anyref on the stack.
|
||||||
body.call(self.heap_alloc)
|
body.call(self.heap_alloc()?)
|
||||||
.local_tee(scratch_i32)
|
.local_tee(scratch_i32)
|
||||||
.local_get(params[i])
|
.local_get(params[i])
|
||||||
.table_set(self.table)
|
.table_set(self.table)
|
||||||
@ -559,13 +577,13 @@ impl Transform<'_> {
|
|||||||
body.local_tee(scratch_i32)
|
body.local_tee(scratch_i32)
|
||||||
.table_get(self.table)
|
.table_get(self.table)
|
||||||
.local_get(scratch_i32)
|
.local_get(scratch_i32)
|
||||||
.call(self.heap_dealloc);
|
.call(self.heap_dealloc()?);
|
||||||
} else {
|
} else {
|
||||||
// Imports are the opposite, we have any anyref on the stack
|
// Imports are the opposite, we have any anyref on the stack
|
||||||
// and convert it to an i32 by allocating space for it and
|
// and convert it to an i32 by allocating space for it and
|
||||||
// storing it there.
|
// storing it there.
|
||||||
body.local_set(scratch_anyref)
|
body.local_set(scratch_anyref)
|
||||||
.call(self.heap_alloc)
|
.call(self.heap_alloc()?)
|
||||||
.local_tee(scratch_i32)
|
.local_tee(scratch_i32)
|
||||||
.local_get(scratch_anyref)
|
.local_get(scratch_anyref)
|
||||||
.table_set(self.table)
|
.table_set(self.table)
|
||||||
@ -604,20 +622,32 @@ impl Transform<'_> {
|
|||||||
let name = format!("{}_anyref_shim", name);
|
let name = format!("{}_anyref_shim", name);
|
||||||
funcs.get_mut(id).name = Some(name);
|
funcs.get_mut(id).name = Some(name);
|
||||||
self.shims.insert(id);
|
self.shims.insert(id);
|
||||||
(id, anyref_ty)
|
Ok((id, anyref_ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rewrite_calls(&mut self, module: &mut Module) {
|
fn rewrite_calls(&mut self, module: &mut Module) -> Result<(), Error> {
|
||||||
for (id, func) in module.funcs.iter_local_mut() {
|
for (id, func) in module.funcs.iter_local_mut() {
|
||||||
if self.shims.contains(&id) {
|
if self.shims.contains(&id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let entry = func.entry_block();
|
let entry = func.entry_block();
|
||||||
dfs_pre_order_mut(&mut Rewrite { xform: self }, func, entry);
|
dfs_pre_order_mut(
|
||||||
|
&mut Rewrite {
|
||||||
|
clone_ref: self.clone_ref()?,
|
||||||
|
heap_dealloc: self.heap_dealloc()?,
|
||||||
|
xform: self,
|
||||||
|
},
|
||||||
|
func,
|
||||||
|
entry,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
|
||||||
struct Rewrite<'a, 'b> {
|
struct Rewrite<'a, 'b> {
|
||||||
xform: &'a Transform<'b>,
|
xform: &'a Transform<'b>,
|
||||||
|
clone_ref: FunctionId,
|
||||||
|
heap_dealloc: FunctionId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VisitorMut for Rewrite<'_, '_> {
|
impl VisitorMut for Rewrite<'_, '_> {
|
||||||
@ -664,8 +694,8 @@ impl Transform<'_> {
|
|||||||
seq.instrs
|
seq.instrs
|
||||||
.insert(i, (RefNull {}.into(), InstrLocId::default()));
|
.insert(i, (RefNull {}.into(), InstrLocId::default()));
|
||||||
}
|
}
|
||||||
Intrinsic::DropRef => call.func = self.xform.heap_dealloc,
|
Intrinsic::DropRef => call.func = self.heap_dealloc,
|
||||||
Intrinsic::CloneRef => call.func = self.xform.clone_ref,
|
Intrinsic::CloneRef => call.func = self.clone_ref,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,3 +197,39 @@ fn bin_crate_works() {
|
|||||||
.success()
|
.success()
|
||||||
.stdout("hello, world\n");
|
.stdout("hello, world\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_interface_types() {
|
||||||
|
let (mut cmd, _out_dir) = Project::new("empty_interface_types")
|
||||||
|
.file(
|
||||||
|
"src/lib.rs",
|
||||||
|
r#"
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn foo() {}
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
&format!(
|
||||||
|
"
|
||||||
|
[package]
|
||||||
|
name = \"empty_interface_types\"
|
||||||
|
authors = []
|
||||||
|
version = \"1.0.0\"
|
||||||
|
edition = '2018'
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
wasm-bindgen = {{ path = '{}' }}
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ['cdylib']
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
",
|
||||||
|
repo_root().display(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.wasm_bindgen("");
|
||||||
|
cmd.env("WASM_INTERFACE_TYPES", "1");
|
||||||
|
cmd.assert().success();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user