Skip to content

Commit aca49e1

Browse files
authored
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
1 parent a8882dc commit aca49e1

File tree

2 files changed

+114
-48
lines changed

2 files changed

+114
-48
lines changed

crates/anyref-xform/src/lib.rs

+78-48
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ struct Transform<'a> {
5858
// Indices of items that we have injected or found. This state is maintained
5959
// during the pass execution.
6060
table: TableId,
61-
clone_ref: FunctionId,
62-
heap_alloc: FunctionId,
63-
heap_dealloc: FunctionId,
61+
clone_ref: Option<FunctionId>,
62+
heap_alloc: Option<FunctionId>,
63+
heap_dealloc: Option<FunctionId>,
6464
stack_pointer: GlobalId,
6565
}
6666

@@ -185,33 +185,34 @@ impl Context {
185185
_ => {}
186186
}
187187
}
188-
let heap_alloc = heap_alloc.ok_or_else(|| anyhow!("failed to find heap alloc"))?;
189-
let heap_dealloc = heap_dealloc.ok_or_else(|| anyhow!("failed to find heap dealloc"))?;
190-
191-
// Create a shim function that looks like:
192-
//
193-
// (func __wbindgen_object_clone_ref (param i32) (result i32)
194-
// (local i32)
195-
// (table.set
196-
// (tee_local 1 (call $heap_alloc))
197-
// (table.get (local.get 0)))
198-
// (local.get 1))
199-
let mut builder =
200-
walrus::FunctionBuilder::new(&mut module.types, &[ValType::I32], &[ValType::I32]);
201-
let arg = module.locals.add(ValType::I32);
202-
let local = module.locals.add(ValType::I32);
203-
204-
let mut body = builder.func_body();
205-
body.call(heap_alloc)
206-
.local_tee(local)
207-
.local_get(arg)
208-
.table_get(table)
209-
.table_set(table)
210-
.local_get(local);
211-
212-
let clone_ref = builder.finish(vec![arg], &mut module.funcs);
213-
let name = "__wbindgen_object_clone_ref".to_string();
214-
module.funcs.get_mut(clone_ref).name = Some(name);
188+
let mut clone_ref = None;
189+
if let Some(heap_alloc) = heap_alloc {
190+
// Create a shim function that looks like:
191+
//
192+
// (func __wbindgen_object_clone_ref (param i32) (result i32)
193+
// (local i32)
194+
// (table.set
195+
// (tee_local 1 (call $heap_alloc))
196+
// (table.get (local.get 0)))
197+
// (local.get 1))
198+
let mut builder =
199+
walrus::FunctionBuilder::new(&mut module.types, &[ValType::I32], &[ValType::I32]);
200+
let arg = module.locals.add(ValType::I32);
201+
let local = module.locals.add(ValType::I32);
202+
203+
let mut body = builder.func_body();
204+
body.call(heap_alloc)
205+
.local_tee(local)
206+
.local_get(arg)
207+
.table_get(table)
208+
.table_set(table)
209+
.local_get(local);
210+
211+
let func = builder.finish(vec![arg], &mut module.funcs);
212+
let name = "__wbindgen_object_clone_ref".to_string();
213+
module.funcs.get_mut(func).name = Some(name);
214+
clone_ref = Some(func);
215+
}
215216

216217
// And run the transformation!
217218
Transform {
@@ -236,9 +237,9 @@ impl Transform<'_> {
236237
self.find_intrinsics(module)?;
237238

238239
// Perform transformations of imports, exports, and function pointers.
239-
self.process_imports(module);
240+
self.process_imports(module)?;
240241
assert!(self.cx.imports.is_empty());
241-
self.process_exports(module);
242+
self.process_exports(module)?;
242243
assert!(self.cx.exports.is_empty());
243244
self.process_elements(module)?;
244245
assert!(self.cx.elements.is_empty());
@@ -251,7 +252,7 @@ impl Transform<'_> {
251252

252253
// Perform all instruction transformations to rewrite calls between
253254
// functions and make sure everything is still hooked up right.
254-
self.rewrite_calls(module);
255+
self.rewrite_calls(module)?;
255256

256257
Ok(())
257258
}
@@ -297,7 +298,22 @@ impl Transform<'_> {
297298
Ok(())
298299
}
299300

