From adb84e2bf6cb2391413e0585d7efade17361c45e Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 9 Nov 2020 15:04:22 +0100 Subject: [PATCH] feat(c-api) Allow extern types to own data. We have known memory leaks with extern types. The idea is to change the code so that extern types can hold/own data. This patch does that. A `wasm_externtype_t` holds a `WasmExternType` enum. This enum owns sibling types such as `WasmFunctionType`, `WasmGlobalType`, `WasmTableType` and `WasmMemoryType`. It is those structures that ows the extern types data, like `params` and `results` as `wasm_valtype_vec_t` for `WasmFunctionType`. That way, for example, `wasm_functype_t` can return a pointer to these vec which it owns. A `wasm_externtype_t` continues to be transmuted to `wasm_functype_t` etc. Nothing changes on that side. --- .../src/wasm_c_api/externals/function.rs | 8 +- lib/c-api/src/wasm_c_api/externals/global.rs | 6 +- lib/c-api/src/wasm_c_api/externals/memory.rs | 6 +- lib/c-api/src/wasm_c_api/externals/table.rs | 6 +- lib/c-api/src/wasm_c_api/macros.rs | 2 + lib/c-api/src/wasm_c_api/module.rs | 4 - lib/c-api/src/wasm_c_api/types/extern_.rs | 257 ++++++++++-------- lib/c-api/src/wasm_c_api/types/function.rs | 154 +++++++---- lib/c-api/src/wasm_c_api/types/global.rs | 80 +++--- lib/c-api/src/wasm_c_api/types/memory.rs | 73 ++--- lib/c-api/src/wasm_c_api/types/table.rs | 84 +++--- 11 files changed, 386 insertions(+), 294 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/externals/function.rs b/lib/c-api/src/wasm_c_api/externals/function.rs index c7b2a3c66..35e468286 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -33,11 +33,11 @@ pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void); #[no_mangle] pub unsafe extern "C" fn wasm_func_new( store: &wasm_store_t, - ft: &wasm_functype_t, + function_type: &wasm_functype_t, callback: wasm_func_callback_t, ) -> Option> { // TODO: handle null pointers? - let func_sig = ft.sig(); + let func_sig = &function_type.inner().function_type; let num_rets = func_sig.results().len(); let inner_callback = move |args: &[Val]| -> Result, RuntimeError> { let processed_args: wasm_val_vec_t = args @@ -85,13 +85,13 @@ pub unsafe extern "C" fn wasm_func_new( #[no_mangle] pub unsafe extern "C" fn wasm_func_new_with_env( store: &wasm_store_t, - ft: &wasm_functype_t, + function_type: &wasm_functype_t, callback: wasm_func_callback_with_env_t, env: *mut c_void, finalizer: wasm_env_finalizer_t, ) -> Option> { // TODO: handle null pointers? - let func_sig = ft.sig(); + let func_sig = &function_type.inner().function_type; let num_rets = func_sig.results().len(); let inner_callback = move |env: &mut *mut c_void, args: &[Val]| -> Result, RuntimeError> { diff --git a/lib/c-api/src/wasm_c_api/externals/global.rs b/lib/c-api/src/wasm_c_api/externals/global.rs index bf0837bd3..39192699c 100644 --- a/lib/c-api/src/wasm_c_api/externals/global.rs +++ b/lib/c-api/src/wasm_c_api/externals/global.rs @@ -13,13 +13,13 @@ pub struct wasm_global_t { #[no_mangle] pub unsafe extern "C" fn wasm_global_new( store: &wasm_store_t, - gt: &wasm_globaltype_t, + global_type: &wasm_globaltype_t, val: &wasm_val_t, ) -> Option> { - let gt = gt.as_globaltype(); + let global_type = &global_type.inner().global_type; let wasm_val = val.try_into().ok()?; let store = &store.inner; - let global = if gt.mutability.is_mutable() { + let global = if global_type.mutability.is_mutable() { Global::new_mut(store, wasm_val) } else { Global::new(store, wasm_val) diff --git a/lib/c-api/src/wasm_c_api/externals/memory.rs b/lib/c-api/src/wasm_c_api/externals/memory.rs index e89828669..2de0e8934 100644 --- a/lib/c-api/src/wasm_c_api/externals/memory.rs +++ b/lib/c-api/src/wasm_c_api/externals/memory.rs @@ -12,10 +12,10 @@ pub struct wasm_memory_t { #[no_mangle] pub unsafe extern "C" fn wasm_memory_new( store: &wasm_store_t, - mt: &wasm_memorytype_t, + memory_type: &wasm_memorytype_t, ) -> Option> { - let md = mt.as_memorytype().clone(); - let memory = c_try!(Memory::new(&store.inner, md)); + let memory_type = memory_type.inner().memory_type.clone(); + let memory = c_try!(Memory::new(&store.inner, memory_type)); Some(Box::new(wasm_memory_t { inner: memory })) } diff --git a/lib/c-api/src/wasm_c_api/externals/table.rs b/lib/c-api/src/wasm_c_api/externals/table.rs index 526c36b2c..c1ce5d1e5 100644 --- a/lib/c-api/src/wasm_c_api/externals/table.rs +++ b/lib/c-api/src/wasm_c_api/externals/table.rs @@ -11,12 +11,12 @@ pub struct wasm_table_t { #[no_mangle] pub unsafe extern "C" fn wasm_table_new( store: &wasm_store_t, - tt: &wasm_tabletype_t, + table_type: &wasm_tabletype_t, init: *const wasm_ref_t, ) -> Option> { - let tt = tt.as_tabletype().clone(); + let table_type = table_type.inner().table_type.clone(); let init_val = todo!("get val from init somehow"); - let table = c_try!(Table::new(&store.inner, tt, init_val)); + let table = c_try!(Table::new(&store.inner, table_type, init_val)); Some(Box::new(wasm_table_t { inner: table })) } diff --git a/lib/c-api/src/wasm_c_api/macros.rs b/lib/c-api/src/wasm_c_api/macros.rs index c3954e109..7e3729780 100644 --- a/lib/c-api/src/wasm_c_api/macros.rs +++ b/lib/c-api/src/wasm_c_api/macros.rs @@ -17,6 +17,7 @@ macro_rules! wasm_declare_vec_inner { macro_rules! wasm_declare_vec { ($name:ident) => { paste::item! { + #[derive(Debug)] #[repr(C)] pub struct [] { pub size: usize, @@ -108,6 +109,7 @@ macro_rules! wasm_declare_vec { macro_rules! wasm_declare_boxed_vec { ($name:ident) => { paste::item! { + #[derive(Debug)] #[repr(C)] pub struct [] { pub size: usize, diff --git a/lib/c-api/src/wasm_c_api/module.rs b/lib/c-api/src/wasm_c_api/module.rs index 949d156c6..ddc7eecc1 100644 --- a/lib/c-api/src/wasm_c_api/module.rs +++ b/lib/c-api/src/wasm_c_api/module.rs @@ -259,11 +259,9 @@ mod tests { wasmer_assert(func_params->size == 2); wasmer_assert(wasm_valtype_kind(func_params->data[0]) == WASM_I32); wasmer_assert(wasm_valtype_kind(func_params->data[1]) == WASM_I64); - wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_params); const wasm_valtype_vec_t* func_results = wasm_functype_results(func_type); wasmer_assert(func_results->size == 0); - wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_results); } { @@ -366,11 +364,9 @@ mod tests { const wasm_valtype_vec_t* func_params = wasm_functype_params(func_type); wasmer_assert(func_params->size == 0); - wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_params); const wasm_valtype_vec_t* func_results = wasm_functype_results(func_type); wasmer_assert(func_results->size == 0); - wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_results); } { diff --git a/lib/c-api/src/wasm_c_api/types/extern_.rs b/lib/c-api/src/wasm_c_api/types/extern_.rs index 3f78ad11f..f33b87bcc 100644 --- a/lib/c-api/src/wasm_c_api/types/extern_.rs +++ b/lib/c-api/src/wasm_c_api/types/extern_.rs @@ -1,47 +1,13 @@ use super::super::externals::wasm_extern_t; -use super::{wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t}; +use super::{ + wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t, WasmFunctionType, + WasmGlobalType, WasmMemoryType, WasmTableType, +}; use std::convert::{TryFrom, TryInto}; use std::mem; use thiserror::Error; use wasmer::ExternType; -#[allow(non_camel_case_types)] -#[derive(Clone, Debug)] -pub struct wasm_externtype_t { - pub(crate) inner: ExternType, -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box { - Box::new(wasm_externtype_t { - inner: e.inner.ty(), - }) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_delete(_et: Option>) {} - -#[no_mangle] -pub extern "C" fn wasm_externtype_copy( - wasm_externtype: &wasm_externtype_t, -) -> Box { - Box::new(wasm_externtype_t { - inner: wasm_externtype.inner.clone(), - }) -} - -impl From for wasm_externtype_t { - fn from(other: ExternType) -> Self { - Self { inner: other } - } -} - -impl From<&ExternType> for wasm_externtype_t { - fn from(other: &ExternType) -> Self { - other.clone().into() - } -} - #[allow(non_camel_case_types)] type wasm_externkind_t = u8; @@ -54,11 +20,6 @@ pub enum wasm_externkind_enum { WASM_EXTERN_MEMORY = 3, } -#[no_mangle] -pub unsafe extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t { - wasm_externkind_enum::from(e.inner.ty()) as wasm_externkind_t -} - impl From for wasm_externkind_enum { fn from(other: ExternType) -> Self { (&other).into() @@ -75,9 +36,81 @@ impl From<&ExternType> for wasm_externkind_enum { } } +#[derive(Debug, Clone)] +pub(crate) enum WasmExternType { + Function(WasmFunctionType), + Global(WasmGlobalType), + Table(WasmTableType), + Memory(WasmMemoryType), +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Clone)] +pub struct wasm_externtype_t { + pub(crate) inner: WasmExternType, +} + +impl wasm_externtype_t { + pub(crate) fn new(extern_type: ExternType) -> Self { + Self { + inner: match extern_type { + ExternType::Function(function_type) => { + WasmExternType::Function(WasmFunctionType::new(function_type)) + } + ExternType::Global(global_type) => { + WasmExternType::Global(WasmGlobalType::new(global_type)) + } + ExternType::Table(table_type) => { + WasmExternType::Table(WasmTableType::new(table_type)) + } + ExternType::Memory(memory_type) => { + WasmExternType::Memory(WasmMemoryType::new(memory_type)) + } + }, + } + } +} + +impl From for wasm_externtype_t { + fn from(extern_type: ExternType) -> Self { + Self::new(extern_type) + } +} + +impl From<&ExternType> for wasm_externtype_t { + fn from(other: &ExternType) -> Self { + other.clone().into() + } +} + #[no_mangle] -pub unsafe extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkind_t { - wasm_externkind_enum::from(&et.inner) as wasm_externkind_t +pub unsafe extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box { + Box::new(wasm_externtype_t::new(e.inner.ty())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_extern_kind(r#extern: &wasm_extern_t) -> wasm_externkind_t { + wasm_externkind_enum::from(r#extern.inner.ty()) as wasm_externkind_t +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_delete(_et: Option>) {} + +#[no_mangle] +pub extern "C" fn wasm_externtype_copy(externtype: &wasm_externtype_t) -> Box { + Box::new(externtype.clone()) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_kind( + extern_type: &wasm_externtype_t, +) -> wasm_externkind_t { + (match extern_type.inner { + WasmExternType::Function(_) => wasm_externkind_enum::WASM_EXTERN_FUNC, + WasmExternType::Global(_) => wasm_externkind_enum::WASM_EXTERN_GLOBAL, + WasmExternType::Table(_) => wasm_externkind_enum::WASM_EXTERN_TABLE, + WasmExternType::Memory(_) => wasm_externkind_enum::WASM_EXTERN_MEMORY, + }) as wasm_externkind_t } #[derive(Debug, Clone, Error)] @@ -94,7 +127,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_functype_t { type Error = ExternTypeConversionError; fn try_from(other: &'static wasm_externtype_t) -> Result { - if let ExternType::Function(_) = other.inner { + if let WasmExternType::Function(_) = other.inner { Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) } else { Err(ExternTypeConversionError("Wrong type: expected function")) @@ -106,7 +139,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t { type Error = ExternTypeConversionError; fn try_from(other: &'static wasm_externtype_t) -> Result { - if let ExternType::Global(_) = other.inner { + if let WasmExternType::Global(_) = other.inner { Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) } else { Err(ExternTypeConversionError("Wrong type: expected global")) @@ -114,23 +147,11 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t { } } -impl TryFrom<&'static wasm_externtype_t> for &'static wasm_memorytype_t { - type Error = ExternTypeConversionError; - - fn try_from(other: &'static wasm_externtype_t) -> Result { - if let ExternType::Memory(_) = other.inner { - Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) - } else { - Err(ExternTypeConversionError("Wrong type: expected memory")) - } - } -} - impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t { type Error = ExternTypeConversionError; fn try_from(other: &'static wasm_externtype_t) -> Result { - if let ExternType::Table(_) = other.inner { + if let WasmExternType::Table(_) = other.inner { Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) } else { Err(ExternTypeConversionError("Wrong type: expected table")) @@ -138,114 +159,126 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t { } } +impl TryFrom<&'static wasm_externtype_t> for &'static wasm_memorytype_t { + type Error = ExternTypeConversionError; + + fn try_from(other: &'static wasm_externtype_t) -> Result { + if let WasmExternType::Memory(_) = other.inner { + Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) + } else { + Err(ExternTypeConversionError("Wrong type: expected memory")) + } + } +} + #[no_mangle] pub unsafe extern "C" fn wasm_externtype_as_functype_const( - et: &'static wasm_externtype_t, + extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_functype_t> { - Some(c_try!(et.try_into())) + Some(c_try!(extern_type.try_into())) } #[no_mangle] pub unsafe extern "C" fn wasm_externtype_as_functype( - et: &'static wasm_externtype_t, + extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_functype_t> { - Some(c_try!(et.try_into())) + Some(c_try!(extern_type.try_into())) } #[no_mangle] pub unsafe extern "C" fn wasm_functype_as_externtype_const( - ft: &'static wasm_functype_t, + function_type: &'static wasm_functype_t, ) -> &'static wasm_externtype_t { - &ft.extern_ + &function_type.extern_type } #[no_mangle] pub unsafe extern "C" fn wasm_functype_as_externtype( - ft: &'static wasm_functype_t, + function_type: &'static wasm_functype_t, ) -> &'static wasm_externtype_t { - &ft.extern_ -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_memorytype_const( - et: &'static wasm_externtype_t, -) -> Option<&'static wasm_memorytype_t> { - Some(c_try!(et.try_into())) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_memorytype( - et: &'static wasm_externtype_t, -) -> Option<&'static wasm_memorytype_t> { - Some(c_try!(et.try_into())) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_as_externtype_const( - mt: &'static wasm_memorytype_t, -) -> &'static wasm_externtype_t { - &mt.extern_ -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_as_externtype( - mt: &'static wasm_memorytype_t, -) -> &'static wasm_externtype_t { - &mt.extern_ + &function_type.extern_type } #[no_mangle] pub unsafe extern "C" fn wasm_externtype_as_globaltype_const( - et: &'static wasm_externtype_t, + extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_globaltype_t> { - Some(c_try!(et.try_into())) + Some(c_try!(extern_type.try_into())) } #[no_mangle] pub unsafe extern "C" fn wasm_externtype_as_globaltype( - et: &'static wasm_externtype_t, + extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_globaltype_t> { - Some(c_try!(et.try_into())) + Some(c_try!(extern_type.try_into())) } #[no_mangle] pub unsafe extern "C" fn wasm_globaltype_as_externtype_const( - gt: &'static wasm_globaltype_t, + global_type: &'static wasm_globaltype_t, ) -> &'static wasm_externtype_t { - >.extern_ + &global_type.extern_type } #[no_mangle] pub unsafe extern "C" fn wasm_globaltype_as_externtype( - gt: &'static wasm_globaltype_t, + global_type: &'static wasm_globaltype_t, ) -> &'static wasm_externtype_t { - >.extern_ + &global_type.extern_type } #[no_mangle] pub unsafe extern "C" fn wasm_externtype_as_tabletype_const( - et: &'static wasm_externtype_t, + extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_tabletype_t> { - Some(c_try!(et.try_into())) + Some(c_try!(extern_type.try_into())) } #[no_mangle] pub unsafe extern "C" fn wasm_externtype_as_tabletype( - et: &'static wasm_externtype_t, + extern_type: &'static wasm_externtype_t, ) -> Option<&'static wasm_tabletype_t> { - Some(c_try!(et.try_into())) + Some(c_try!(extern_type.try_into())) } #[no_mangle] pub unsafe extern "C" fn wasm_tabletype_as_externtype_const( - tt: &'static wasm_tabletype_t, + table_type: &'static wasm_tabletype_t, ) -> &'static wasm_externtype_t { - &tt.extern_ + &table_type.extern_type } #[no_mangle] pub unsafe extern "C" fn wasm_tabletype_as_externtype( - tt: &'static wasm_tabletype_t, + table_type: &'static wasm_tabletype_t, ) -> &'static wasm_externtype_t { - &tt.extern_ + &table_type.extern_type +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_as_memorytype_const( + extern_type: &'static wasm_externtype_t, +) -> Option<&'static wasm_memorytype_t> { + Some(c_try!(extern_type.try_into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_as_memorytype( + extern_type: &'static wasm_externtype_t, +) -> Option<&'static wasm_memorytype_t> { + Some(c_try!(extern_type.try_into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_memorytype_as_externtype_const( + memory_type: &'static wasm_memorytype_t, +) -> &'static wasm_externtype_t { + &memory_type.extern_type +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_memorytype_as_externtype( + memory_type: &'static wasm_memorytype_t, +) -> &'static wasm_externtype_t { + &memory_type.extern_type } 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 54befedfc..68d2697ae 100644 --- a/lib/c-api/src/wasm_c_api/types/function.rs +++ b/lib/c-api/src/wasm_c_api/types/function.rs @@ -1,28 +1,90 @@ -use super::{wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t}; +use super::{wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t, WasmExternType}; use std::mem; use std::ptr::NonNull; use wasmer::{ExternType, FunctionType, ValType}; +#[derive(Debug)] +pub(crate) struct WasmFunctionType { + pub(crate) function_type: FunctionType, + params: Box, + results: Box, +} + +impl WasmFunctionType { + pub(crate) fn new(function_type: FunctionType) -> Self { + let params = { + let mut valtypes = function_type + .params() + .iter() + .cloned() + .map(Into::into) + .map(Box::new) + .map(Box::into_raw) + .collect::>(); + + let valtypes_vec = Box::new(wasm_valtype_vec_t { + size: valtypes.len(), + data: valtypes.as_mut_ptr(), + }); + + mem::forget(valtypes); + + valtypes_vec + }; + let results = { + let mut valtypes = function_type + .results() + .iter() + .cloned() + .map(Into::into) + .map(Box::new) + .map(Box::into_raw) + .collect::>(); + + let valtypes_vec = Box::new(wasm_valtype_vec_t { + size: valtypes.len(), + data: valtypes.as_mut_ptr(), + }); + + mem::forget(valtypes); + + valtypes_vec + }; + + Self { + function_type, + params, + results, + } + } +} + +impl Clone for WasmFunctionType { + fn clone(&self) -> Self { + Self::new(self.function_type.clone()) + } +} + #[allow(non_camel_case_types)] -#[derive(Clone, Debug)] +#[derive(Debug)] +#[repr(transparent)] pub struct wasm_functype_t { - pub(crate) extern_: wasm_externtype_t, + pub(crate) extern_type: wasm_externtype_t, } impl wasm_functype_t { - pub(crate) fn sig(&self) -> &FunctionType { - if let ExternType::Function(ref f) = self.extern_.inner { - f - } else { - unreachable!("data corruption: `wasm_functype_t` does not contain a function") + pub(crate) fn new(function_type: FunctionType) -> Self { + Self { + extern_type: wasm_externtype_t::new(ExternType::Function(function_type)), } } - pub(crate) fn new(function_type: FunctionType) -> Self { - Self { - extern_: wasm_externtype_t { - inner: ExternType::Function(function_type), - }, + pub(crate) fn inner(&self) -> &WasmFunctionType { + match &self.extern_type.inner { + WasmExternType::Function(wasm_function_type) => &wasm_function_type, + _ => { + unreachable!("Data corruption: `wasm_functype_t` does not contain a function type") + } } } } @@ -36,24 +98,18 @@ pub unsafe extern "C" fn wasm_functype_new( // own results: Option>, ) -> Option> { - wasm_functype_new_inner(params?, results?) -} + let params = params?; + let results = results?; -unsafe fn wasm_functype_new_inner( - // own - params: NonNull, - // own - results: NonNull, -) -> Option> { - let params = params.as_ref(); - let results = results.as_ref(); let params: Vec = params + .as_ref() .into_slice()? .iter() .map(|ptr| **ptr) .map(Into::into) .collect::>(); let results: Vec = results + .as_ref() .into_slice()? .iter() .map(|ptr| **ptr) @@ -66,51 +122,29 @@ unsafe fn wasm_functype_new_inner( } #[no_mangle] -pub unsafe extern "C" fn wasm_functype_delete(_ft: Option>) {} +pub unsafe extern "C" fn wasm_functype_delete(_function_type: Option>) {} #[no_mangle] pub unsafe extern "C" fn wasm_functype_copy( - arg: Option>, + function_type: Option>, ) -> Option> { - let arg = arg?; - let funcsig = arg.as_ref(); - Some(Box::new(funcsig.clone())) + let function_type = function_type?; + + Some(Box::new(wasm_functype_t::new( + function_type.as_ref().inner().function_type.clone(), + ))) } #[no_mangle] -pub unsafe extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t { - let mut valtypes = ft - .sig() - .params() - .iter() - .cloned() - .map(Into::into) - .map(Box::new) - .map(Box::into_raw) - .collect::>(); - let out = Box::into_raw(Box::new(wasm_valtype_vec_t { - size: valtypes.len(), - data: valtypes.as_mut_ptr(), - })); - mem::forget(valtypes); - out as *const _ +pub unsafe extern "C" fn wasm_functype_params( + function_type: &wasm_functype_t, +) -> *const wasm_valtype_vec_t { + function_type.inner().params.as_ref() as *const _ } #[no_mangle] -pub unsafe extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t { - let mut valtypes = ft - .sig() - .results() - .iter() - .cloned() - .map(Into::into) - .map(Box::new) - .map(Box::into_raw) - .collect::>(); - let out = Box::into_raw(Box::new(wasm_valtype_vec_t { - size: valtypes.len(), - data: valtypes.as_mut_ptr(), - })); - mem::forget(valtypes); - out as *const _ +pub unsafe extern "C" fn wasm_functype_results( + function_type: &wasm_functype_t, +) -> *const wasm_valtype_vec_t { + function_type.inner().results.as_ref() as *const _ } 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 ee259650e..468deb547 100644 --- a/lib/c-api/src/wasm_c_api/types/global.rs +++ b/lib/c-api/src/wasm_c_api/types/global.rs @@ -1,31 +1,41 @@ use super::{ - wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, wasm_valtype_delete, wasm_valtype_t, + wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, wasm_valtype_delete, + wasm_valtype_t, WasmExternType, }; use std::convert::TryInto; use wasmer::{ExternType, GlobalType}; +#[derive(Debug, Clone)] +pub(crate) struct WasmGlobalType { + pub(crate) global_type: GlobalType, +} + +impl WasmGlobalType { + pub(crate) fn new(global_type: GlobalType) -> Self { + Self { global_type } + } +} + #[allow(non_camel_case_types)] -#[derive(Clone, Debug)] +#[derive(Debug)] +#[repr(transparent)] pub struct wasm_globaltype_t { - pub(crate) extern_: wasm_externtype_t, + pub(crate) extern_type: wasm_externtype_t, } impl wasm_globaltype_t { - pub(crate) fn as_globaltype(&self) -> &GlobalType { - if let ExternType::Global(ref g) = self.extern_.inner { - g - } else { - unreachable!( - "Data corruption detected: `wasm_globaltype_t` does not contain a `GlobalType`" - ); + pub(crate) fn new(global_type: GlobalType) -> Self { + Self { + extern_type: wasm_externtype_t::new(ExternType::Global(global_type)), } } - pub(crate) fn new(global_type: GlobalType) -> Self { - Self { - extern_: wasm_externtype_t { - inner: ExternType::Global(global_type), - }, + pub(crate) fn inner(&self) -> &WasmGlobalType { + match &self.extern_type.inner { + WasmExternType::Global(wasm_global_type) => &wasm_global_type, + _ => { + unreachable!("Data corruption: `wasm_globaltype_t` does not contain a global type") + } } } } @@ -38,41 +48,35 @@ pub unsafe extern "C" fn wasm_globaltype_new( valtype: Option>, mutability: wasm_mutability_t, ) -> Option> { - wasm_globaltype_new_inner(valtype?, mutability) + let valtype = valtype?; + let mutability: wasm_mutability_enum = mutability.try_into().ok()?; + let global_type = Box::new(wasm_globaltype_t::new(GlobalType::new( + (*valtype).into(), + mutability.into(), + ))); + + wasm_valtype_delete(Some(valtype)); + + Some(global_type) } #[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_delete(_globaltype: Option>) {} - -unsafe fn wasm_globaltype_new_inner( - // own - valtype: Box, - mutability: wasm_mutability_t, -) -> Option> { - let me: wasm_mutability_enum = mutability.try_into().ok()?; - let gd = Box::new(wasm_globaltype_t::new(GlobalType::new( - (*valtype).into(), - me.into(), - ))); - wasm_valtype_delete(Some(valtype)); - - Some(gd) -} +pub unsafe extern "C" fn wasm_globaltype_delete(_global_type: Option>) {} #[no_mangle] pub unsafe extern "C" fn wasm_globaltype_mutability( - globaltype: &wasm_globaltype_t, + global_type: &wasm_globaltype_t, ) -> wasm_mutability_t { - let gt = globaltype.as_globaltype(); - wasm_mutability_enum::from(gt.mutability).into() + wasm_mutability_enum::from(global_type.inner().global_type.mutability).into() } // TODO: fix memory leak // this function leaks memory because the returned limits pointer is not owned #[no_mangle] pub unsafe extern "C" fn wasm_globaltype_content( - globaltype: &wasm_globaltype_t, + global_type: &wasm_globaltype_t, ) -> *const wasm_valtype_t { - let gt = globaltype.as_globaltype(); - Box::into_raw(Box::new(gt.ty.into())) + let global_type = global_type.inner().global_type; + + Box::into_raw(Box::new(global_type.ty.into())) } 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 43211ca9d..0e5671b7c 100644 --- a/lib/c-api/src/wasm_c_api/types/memory.rs +++ b/lib/c-api/src/wasm_c_api/types/memory.rs @@ -1,49 +1,46 @@ -use super::wasm_externtype_t; +use super::{wasm_externtype_t, WasmExternType}; use wasmer::{ExternType, MemoryType, Pages}; -// opaque type wrapping `MemoryType` +#[derive(Debug, Clone)] +pub(crate) struct WasmMemoryType { + pub(crate) memory_type: MemoryType, +} + +impl WasmMemoryType { + pub(crate) fn new(memory_type: MemoryType) -> Self { + Self { memory_type } + } +} + #[allow(non_camel_case_types)] -#[derive(Clone, Debug)] +#[derive(Debug)] +#[repr(transparent)] pub struct wasm_memorytype_t { - pub(crate) extern_: wasm_externtype_t, + pub(crate) extern_type: wasm_externtype_t, } impl wasm_memorytype_t { - pub(crate) fn as_memorytype(&self) -> &MemoryType { - if let ExternType::Memory(ref mt) = self.extern_.inner { - mt - } else { - unreachable!( - "Data corruption detected: `wasm_memorytype_t` does not contain a `MemoryType`" - ); + pub(crate) fn new(memory_type: MemoryType) -> Self { + Self { + extern_type: wasm_externtype_t::new(ExternType::Memory(memory_type)), } } - pub(crate) fn new(memory_type: MemoryType) -> Self { - Self { - extern_: wasm_externtype_t { - inner: ExternType::Memory(memory_type), - }, + pub(crate) fn inner(&self) -> &WasmMemoryType { + match &self.extern_type.inner { + WasmExternType::Memory(wasm_memory_type) => &wasm_memory_type, + _ => { + unreachable!("Data corruption: `wasm_memorytype_t` does not contain a memory type") + } } } } wasm_declare_vec!(memorytype); -#[allow(non_camel_case_types)] -#[derive(Copy, Clone, Debug)] -#[repr(C)] -pub struct wasm_limits_t { - pub(crate) min: u32, - pub(crate) max: u32, -} - -const LIMITS_MAX_SENTINEL: u32 = u32::max_value(); - #[no_mangle] pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box { let min_pages = Pages(limits.min as _); - // u32::max_value() is a sentinel value for no max specified let max_pages = if limits.max == LIMITS_MAX_SENTINEL { None } else { @@ -56,17 +53,29 @@ pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box>) {} +pub unsafe extern "C" fn wasm_memorytype_delete(_memory_type: Option>) {} + +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct wasm_limits_t { + pub(crate) min: u32, + pub(crate) max: u32, +} + +const LIMITS_MAX_SENTINEL: u32 = u32::max_value(); // TODO: fix memory leak // this function leaks memory because the returned limits pointer is not owned #[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_limits(mt: &wasm_memorytype_t) -> *const wasm_limits_t { - let md = mt.as_memorytype(); +pub unsafe extern "C" fn wasm_memorytype_limits( + memory_type: &wasm_memorytype_t, +) -> *const wasm_limits_t { + let memory_type = memory_type.inner().memory_type; Box::into_raw(Box::new(wasm_limits_t { - min: md.minimum.0 as _, - max: md + min: memory_type.minimum.0 as _, + max: memory_type .maximum .map(|max| max.0 as _) .unwrap_or(LIMITS_MAX_SENTINEL), 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 0cdbad1c1..8632d5b65 100644 --- a/lib/c-api/src/wasm_c_api/types/table.rs +++ b/lib/c-api/src/wasm_c_api/types/table.rs @@ -1,68 +1,82 @@ -use super::{wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t}; +use super::{ + wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t, WasmExternType, +}; use wasmer::{ExternType, TableType}; #[allow(non_camel_case_types)] pub type wasm_table_size_t = u32; -#[allow(non_camel_case_types)] -#[derive(Clone, Debug)] -#[repr(C)] -pub struct wasm_tabletype_t { - pub(crate) extern_: wasm_externtype_t, +const LIMITS_MAX_SENTINEL: u32 = u32::max_value(); + +#[derive(Debug, Clone)] +pub(crate) struct WasmTableType { + pub(crate) table_type: TableType, } -wasm_declare_vec!(tabletype); +impl WasmTableType { + pub(crate) fn new(table_type: TableType) -> Self { + Self { table_type } + } +} + +#[allow(non_camel_case_types)] +#[derive(Debug)] +#[repr(transparent)] +pub struct wasm_tabletype_t { + pub(crate) extern_type: wasm_externtype_t, +} impl wasm_tabletype_t { - pub(crate) fn as_tabletype(&self) -> &TableType { - if let ExternType::Table(ref t) = self.extern_.inner { - t - } else { - unreachable!( - "Data corruption detected: `wasm_tabletype_t` does not contain a `TableType`" - ); + pub(crate) fn new(table_type: TableType) -> Self { + Self { + extern_type: wasm_externtype_t::new(ExternType::Table(table_type)), + } + } + + pub(crate) fn inner(&self) -> &WasmTableType { + match &self.extern_type.inner { + WasmExternType::Table(wasm_table_type) => &wasm_table_type, + _ => unreachable!("Data corruption: `wasm_tabletype_t` does not contain a table type"), } } } -const LIMITS_MAX_SENTINEL: u32 = u32::max_value(); +wasm_declare_vec!(tabletype); #[no_mangle] pub unsafe extern "C" fn wasm_tabletype_new( // own - valtype: Box, + valtype: Option>, limits: &wasm_limits_t, -) -> Box { +) -> Option> { + let valtype = valtype?; let max_elements = if limits.max == LIMITS_MAX_SENTINEL { None } else { Some(limits.max as _) }; - let out = Box::new(wasm_tabletype_t { - extern_: wasm_externtype_t { - inner: ExternType::Table(TableType::new( - (*valtype).into(), - limits.min as _, - max_elements, - )), - }, - }); + let table_type = Box::new(wasm_tabletype_t::new(TableType::new( + (*valtype).into(), + limits.min as _, + max_elements, + ))); + wasm_valtype_delete(Some(valtype)); - out + Some(table_type) } // TODO: fix memory leak // this function leaks memory because the returned limits pointer is not owned #[no_mangle] pub unsafe extern "C" fn wasm_tabletype_limits( - tabletype: &wasm_tabletype_t, + table_type: &wasm_tabletype_t, ) -> *const wasm_limits_t { - let tt = tabletype.as_tabletype(); + let table_type = table_type.inner().table_type; Box::into_raw(Box::new(wasm_limits_t { - min: tt.minimum as _, - max: tt.maximum.unwrap_or(LIMITS_MAX_SENTINEL), + min: table_type.minimum as _, + max: table_type.maximum.unwrap_or(LIMITS_MAX_SENTINEL), })) } @@ -70,12 +84,12 @@ pub unsafe extern "C" fn wasm_tabletype_limits( // this function leaks memory because the returned limits pointer is not owned #[no_mangle] pub unsafe extern "C" fn wasm_tabletype_element( - tabletype: &wasm_tabletype_t, + table_type: &wasm_tabletype_t, ) -> *const wasm_valtype_t { - let tt = tabletype.as_tabletype(); + let table_type = table_type.inner().table_type; - Box::into_raw(Box::new(tt.ty.into())) + Box::into_raw(Box::new(table_type.ty.into())) } #[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_delete(_tabletype: Option>) {} +pub unsafe extern "C" fn wasm_tabletype_delete(_table_type: Option>) {}