From be953c192920bab53897fe134456cbfad0c0f1ce Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Fri, 26 Jul 2024 12:08:28 +0100 Subject: [PATCH] fully functional Rust code generation for symmetric strings example --- crates/core/src/abi.rs | 8 +- crates/cpp/src/lib.rs | 36 +++--- .../rust_comp_a/src/the_world.rs | 107 ++++++++++-------- crates/rust/src/bindgen.rs | 22 +++- crates/rust/src/interface.rs | 51 +++++---- 5 files changed, 128 insertions(+), 96 deletions(-) diff --git a/crates/core/src/abi.rs b/crates/core/src/abi.rs index 94073c42c..86a1a36b9 100644 --- a/crates/core/src/abi.rs +++ b/crates/core/src/abi.rs @@ -741,7 +741,7 @@ pub fn call( async_: bool, ) { if matches!(lift_lower, LiftLower::Symmetric) { - let sig = wasm_signature_symmetric(resolve, variant, func); + let sig = wasm_signature_symmetric(resolve, variant, func, true); Generator::new(resolve, variant, lift_lower, bindgen, async_) .call_with_signature(func, sig); } else { @@ -2276,9 +2276,13 @@ fn push_flat_symmetric(resolve: &Resolve, ty: &Type, vec: &mut Vec) { // another hack pub fn wasm_signature_symmetric( resolve: &Resolve, - _variant: AbiVariant, + variant: AbiVariant, func: &Function, + symmetric: bool, ) -> WasmSignature { + if !symmetric { + return resolve.wasm_signature(variant, func); + } const MAX_FLAT_PARAMS: usize = 16; const MAX_FLAT_RESULTS: usize = 1; diff --git a/crates/cpp/src/lib.rs b/crates/cpp/src/lib.rs index b14f3f1f0..a613b4e6c 100644 --- a/crates/cpp/src/lib.rs +++ b/crates/cpp/src/lib.rs @@ -969,26 +969,22 @@ impl CppInterfaceGenerator<'_> { // local patching of borrows function needs more complex solution fn patched_wasm_signature(&self, variant: AbiVariant, func: &Function) -> WasmSignature { - if self.gen.opts.symmetric { - abi::wasm_signature_symmetric(self.resolve, variant, func) - } else { - self.resolve.wasm_signature(variant, func) - // if matches!(res.params.get(0), Some(WasmType::I32)) - // && matches!(func.kind, FunctionKind::Freestanding) - // { - // if let Some((_, ty)) = func.params.get(0) { - // if let Type::Id(id) = ty { - // if let Some(td) = self.resolve.types.get(*id) { - // if let TypeDefKind::Handle(Handle::Borrow(id2)) = &td.kind { - // if let Some(ty2) = self.resolve.types.get(*id2) { - // dbg!((&self.gen.imported_interfaces, id2, ty2, &func)); - // } - // } - // } - // } - // } - // } - } + abi::wasm_signature_symmetric(self.resolve, variant, func, self.gen.opts.symmetric) + // if matches!(res.params.get(0), Some(WasmType::I32)) + // && matches!(func.kind, FunctionKind::Freestanding) + // { + // if let Some((_, ty)) = func.params.get(0) { + // if let Type::Id(id) = ty { + // if let Some(td) = self.resolve.types.get(*id) { + // if let TypeDefKind::Handle(Handle::Borrow(id2)) = &td.kind { + // if let Some(ty2) = self.resolve.types.get(*id2) { + // dbg!((&self.gen.imported_interfaces, id2, ty2, &func)); + // } + // } + // } + // } + // } + // } } // print the signature of the guest export (lowered (wasm) function calling into highlevel) diff --git a/crates/cpp/tests/meshless_strings/rust_comp_a/src/the_world.rs b/crates/cpp/tests/meshless_strings/rust_comp_a/src/the_world.rs index e9fa6cdc2..617e95fae 100644 --- a/crates/cpp/tests/meshless_strings/rust_comp_a/src/the_world.rs +++ b/crates/cpp/tests/meshless_strings/rust_comp_a/src/the_world.rs @@ -1,6 +1,5 @@ -// Generated by `wit-bindgen` 0.27.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.28.0. DO NOT EDIT! // Options used: -// * with "foo:foo/strings" = generate #[allow(dead_code)] pub mod foo { #[allow(dead_code)] @@ -13,7 +12,7 @@ pub mod foo { static __FORCE_SECTION_REF: fn() = super::super::super::__link_custom_section_describing_imports; use super::super::super::_rt; #[allow(unused_unsafe, clippy::all)] - pub fn a(x: &str,){ + pub fn a(x: &str,) -> (){ unsafe { let vec0 = x; let ptr0 = vec0.as_ptr().cast::(); @@ -30,32 +29,40 @@ pub mod foo { #[allow(unused_unsafe, clippy::all)] pub fn b() -> _rt::String{ unsafe { - #[repr(align(8))] - struct RetArea([::core::mem::MaybeUninit::; 16]); - let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + + #[cfg_attr(target_pointer_width="64", repr(align(8)))] + #[cfg_attr(target_pointer_width="32", repr(align(4)))] + struct RetArea([::core::mem::MaybeUninit::; (2*core::mem::size_of::<*const u8>())]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); (2*core::mem::size_of::<*const u8>())]); let ptr0 = ret_area.0.as_mut_ptr().cast::(); #[link(wasm_import_module = "foo:foo/strings")] extern "C" { #[cfg_attr(target_arch = "wasm32", link_name = "b")] - fn fooX3AfooX2FstringsX00b(_: *mut u8); - #[cfg_attr(target_arch = "wasm32", link_name = "cabi_post_b")] - fn cabi_post_fooX3AfooX2FstringsX00b(_: *mut u8); + fn fooX3AfooX2FstringsX00b(_: *mut u8, ); } fooX3AfooX2FstringsX00b(ptr0); let l1 = *ptr0.add(0).cast::<*mut u8>(); - let l2 = *ptr0.add(8).cast::(); + let l2 = *ptr0.add(core::mem::size_of::<*const u8>()).cast::(); let len3 = l2; - let res = String::from(std::str::from_utf8(std::slice::from_raw_parts(l1, len3)).unwrap()); + let string3 = String::from(std::str::from_utf8(std::slice::from_raw_parts(l1, len3)).unwrap()); + + #[link(wasm_import_module = "cabi_post_foo:foo/strings")] + extern "C" { + #[cfg_attr(target_arch = "wasm32", link_name = "b")] + fn cabi_post_fooX3AfooX2FstringsX00b(_: *mut u8, ); + } cabi_post_fooX3AfooX2FstringsX00b(ptr0); - res + string3 } } #[allow(unused_unsafe, clippy::all)] pub fn c(a: &str,b: &str,) -> _rt::String{ unsafe { - #[repr(align(8))] - struct RetArea([::core::mem::MaybeUninit::; 16]); - let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); 16]); + + #[cfg_attr(target_pointer_width="64", repr(align(8)))] + #[cfg_attr(target_pointer_width="32", repr(align(4)))] + struct RetArea([::core::mem::MaybeUninit::; (2*core::mem::size_of::<*const u8>())]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); (2*core::mem::size_of::<*const u8>())]); let vec0 = a; let ptr0 = vec0.as_ptr().cast::(); let len0 = vec0.len(); @@ -66,17 +73,21 @@ pub mod foo { #[link(wasm_import_module = "foo:foo/strings")] extern "C" { #[cfg_attr(target_arch = "wasm32", link_name = "c")] - fn fooX3AfooX2FstringsX00c(_: *mut u8, _: usize, _: *mut u8, _: usize, _: *mut u8); - #[cfg_attr(target_arch = "wasm32", link_name = "cabi_post_c")] - fn cabi_post_fooX3AfooX2FstringsX00c(_: *mut u8); + fn fooX3AfooX2FstringsX00c(_: *mut u8, _: usize, _: *mut u8, _: usize, _: *mut u8, ); } fooX3AfooX2FstringsX00c(ptr0.cast_mut(), len0, ptr1.cast_mut(), len1, ptr2); let l3 = *ptr2.add(0).cast::<*mut u8>(); - let l4 = *ptr2.add(8).cast::(); + let l4 = *ptr2.add(core::mem::size_of::<*const u8>()).cast::(); let len5 = l4; - let res = String::from(std::str::from_utf8(std::slice::from_raw_parts(l3, len5)).unwrap()); + let string5 = String::from(std::str::from_utf8(std::slice::from_raw_parts(l3, len5)).unwrap()); + + #[link(wasm_import_module = "cabi_post_foo:foo/strings")] + extern "C" { + #[cfg_attr(target_arch = "wasm32", link_name = "c")] + fn cabi_post_fooX3AfooX2FstringsX00c(_: *mut u8, ); + } cabi_post_fooX3AfooX2FstringsX00c(ptr2); - res + string5 } } @@ -101,52 +112,51 @@ pub mod exports { #[allow(non_snake_case)] pub unsafe fn _export_a_cabi(arg0: *mut u8,arg1: usize,) {#[cfg(target_arch="wasm32")] _rt::run_ctors_once();let len0 = arg1; - let s = String::from(std::str::from_utf8(std::slice::from_raw_parts(arg0, len0)).unwrap()); - // let bytes0 = _rt::Vec::from_raw_parts(arg0.cast(), len0, len0); - T::a(s); + let string0 = String::from(std::str::from_utf8(std::slice::from_raw_parts(arg0, len0)).unwrap()); + T::a(string0); } #[doc(hidden)] #[allow(non_snake_case)] - pub unsafe fn _export_b_cabi(ptr1: *mut u8) {#[cfg(target_arch="wasm32")] + pub unsafe fn _export_b_cabi(arg0: *mut u8,) {#[cfg(target_arch="wasm32")] _rt::run_ctors_once();let result0 = T::b(); - let vec2 = (result0.into_bytes()).into_boxed_slice(); - let ptr2 = vec2.as_ptr().cast::(); - let len2 = vec2.len(); - ::core::mem::forget(vec2); - *ptr1.add(8).cast::() = len2; - *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + let vec1 = (result0.into_bytes()).into_boxed_slice(); + let ptr1 = vec1.as_ptr().cast::(); + let len1 = vec1.len(); + ::core::mem::forget(vec1); + *arg0.add(core::mem::size_of::<*const u8>()).cast::() = len1; + *arg0.add(0).cast::<*mut u8>() = ptr1.cast_mut(); } #[doc(hidden)] #[allow(non_snake_case)] pub unsafe fn __post_return_b(arg0: *mut u8,) { let l0 = *arg0.add(0).cast::<*mut u8>(); - let l1 = *arg0.add(8).cast::(); + let l1 = *arg0.add(core::mem::size_of::<*const u8>()).cast::(); _rt::cabi_dealloc(l0, l1, 1); } #[doc(hidden)] #[allow(non_snake_case)] - pub unsafe fn _export_c_cabi(arg0: *mut u8,arg1: usize,arg2: *mut u8,arg3: usize, ptr3: *mut u8) {#[cfg(target_arch="wasm32")] + pub unsafe fn _export_c_cabi(arg0: *mut u8,arg1: usize,arg2: *mut u8,arg3: usize,arg4: *mut u8,) {#[cfg(target_arch="wasm32")] _rt::run_ctors_once();let len0 = arg1; - let bytes0 = String::from(std::str::from_utf8(std::slice::from_raw_parts(arg0, len0)).unwrap()); + let string0 = String::from(std::str::from_utf8(std::slice::from_raw_parts(arg0, len0)).unwrap()); let len1 = arg3; - let bytes1 = String::from(std::str::from_utf8(std::slice::from_raw_parts(arg2, len1)).unwrap()); - let result2 = T::c(bytes0, bytes1); - let vec4 = (result2.into_bytes()).into_boxed_slice(); - let ptr4 = vec4.as_ptr().cast::(); - let len4 = vec4.len(); - ::core::mem::forget(vec4); - *ptr3.add(8).cast::() = len4; - *ptr3.add(0).cast::<*mut u8>() = ptr4.cast_mut(); + let string1 = String::from(std::str::from_utf8(std::slice::from_raw_parts(arg2, len1)).unwrap()); + let result2 = T::c(string0, string1); + let vec3 = (result2.into_bytes()).into_boxed_slice(); + let ptr3 = vec3.as_ptr().cast::(); + let len3 = vec3.len(); + ::core::mem::forget(vec3); + *arg4.add(core::mem::size_of::<*const u8>()).cast::() = len3; + *arg4.add(0).cast::<*mut u8>() = ptr3.cast_mut(); } #[doc(hidden)] #[allow(non_snake_case)] pub unsafe fn __post_return_c(arg0: *mut u8,) { let l0 = *arg0.add(0).cast::<*mut u8>(); - let l1 = *arg0.add(8).cast::(); + let l1 = *arg0.add(core::mem::size_of::<*const u8>()).cast::(); _rt::cabi_dealloc(l0, l1, 1); } pub trait Guest { - fn a(x: _rt::String,); + fn a(x: _rt::String,) -> (); fn b() -> _rt::String; fn c(a: _rt::String,b: _rt::String,) -> _rt::String; } @@ -192,7 +202,8 @@ pub mod exports { } mod _rt { pub use alloc_crate::string::String; - + pub use alloc_crate::vec::Vec; + #[cfg(target_arch = "wasm32")] pub fn run_ctors_once() { wit_bindgen::rt::run_ctors_once(); @@ -202,7 +213,7 @@ mod _rt { return; } let layout = alloc::Layout::from_size_align_unchecked(size, align); - alloc::dealloc(ptr as *mut u8, layout); + alloc::dealloc(ptr, layout); } extern crate alloc as alloc_crate; pub use alloc_crate::alloc; @@ -237,7 +248,7 @@ macro_rules! __export_the_world_impl { pub(crate) use __export_the_world_impl as export; #[cfg(target_arch = "wasm32")] -#[link_section = "component-type:wit-bindgen:0.27.0:the-world:encoded world"] +#[link_section = "component-type:wit-bindgen:0.28.0:the-world:encoded world"] #[doc(hidden)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 286] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\x9e\x01\x01A\x02\x01\ @@ -246,7 +257,7 @@ A\x04\x01B\x06\x01@\x01\x01xs\x01\0\x04\0\x01a\x01\0\x01@\0\0s\x04\0\x01b\x01\x0 B\x06\x01@\x01\x01xs\x01\0\x04\0\x01a\x01\0\x01@\0\0s\x04\0\x01b\x01\x01\x01@\x02\ \x01as\x01bs\0s\x04\0\x01c\x01\x02\x04\x01\x0ffoo:foo/strings\x05\x01\x04\x01\x11\ foo:foo/the-world\x04\0\x0b\x0f\x01\0\x09the-world\x03\0\0\0G\x09producers\x01\x0c\ -processed-by\x02\x0dwit-component\x070.212.0\x10wit-bindgen-rust\x060.27.0"; +processed-by\x02\x0dwit-component\x070.214.0\x10wit-bindgen-rust\x060.28.0"; #[inline(never)] #[doc(hidden)] diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index 3e4421166..dcc03329d 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -66,7 +66,13 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> { } } - fn declare_import(&mut self, module_prefix: &str, name: &str, params: &[WasmType], results: &[WasmType]) -> String { + fn declare_import( + &mut self, + module_prefix: &str, + name: &str, + params: &[WasmType], + results: &[WasmType], + ) -> String { // Define the actual function we're calling inline // let tmp = self.tmp(); let mut sig = "(".to_owned(); @@ -82,7 +88,8 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> { sig.push_str(wasm_type(*result)); } let module_name = self.wasm_import_module; - let export_name = String::from(module_prefix) + &make_external_symbol(module_name, name, AbiVariant::GuestImport); + let export_name = String::from(module_prefix) + + &make_external_symbol(module_name, name, AbiVariant::GuestImport); uwrite!( self.src, " @@ -709,7 +716,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let val = format!("vec{}", tmp); let ptr = format!("ptr{}", tmp); let len = format!("len{}", tmp); - if realloc.is_none() || self.gen.gen.opts.symmetric { + if realloc.is_none() || (self.gen.in_import && self.gen.gen.opts.symmetric) { self.push_str(&format!("let {} = {};\n", val, operands[0])); } else { let op0 = format!("{}.into_bytes()", operands[0]); @@ -717,7 +724,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { } self.push_str(&format!("let {} = {}.as_ptr().cast::();\n", ptr, val)); self.push_str(&format!("let {} = {}.len();\n", len, val)); - if realloc.is_some() && !self.gen.gen.opts.symmetric { + if realloc.is_some() && !(self.gen.in_import && self.gen.gen.opts.symmetric) { self.push_str(&format!("::core::mem::forget({});\n", val)); } results.push(format!("{ptr}.cast_mut()")); @@ -838,7 +845,12 @@ impl Bindgen for FunctionBindgen<'_, '_> { Instruction::IterBasePointer => results.push("base".to_string()), - Instruction::CallWasm { name, sig, module_prefix, .. } => { + Instruction::CallWasm { + name, + sig, + module_prefix, + .. + } => { let func = self.declare_import(module_prefix, name, &sig.params, &sig.results); // ... then call the function with all our operands diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index b71c43e89..830496bde 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -378,22 +378,23 @@ macro_rules! {macro_name} {{ } } + pub fn align_area(&mut self, alignment: Alignment) { + match alignment { + Alignment::Pointer => uwriteln!( + self.src, + "#[cfg_attr(target_pointer_width=\"64\", repr(align(8)))] + #[cfg_attr(target_pointer_width=\"32\", repr(align(4)))]" + ), + Alignment::Bytes(bytes) => { + uwriteln!(self.src, "#[repr(align({align}))]", align = bytes.get()) + } + } + } + pub fn finish(&mut self) -> String { if !self.return_pointer_area_size.is_empty() { - match self.return_pointer_area_align { - Alignment::Pointer => uwriteln!( - self.src, - "\ - #[cgf_attr(target_pointer_width=\"64\", repr(align(8))] - #[cgf_attr(target_pointer_width=\"32\", repr(align(4))]" - ), - Alignment::Bytes(bytes) => uwriteln!( - self.src, - "\ - #[repr(align({align}))]", - align = bytes.get() - ), - } + uwriteln!(self.src,); + self.align_area(self.return_pointer_area_align); uwrite!( self.src, "struct _RetArea([::core::mem::MaybeUninit::; {size}]); @@ -851,14 +852,13 @@ impl {async_support}::StreamPayload for {name} {{ } assert!(handle_decls.is_empty()); if !import_return_pointer_area_size.is_empty() { + uwriteln!(self.src,); + self.align_area(import_return_pointer_area_align); uwrite!( self.src, - "\ - #[repr(align({import_return_pointer_area_align}))] - struct RetArea([::core::mem::MaybeUninit::; {import_return_pointer_area_size}]); + "struct RetArea([::core::mem::MaybeUninit::; {import_return_pointer_area_size}]); let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); {import_return_pointer_area_size}]); -", import_return_pointer_area_size = import_return_pointer_area_size.format(POINTER_SIZE_EXPRESSION), -import_return_pointer_area_align = import_return_pointer_area_align.format(POINTER_SIZE_EXPRESSION) +", import_return_pointer_area_size = import_return_pointer_area_size.format(POINTER_SIZE_EXPRESSION) ); } self.src.push_str(&String::from(src)); @@ -911,7 +911,11 @@ import_return_pointer_area_align = import_return_pointer_area_align.format(POINT abi::call( f.gen.resolve, AbiVariant::GuestExport, - LiftLower::LiftArgsLowerResults, + if f.gen.gen.opts.symmetric { + LiftLower::Symmetric + } else { + LiftLower::LiftArgsLowerResults + }, func, &mut f, async_, @@ -1050,7 +1054,12 @@ import_return_pointer_area_align = import_return_pointer_area_align.format(POINT fn print_export_sig(&mut self, func: &Function) -> Vec { self.src.push_str("("); - let sig = self.resolve.wasm_signature(AbiVariant::GuestExport, func); + let sig = abi::wasm_signature_symmetric( + self.resolve, + AbiVariant::GuestExport, + func, + self.gen.opts.symmetric, + ); let mut params = Vec::new(); for (i, param) in sig.params.iter().enumerate() { let name = format!("arg{}", i);