300-
fn process_imports(&mut self, module: &mut Module) {
301+
fn heap_alloc(&self) -> Result<FunctionId, Error> {
302+
self.heap_alloc
303+
.ok_or_else(|| anyhow!("failed to find the `__wbindgen_anyref_table_alloc` function"))
304+
}
305+
306+
fn clone_ref(&self) -> Result<FunctionId, Error> {
307+
self.clone_ref
308+
.ok_or_else(|| anyhow!("failed to find intrinsics to enable `clone_ref` function"))
309+
}
310+
311+
fn heap_dealloc(&self) -> Result<FunctionId, Error> {
312+
self.heap_dealloc
313+
.ok_or_else(|| anyhow!("failed to find the `__wbindgen_anyref_table_dealloc` function"))
314+
}
315+
316+
fn process_imports(&mut self, module: &mut Module) -> Result<(), Error> {
301317
for import in module.imports.iter_mut() {
302318
let f = match import.kind {
303319
walrus::ImportKind::Function(f) => f,
@@ -315,16 +331,17 @@ impl Transform<'_> {
315331
&mut module.types,
316332
&mut module.funcs,
317333
&mut module.locals,
318-
);
334+
)?;
319335
self.import_map.insert(f, shim);
320336
match &mut module.funcs.get_mut(f).kind {
321337
walrus::FunctionKind::Import(f) => f.ty = anyref_ty,
322338
_ => unreachable!(),
323339
}
324340
}
341+
Ok(())
325342
}
326343

327-
fn process_exports(&mut self, module: &mut Module) {
344+
fn process_exports(&mut self, module: &mut Module) -> Result<(), Error> {
328345
// let mut new_exports = Vec::new();
329346
for export in module.exports.iter_mut() {
330347
let f = match export.item {
@@ -342,9 +359,10 @@ impl Transform<'_> {
342359
&mut module.types,
343360
&mut module.funcs,
344361
&mut module.locals,
345-
);
362+
)?;
346363
export.item = shim.into();
347364
}
365+
Ok(())
348366
}
349367

350368
fn process_elements(&mut self, module: &mut Module) -> Result<(), Error> {
@@ -372,7 +390,7 @@ impl Transform<'_> {
372390
&mut module.types,
373391
&mut module.funcs,
374392
&mut module.locals,
375-
);
393+
)?;
376394
kind.elements.push(Some(shim));
377395
}
378396

