From b8996eb0a35c5513871b7722c0222f3a200d3663 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 Apr 2022 11:33:06 -0700 Subject: [PATCH 1/2] Change the ABI for multi-value returns This commit aligns the implementation of wit-bindgen to the current draft of the canonical ABI to have multi-value returns expressed via pointers to the in-memory canonical ABI rather than the prior pointers-to-the-lowered-values-in-memory ABI. Due to the structure of wit-bindgen this ended up being a relatively simple change where the lowered instructions generators are using were already almost all appropriate. Mostly the parser ABI implementation changed here along with some fiddly bits in `wasmlink`. --- crates/gen-c/src/lib.rs | 32 ++- crates/gen-js/src/lib.rs | 2 +- crates/gen-rust-wasm/src/lib.rs | 35 ++- crates/gen-spidermonkey/src/lib.rs | 100 ++++---- crates/gen-wasmtime-py/src/lib.rs | 2 +- crates/gen-wasmtime/src/lib.rs | 2 +- crates/parser/src/abi.rs | 204 +++++++-------- crates/wasmlink/src/adapter/call.rs | 62 ++--- crates/wasmlink/src/module.rs | 2 +- crates/wasmlink/tests/lists.baseline | 234 +++++++---------- crates/wasmlink/tests/records.baseline | 52 +--- crates/wasmlink/tests/resources.baseline | 46 ++-- crates/wasmlink/tests/retptr.baseline | 8 +- crates/wasmlink/tests/string.baseline | 14 +- crates/wasmlink/tests/variants.baseline | 240 +++--------------- crates/wit-component/src/encoding.rs | 2 +- .../components/lower-options/component.wat | 8 +- 17 files changed, 372 insertions(+), 673 deletions(-) diff --git a/crates/gen-c/src/lib.rs b/crates/gen-c/src/lib.rs index 4a8bf1a21..bdb785c5d 100644 --- a/crates/gen-c/src/lib.rs +++ b/crates/gen-c/src/lib.rs @@ -12,7 +12,8 @@ pub struct C { in_import: bool, opts: Opts, funcs: HashMap>, - i64_return_pointer_area_size: usize, + return_pointer_area_size: usize, + return_pointer_area_align: usize, sizes: SizeAlign, names: Ns, @@ -658,9 +659,13 @@ impl Generator for C { for func in iface.functions.iter() { let sig = iface.wasm_signature(variant, func); - if let Some(results) = sig.retptr { - self.i64_return_pointer_area_size = - self.i64_return_pointer_area_size.max(results.len()); + if sig.retptr { + self.return_pointer_area_size = self + .return_pointer_area_size + .max(self.sizes.size(&func.result)); + self.return_pointer_area_align = self + .return_pointer_area_align + .max(self.sizes.align(&func.result)); } } } @@ -1133,10 +1138,13 @@ impl Generator for C { } } - if self.i64_return_pointer_area_size > 0 { + if self.return_pointer_area_size > 0 { self.src.c(&format!( - "static int64_t RET_AREA[{}];\n", - self.i64_return_pointer_area_size, + " + __attribute__((aligned({}))) + static uint8_t RET_AREA[{}]; + ", + self.return_pointer_area_align, self.return_pointer_area_size, )); } @@ -1254,8 +1262,7 @@ impl Bindgen for FunctionBindgen<'_> { self.blocks.push((src.into(), mem::take(operands))); } - fn i64_return_pointer_area(&mut self, amt: usize) -> String { - assert!(amt <= self.gen.i64_return_pointer_area_size); + fn return_pointer(&mut self, _iface: &Interface, _ty: &Type) -> String { let ptr = self.locals.tmp("ptr"); self.src .push_str(&format!("int32_t {} = (int32_t) &RET_AREA;\n", ptr)); @@ -1761,6 +1768,8 @@ impl Bindgen for FunctionBindgen<'_> { Instruction::I64Store { offset } => self.store("int64_t", *offset, operands), Instruction::F32Store { offset } => self.store("float", *offset, operands), Instruction::F64Store { offset } => self.store("double", *offset, operands), + Instruction::I32Store8 { offset } => self.store("int8_t", *offset, operands), + Instruction::I32Store16 { offset } => self.store("int16_t", *offset, operands), Instruction::I32Load8U { offset } => { self.load_ext("uint8_t", *offset, operands, results) @@ -1775,11 +1784,6 @@ impl Bindgen for FunctionBindgen<'_> { self.load_ext("int16_t", *offset, operands, results) } - Instruction::I32Store8 { offset } | Instruction::I32Store16 { offset } => { - drop(offset); - self.src.push_str("INVALIDSTORE"); - } - i => unimplemented!("{:?}", i), } } diff --git a/crates/gen-js/src/lib.rs b/crates/gen-js/src/lib.rs index 1d164191f..55776bfde 100644 --- a/crates/gen-js/src/lib.rs +++ b/crates/gen-js/src/lib.rs @@ -1158,7 +1158,7 @@ impl Bindgen for FunctionBindgen<'_> { self.blocks.push((src.into(), mem::take(operands))); } - fn i64_return_pointer_area(&mut self, _amt: usize) -> String { + fn return_pointer(&mut self, _iface: &Interface, _ty: &Type) -> String { unimplemented!() } diff --git a/crates/gen-rust-wasm/src/lib.rs b/crates/gen-rust-wasm/src/lib.rs index a119ece17..0b7ce8bde 100644 --- a/crates/gen-rust-wasm/src/lib.rs +++ b/crates/gen-rust-wasm/src/lib.rs @@ -20,7 +20,8 @@ pub struct RustWasm { traits: BTreeMap, in_trait: bool, trait_name: String, - i64_return_pointer_area_size: usize, + return_pointer_area_size: usize, + return_pointer_area_align: usize, sizes: SizeAlign, } @@ -157,14 +158,19 @@ impl Generator for RustWasm { .push_str(&format!("use {} as wit_bindgen_rust;\n", alias)); } + self.sizes.fill(iface); + for func in iface.functions.iter() { let sig = iface.wasm_signature(variant, func); - if let Some(results) = sig.retptr { - self.i64_return_pointer_area_size = - self.i64_return_pointer_area_size.max(results.len()); + if sig.retptr { + self.return_pointer_area_size = self + .return_pointer_area_size + .max(self.sizes.size(&func.result)); + self.return_pointer_area_align = self + .return_pointer_area_align + .max(self.sizes.align(&func.result)); } } - self.sizes.fill(iface); } fn type_record( @@ -605,10 +611,15 @@ impl Generator for RustWasm { } } - if self.i64_return_pointer_area_size > 0 { + if self.return_pointer_area_align > 0 { src.push_str(&format!( - "static mut RET_AREA: [i64; {0}] = [0; {0}];\n", - self.i64_return_pointer_area_size, + " + #[repr(align({align}))] + struct RetArea([u8; {size}]); + static mut RET_AREA: RetArea = RetArea([0; {size}]); + ", + align = self.return_pointer_area_align, + size = self.return_pointer_area_size, )); } @@ -780,10 +791,12 @@ impl Bindgen for FunctionBindgen<'_> { } } - fn i64_return_pointer_area(&mut self, amt: usize) -> String { - assert!(amt <= self.gen.i64_return_pointer_area_size); + fn return_pointer(&mut self, _iface: &Interface, _ty: &Type) -> String { let tmp = self.tmp(); - self.push_str(&format!("let ptr{} = RET_AREA.as_mut_ptr() as i32;\n", tmp)); + self.push_str(&format!( + "let ptr{} = RET_AREA.0.as_mut_ptr() as i32;\n", + tmp + )); format!("ptr{}", tmp) } diff --git a/crates/gen-spidermonkey/src/lib.rs b/crates/gen-spidermonkey/src/lib.rs index 63b70d8ec..13b1acf31 100644 --- a/crates/gen-spidermonkey/src/lib.rs +++ b/crates/gen-spidermonkey/src/lib.rs @@ -48,7 +48,7 @@ lazy_static! { WasmSignature { params: vec![], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -56,7 +56,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -64,7 +64,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32, WasmType::I32, WasmType::I32], results: vec![WasmType::I32], - retptr: None, + retptr: false, }, ), ( @@ -72,7 +72,7 @@ lazy_static! { WasmSignature { params: vec![], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -80,7 +80,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32], results: vec![WasmType::I32], - retptr: None, + retptr: false, }, ), ( @@ -88,7 +88,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32, WasmType::I32, WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -96,7 +96,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -104,7 +104,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -112,7 +112,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32], results: vec![WasmType::I32], - retptr: None, + retptr: false, }, ), ( @@ -120,7 +120,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, } ), ( @@ -128,7 +128,7 @@ lazy_static! { WasmSignature { params: vec![], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -136,7 +136,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -144,7 +144,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32, WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -152,7 +152,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -160,7 +160,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -168,7 +168,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32], results: vec![WasmType::I32], - retptr: None, + retptr: false, }, ), ( @@ -176,7 +176,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -184,7 +184,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -192,7 +192,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -200,7 +200,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32], results: vec![WasmType::I32], - retptr: None, + retptr: false, }, ), ( @@ -208,7 +208,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -216,7 +216,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32, WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -224,7 +224,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32], results: vec![], - retptr: None, + retptr: false, }, ), ( @@ -232,7 +232,7 @@ lazy_static! { WasmSignature { params: vec![WasmType::I32], results: vec![WasmType::I32], - retptr: None, + retptr: false, }, ), ]; @@ -324,7 +324,8 @@ pub struct SpiderMonkeyWasm<'a> { /// The JS source code. js: Cow<'a, str>, - i64_return_pointer_area_size: usize, + return_pointer_area_size: usize, + return_pointer_area_align: usize, num_import_functions: Option, num_export_functions: Option, @@ -371,7 +372,8 @@ impl<'a> SpiderMonkeyWasm<'a> { SpiderMonkeyWasm { js_name, js, - i64_return_pointer_area_size: 0, + return_pointer_area_size: 0, + return_pointer_area_align: 0, num_import_functions: None, num_export_functions: None, import_spidermonkey: false, @@ -582,7 +584,7 @@ impl<'a> SpiderMonkeyWasm<'a> { let ty_index = self.intern_type(WasmSignature { params: vec![], results: vec![], - retptr: None, + retptr: false, }); funcs.function(ty_index); @@ -623,16 +625,20 @@ impl<'a> SpiderMonkeyWasm<'a> { // Allocate space in the `spidermonkey.wasm` memory for the return // pointer area and save it to the return pointer global. - self.malloc_static_size( - &mut wizer_init, - u32::try_from(self.i64_return_pointer_area_size).unwrap(), - ret_ptr_local, - ); - // [] - wizer_init.instruction(&Instruction::LocalGet(ret_ptr_local)); - // [i32] - wizer_init.instruction(&Instruction::GlobalSet(RET_PTR_GLOBAL)); - // [] + // + // TODO: handle `self.return_pointer_area_align` here + if self.return_pointer_area_size > 0 { + self.malloc_static_size( + &mut wizer_init, + u32::try_from(self.return_pointer_area_size).unwrap(), + ret_ptr_local, + ); + // [] + wizer_init.instruction(&Instruction::LocalGet(ret_ptr_local)); + // [i32] + wizer_init.instruction(&Instruction::GlobalSet(RET_PTR_GLOBAL)); + // [] + } // Call `SMW_initialize_engine`: // @@ -913,11 +919,16 @@ impl Generator for SpiderMonkeyWasm<'_> { .zip(std::iter::repeat(AbiVariant::GuestExport)), ) { + self.sizes.fill(iface); for func in iface.functions.iter() { let sig = iface.wasm_signature(variant, func); - if let Some(results) = sig.retptr { - self.i64_return_pointer_area_size = - self.i64_return_pointer_area_size.max(results.len()); + if sig.retptr { + self.return_pointer_area_size = self + .return_pointer_area_size + .max(self.sizes.size(&func.result)); + self.return_pointer_area_align = self + .return_pointer_area_align + .max(self.sizes.align(&func.result)); } } } @@ -1089,7 +1100,7 @@ impl Generator for SpiderMonkeyWasm<'_> { // bool WasmType::I32, ], - retptr: None, + retptr: false, }); for f in &self.import_glue_fns { funcs.function(js_native_type_index); @@ -1527,8 +1538,8 @@ impl abi::Bindgen for Bindgen<'_, '_> { // Make sure our return pointer area can hold at least two // `u32`s, since we will use it that way with // `SMW_{list,string}_canon_lower`. - self.gen.i64_return_pointer_area_size = - self.gen.i64_return_pointer_area_size.max(1); + self.gen.return_pointer_area_size = self.gen.return_pointer_area_size.max(1); + self.gen.return_pointer_area_align = self.gen.return_pointer_area_align.max(4); // [] self.inst(Instruction::GlobalGet(RET_PTR_GLOBAL)); @@ -2110,8 +2121,7 @@ impl abi::Bindgen for Bindgen<'_, '_> { } } - fn i64_return_pointer_area(&mut self, amt: usize) -> Self::Operand { - assert!(amt <= self.gen.i64_return_pointer_area_size); + fn return_pointer(&mut self, _iface: &Interface, _ty: &Type) -> Self::Operand { let local = self.new_local(wasm_encoder::ValType::I32); // [] diff --git a/crates/gen-wasmtime-py/src/lib.rs b/crates/gen-wasmtime-py/src/lib.rs index 785759877..f8c1879b8 100644 --- a/crates/gen-wasmtime-py/src/lib.rs +++ b/crates/gen-wasmtime-py/src/lib.rs @@ -1303,7 +1303,7 @@ impl Bindgen for FunctionBindgen<'_> { self.blocks.push((src.into(), mem::take(operands))); } - fn i64_return_pointer_area(&mut self, _amt: usize) -> String { + fn return_pointer(&mut self, _iface: &Interface, _ty: &Type) -> String { unimplemented!() } diff --git a/crates/gen-wasmtime/src/lib.rs b/crates/gen-wasmtime/src/lib.rs index 651b17ec9..22036fa16 100644 --- a/crates/gen-wasmtime/src/lib.rs +++ b/crates/gen-wasmtime/src/lib.rs @@ -1374,7 +1374,7 @@ impl Bindgen for FunctionBindgen<'_> { self.caller_memory_available = false; } - fn i64_return_pointer_area(&mut self, _amt: usize) -> String { + fn return_pointer(&mut self, _iface: &Interface, _ty: &Type) -> String { unimplemented!() } diff --git a/crates/parser/src/abi.rs b/crates/parser/src/abi.rs index 6cb5a7b93..f42fa2562 100644 --- a/crates/parser/src/abi.rs +++ b/crates/parser/src/abi.rs @@ -10,9 +10,8 @@ pub struct WasmSignature { pub params: Vec, /// The WebAssembly results of this function. pub results: Vec, - /// The raw types, if needed, returned through return pointer located in - /// `params`. - pub retptr: Option>, + /// TODO + pub retptr: bool, } /// Enumerates wasm types used by interface types when lowering/lifting. @@ -745,15 +744,8 @@ pub trait Bindgen { results: &mut Vec, ); - /// Allocates temporary space in linear memory for a fixed number of `i64` - /// values. - /// - /// This is only called when a function would otherwise have multiple - /// results. - /// - /// Returns an `Operand` which has type `i32` and points to the base of the - /// fixed-size-array allocation. - fn i64_return_pointer_area(&mut self, amt: usize) -> Self::Operand; + /// TODO + fn return_pointer(&mut self, iface: &Interface, ty: &Type) -> Self::Operand; /// Enters a new block of code to generate code for. /// @@ -804,7 +796,7 @@ impl Interface { self.push_wasm(variant, &func.result, &mut results); - let mut retptr = None; + let mut retptr = false; if func.is_async { // Asynchronous functions never actually return anything since // they're all callback-based, meaning that we always put all the @@ -817,11 +809,13 @@ impl Interface { // argument to pass to this function. match variant { AbiVariant::GuestExport => { - retptr = Some(mem::take(&mut results)); + retptr = true; + results.truncate(0); params.push(WasmType::I32); } AbiVariant::GuestImport => { - retptr = Some(mem::take(&mut results)); + retptr = true; + results.truncate(0); params.push(WasmType::I32); params.push(WasmType::I32); } @@ -832,7 +826,8 @@ impl Interface { // return pointer to write into and exports return a pointer they wrote // into. if results.len() > 1 { - retptr = Some(mem::take(&mut results)); + retptr = true; + results.truncate(0); match variant { AbiVariant::GuestImport => { params.push(WasmType::I32); @@ -972,7 +967,7 @@ struct Generator<'a, B: Bindgen> { operands: Vec, results: Vec, stack: Vec, - return_pointers: Vec, + return_pointer: Option, } impl<'a, B: Bindgen> Generator<'a, B> { @@ -990,7 +985,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { operands: Vec::new(), results: Vec::new(), stack: Vec::new(), - return_pointers: Vec::new(), + return_pointer: None, } } @@ -1013,7 +1008,9 @@ impl<'a, B: Bindgen> Generator<'a, B> { // // Note that no return pointer goop happens here because // that's all done through parameters of callbacks instead. - let tys = sig.retptr.as_ref().unwrap(); + let mut results = Vec::new(); + self.iface + .push_wasm(self.variant, &func.result, &mut results); match self.variant { AbiVariant::GuestImport => { assert_eq!(self.stack.len(), sig.params.len() - 2); @@ -1021,7 +1018,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { module: &self.iface.name, name: &func.name, params: &sig.params, - results: tys, + results: &results, }); } AbiVariant::GuestExport => { @@ -1030,17 +1027,19 @@ impl<'a, B: Bindgen> Generator<'a, B> { module: &self.iface.name, name: &func.name, params: &sig.params, - results: tys, + results: &results, }); } } + + self.lift(&func.result); } else { - // If necessary we may need to prepare a return pointer for this - // ABI. The `Preview1` ABI has most return values returned - // through pointers, and the `Canonical` ABI returns more-than-one - // values through a return pointer. - if self.variant == AbiVariant::GuestImport { - self.prep_return_pointer(&sig, &func.result); + // If necessary we may need to prepare a return pointer for + // this ABI. + if self.variant == AbiVariant::GuestImport && sig.retptr { + let ptr = self.bindgen.return_pointer(self.iface, &func.result); + self.return_pointer = Some(ptr.clone()); + self.stack.push(ptr); } // Now that all the wasm args are prepared we can call the @@ -1052,23 +1051,34 @@ impl<'a, B: Bindgen> Generator<'a, B> { sig: &sig, }); - // In the `Canonical` ABI we model multiple return values by going - // through memory. Remove that indirection here by loading - // everything to simulate the function having many return values - // in our stack discipline. - if let Some(actual) = &sig.retptr { - if self.variant == AbiVariant::GuestImport { - assert_eq!(self.return_pointers.len(), 1); - self.stack.push(self.return_pointers.pop().unwrap()); - } - self.load_retptr(actual); + // If a return pointer is in use + if !sig.retptr { + // With no return pointer in use we can simply lift the + // result of the function from the result of the core + // wasm function. + self.lift(&func.result); + } else { + let ptr = match self.variant { + // imports into guests means it's a wasm module + // calling an imported function. We supplied the + // return poitner as the last argument (saved in + // `self.return_pointer`) so we use that to read + // the result of the function from memory. + AbiVariant::GuestImport => { + assert!(sig.results.len() == 0); + self.return_pointer.take().unwrap() + } + + // guest exports means that this is a host + // calling wasm so wasm returned a pointer to where + // the result is stored + AbiVariant::GuestExport => self.stack.pop().unwrap(), + }; + + self.read_from_memory(&func.result, ptr, 0); } } - // Batch-lift all result values now that all the function's return - // values are on the stack. - self.lift(&func.result); - self.emit(&Instruction::Return { func, amt: 1 }); } LiftLower::LiftArgsLowerResults => { @@ -1084,7 +1094,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { AbiVariant::GuestImport => 2, } } else { - (sig.retptr.is_some() && self.variant == AbiVariant::GuestImport) as usize + (sig.retptr && self.variant == AbiVariant::GuestImport) as usize }; sig.params.len() - skip_cnt }; @@ -1102,14 +1112,17 @@ impl<'a, B: Bindgen> Generator<'a, B> { func, }); - // ... and at the end we lower everything back into return - // values. - self.lower(&func.result); - if func.is_async { - let tys = sig.retptr.as_ref().unwrap(); match self.variant { + // Returning from a guest import means that the + // completion callback needs to be called which is + // currently given the lowered representation of the + // result. AbiVariant::GuestImport => { + self.lower(&func.result); + + let mut tys = Vec::new(); + self.iface.push_wasm(self.variant, &func.result, &mut tys); assert_eq!(self.stack.len(), tys.len()); let operands = mem::take(&mut self.stack); // function index to call @@ -1126,25 +1139,19 @@ impl<'a, B: Bindgen> Generator<'a, B> { params: tys.len(), }); } + + // Returning from a guest export means that we need to + // invoke the completion intrinsics with where the + // result is stored in linear memory. AbiVariant::GuestExport => { - // Store all results, if any, into the general - // return pointer area. - let retptr = if !tys.is_empty() { - let op = self.bindgen.i64_return_pointer_area(tys.len()); - self.stack.push(op); - Some(self.store_retptr(tys)) - } else { - None - }; + let ptr = self.bindgen.return_pointer(self.iface, &func.result); + self.write_to_memory(&func.result, ptr.clone(), 0); // Get the caller's context index. self.emit(&Instruction::GetArg { nth: sig.params.len() - 1, }); - match retptr { - Some(ptr) => self.stack.push(ptr), - None => self.emit(&Instruction::I32Const { val: 0 }), - } + self.stack.push(ptr); // This will call the "done" function with the // context/pointer argument @@ -1152,25 +1159,37 @@ impl<'a, B: Bindgen> Generator<'a, B> { } } } else { - // Our ABI dictates that a list of returned types are - // returned through memories, so after we've got all the - // values on the stack perform all of the stores here. - if let Some(tys) = &sig.retptr { + if !sig.retptr { + // With no return pointer in use we simply lower the + // result and return that directly from the function. + self.lower(&func.result); + } else { match self.variant { + // When a function is imported to a guest this means + // it's a host providing the implementation of the + // import. The result is stored in the pointer + // specified in the last argument, so we get the + // pointer here and then write the return value into + // it. AbiVariant::GuestImport => { self.emit(&Instruction::GetArg { nth: sig.params.len() - 1, }); + let ptr = self.stack.pop().unwrap(); + self.write_to_memory(&func.result, ptr, 0); } + + // For a guest import this is a function defined in + // wasm, so we're returning a pointer where the + // value was stored at. Allocate some space here + // (statically) and then write the result into that + // memory, returning the pointer at the end. AbiVariant::GuestExport => { - let op = self.bindgen.i64_return_pointer_area(tys.len()); - self.stack.push(op); + let ptr = self.bindgen.return_pointer(self.iface, &func.result); + self.write_to_memory(&func.result, ptr.clone(), 0); + self.stack.push(ptr); } } - let retptr = self.store_retptr(tys); - if self.variant == AbiVariant::GuestExport { - self.stack.push(retptr); - } } self.emit(&Instruction::Return { @@ -1188,20 +1207,6 @@ impl<'a, B: Bindgen> Generator<'a, B> { ); } - fn load_retptr(&mut self, types: &[WasmType]) { - let rp = self.stack.pop().unwrap(); - for (i, ty) in types.iter().enumerate() { - self.stack.push(rp.clone()); - let offset = (i * 8) as i32; - match ty { - WasmType::I32 => self.emit(&Instruction::I32Load { offset }), - WasmType::I64 => self.emit(&Instruction::I64Load { offset }), - WasmType::F32 => self.emit(&Instruction::F32Load { offset }), - WasmType::F64 => self.emit(&Instruction::F64Load { offset }), - } - } - } - /// Assumes that the wasm values to create `tys` are all located on the /// stack. /// @@ -1243,25 +1248,6 @@ impl<'a, B: Bindgen> Generator<'a, B> { } } - /// Assumes `types.len()` values are on the stack and stores them all into - /// the return pointer of this function, specified in the last argument. - /// - /// This is only used with `Abi::Next`. - fn store_retptr(&mut self, types: &[WasmType]) -> B::Operand { - let retptr = self.stack.pop().unwrap(); - for (i, ty) in types.iter().enumerate().rev() { - self.stack.push(retptr.clone()); - let offset = (i * 8) as i32; - match ty { - WasmType::I32 => self.emit(&Instruction::I32Store { offset }), - WasmType::I64 => self.emit(&Instruction::I64Store { offset }), - WasmType::F32 => self.emit(&Instruction::F32Store { offset }), - WasmType::F64 => self.emit(&Instruction::F64Store { offset }), - } - } - retptr - } - fn emit(&mut self, inst: &Instruction<'_>) { self.operands.clear(); self.results.clear(); @@ -1474,18 +1460,6 @@ impl<'a, B: Bindgen> Generator<'a, B> { } } - fn prep_return_pointer(&mut self, sig: &WasmSignature, result: &Type) { - drop(result); // FIXME: update to the new canonical abi and use this - // If a return pointer was automatically injected into this function - // then we need to allocate a proper amount of space for it and then - // add it to the stack to get passed to the callee. - if let Some(results) = &sig.retptr { - let ptr = self.bindgen.i64_return_pointer_area(results.len()); - self.return_pointers.push(ptr.clone()); - self.stack.push(ptr); - } - } - /// Note that in general everything in this function is the opposite of the /// `lower` function above. This is intentional and should be kept this way! fn lift(&mut self, ty: &Type) { diff --git a/crates/wasmlink/src/adapter/call.rs b/crates/wasmlink/src/adapter/call.rs index 24afa502d..6bd7dc69c 100644 --- a/crates/wasmlink/src/adapter/call.rs +++ b/crates/wasmlink/src/adapter/call.rs @@ -96,8 +96,6 @@ enum ValueRef { ElementOffset(u32), /// A reference to a 32-bit value returned from a function stored in a local (single-value return). Return(u32), - /// A reference to a 32-bit value via an index into the retptr array (multi-value return). - RetPtr(u32), } impl ValueRef { @@ -105,7 +103,6 @@ impl ValueRef { match self { ValueRef::Local(_) | ValueRef::Return(_) => None, ValueRef::ElementOffset(o) => Some(*o), - ValueRef::RetPtr(i) => Some(*i * 8), } } @@ -120,7 +117,7 @@ impl ValueRef { function.instruction(&Instruction::LocalGet(*i)); return; } - ValueRef::RetPtr(_) | ValueRef::ElementOffset(_) => {} + ValueRef::ElementOffset(_) => {} } let base = base.expect("cannot load via an element offset without a base"); @@ -187,7 +184,6 @@ impl Operand<'_> { enum PushMode { Params, Return, - RetPtr, } impl PushMode { @@ -195,7 +191,6 @@ impl PushMode { match self { Self::Params => ValueRef::Local(val), Self::Return => ValueRef::Return(val), - Self::RetPtr => ValueRef::RetPtr(val), } } } @@ -211,6 +206,7 @@ pub(crate) struct CallAdapter<'a> { free_index: Option, parent_realloc_index: Option, resource_functions: &'a HashMap<&'a str, (u32, u32)>, + result_size: usize, } impl<'a> CallAdapter<'a> { @@ -244,18 +240,17 @@ impl<'a> CallAdapter<'a> { ); } - let results = if let Some(retptr) = &signature.retptr { + let results = if signature.retptr { // For the callee's retptr locals_count += 1; - let mut iter = 0..retptr.len() as u32; let mut results = Vec::new(); - Self::push_operands( + Self::push_element_operands( inner, sizes, &func.result, - &mut iter, - PushMode::RetPtr, + 0, + PushMode::Return, &mut locals_count, &mut results, ); @@ -295,6 +290,7 @@ impl<'a> CallAdapter<'a> { free_index, parent_realloc_index, resource_functions, + result_size: sizes.size(&func.result), } } @@ -320,7 +316,7 @@ impl<'a> CallAdapter<'a> { } fn emit_call(&self, function: &mut wasm_encoder::Function, locals: &Locals) { - let params = if self.signature.retptr.is_some() { + let params = if self.signature.retptr { self.signature.params.len() as u32 - 1 } else { self.signature.params.len() as u32 @@ -334,37 +330,19 @@ impl<'a> CallAdapter<'a> { } fn copy_results(&self, function: &mut wasm_encoder::Function, locals: &mut Locals) { - if self.signature.retptr.is_some() { + if self.signature.retptr { let src_retptr = locals.allocate(); let dst_retptr = self.signature.params.len() as u32 - 1; - - // Store the retptr returned from the call function.instruction(&Instruction::LocalSet(src_retptr)); - // Copy each 8 byte value in the return space - for i in 0..self - .signature - .retptr - .as_ref() - .expect("function must have a retptr") - .len() - { + if self.result_size > 0 { function.instruction(&Instruction::LocalGet(dst_retptr)); function.instruction(&Instruction::LocalGet(src_retptr)); - function.instruction(&Instruction::I64Load(MemArg { - offset: (i * 8) as u64, - align: 3, - memory_index: ADAPTED_MEMORY_INDEX, - })); - function.instruction(&Instruction::I64Store(MemArg { - offset: (i * 8) as u64, - align: 3, - memory_index: PARENT_MEMORY_INDEX, - })); - } - - if self.results.is_empty() { - return; + function.instruction(&Instruction::I32Const(self.result_size as i32)); + function.instruction(&Instruction::MemoryCopy { + src: ADAPTED_MEMORY_INDEX, + dst: PARENT_MEMORY_INDEX, + }); } let src_base = ElementBase { @@ -452,7 +430,6 @@ impl<'a> CallAdapter<'a> { // Every list copied needs a destination local (and a source for retptr) *locals_count += match mode { PushMode::Params => 1, - PushMode::RetPtr => 2, PushMode::Return => unreachable!(), }; @@ -549,7 +526,6 @@ impl<'a> CallAdapter<'a> { // retptr) *locals_count += match mode { PushMode::Params => 1, - PushMode::RetPtr => 2, PushMode::Return => unreachable!(), }; @@ -567,7 +543,7 @@ impl<'a> CallAdapter<'a> { // Params need to be cloned, so add a local *locals_count += match mode { PushMode::Params => 1, - PushMode::RetPtr | PushMode::Return => 0, + PushMode::Return => 0, }; operands.push(Operand::Handle { @@ -701,7 +677,7 @@ impl<'a> CallAdapter<'a> { // Params need to be cloned, so add a local *locals_count += match mode { PushMode::Params => 1, - PushMode::RetPtr | PushMode::Return => 0, + PushMode::Return => 0, }; operands.push(Operand::Handle { @@ -845,7 +821,7 @@ impl<'a> CallAdapter<'a> { let dst = match addr { ValueRef::Local(i) | ValueRef::Return(i) => locals.map(*i), - ValueRef::ElementOffset(_) | ValueRef::RetPtr(_) => locals.allocate(), + ValueRef::ElementOffset(_) => locals.allocate(), }; function.instruction(&Instruction::LocalSet(dst)); @@ -965,7 +941,7 @@ impl<'a> CallAdapter<'a> { let (src, dst) = match addr { ValueRef::Local(i) => (i, locals.map(i)), - ValueRef::ElementOffset(_) | ValueRef::RetPtr(_) => { + ValueRef::ElementOffset(_) => { let src = locals.allocate(); addr.emit_load(function, src_base, LoadType::I32); function.instruction(&Instruction::LocalSet(src)); diff --git a/crates/wasmlink/src/module.rs b/crates/wasmlink/src/module.rs index aec8538eb..bf60744ef 100644 --- a/crates/wasmlink/src/module.rs +++ b/crates/wasmlink/src/module.rs @@ -91,7 +91,7 @@ impl Interface { let import_type = Self::sig_to_type(&import_signature); let export_type = Self::sig_to_type(&export_signature); - let has_retptr = import_signature.retptr.is_some(); + let has_retptr = import_signature.retptr; // A function must be adapted if it has a return pointer or any parameter or result // that needs to be adapted. diff --git a/crates/wasmlink/tests/lists.baseline b/crates/wasmlink/tests/lists.baseline index 1b8841918..8565c9c85 100644 --- a/crates/wasmlink/tests/lists.baseline +++ b/crates/wasmlink/tests/lists.baseline @@ -356,12 +356,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -370,7 +366,7 @@ i32.const 0 i32.const 1 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 call 0 local.tee 3 br_if 0 (;@1;) @@ -379,7 +375,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 memory.copy 0 1 local.get 0 local.get 3 @@ -387,7 +383,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 1 call 2) (func (;40;) (type 1) (param i32) @@ -396,12 +392,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -410,7 +402,7 @@ i32.const 0 i32.const 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 2 i32.mul call 0 @@ -421,7 +413,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 2 i32.mul memory.copy 0 1 @@ -431,7 +423,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 2 i32.mul i32.const 2 @@ -442,12 +434,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -456,7 +444,7 @@ i32.const 0 i32.const 4 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul call 0 @@ -467,7 +455,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul memory.copy 0 1 @@ -477,7 +465,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul i32.const 4 @@ -488,12 +476,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -502,7 +486,7 @@ i32.const 0 i32.const 8 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul call 0 @@ -513,7 +497,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul memory.copy 0 1 @@ -523,7 +507,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul i32.const 8 @@ -534,12 +518,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -548,7 +528,7 @@ i32.const 0 i32.const 1 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 call 0 local.tee 3 br_if 0 (;@1;) @@ -557,7 +537,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 memory.copy 0 1 local.get 0 local.get 3 @@ -565,7 +545,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 1 call 2) (func (;44;) (type 1) (param i32) @@ -574,12 +554,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -588,7 +564,7 @@ i32.const 0 i32.const 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 2 i32.mul call 0 @@ -599,7 +575,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 2 i32.mul memory.copy 0 1 @@ -609,7 +585,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 2 i32.mul i32.const 2 @@ -620,12 +596,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -634,7 +606,7 @@ i32.const 0 i32.const 4 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul call 0 @@ -645,7 +617,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul memory.copy 0 1 @@ -655,7 +627,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul i32.const 4 @@ -666,12 +638,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -680,7 +648,7 @@ i32.const 0 i32.const 8 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul call 0 @@ -691,7 +659,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul memory.copy 0 1 @@ -701,7 +669,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul i32.const 8 @@ -712,12 +680,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -726,7 +690,7 @@ i32.const 0 i32.const 4 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul call 0 @@ -737,7 +701,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul memory.copy 0 1 @@ -747,7 +711,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul i32.const 4 @@ -758,12 +722,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 1 i32.load (memory 1) local.set 2 @@ -772,7 +732,7 @@ i32.const 0 i32.const 8 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul call 0 @@ -783,7 +743,7 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul memory.copy 0 1 @@ -793,7 +753,7 @@ local.get 1 i32.load (memory 1) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul i32.const 8 @@ -824,12 +784,8 @@ local.set 4 local.get 2 local.get 4 - i64.load (memory 1) - i64.store - local.get 2 - local.get 4 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 4 i32.load (memory 1) local.set 5 @@ -838,7 +794,7 @@ i32.const 0 i32.const 8 local.get 4 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 16 i32.mul call 0 @@ -849,7 +805,7 @@ local.get 6 local.get 5 local.get 4 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 16 i32.mul memory.copy 0 1 @@ -859,7 +815,7 @@ local.get 4 i32.load (memory 1) local.get 4 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 16 i32.mul i32.const 8 @@ -943,12 +899,8 @@ local.set 7 local.get 2 local.get 7 - i64.load (memory 1) - i64.store - local.get 2 - local.get 7 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 7 i32.load (memory 1) local.set 8 @@ -957,7 +909,7 @@ i32.const 0 i32.const 4 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 12 i32.mul call 0 @@ -968,7 +920,7 @@ local.get 9 local.get 8 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 12 i32.mul memory.copy 0 1 @@ -980,7 +932,7 @@ block ;; label = @1 loop ;; label = @2 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.get 10 i32.eq br_if 1 (;@1;) @@ -1046,7 +998,7 @@ local.get 7 i32.load (memory 1) local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 12 i32.mul i32.const 4 @@ -1130,12 +1082,8 @@ local.set 7 local.get 2 local.get 7 - i64.load (memory 1) - i64.store - local.get 2 - local.get 7 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 7 i32.load (memory 1) local.set 8 @@ -1144,7 +1092,7 @@ i32.const 0 i32.const 4 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul call 0 @@ -1155,7 +1103,7 @@ local.get 9 local.get 8 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul memory.copy 0 1 @@ -1167,7 +1115,7 @@ block ;; label = @1 loop ;; label = @2 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.get 10 i32.eq br_if 1 (;@1;) @@ -1233,7 +1181,7 @@ local.get 7 i32.load (memory 1) local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul i32.const 4 @@ -1393,12 +1341,8 @@ local.set 11 local.get 2 local.get 11 - i64.load (memory 1) - i64.store - local.get 2 - local.get 11 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 11 i32.load (memory 1) local.set 12 @@ -1407,7 +1351,7 @@ i32.const 0 i32.const 8 local.get 11 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 48 i32.mul call 0 @@ -1418,7 +1362,7 @@ local.get 13 local.get 12 local.get 11 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 48 i32.mul memory.copy 0 1 @@ -1430,7 +1374,7 @@ block ;; label = @1 loop ;; label = @2 local.get 11 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.get 14 i32.eq br_if 1 (;@1;) @@ -1548,7 +1492,7 @@ local.get 11 i32.load (memory 1) local.get 11 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 48 i32.mul i32.const 8 @@ -1765,12 +1709,8 @@ local.set 12 local.get 2 local.get 12 - i64.load (memory 1) - i64.store - local.get 2 - local.get 12 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 12 i32.load (memory 1) local.set 13 @@ -1779,7 +1719,7 @@ i32.const 0 i32.const 4 local.get 12 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 12 i32.mul call 0 @@ -1790,7 +1730,7 @@ local.get 14 local.get 13 local.get 12 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 12 i32.mul memory.copy 0 1 @@ -1802,7 +1742,7 @@ block ;; label = @1 loop ;; label = @2 local.get 12 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.get 15 i32.eq br_if 1 (;@1;) @@ -1879,7 +1819,7 @@ local.get 12 i32.load (memory 1) local.get 12 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 12 i32.mul i32.const 4 @@ -1963,12 +1903,8 @@ local.set 7 local.get 2 local.get 7 - i64.load (memory 1) - i64.store - local.get 2 - local.get 7 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 7 i32.load (memory 1) local.set 8 @@ -1977,7 +1913,7 @@ i32.const 0 i32.const 8 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 64 i32.mul call 0 @@ -1988,7 +1924,7 @@ local.get 9 local.get 8 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 64 i32.mul memory.copy 0 1 @@ -2000,7 +1936,7 @@ block ;; label = @1 loop ;; label = @2 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.get 10 i32.eq br_if 1 (;@1;) @@ -2066,7 +2002,7 @@ local.get 7 i32.load (memory 1) local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 64 i32.mul i32.const 8 diff --git a/crates/wasmlink/tests/records.baseline b/crates/wasmlink/tests/records.baseline index 7a0fb6c2a..b4bd9e45f 100644 --- a/crates/wasmlink/tests/records.baseline +++ b/crates/wasmlink/tests/records.baseline @@ -77,24 +77,16 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8) + i32.const 8 + memory.copy 0 1) (func (;15;) (type 1) (param i32) (local i32) call 8 local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8) + i32.const 8 + memory.copy 0 1) (func (;16;) (type 1) (param i32) local.get 0 call 9) @@ -129,37 +121,17 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 - local.get 0 - local.get 1 - i64.load (memory 1) offset=16 - i64.store offset=16 - local.get 0 - local.get 1 - i64.load (memory 1) offset=24 - i64.store offset=24 - local.get 0 - local.get 1 - i64.load (memory 1) offset=32 - i64.store offset=32 - local.get 0 - local.get 1 - i64.load (memory 1) offset=40 - i64.store offset=40 + i32.const 24 + memory.copy 0 1 local.get 1 - i32.load (memory 1) offset=24 + i32.load (memory 1) offset=12 local.set 2 block ;; label = @1 i32.const 0 i32.const 0 i32.const 1 local.get 1 - i32.load (memory 1) offset=32 + i32.load (memory 1) offset=16 call 0 local.tee 3 br_if 0 (;@1;) @@ -168,15 +140,15 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=32 + i32.load (memory 1) offset=16 memory.copy 0 1 local.get 0 local.get 3 - i32.store offset=24 + i32.store offset=12 local.get 1 - i32.load (memory 1) offset=24 + i32.load (memory 1) offset=12 local.get 1 - i32.load (memory 1) offset=32 + i32.load (memory 1) offset=16 i32.const 1 call 2) (export "memory" (memory 1)) diff --git a/crates/wasmlink/tests/resources.baseline b/crates/wasmlink/tests/resources.baseline index f76bafc7f..cd48cbeca 100644 --- a/crates/wasmlink/tests/resources.baseline +++ b/crates/wasmlink/tests/resources.baseline @@ -208,12 +208,8 @@ local.set 7 local.get 2 local.get 7 - i64.load (memory 1) - i64.store - local.get 2 - local.get 7 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 7 i32.load (memory 1) local.set 8 @@ -222,7 +218,7 @@ i32.const 0 i32.const 4 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul call 0 @@ -233,7 +229,7 @@ local.get 9 local.get 8 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul memory.copy 0 1 @@ -245,7 +241,7 @@ block ;; label = @1 loop ;; label = @2 local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.get 10 i32.eq br_if 1 (;@1;) @@ -267,7 +263,7 @@ local.get 7 i32.load (memory 1) local.get 7 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 4 i32.mul i32.const 4 @@ -282,12 +278,8 @@ local.set 3 local.get 1 local.get 3 - i64.load (memory 1) - i64.store - local.get 1 - local.get 3 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 3 i32.load (memory 1) local.set 4 @@ -296,7 +288,7 @@ i32.const 0 i32.const 1 local.get 3 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 call 0 local.tee 5 br_if 0 (;@1;) @@ -305,7 +297,7 @@ local.get 5 local.get 4 local.get 3 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 memory.copy 0 1 local.get 1 local.get 5 @@ -313,7 +305,7 @@ local.get 3 i32.load (memory 1) local.get 3 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 1 call 6) (func (;20;) (type 1) (param i32 i32 i32) @@ -372,12 +364,8 @@ local.set 6 local.get 2 local.get 6 - i64.load (memory 1) - i64.store - local.get 2 - local.get 6 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 6 i32.load (memory 1) local.set 7 @@ -386,7 +374,7 @@ i32.const 0 i32.const 4 local.get 6 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul call 0 @@ -397,7 +385,7 @@ local.get 8 local.get 7 local.get 6 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul memory.copy 0 1 @@ -409,7 +397,7 @@ block ;; label = @1 loop ;; label = @2 local.get 6 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.get 9 i32.eq br_if 1 (;@1;) @@ -475,7 +463,7 @@ local.get 6 i32.load (memory 1) local.get 6 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 8 i32.mul i32.const 4 diff --git a/crates/wasmlink/tests/retptr.baseline b/crates/wasmlink/tests/retptr.baseline index d3f4354a2..bec0a30bf 100644 --- a/crates/wasmlink/tests/retptr.baseline +++ b/crates/wasmlink/tests/retptr.baseline @@ -20,11 +20,7 @@ local.set 3 local.get 2 local.get 3 - i64.load (memory 1) - i64.store - local.get 2 - local.get 3 - i64.load (memory 1) offset=8 - i64.store offset=8) + i32.const 8 + memory.copy 0 1) (export "memory" (memory 1)) (export "f1" (func 1))) diff --git a/crates/wasmlink/tests/string.baseline b/crates/wasmlink/tests/string.baseline index 50ec62d9e..dba13c4bc 100644 --- a/crates/wasmlink/tests/string.baseline +++ b/crates/wasmlink/tests/string.baseline @@ -46,12 +46,8 @@ local.set 4 local.get 2 local.get 4 - i64.load (memory 1) - i64.store - local.get 2 - local.get 4 - i64.load (memory 1) offset=8 - i64.store offset=8 + i32.const 8 + memory.copy 0 1 local.get 4 i32.load (memory 1) local.set 5 @@ -60,7 +56,7 @@ i32.const 0 i32.const 1 local.get 4 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 call 0 local.tee 6 br_if 0 (;@1;) @@ -69,7 +65,7 @@ local.get 6 local.get 5 local.get 4 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 memory.copy 0 1 local.get 2 local.get 6 @@ -77,7 +73,7 @@ local.get 4 i32.load (memory 1) local.get 4 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 i32.const 1 call 2) (export "memory" (memory 1)) diff --git a/crates/wasmlink/tests/variants.baseline b/crates/wasmlink/tests/variants.baseline index c25b926b9..e92836b03 100644 --- a/crates/wasmlink/tests/variants.baseline +++ b/crates/wasmlink/tests/variants.baseline @@ -98,12 +98,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8) + i32.const 8 + memory.copy 0 1) (func (;20;) (type 3) (param i32 i32 i32) (local i32) block ;; label = @1 @@ -138,16 +134,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 - local.get 0 - local.get 1 - i64.load (memory 1) offset=16 - i64.store offset=16 + i32.const 12 + memory.copy 0 1 block ;; label = @1 local.get 1 i32.load8_u (memory 1) @@ -155,14 +143,14 @@ i32.ne br_if 0 (;@1;) local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.set 2 block ;; label = @2 i32.const 0 i32.const 0 i32.const 1 local.get 1 - i32.load (memory 1) offset=16 + i32.load (memory 1) offset=8 call 0 local.tee 3 br_if 0 (;@2;) @@ -171,15 +159,15 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=16 + i32.load (memory 1) offset=8 memory.copy 0 1 local.get 0 local.get 3 - i32.store offset=8 + i32.store offset=4 local.get 1 - i32.load (memory 1) offset=8 + i32.load (memory 1) offset=4 local.get 1 - i32.load (memory 1) offset=16 + i32.load (memory 1) offset=8 i32.const 1 call 2 end) @@ -211,64 +199,8 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 - local.get 0 - local.get 1 - i64.load (memory 1) offset=16 - i64.store offset=16 - local.get 0 - local.get 1 - i64.load (memory 1) offset=24 - i64.store offset=24 - local.get 0 - local.get 1 - i64.load (memory 1) offset=32 - i64.store offset=32 - local.get 0 - local.get 1 - i64.load (memory 1) offset=40 - i64.store offset=40 - local.get 0 - local.get 1 - i64.load (memory 1) offset=48 - i64.store offset=48 - local.get 0 - local.get 1 - i64.load (memory 1) offset=56 - i64.store offset=56 - local.get 0 - local.get 1 - i64.load (memory 1) offset=64 - i64.store offset=64 - local.get 0 - local.get 1 - i64.load (memory 1) offset=72 - i64.store offset=72 - local.get 0 - local.get 1 - i64.load (memory 1) offset=80 - i64.store offset=80 - local.get 0 - local.get 1 - i64.load (memory 1) offset=88 - i64.store offset=88 - local.get 0 - local.get 1 - i64.load (memory 1) offset=96 - i64.store offset=96 - local.get 0 - local.get 1 - i64.load (memory 1) offset=104 - i64.store offset=104 - local.get 0 - local.get 1 - i64.load (memory 1) offset=112 - i64.store offset=112) + i32.const 40 + memory.copy 0 1) (func (;26;) (type 5) (param i32 i32 i32 i64 i32 i64 i32 i64 i32 i64 i32 i32 i32 i32) (local i32) local.get 0 @@ -288,56 +220,8 @@ local.set 14 local.get 13 local.get 14 - i64.load (memory 1) - i64.store - local.get 13 - local.get 14 - i64.load (memory 1) offset=8 - i64.store offset=8 - local.get 13 - local.get 14 - i64.load (memory 1) offset=16 - i64.store offset=16 - local.get 13 - local.get 14 - i64.load (memory 1) offset=24 - i64.store offset=24 - local.get 13 - local.get 14 - i64.load (memory 1) offset=32 - i64.store offset=32 - local.get 13 - local.get 14 - i64.load (memory 1) offset=40 - i64.store offset=40 - local.get 13 - local.get 14 - i64.load (memory 1) offset=48 - i64.store offset=48 - local.get 13 - local.get 14 - i64.load (memory 1) offset=56 - i64.store offset=56 - local.get 13 - local.get 14 - i64.load (memory 1) offset=64 - i64.store offset=64 - local.get 13 - local.get 14 - i64.load (memory 1) offset=72 - i64.store offset=72 - local.get 13 - local.get 14 - i64.load (memory 1) offset=80 - i64.store offset=80 - local.get 13 - local.get 14 - i64.load (memory 1) offset=88 - i64.store offset=88 - local.get 13 - local.get 14 - i64.load (memory 1) offset=96 - i64.store offset=96) + i32.const 88 + memory.copy 0 1) (func (;27;) (type 6) (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (local i32 i32 i32) block ;; label = @1 @@ -432,77 +316,29 @@ local.set 1 local.get 0 local.get 1 - i64.load (memory 1) - i64.store - local.get 0 - local.get 1 - i64.load (memory 1) offset=8 - i64.store offset=8 - local.get 0 - local.get 1 - i64.load (memory 1) offset=16 - i64.store offset=16 - local.get 0 - local.get 1 - i64.load (memory 1) offset=24 - i64.store offset=24 - local.get 0 - local.get 1 - i64.load (memory 1) offset=32 - i64.store offset=32 - local.get 0 - local.get 1 - i64.load (memory 1) offset=40 - i64.store offset=40 - local.get 0 - local.get 1 - i64.load (memory 1) offset=48 - i64.store offset=48 - local.get 0 - local.get 1 - i64.load (memory 1) offset=56 - i64.store offset=56 - local.get 0 - local.get 1 - i64.load (memory 1) offset=64 - i64.store offset=64 - local.get 0 - local.get 1 - i64.load (memory 1) offset=72 - i64.store offset=72 - local.get 0 - local.get 1 - i64.load (memory 1) offset=80 - i64.store offset=80 - local.get 0 - local.get 1 - i64.load (memory 1) offset=88 - i64.store offset=88 - local.get 0 - local.get 1 - i64.load (memory 1) offset=96 - i64.store offset=96 + i32.const 36 + memory.copy 0 1 block ;; label = @1 local.get 1 - i32.load8_u (memory 1) offset=48 + i32.load8_u (memory 1) offset=8 i32.const 1 i32.ne br_if 0 (;@1;) block ;; label = @2 local.get 1 - i32.load8_u (memory 1) offset=56 + i32.load8_u (memory 1) offset=12 i32.const 3 i32.ne br_if 0 (;@2;) local.get 1 - i32.load (memory 1) offset=64 + i32.load (memory 1) offset=16 local.set 2 block ;; label = @3 i32.const 0 i32.const 0 i32.const 1 local.get 1 - i32.load (memory 1) offset=72 + i32.load (memory 1) offset=20 call 0 local.tee 3 br_if 0 (;@3;) @@ -511,34 +347,34 @@ local.get 3 local.get 2 local.get 1 - i32.load (memory 1) offset=72 + i32.load (memory 1) offset=20 memory.copy 0 1 local.get 0 local.get 3 - i32.store offset=64 + i32.store offset=16 local.get 1 - i32.load (memory 1) offset=64 + i32.load (memory 1) offset=16 local.get 1 - i32.load (memory 1) offset=72 + i32.load (memory 1) offset=20 i32.const 1 call 2 end end block ;; label = @1 local.get 1 - i32.load8_u (memory 1) offset=80 + i32.load8_u (memory 1) offset=24 i32.const 0 i32.ne br_if 0 (;@1;) local.get 1 - i32.load (memory 1) offset=88 + i32.load (memory 1) offset=28 local.set 4 block ;; label = @2 i32.const 0 i32.const 0 i32.const 1 local.get 1 - i32.load (memory 1) offset=96 + i32.load (memory 1) offset=32 call 0 local.tee 5 br_if 0 (;@2;) @@ -547,33 +383,33 @@ local.get 5 local.get 4 local.get 1 - i32.load (memory 1) offset=96 + i32.load (memory 1) offset=32 memory.copy 0 1 local.get 0 local.get 5 - i32.store offset=88 + i32.store offset=28 local.get 1 - i32.load (memory 1) offset=88 + i32.load (memory 1) offset=28 local.get 1 - i32.load (memory 1) offset=96 + i32.load (memory 1) offset=32 i32.const 1 call 2 end block ;; label = @1 local.get 1 - i32.load8_u (memory 1) offset=80 + i32.load8_u (memory 1) offset=24 i32.const 1 i32.ne br_if 0 (;@1;) local.get 1 - i32.load (memory 1) offset=88 + i32.load (memory 1) offset=28 local.set 6 block ;; label = @2 i32.const 0 i32.const 0 i32.const 1 local.get 1 - i32.load (memory 1) offset=96 + i32.load (memory 1) offset=32 call 0 local.tee 7 br_if 0 (;@2;) @@ -582,15 +418,15 @@ local.get 7 local.get 6 local.get 1 - i32.load (memory 1) offset=96 + i32.load (memory 1) offset=32 memory.copy 0 1 local.get 0 local.get 7 - i32.store offset=88 + i32.store offset=28 local.get 1 - i32.load (memory 1) offset=88 + i32.load (memory 1) offset=28 local.get 1 - i32.load (memory 1) offset=96 + i32.load (memory 1) offset=32 i32.const 1 call 2 end) diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index e506b436f..919329a42 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -668,7 +668,7 @@ impl<'a> ImportEncoder<'a> { .map(|(i, f)| { let sig = interface.wasm_signature(AbiVariant::GuestImport, f); let options = RequiredOptions::for_function(interface, f) - | if sig.retptr.is_some() { + | if sig.retptr { RequiredOptions::Into } else { RequiredOptions::None diff --git a/crates/wit-component/tests/components/lower-options/component.wat b/crates/wit-component/tests/components/lower-options/component.wat index cfb575e84..6664b7c09 100644 --- a/crates/wit-component/tests/components/lower-options/component.wat +++ b/crates/wit-component/tests/components/lower-options/component.wat @@ -108,7 +108,6 @@ (type (;0;) (func (param i32 i32))) (type (;1;) (func (param i32 i32 i32))) (type (;2;) (func (param i32))) - (type (;3;) (func (param i32))) (func (;0;) (type 0) (param i32 i32) local.get 0 local.get 1 @@ -161,10 +160,10 @@ i32.const 8 call_indirect (type 2) ) - (func (;9;) (type 3) (param i32) + (func (;9;) (type 2) (param i32) local.get 0 i32.const 9 - call_indirect (type 3) + call_indirect (type 2) ) (func (;10;) (type 2) (param i32) local.get 0 @@ -189,7 +188,6 @@ (type (;0;) (func (param i32 i32))) (type (;1;) (func (param i32 i32 i32))) (type (;2;) (func (param i32))) - (type (;3;) (func (param i32))) (import "" "0" (func (;0;) (type 0))) (import "" "1" (func (;1;) (type 0))) (import "" "2" (func (;2;) (type 1))) @@ -199,7 +197,7 @@ (import "" "6" (func (;6;) (type 2))) (import "" "7" (func (;7;) (type 2))) (import "" "8" (func (;8;) (type 2))) - (import "" "9" (func (;9;) (type 3))) + (import "" "9" (func (;9;) (type 2))) (import "" "10" (func (;10;) (type 2))) (import "" "$imports" (table (;0;) 11 11 funcref)) (elem (;0;) (i32.const 0) func 0 1 2 3 4 5 6 7 8 9 10) From 7b662382ddcbfc9f355684efe9576ad5f423bc01 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 28 Apr 2022 11:52:46 -0700 Subject: [PATCH 2/2] Review comments --- crates/parser/src/abi.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/parser/src/abi.rs b/crates/parser/src/abi.rs index f42fa2562..991cbefa7 100644 --- a/crates/parser/src/abi.rs +++ b/crates/parser/src/abi.rs @@ -10,7 +10,10 @@ pub struct WasmSignature { pub params: Vec, /// The WebAssembly results of this function. pub results: Vec, - /// TODO + /// Whether or not this signature is using a return pointer to store the + /// result of the function, which is reflected either in `params` or + /// `results` depending on the context this function is used (e.g. an import + /// or an export). pub retptr: bool, } @@ -1051,7 +1054,6 @@ impl<'a, B: Bindgen> Generator<'a, B> { sig: &sig, }); - // If a return pointer is in use if !sig.retptr { // With no return pointer in use we can simply lift the // result of the function from the result of the core