From 62663ab5e1cbeb4a47d9ba4e885b90325fd3e866 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 17 Dec 2020 14:35:55 -0800 Subject: [PATCH 1/2] Get `multi.c` working in the Wasm C API --- lib/c-api/src/wasm_c_api/externals/mod.rs | 1 + lib/c-api/src/wasm_c_api/macros.rs | 96 +++++++++++++++++++--- lib/c-api/src/wasm_c_api/types/export.rs | 1 + lib/c-api/src/wasm_c_api/types/function.rs | 10 +-- lib/c-api/src/wasm_c_api/types/global.rs | 2 +- lib/c-api/src/wasm_c_api/types/import.rs | 1 + lib/c-api/src/wasm_c_api/types/memory.rs | 2 +- lib/c-api/src/wasm_c_api/types/table.rs | 2 +- lib/c-api/src/wasm_c_api/value.rs | 33 ++++++++ lib/c-api/tests/Makefile | 4 +- lib/c-api/tests/wasm-c-api/example/multi.c | 16 +++- 11 files changed, 146 insertions(+), 22 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index aae406712ab..05fc8043543 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -11,6 +11,7 @@ pub use table::*; use wasmer::{Extern, Instance}; #[allow(non_camel_case_types)] +#[derive(Clone)] pub struct wasm_extern_t { // this is how we ensure the instance stays alive pub(crate) instance: Option>, diff --git a/lib/c-api/src/wasm_c_api/macros.rs b/lib/c-api/src/wasm_c_api/macros.rs index f0225f3ddd2..333a81c64b6 100644 --- a/lib/c-api/src/wasm_c_api/macros.rs +++ b/lib/c-api/src/wasm_c_api/macros.rs @@ -27,6 +27,33 @@ macro_rules! wasm_declare_vec { pub data: *mut [], } + impl Clone for [] { + fn clone(&self) -> Self { + if self.data.is_null() { + return Self { + size: self.size, + data: ::std::ptr::null_mut(), + }; + } + let data = + unsafe { + let vec = Vec::from_raw_parts(self.data, self.size, self.size); + let mut vec_copy = vec.clone().into_boxed_slice(); + let new_ptr = vec_copy.as_mut_ptr(); + + ::std::mem::forget(vec); + ::std::mem::forget(vec_copy); + + new_ptr + }; + + Self { + size: self.size, + data, + } + } + } + impl<'a> From]>> for [] { fn from(mut vec: Vec<[]>) -> Self { vec.shrink_to_fit(); @@ -108,6 +135,15 @@ macro_rules! wasm_declare_vec { ::std::mem::forget(bytes); } + #[doc = "Performs a deep copy of a vector of [`wasm_" $name "_t`]."] + #[no_mangle] + pub unsafe extern "C" fn []( + out_ptr: &mut [], + in_ptr: & []) + { + *out_ptr = in_ptr.clone(); + } + #[doc = "Deletes a vector of [`wasm_" $name "_t`]."] #[no_mangle] pub unsafe extern "C" fn [](ptr: Option<&mut []>) { @@ -138,6 +174,34 @@ macro_rules! wasm_declare_boxed_vec { pub data: *mut *mut [], } + impl Clone for [] { + fn clone(&self) -> Self { + if self.data.is_null() { + return Self { + size: self.size, + data: ::std::ptr::null_mut(), + }; + } + let data = + unsafe { + let data: *mut Option]>> = self.data as _; + let vec = Vec::from_raw_parts(data, self.size, self.size); + let mut vec_copy = vec.clone().into_boxed_slice(); + let new_ptr = vec_copy.as_mut_ptr() as *mut *mut []; + + ::std::mem::forget(vec); + ::std::mem::forget(vec_copy); + + new_ptr + }; + + Self { + size: self.size, + data, + } + } + } + impl<'a> From]>>> for [] { fn from(other: Vec]>>) -> Self { let boxed_slice: Box<[Box<[]>]> = other.into_boxed_slice(); @@ -174,11 +238,11 @@ macro_rules! wasm_declare_boxed_vec { for i in 0..length { bytes.push(*init.add(i)); } - let pointer = bytes.as_mut_ptr(); - debug_assert!(bytes.len() == bytes.capacity()); + let mut boxed_vec = bytes.into_boxed_slice(); + let pointer = boxed_vec.as_mut_ptr(); (*out).data = pointer; (*out).size = length; - ::std::mem::forget(bytes); + ::std::mem::forget(boxed_vec); } #[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`]."] @@ -191,15 +255,27 @@ macro_rules! wasm_declare_boxed_vec { ::std::mem::forget(bytes); } + #[doc = "Performs a deep copy of a vector of [`wasm_" $name "_t`]."] + #[no_mangle] + pub unsafe extern "C" fn []( + out_ptr: &mut [], + in_ptr: & []) + { + *out_ptr = in_ptr.clone(); + } + + #[doc = "Deletes a vector of [`wasm_" $name "_t`]."] #[no_mangle] - pub unsafe extern "C" fn [](ptr: *mut []) { - let vec = &mut *ptr; - if !vec.data.is_null() { - let data: Vec<*mut []> = Vec::from_raw_parts(vec.data, vec.size, vec.size); - let _data: Vec]>> = ::std::mem::transmute(data); - vec.data = ::std::ptr::null_mut(); - vec.size = 0; + pub unsafe extern "C" fn [](ptr: Option<&mut[]>) { + if let Some(vec) = ptr { + if !vec.data.is_null() { + let ptr: *mut Option]>> = vec.data as _; + let data: Vec]>>> = Vec::from_raw_parts(ptr, vec.size, vec.size); + + vec.data = ::std::ptr::null_mut(); + vec.size = 0; + } } } } diff --git a/lib/c-api/src/wasm_c_api/types/export.rs b/lib/c-api/src/wasm_c_api/types/export.rs index 26c6a5bb36f..1654de8193e 100644 --- a/lib/c-api/src/wasm_c_api/types/export.rs +++ b/lib/c-api/src/wasm_c_api/types/export.rs @@ -2,6 +2,7 @@ use super::{wasm_externtype_t, wasm_name_t}; use wasmer::ExportType; #[allow(non_camel_case_types)] +#[derive(Clone)] pub struct wasm_exporttype_t { name: Box, extern_type: Box, diff --git a/lib/c-api/src/wasm_c_api/types/function.rs b/lib/c-api/src/wasm_c_api/types/function.rs index 35b845481d6..ae355993d6c 100644 --- a/lib/c-api/src/wasm_c_api/types/function.rs +++ b/lib/c-api/src/wasm_c_api/types/function.rs @@ -67,7 +67,7 @@ impl Clone for WasmFunctionType { } #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(transparent)] pub struct wasm_functype_t { pub(crate) extern_type: wasm_externtype_t, @@ -111,8 +111,8 @@ pub unsafe extern "C" fn wasm_functype_new( .map(|val| val.as_ref().into()) .collect::>(); - wasm_valtype_vec_delete(Box::into_raw(params)); - wasm_valtype_vec_delete(Box::into_raw(results)); + wasm_valtype_vec_delete(Some(&mut *Box::into_raw(params))); + wasm_valtype_vec_delete(Some(&mut *Box::into_raw(results))); Some(Box::new(wasm_functype_t::new(FunctionType::new( params_as_valtype, @@ -129,9 +129,7 @@ pub unsafe extern "C" fn wasm_functype_copy( ) -> Option> { let function_type = function_type?; - Some(Box::new(wasm_functype_t::new( - function_type.inner().function_type.clone(), - ))) + Some(Box::new(function_type.clone())) } #[no_mangle] diff --git a/lib/c-api/src/wasm_c_api/types/global.rs b/lib/c-api/src/wasm_c_api/types/global.rs index 2195933334c..d64e282e9fa 100644 --- a/lib/c-api/src/wasm_c_api/types/global.rs +++ b/lib/c-api/src/wasm_c_api/types/global.rs @@ -23,7 +23,7 @@ impl WasmGlobalType { } #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(transparent)] pub struct wasm_globaltype_t { pub(crate) extern_type: wasm_externtype_t, diff --git a/lib/c-api/src/wasm_c_api/types/import.rs b/lib/c-api/src/wasm_c_api/types/import.rs index 4d3b2fe7244..a1f94f800a3 100644 --- a/lib/c-api/src/wasm_c_api/types/import.rs +++ b/lib/c-api/src/wasm_c_api/types/import.rs @@ -2,6 +2,7 @@ use super::{wasm_externtype_t, wasm_name_t}; use wasmer::ImportType; #[allow(non_camel_case_types)] +#[derive(Clone)] pub struct wasm_importtype_t { module: Box, name: Box, diff --git a/lib/c-api/src/wasm_c_api/types/memory.rs b/lib/c-api/src/wasm_c_api/types/memory.rs index d38385b88e5..12cedfac6be 100644 --- a/lib/c-api/src/wasm_c_api/types/memory.rs +++ b/lib/c-api/src/wasm_c_api/types/memory.rs @@ -25,7 +25,7 @@ impl WasmMemoryType { } #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(transparent)] pub struct wasm_memorytype_t { pub(crate) extern_type: wasm_externtype_t, diff --git a/lib/c-api/src/wasm_c_api/types/table.rs b/lib/c-api/src/wasm_c_api/types/table.rs index 31e2525eddd..d968cae0ddb 100644 --- a/lib/c-api/src/wasm_c_api/types/table.rs +++ b/lib/c-api/src/wasm_c_api/types/table.rs @@ -32,7 +32,7 @@ impl WasmTableType { } #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(transparent)] pub struct wasm_tabletype_t { pub(crate) extern_type: wasm_externtype_t, diff --git a/lib/c-api/src/wasm_c_api/value.rs b/lib/c-api/src/wasm_c_api/value.rs index 7449918bf9e..2415f3bea35 100644 --- a/lib/c-api/src/wasm_c_api/value.rs +++ b/lib/c-api/src/wasm_c_api/value.rs @@ -77,6 +77,39 @@ pub struct wasm_val_t { pub of: wasm_val_inner, } +impl std::fmt::Debug for wasm_val_t { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let mut ds = f.debug_struct("wasm_val_t"); + ds.field("kind", &self.kind); + + match self.kind.try_into() { + Ok(wasm_valkind_enum::WASM_I32) => { + ds.field("i32", &unsafe { self.of.int32_t }); + } + Ok(wasm_valkind_enum::WASM_I64) => { + ds.field("i64", &unsafe { self.of.int64_t }); + } + Ok(wasm_valkind_enum::WASM_F32) => { + ds.field("f32", &unsafe { self.of.float32_t }); + } + Ok(wasm_valkind_enum::WASM_F64) => { + ds.field("f64", &unsafe { self.of.float64_t }); + } + Ok(wasm_valkind_enum::WASM_ANYREF) => { + ds.field("anyref", &unsafe { self.of.wref }); + } + + Ok(wasm_valkind_enum::WASM_FUNCREF) => { + ds.field("funcref", &unsafe { self.of.wref }); + } + Err(_) => { + ds.field("value", &"Invalid value type"); + } + } + ds.finish() + } +} + wasm_declare_vec!(val); impl Clone for wasm_val_t { diff --git a/lib/c-api/tests/Makefile b/lib/c-api/tests/Makefile index 1b44e95faad..42b95bb6628 100644 --- a/lib/c-api/tests/Makefile +++ b/lib/c-api/tests/Makefile @@ -20,10 +20,10 @@ CAPI_WASMER_TESTS = \ CAPI_BASE_TESTS = \ wasm-c-api/example/callback wasm-c-api/example/global wasm-c-api/example/hello \ wasm-c-api/example/memory wasm-c-api/example/reflect wasm-c-api/example/serialize \ - wasm-c-api/example/start wasm-c-api/example/trap + wasm-c-api/example/start wasm-c-api/example/trap wasm-c-api/example/multi CAPI_BASE_TESTS_NOT_WORKING = \ - wasm-c-api/example/finalize wasm-c-api/example/hostref wasm-c-api/example/multi \ + wasm-c-api/example/finalize wasm-c-api/example/hostref \ wasm-c-api/example/table wasm-c-api/example/threads DEPRECATED_TESTS = \ diff --git a/lib/c-api/tests/wasm-c-api/example/multi.c b/lib/c-api/tests/wasm-c-api/example/multi.c index 846c6ec92af..908aad7e02f 100644 --- a/lib/c-api/tests/wasm-c-api/example/multi.c +++ b/lib/c-api/tests/wasm-c-api/example/multi.c @@ -7,6 +7,19 @@ #define own +int wasmer_last_error_length(void); +void wasmer_last_error_message(char*, int); + +// Use the last_error API to retrieve error messages +void print_wasmer_error() +{ + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); +} + // A function to be called from Wasm code. own wasm_trap_t* callback( const wasm_val_vec_t* args, wasm_val_vec_t* results @@ -121,7 +134,7 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); wasm_val_t vals[4] = { - WASM_I32_VAL(1), WASM_I32_VAL(2), WASM_I32_VAL(3), WASM_I32_VAL(4) + WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4) }; wasm_val_t res[4] = { WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL @@ -130,6 +143,7 @@ int main(int argc, const char* argv[]) { wasm_val_vec_t results = WASM_ARRAY_VEC(res); if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); + print_wasmer_error(); return 1; } From d44116251f3b505deccceb1a4de88b3f4873dbee Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 18 Dec 2020 07:13:38 -0800 Subject: [PATCH 2/2] Remove debug code from `multi.c` --- lib/c-api/tests/wasm-c-api/example/multi.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/c-api/tests/wasm-c-api/example/multi.c b/lib/c-api/tests/wasm-c-api/example/multi.c index 908aad7e02f..4a31e7e4da5 100644 --- a/lib/c-api/tests/wasm-c-api/example/multi.c +++ b/lib/c-api/tests/wasm-c-api/example/multi.c @@ -7,19 +7,6 @@ #define own -int wasmer_last_error_length(void); -void wasmer_last_error_message(char*, int); - -// Use the last_error API to retrieve error messages -void print_wasmer_error() -{ - int error_len = wasmer_last_error_length(); - printf("Error len: `%d`\n", error_len); - char *error_str = malloc(error_len); - wasmer_last_error_message(error_str, error_len); - printf("Error str: `%s`\n", error_str); -} - // A function to be called from Wasm code. own wasm_trap_t* callback( const wasm_val_vec_t* args, wasm_val_vec_t* results @@ -143,7 +130,6 @@ int main(int argc, const char* argv[]) { wasm_val_vec_t results = WASM_ARRAY_VEC(res); if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); - print_wasmer_error(); return 1; }