@@ -393,7 +411,7 @@ impl Transform<'_> {
393411
types: &mut walrus::ModuleTypes,
394412
funcs: &mut walrus::ModuleFunctions,
395413
locals: &mut walrus::ModuleLocals,
396-
) -> (FunctionId, TypeId) {
414+
) -> Result<(FunctionId, TypeId), Error> {
397415
let target = funcs.get_mut(shim_target);
398416
let (is_export, ty) = match &target.kind {
399417
walrus::FunctionKind::Import(f) => (false, f.ty),
@@ -508,15 +526,15 @@ impl Transform<'_> {
508526
body.local_get(params[i])
509527
.table_get(self.table)
510528
.local_get(params[i])
511-
.call(self.heap_dealloc);
529+
.call(self.heap_dealloc()?);
512530
}
513531
Convert::Load { owned: false } => {
514532
body.local_get(params[i]).table_get(self.table);
515533
}
516534
Convert::Store { owned: true } => {
517535
// Allocate space for the anyref, store it, and then leave
518536
// the index of the allocated anyref on the stack.
519-
body.call(self.heap_alloc)
537+
body.call(self.heap_alloc()?)
520538
.local_tee(scratch_i32)
521539
.local_get(params[i])
522540
.table_set(self.table)
@@ -559,13 +577,13 @@ impl Transform<'_> {
559577
body.local_tee(scratch_i32)
560578
.table_get(self.table)
561579
.local_get(scratch_i32)
562-
.call(self.heap_dealloc);
580+
.call(self.heap_dealloc()?);
563581
} else {
564582
// Imports are the opposite, we have any anyref on the stack
565583
// and convert it to an i32 by allocating space for it and
566584
// storing it there.
567585
body.local_set(scratch_anyref)
568-
.call(self.heap_alloc)
586+
.call(self.heap_alloc()?)
569587
.local_tee(scratch_i32)
570588
.local_get(scratch_anyref)
571589
.table_set(self.table)
@@ -604,20 +622,32 @@ impl Transform<'_> {
604622
let name = format!("{}_anyref_shim", name);
605623
funcs.get_mut(id).name = Some(name);
606624
self.shims.insert(id);
607-
(id, anyref_ty)
625+
Ok((id, anyref_ty))
608626
}
609627

610-
fn rewrite_calls(&mut self, module: &mut Module) {
628+
fn rewrite_calls(&mut self, module: &mut Module) -> Result<(), Error> {
611629
for (id, func) in module.funcs.iter_local_mut() {
612630
if self.shims.contains(&id) {
613631
continue;
614632
}
615633
let entry = func.entry_block();
616-
dfs_pre_order_mut(&mut Rewrite { xform: self }, func, entry);
634+
dfs_pre_order_mut(
635+
&mut Rewrite {
636+
clone_ref: self.clone_ref()?,
637+
heap_dealloc: self.heap_dealloc()?,
638+
xform: self,
639+
},
640+
func,
641+
entry,
642+
);
617643
}
618644

645+
return Ok(());
646+
619647
struct Rewrite<'a, 'b> {
620648
xform: &'a Transform<'b>,
649+
clone_ref: FunctionId,
650+
heap_dealloc: FunctionId,
621651
}
622652

623653
impl VisitorMut for Rewrite<'_, '_> {
@@ -664,8 +694,8 @@ impl Transform<'_> {
664694
seq.instrs
665695
.insert(i, (RefNull {}.into(), InstrLocId::default()));
666696
}
667-
Intrinsic::DropRef => call.func = self.xform.heap_dealloc,
668-
Intrinsic::CloneRef => call.func = self.xform.clone_ref,
697+
Intrinsic::DropRef => call.func = self.heap_dealloc,
698+
Intrinsic::CloneRef => call.func = self.clone_ref,
669699
}
670700
}
671701
}

crates/cli/tests/wasm-bindgen/main.rs

+36
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,39 @@ fn bin_crate_works() {
197197
.success()
198198
.stdout("hello, world\n");
199199
}
200+
201+
#[test]
202+
fn empty_interface_types() {
203+
let (mut cmd, _out_dir) = Project::new("empty_interface_types")
204+
.file(
205+
"src/lib.rs",
206+
r#"
207+
#[no_mangle]
208+
pub extern fn foo() {}
209+
"#
210+
)
211+
.file(
212+
"Cargo.toml",
213+
&format!(
214+
"
215+
[package]
216+
name = \"empty_interface_types\"
217+
authors = []
218+
version = \"1.0.0\"
219+
edition = '2018'
220+
221+
[dependencies]
222+
wasm-bindgen = {{ path = '{}' }}
223+
224+
[lib]
225+
crate-type = ['cdylib']
226+
227+
[workspace]
228+
",
229+
repo_root().display(),
230+
),
231+
)
232+
.wasm_bindgen("");
233+
cmd.env("WASM_INTERFACE_TYPES", "1");
234+
cmd.assert().success();
235+
}

0 commit comments

Comments
 (0)