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 361009415..9f3fe269c 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -1,6 +1,7 @@ use super::super::store::wasm_store_t; +use super::super::trap::wasm_trap_t; +use super::super::types::{wasm_functype_t, wasm_valkind_enum}; use super::super::value::{wasm_val_inner, wasm_val_t}; -use super::super::{wasm_functype_t, wasm_trap_t, wasm_valkind_enum}; use std::convert::TryInto; use std::ffi::c_void; use std::ptr::NonNull; 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 9c8f64ed0..383e00ed9 100644 --- a/lib/c-api/src/wasm_c_api/externals/global.rs +++ b/lib/c-api/src/wasm_c_api/externals/global.rs @@ -1,6 +1,6 @@ use super::super::store::wasm_store_t; +use super::super::types::wasm_globaltype_t; use super::super::value::wasm_val_t; -use super::super::wasm_globaltype_t; use std::convert::TryInto; use std::ptr::NonNull; use wasmer::{Global, Store, 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 12bb666a5..b8336b7fa 100644 --- a/lib/c-api/src/wasm_c_api/externals/memory.rs +++ b/lib/c-api/src/wasm_c_api/externals/memory.rs @@ -1,6 +1,5 @@ use super::super::store::wasm_store_t; -use super::super::wasm_memorytype_t; -use crate::c_try; +use super::super::types::wasm_memorytype_t; use std::mem; use std::ptr::NonNull; use wasmer::{Memory, Pages, Store}; 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 6cb5faf61..e0ca9b673 100644 --- a/lib/c-api/src/wasm_c_api/externals/table.rs +++ b/lib/c-api/src/wasm_c_api/externals/table.rs @@ -1,6 +1,5 @@ use super::super::store::wasm_store_t; -use super::super::{wasm_ref_t, wasm_table_size_t, wasm_tabletype_t}; -use crate::c_try; +use super::super::types::{wasm_ref_t, wasm_table_size_t, wasm_tabletype_t}; use std::ptr::NonNull; use wasmer::{Store, Table}; diff --git a/lib/c-api/src/wasm_c_api/instance.rs b/lib/c-api/src/wasm_c_api/instance.rs index 617413811..0f59866bc 100644 --- a/lib/c-api/src/wasm_c_api/instance.rs +++ b/lib/c-api/src/wasm_c_api/instance.rs @@ -1,10 +1,7 @@ -use super::{ - externals::{wasm_extern_t, wasm_extern_vec_t}, - module::wasm_module_t, - store::wasm_store_t, - wasm_trap_t, -}; -use crate::c_try; +use super::externals::{wasm_extern_t, wasm_extern_vec_t}; +use super::module::wasm_module_t; +use super::store::wasm_store_t; +use super::trap::wasm_trap_t; use crate::ordered_resolver::OrderedResolver; use std::mem; use std::ptr::NonNull; diff --git a/lib/c-api/src/wasm_c_api/macros.rs b/lib/c-api/src/wasm_c_api/macros.rs index abc64711e..f37d9b71a 100644 --- a/lib/c-api/src/wasm_c_api/macros.rs +++ b/lib/c-api/src/wasm_c_api/macros.rs @@ -155,3 +155,21 @@ macro_rules! wasm_declare_own { } }; } + +#[macro_export] +macro_rules! c_try { + ($expr:expr) => {{ + let res: Result<_, _> = $expr; + match res { + Ok(val) => val, + Err(err) => { + crate::error::update_last_error(err); + return None; + } + } + }}; + ($expr:expr, $e:expr) => {{ + let opt: Option<_> = $expr; + c_try!(opt.ok_or_else(|| $e)) + }}; +} diff --git a/lib/c-api/src/wasm_c_api/mod.rs b/lib/c-api/src/wasm_c_api/mod.rs index 1e24d7d63..830c46944 100644 --- a/lib/c-api/src/wasm_c_api/mod.rs +++ b/lib/c-api/src/wasm_c_api/mod.rs @@ -8,905 +8,8 @@ pub mod externals; pub mod instance; pub mod module; pub mod store; -pub(crate) mod utils; +pub mod trap; +pub mod types; pub mod value; #[cfg(feature = "wasi")] pub mod wasi; - -// required due to really weird Rust resolution rules -// https://github.com/rust-lang/rust/issues/57966 -use crate::c_try; -use externals::wasm_extern_t; -use std::convert::{TryFrom, TryInto}; -use std::mem; -use std::ptr::NonNull; -use thiserror::Error; -use value::wasm_valkind_t; -use wasmer::{ - ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability, Pages, - RuntimeError, TableType, ValType, -}; -#[cfg(feature = "jit")] -use wasmer_engine_jit::JIT; - -#[allow(non_camel_case_types)] -pub type wasm_table_size_t = u32; - -#[allow(non_camel_case_types)] -pub type wasm_mutability_t = u8; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(non_camel_case_types)] -#[repr(u8)] -enum wasm_mutability_enum { - WASM_CONST = 0, - WASM_VAR, -} - -impl wasm_mutability_enum { - #[allow(dead_code)] - fn is_mutable(self) -> bool { - self == Self::WASM_VAR - } -} - -impl TryFrom for wasm_mutability_enum { - type Error = &'static str; - - fn try_from(item: wasm_mutability_t) -> Result { - Ok(match item { - 0 => wasm_mutability_enum::WASM_CONST, - 1 => wasm_mutability_enum::WASM_VAR, - _ => return Err("wasm_mutability_t value out of bounds"), - }) - } -} - -impl From for wasm_mutability_t { - fn from(other: wasm_mutability_enum) -> Self { - other as wasm_mutability_t - } -} - -impl From for Mutability { - fn from(other: wasm_mutability_enum) -> Self { - match other { - wasm_mutability_enum::WASM_CONST => Mutability::Const, - wasm_mutability_enum::WASM_VAR => Mutability::Var, - } - } -} - -impl From for wasm_mutability_enum { - fn from(other: Mutability) -> Self { - match other { - Mutability::Const => wasm_mutability_enum::WASM_CONST, - Mutability::Var => wasm_mutability_enum::WASM_VAR, - } - } -} - -impl From for ValType { - fn from(other: wasm_valkind_enum) -> Self { - use wasm_valkind_enum::*; - match other { - WASM_I32 => ValType::I32, - WASM_I64 => ValType::I64, - WASM_F32 => ValType::F32, - WASM_F64 => ValType::F64, - WASM_ANYREF => ValType::ExternRef, - WASM_FUNCREF => ValType::FuncRef, - } - } -} - -impl From for ValType { - fn from(other: wasm_valtype_t) -> Self { - other.valkind.into() - } -} - -impl From for wasm_valtype_t { - fn from(other: ValType) -> Self { - Self { - valkind: other.into(), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(non_camel_case_types)] -#[repr(u8)] -pub enum wasm_valkind_enum { - WASM_I32 = 0, - WASM_I64 = 1, - WASM_F32 = 2, - WASM_F64 = 3, - WASM_ANYREF = 128, - WASM_FUNCREF = 129, -} - -impl From for wasm_valkind_enum { - fn from(other: ValType) -> Self { - match other { - ValType::I32 => Self::WASM_I32, - ValType::I64 => Self::WASM_I64, - ValType::F32 => Self::WASM_F32, - ValType::F64 => Self::WASM_F64, - ValType::V128 => todo!("no v128 type in Wasm C API yet!"), - ValType::ExternRef => Self::WASM_ANYREF, - ValType::FuncRef => Self::WASM_FUNCREF, - } - } -} - -#[allow(non_camel_case_types)] -pub type wasm_byte_t = u8; -wasm_declare_vec!(byte); - -// opaque type over `ExternRef`? -#[allow(non_camel_case_types)] -pub struct wasm_ref_t; - -// opaque type which is a `RuntimeError` -#[repr(C)] -pub struct wasm_trap_t {} - -#[no_mangle] -pub unsafe extern "C" fn wasm_trap_delete(trap: Option>) { - if let Some(t_inner) = trap { - let _ = Box::from_raw(t_inner.cast::().as_ptr()); - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_trap_message( - trap: *const wasm_trap_t, - out_ptr: *mut wasm_byte_vec_t, -) { - let re = &*(trap as *const RuntimeError); - // this code assumes no nul bytes appear in the message - let mut message = format!("{}\0", re); - message.shrink_to_fit(); - - // TODO use `String::into_raw_parts` when it gets stabilized - (*out_ptr).size = message.as_bytes().len(); - (*out_ptr).data = message.as_mut_ptr(); - mem::forget(message); -} - -// in trap/RuntimeError we need to store -// 1. message -// 2. origin (frame); frame contains: -// 1. func index -// 2. func offset -// 3. module offset -// 4. which instance this was apart of - -/*#[no_mangle] -pub unsafe extern "C" fn wasm_trap_trace(trap: *const wasm_trap_t, out_ptr: *mut wasm_frame_vec_t) { - let re = &*(trap as *const RuntimeError); - todo!() -}*/ - -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct wasm_valtype_t { - valkind: wasm_valkind_enum, -} - -impl Default for wasm_valtype_t { - fn default() -> Self { - Self { - valkind: wasm_valkind_enum::WASM_I32, - } - } -} - -wasm_declare_boxed_vec!(valtype); - -#[no_mangle] -pub extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> Option> { - let kind_enum = kind.try_into().ok()?; - let valtype = wasm_valtype_t { valkind: kind_enum }; - Some(Box::new(valtype)) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_delete(_valtype: Option>) {} - -#[no_mangle] -pub unsafe extern "C" fn wasm_valtype_kind(valtype: *const wasm_valtype_t) -> wasm_valkind_t { - if valtype.is_null() { - // TODO: handle error - panic!("wasm_valtype_kind: argument is null pointer"); - } - return (*valtype).valkind as wasm_valkind_t; -} - -//wasm_declare_ref!(trap); -//wasm_declare_ref!(foreign); - -#[derive(Clone, Debug)] -#[repr(transparent)] -#[allow(non_camel_case_types)] -pub struct wasm_globaltype_t { - extern_: wasm_externtype_t, -} - -impl wasm_globaltype_t { - 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`" - ); - } - } -} - -wasm_declare_vec!(globaltype); - -#[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_new( - // own - valtype: Option>, - mutability: wasm_mutability_t, -) -> Option> { - wasm_globaltype_new_inner(valtype?, mutability) -} - -#[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 { - extern_: wasm_externtype_t { - inner: ExternType::Global(GlobalType::new((*valtype).into(), me.into())), - }, - }); - wasm_valtype_delete(Some(valtype)); - - Some(gd) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_mutability( - globaltype: &wasm_globaltype_t, -) -> wasm_mutability_t { - let gt = globaltype.as_globaltype(); - wasm_mutability_enum::from(gt.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, -) -> *const wasm_valtype_t { - let gt = globaltype.as_globaltype(); - Box::into_raw(Box::new(gt.ty.into())) -} - -#[derive(Clone, Debug)] -#[repr(C)] -#[allow(non_camel_case_types)] -pub struct wasm_tabletype_t { - extern_: wasm_externtype_t, -} - -wasm_declare_vec!(tabletype); - -impl wasm_tabletype_t { - 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`" - ); - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_new( - // own - valtype: Box, - limits: &wasm_limits_t, -) -> Box { - // TODO: investigate if `0` is in fact a sentinel value here - let max_elements = if limits.max == 0 { - 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, - )), - }, - }); - wasm_valtype_delete(Some(valtype)); - - out -} - -// 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, -) -> *const wasm_limits_t { - let tt = tabletype.as_tabletype(); - Box::into_raw(Box::new(wasm_limits_t { - min: tt.minimum as _, - max: tt.maximum.unwrap_or(0), - })) -} - -// 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_element( - tabletype: &wasm_tabletype_t, -) -> *const wasm_valtype_t { - let tt = tabletype.as_tabletype(); - - Box::into_raw(Box::new(tt.ty.into())) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_delete(_tabletype: Option>) {} - -// opaque type wrapping `MemoryType` -#[derive(Clone, Debug)] -#[repr(transparent)] -#[allow(non_camel_case_types)] -pub struct wasm_memorytype_t { - extern_: 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`" - ); - } - } -} - -wasm_declare_vec!(memorytype); - -#[derive(Copy, Clone, Debug)] -#[repr(C)] -pub struct wasm_limits_t { - min: u32, - max: u32, -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box { - let min_pages = Pages(limits.min as _); - // TODO: investigate if `0` is in fact a sentinel value here - let max_pages = if limits.max == 0 { - None - } else { - Some(Pages(limits.max as _)) - }; - Box::new(wasm_memorytype_t { - extern_: wasm_externtype_t { - inner: ExternType::Memory(MemoryType::new(min_pages, max_pages, false)), - }, - }) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_delete(_memorytype: Option>) {} - -// 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(); - Box::into_raw(Box::new(wasm_limits_t { - min: md.minimum.bytes().0 as _, - max: md.maximum.map(|max| max.bytes().0 as _).unwrap_or(0), - })) -} - -#[derive(Clone, Debug)] -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct wasm_functype_t { - extern_: 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") - } - } -} - -wasm_declare_vec!(functype); - -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_new( - // own - params: Option>, - // own - results: Option>, -) -> Option> { - wasm_functype_new_inner(params?, 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 - .into_slice()? - .iter() - .map(|&ptr| *ptr) - .map(Into::into) - .collect::>(); - let results: Vec = results - .into_slice()? - .iter() - .map(|&ptr| *ptr) - .map(Into::into) - .collect::>(); - - let extern_ = wasm_externtype_t { - inner: ExternType::Function(FunctionType::new(params, results)), - }; - Some(Box::new(wasm_functype_t { extern_ })) -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_delete(_ft: Option>) {} - -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_copy( - arg: Option>, -) -> Option> { - let arg = arg?; - let funcsig = arg.as_ref(); - Some(Box::new(funcsig.clone())) -} - -// TODO: fix memory leak -#[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 _ -} - -// TODO: fix memory leak -#[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 _ -} - -#[derive(Debug)] -#[repr(C)] -pub struct wasm_frame_t {} - -wasm_declare_vec!(frame); - -#[derive(Clone, Debug)] -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct wasm_externtype_t { - 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>) {} - -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; - -#[allow(non_camel_case_types)] -#[repr(u8)] -pub enum wasm_externkind_enum { - WASM_EXTERN_FUNC = 0, - WASM_EXTERN_GLOBAL = 1, - WASM_EXTERN_TABLE = 2, - 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() - } -} -impl From<&ExternType> for wasm_externkind_enum { - fn from(other: &ExternType) -> Self { - match other { - ExternType::Function(_) => Self::WASM_EXTERN_FUNC, - ExternType::Global(_) => Self::WASM_EXTERN_GLOBAL, - ExternType::Table(_) => Self::WASM_EXTERN_TABLE, - ExternType::Memory(_) => Self::WASM_EXTERN_MEMORY, - } - } -} - -#[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 -} - -#[derive(Debug, Clone, Error)] -#[error("failed to convert from `wasm_externtype_t`: {0}")] -pub struct ExternTypeConversionError(&'static str); -impl From<&'static str> for ExternTypeConversionError { - fn from(other: &'static str) -> Self { - Self(other) - } -} - -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 { - Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) - } else { - Err(ExternTypeConversionError("Wrong type: expected function")) - } - } -} -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 { - Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) - } else { - Err(ExternTypeConversionError("Wrong type: expected global")) - } - } -} -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 { - Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) - } else { - Err(ExternTypeConversionError("Wrong type: expected table")) - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_functype_const( - et: &'static wasm_externtype_t, -) -> Option<&'static wasm_functype_t> { - Some(c_try!(et.try_into())) -} -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_functype( - et: &'static wasm_externtype_t, -) -> Option<&'static wasm_functype_t> { - Some(c_try!(et.try_into())) -} -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_as_externtype_const( - ft: &'static wasm_functype_t, -) -> &'static wasm_externtype_t { - &ft.extern_ -} -#[no_mangle] -pub unsafe extern "C" fn wasm_functype_as_externtype( - ft: &'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_ -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_globaltype_const( - et: &'static wasm_externtype_t, -) -> Option<&'static wasm_globaltype_t> { - Some(c_try!(et.try_into())) -} -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_globaltype( - et: &'static wasm_externtype_t, -) -> Option<&'static wasm_globaltype_t> { - Some(c_try!(et.try_into())) -} -#[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_as_externtype_const( - gt: &'static wasm_globaltype_t, -) -> &'static wasm_externtype_t { - >.extern_ -} -#[no_mangle] -pub unsafe extern "C" fn wasm_globaltype_as_externtype( - gt: &'static wasm_globaltype_t, -) -> &'static wasm_externtype_t { - >.extern_ -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_tabletype_const( - et: &'static wasm_externtype_t, -) -> Option<&'static wasm_tabletype_t> { - Some(c_try!(et.try_into())) -} -#[no_mangle] -pub unsafe extern "C" fn wasm_externtype_as_tabletype( - et: &'static wasm_externtype_t, -) -> Option<&'static wasm_tabletype_t> { - Some(c_try!(et.try_into())) -} -#[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_as_externtype_const( - tt: &'static wasm_tabletype_t, -) -> &'static wasm_externtype_t { - &tt.extern_ -} -#[no_mangle] -pub unsafe extern "C" fn wasm_tabletype_as_externtype( - tt: &'static wasm_tabletype_t, -) -> &'static wasm_externtype_t { - &tt.extern_ -} - -#[allow(non_camel_case_types)] -type wasm_name_t = wasm_byte_vec_t; - -#[repr(C)] -#[allow(non_camel_case_types)] -pub struct wasm_exporttype_t { - name: NonNull, - extern_type: NonNull, -} - -wasm_declare_boxed_vec!(exporttype); - -#[no_mangle] -pub extern "C" fn wasm_exporttype_new( - name: NonNull, - extern_type: NonNull, -) -> Box { - Box::new(wasm_exporttype_t { name, extern_type }) -} - -#[no_mangle] -pub extern "C" fn wasm_exporttype_name(et: &'static wasm_exporttype_t) -> &'static wasm_name_t { - unsafe { et.name.as_ref() } -} - -#[no_mangle] -pub extern "C" fn wasm_exporttype_type( - et: &'static wasm_exporttype_t, -) -> &'static wasm_externtype_t { - unsafe { et.extern_type.as_ref() } -} - -impl From for wasm_exporttype_t { - fn from(other: ExportType) -> Self { - (&other).into() - } -} - -impl From<&ExportType> for wasm_exporttype_t { - fn from(other: &ExportType) -> Self { - // TODO: double check that freeing String as `Vec` is valid - let name = { - let mut heap_str: Box = other.name().to_string().into_boxed_str(); - let char_ptr = heap_str.as_mut_ptr(); - let str_len = heap_str.bytes().len(); - let name_inner = wasm_name_t { - size: str_len, - data: char_ptr, - }; - Box::leak(heap_str); - unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) } - }; - - let extern_type = { - let extern_type: wasm_externtype_t = other.ty().into(); - unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) } - }; - - wasm_exporttype_t { name, extern_type } - } -} - -// TODO: improve ownership in `importtype_t` (can we safely use `Box` here?) -#[repr(C)] -#[allow(non_camel_case_types)] -pub struct wasm_importtype_t { - module: NonNull, - name: NonNull, - extern_type: NonNull, -} - -wasm_declare_boxed_vec!(importtype); - -#[no_mangle] -pub extern "C" fn wasm_importtype_new( - module: NonNull, - name: NonNull, - extern_type: NonNull, -) -> Box { - Box::new(wasm_importtype_t { - name, - module, - extern_type, - }) -} - -#[no_mangle] -pub extern "C" fn wasm_importtype_module(et: &'static wasm_importtype_t) -> &'static wasm_name_t { - unsafe { et.module.as_ref() } -} - -#[no_mangle] -pub extern "C" fn wasm_importtype_name(et: &'static wasm_importtype_t) -> &'static wasm_name_t { - unsafe { et.name.as_ref() } -} - -#[no_mangle] -pub extern "C" fn wasm_importtype_type( - et: &'static wasm_importtype_t, -) -> &'static wasm_externtype_t { - unsafe { et.extern_type.as_ref() } -} - -#[no_mangle] -pub unsafe extern "C" fn wasm_importtype_delete(_importtype: Option>) {} - -impl From for wasm_importtype_t { - fn from(other: ImportType) -> Self { - (&other).into() - } -} - -impl From<&ImportType> for wasm_importtype_t { - fn from(other: &ImportType) -> Self { - // TODO: double check that freeing String as `Vec` is valid - let name = { - let mut heap_str: Box = other.name().to_string().into_boxed_str(); - let char_ptr = heap_str.as_mut_ptr(); - let str_len = heap_str.bytes().len(); - let name_inner = wasm_name_t { - size: str_len, - data: char_ptr, - }; - Box::leak(heap_str); - unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) } - }; - - // TODO: double check that freeing String as `Vec` is valid - let module = { - let mut heap_str: Box = other.module().to_string().into_boxed_str(); - let char_ptr = heap_str.as_mut_ptr(); - let str_len = heap_str.bytes().len(); - let name_inner = wasm_name_t { - size: str_len, - data: char_ptr, - }; - Box::leak(heap_str); - unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) } - }; - - let extern_type = { - let extern_type: wasm_externtype_t = other.ty().into(); - unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) } - }; - - wasm_importtype_t { - name, - module, - extern_type, - } - } -} diff --git a/lib/c-api/src/wasm_c_api/module.rs b/lib/c-api/src/wasm_c_api/module.rs index de6273215..9133d53af 100644 --- a/lib/c-api/src/wasm_c_api/module.rs +++ b/lib/c-api/src/wasm_c_api/module.rs @@ -1,9 +1,8 @@ use super::store::wasm_store_t; -use super::{ +use super::types::{ wasm_byte_vec_t, wasm_exporttype_t, wasm_exporttype_vec_t, wasm_importtype_t, wasm_importtype_vec_t, }; -use crate::c_try; use std::mem; use std::ptr::NonNull; use std::slice; diff --git a/lib/c-api/src/wasm_c_api/trap.rs b/lib/c-api/src/wasm_c_api/trap.rs new file mode 100644 index 000000000..d2503a636 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/trap.rs @@ -0,0 +1,48 @@ +use super::types::wasm_byte_vec_t; +use std::mem; +use std::ptr::NonNull; +use wasmer::RuntimeError; + +// opaque type which is a `RuntimeError` +#[repr(C)] +pub struct wasm_trap_t {} + +#[no_mangle] +pub unsafe extern "C" fn wasm_trap_delete(trap: Option>) { + if let Some(t_inner) = trap { + let _ = Box::from_raw(t_inner.cast::().as_ptr()); + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_trap_message( + trap: *const wasm_trap_t, + out_ptr: *mut wasm_byte_vec_t, +) { + let re = &*(trap as *const RuntimeError); + // this code assumes no nul bytes appear in the message + let mut message = format!("{}\0", re); + message.shrink_to_fit(); + + // TODO use `String::into_raw_parts` when it gets stabilized + (*out_ptr).size = message.as_bytes().len(); + (*out_ptr).data = message.as_mut_ptr(); + mem::forget(message); +} + +// in trap/RuntimeError we need to store +// 1. message +// 2. origin (frame); frame contains: +// 1. func index +// 2. func offset +// 3. module offset +// 4. which instance this was apart of + +/*#[no_mangle] +pub unsafe extern "C" fn wasm_trap_trace(trap: *const wasm_trap_t, out_ptr: *mut wasm_frame_vec_t) { + let re = &*(trap as *const RuntimeError); + todo!() +}*/ + +//wasm_declare_ref!(trap); +//wasm_declare_ref!(foreign); diff --git a/lib/c-api/src/wasm_c_api/types/byte.rs b/lib/c-api/src/wasm_c_api/types/byte.rs new file mode 100644 index 000000000..20ee607e6 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/byte.rs @@ -0,0 +1,4 @@ +#[allow(non_camel_case_types)] +pub type wasm_byte_t = u8; + +wasm_declare_vec!(byte); diff --git a/lib/c-api/src/wasm_c_api/types/export.rs b/lib/c-api/src/wasm_c_api/types/export.rs new file mode 100644 index 000000000..237256039 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/export.rs @@ -0,0 +1,62 @@ +use super::{wasm_externtype_t, wasm_name_t}; +use std::ptr::NonNull; +use wasmer::ExportType; + +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct wasm_exporttype_t { + name: NonNull, + extern_type: NonNull, +} + +wasm_declare_boxed_vec!(exporttype); + +#[no_mangle] +pub extern "C" fn wasm_exporttype_new( + name: NonNull, + extern_type: NonNull, +) -> Box { + Box::new(wasm_exporttype_t { name, extern_type }) +} + +#[no_mangle] +pub extern "C" fn wasm_exporttype_name(et: &'static wasm_exporttype_t) -> &'static wasm_name_t { + unsafe { et.name.as_ref() } +} + +#[no_mangle] +pub extern "C" fn wasm_exporttype_type( + et: &'static wasm_exporttype_t, +) -> &'static wasm_externtype_t { + unsafe { et.extern_type.as_ref() } +} + +impl From for wasm_exporttype_t { + fn from(other: ExportType) -> Self { + (&other).into() + } +} + +impl From<&ExportType> for wasm_exporttype_t { + fn from(other: &ExportType) -> Self { + // TODO: double check that freeing String as `Vec` is valid + let name = { + let mut heap_str: Box = other.name().to_string().into_boxed_str(); + let char_ptr = heap_str.as_mut_ptr(); + let str_len = heap_str.bytes().len(); + let name_inner = wasm_name_t { + size: str_len, + data: char_ptr, + }; + Box::leak(heap_str); + unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) } + }; + + let extern_type = { + let extern_type: wasm_externtype_t = other.ty().into(); + unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) } + }; + + wasm_exporttype_t { name, extern_type } + } +} diff --git a/lib/c-api/src/wasm_c_api/types/extern_.rs b/lib/c-api/src/wasm_c_api/types/extern_.rs new file mode 100644 index 000000000..0cd826085 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/extern_.rs @@ -0,0 +1,243 @@ +use super::super::externals::wasm_extern_t; +use super::{wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t}; +use std::convert::{TryFrom, TryInto}; +use std::mem; +use thiserror::Error; +use wasmer::ExternType; + +#[derive(Clone, Debug)] +#[allow(non_camel_case_types)] +#[repr(transparent)] +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>) {} + +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; + +#[allow(non_camel_case_types)] +#[repr(u8)] +pub enum wasm_externkind_enum { + WASM_EXTERN_FUNC = 0, + WASM_EXTERN_GLOBAL = 1, + WASM_EXTERN_TABLE = 2, + 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() + } +} +impl From<&ExternType> for wasm_externkind_enum { + fn from(other: &ExternType) -> Self { + match other { + ExternType::Function(_) => Self::WASM_EXTERN_FUNC, + ExternType::Global(_) => Self::WASM_EXTERN_GLOBAL, + ExternType::Table(_) => Self::WASM_EXTERN_TABLE, + ExternType::Memory(_) => Self::WASM_EXTERN_MEMORY, + } + } +} + +#[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 +} + +#[derive(Debug, Clone, Error)] +#[error("failed to convert from `wasm_externtype_t`: {0}")] +pub struct ExternTypeConversionError(&'static str); + +impl From<&'static str> for ExternTypeConversionError { + fn from(other: &'static str) -> Self { + Self(other) + } +} + +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 { + Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) + } else { + Err(ExternTypeConversionError("Wrong type: expected function")) + } + } +} + +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 { + Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) + } else { + Err(ExternTypeConversionError("Wrong type: expected global")) + } + } +} + +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 { + Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) + } else { + Err(ExternTypeConversionError("Wrong type: expected table")) + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_as_functype_const( + et: &'static wasm_externtype_t, +) -> Option<&'static wasm_functype_t> { + Some(c_try!(et.try_into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_as_functype( + et: &'static wasm_externtype_t, +) -> Option<&'static wasm_functype_t> { + Some(c_try!(et.try_into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_functype_as_externtype_const( + ft: &'static wasm_functype_t, +) -> &'static wasm_externtype_t { + &ft.extern_ +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_functype_as_externtype( + ft: &'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_ +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_as_globaltype_const( + et: &'static wasm_externtype_t, +) -> Option<&'static wasm_globaltype_t> { + Some(c_try!(et.try_into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_as_globaltype( + et: &'static wasm_externtype_t, +) -> Option<&'static wasm_globaltype_t> { + Some(c_try!(et.try_into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_globaltype_as_externtype_const( + gt: &'static wasm_globaltype_t, +) -> &'static wasm_externtype_t { + >.extern_ +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_globaltype_as_externtype( + gt: &'static wasm_globaltype_t, +) -> &'static wasm_externtype_t { + >.extern_ +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_as_tabletype_const( + et: &'static wasm_externtype_t, +) -> Option<&'static wasm_tabletype_t> { + Some(c_try!(et.try_into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_externtype_as_tabletype( + et: &'static wasm_externtype_t, +) -> Option<&'static wasm_tabletype_t> { + Some(c_try!(et.try_into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_tabletype_as_externtype_const( + tt: &'static wasm_tabletype_t, +) -> &'static wasm_externtype_t { + &tt.extern_ +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_tabletype_as_externtype( + tt: &'static wasm_tabletype_t, +) -> &'static wasm_externtype_t { + &tt.extern_ +} diff --git a/lib/c-api/src/wasm_c_api/types/frame.rs b/lib/c-api/src/wasm_c_api/types/frame.rs new file mode 100644 index 000000000..ca2539667 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/frame.rs @@ -0,0 +1,5 @@ +#[derive(Debug)] +#[repr(C)] +pub struct wasm_frame_t {} + +wasm_declare_vec!(frame); diff --git a/lib/c-api/src/wasm_c_api/types/function.rs b/lib/c-api/src/wasm_c_api/types/function.rs new file mode 100644 index 000000000..d42d62245 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/function.rs @@ -0,0 +1,112 @@ +use super::{wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_t}; +use std::mem; +use std::ptr::NonNull; +use wasmer::{ExternType, FunctionType, ValType}; + +#[derive(Clone, Debug)] +#[allow(non_camel_case_types)] +#[repr(transparent)] +pub struct wasm_functype_t { + pub(crate) extern_: 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") + } + } +} + +wasm_declare_vec!(functype); + +#[no_mangle] +pub unsafe extern "C" fn wasm_functype_new( + // own + params: Option>, + // own + results: Option>, +) -> Option> { + wasm_functype_new_inner(params?, 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 + .into_slice()? + .iter() + .map(|&ptr| *ptr) + .map(Into::into) + .collect::>(); + let results: Vec = results + .into_slice()? + .iter() + .map(|&ptr| *ptr) + .map(Into::into) + .collect::>(); + + let extern_ = wasm_externtype_t { + inner: ExternType::Function(FunctionType::new(params, results)), + }; + Some(Box::new(wasm_functype_t { extern_ })) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_functype_delete(_ft: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn wasm_functype_copy( + arg: Option>, +) -> Option> { + let arg = arg?; + let funcsig = arg.as_ref(); + Some(Box::new(funcsig.clone())) +} + +// TODO: fix memory leak +#[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 _ +} + +// TODO: fix memory leak +#[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 _ +} diff --git a/lib/c-api/src/wasm_c_api/types/global.rs b/lib/c-api/src/wasm_c_api/types/global.rs new file mode 100644 index 000000000..185a4d92e --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/global.rs @@ -0,0 +1,72 @@ +use super::{ + wasm_externtype_t, wasm_mutability_enum, wasm_mutability_t, wasm_valtype_delete, wasm_valtype_t, +}; +use std::convert::TryInto; +use wasmer::{ExternType, GlobalType}; + +#[derive(Clone, Debug)] +#[repr(transparent)] +#[allow(non_camel_case_types)] +pub struct wasm_globaltype_t { + pub(crate) extern_: 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`" + ); + } + } +} + +wasm_declare_vec!(globaltype); + +#[no_mangle] +pub unsafe extern "C" fn wasm_globaltype_new( + // own + valtype: Option>, + mutability: wasm_mutability_t, +) -> Option> { + wasm_globaltype_new_inner(valtype?, mutability) +} + +#[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 { + extern_: wasm_externtype_t { + inner: ExternType::Global(GlobalType::new((*valtype).into(), me.into())), + }, + }); + wasm_valtype_delete(Some(valtype)); + + Some(gd) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_globaltype_mutability( + globaltype: &wasm_globaltype_t, +) -> wasm_mutability_t { + let gt = globaltype.as_globaltype(); + wasm_mutability_enum::from(gt.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, +) -> *const wasm_valtype_t { + let gt = globaltype.as_globaltype(); + Box::into_raw(Box::new(gt.ty.into())) +} diff --git a/lib/c-api/src/wasm_c_api/types/import.rs b/lib/c-api/src/wasm_c_api/types/import.rs new file mode 100644 index 000000000..a45b1644b --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/import.rs @@ -0,0 +1,94 @@ +use super::{wasm_externtype_t, wasm_name_t}; +use std::ptr::NonNull; +use wasmer::ImportType; + +// TODO: improve ownership in `importtype_t` (can we safely use `Box` here?) +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct wasm_importtype_t { + pub(crate) module: NonNull, + pub(crate) name: NonNull, + pub(crate) extern_type: NonNull, +} + +wasm_declare_boxed_vec!(importtype); + +#[no_mangle] +pub extern "C" fn wasm_importtype_new( + module: NonNull, + name: NonNull, + extern_type: NonNull, +) -> Box { + Box::new(wasm_importtype_t { + name, + module, + extern_type, + }) +} + +#[no_mangle] +pub extern "C" fn wasm_importtype_module(et: &'static wasm_importtype_t) -> &'static wasm_name_t { + unsafe { et.module.as_ref() } +} + +#[no_mangle] +pub extern "C" fn wasm_importtype_name(et: &'static wasm_importtype_t) -> &'static wasm_name_t { + unsafe { et.name.as_ref() } +} + +#[no_mangle] +pub extern "C" fn wasm_importtype_type( + et: &'static wasm_importtype_t, +) -> &'static wasm_externtype_t { + unsafe { et.extern_type.as_ref() } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_importtype_delete(_importtype: Option>) {} + +impl From for wasm_importtype_t { + fn from(other: ImportType) -> Self { + (&other).into() + } +} + +impl From<&ImportType> for wasm_importtype_t { + fn from(other: &ImportType) -> Self { + // TODO: double check that freeing String as `Vec` is valid + let name = { + let mut heap_str: Box = other.name().to_string().into_boxed_str(); + let char_ptr = heap_str.as_mut_ptr(); + let str_len = heap_str.bytes().len(); + let name_inner = wasm_name_t { + size: str_len, + data: char_ptr, + }; + Box::leak(heap_str); + unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) } + }; + + // TODO: double check that freeing String as `Vec` is valid + let module = { + let mut heap_str: Box = other.module().to_string().into_boxed_str(); + let char_ptr = heap_str.as_mut_ptr(); + let str_len = heap_str.bytes().len(); + let name_inner = wasm_name_t { + size: str_len, + data: char_ptr, + }; + Box::leak(heap_str); + unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(name_inner))) } + }; + + let extern_type = { + let extern_type: wasm_externtype_t = other.ty().into(); + unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(extern_type))) } + }; + + wasm_importtype_t { + name, + module, + extern_type, + } + } +} diff --git a/lib/c-api/src/wasm_c_api/types/memory.rs b/lib/c-api/src/wasm_c_api/types/memory.rs new file mode 100644 index 000000000..2591a2db0 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/memory.rs @@ -0,0 +1,61 @@ +use super::wasm_externtype_t; +use wasmer::{ExternType, MemoryType, Pages}; + +// opaque type wrapping `MemoryType` +#[derive(Clone, Debug)] +#[repr(transparent)] +#[allow(non_camel_case_types)] +pub struct wasm_memorytype_t { + pub(crate) extern_: 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`" + ); + } + } +} + +wasm_declare_vec!(memorytype); + +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct wasm_limits_t { + pub(crate) min: u32, + pub(crate) max: u32, +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box { + let min_pages = Pages(limits.min as _); + // TODO: investigate if `0` is in fact a sentinel value here + let max_pages = if limits.max == 0 { + None + } else { + Some(Pages(limits.max as _)) + }; + Box::new(wasm_memorytype_t { + extern_: wasm_externtype_t { + inner: ExternType::Memory(MemoryType::new(min_pages, max_pages, false)), + }, + }) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_memorytype_delete(_memorytype: Option>) {} + +// 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(); + Box::into_raw(Box::new(wasm_limits_t { + min: md.minimum.bytes().0 as _, + max: md.maximum.map(|max| max.bytes().0 as _).unwrap_or(0), + })) +} diff --git a/lib/c-api/src/wasm_c_api/types/mod.rs b/lib/c-api/src/wasm_c_api/types/mod.rs new file mode 100644 index 000000000..d25d872c3 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/mod.rs @@ -0,0 +1,27 @@ +mod byte; +mod export; +mod extern_; +mod frame; +mod function; +mod global; +mod import; +mod memory; +mod mutability; +mod name; +mod reference; +mod table; +mod value; + +pub use byte::*; +pub use export::*; +pub use extern_::*; +pub use frame::*; +pub use function::*; +pub use global::*; +pub use import::*; +pub use memory::*; +pub use mutability::*; +pub use name::*; +pub use reference::*; +pub use table::*; +pub use value::*; diff --git a/lib/c-api/src/wasm_c_api/types/mutability.rs b/lib/c-api/src/wasm_c_api/types/mutability.rs new file mode 100644 index 000000000..23f52959c --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/mutability.rs @@ -0,0 +1,56 @@ +use std::convert::TryFrom; +use wasmer::Mutability; + +#[allow(non_camel_case_types)] +pub type wasm_mutability_t = u8; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[allow(non_camel_case_types)] +#[repr(u8)] +pub enum wasm_mutability_enum { + WASM_CONST = 0, + WASM_VAR, +} + +impl wasm_mutability_enum { + #[allow(dead_code)] + fn is_mutable(self) -> bool { + self == Self::WASM_VAR + } +} + +impl TryFrom for wasm_mutability_enum { + type Error = &'static str; + + fn try_from(item: wasm_mutability_t) -> Result { + Ok(match item { + 0 => wasm_mutability_enum::WASM_CONST, + 1 => wasm_mutability_enum::WASM_VAR, + _ => return Err("wasm_mutability_t value out of bounds"), + }) + } +} + +impl From for wasm_mutability_t { + fn from(other: wasm_mutability_enum) -> Self { + other as wasm_mutability_t + } +} + +impl From for Mutability { + fn from(other: wasm_mutability_enum) -> Self { + match other { + wasm_mutability_enum::WASM_CONST => Mutability::Const, + wasm_mutability_enum::WASM_VAR => Mutability::Var, + } + } +} + +impl From for wasm_mutability_enum { + fn from(other: Mutability) -> Self { + match other { + Mutability::Const => wasm_mutability_enum::WASM_CONST, + Mutability::Var => wasm_mutability_enum::WASM_VAR, + } + } +} diff --git a/lib/c-api/src/wasm_c_api/types/name.rs b/lib/c-api/src/wasm_c_api/types/name.rs new file mode 100644 index 000000000..aedee66cb --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/name.rs @@ -0,0 +1,4 @@ +use super::wasm_byte_vec_t; + +#[allow(non_camel_case_types)] +pub type wasm_name_t = wasm_byte_vec_t; diff --git a/lib/c-api/src/wasm_c_api/types/reference.rs b/lib/c-api/src/wasm_c_api/types/reference.rs new file mode 100644 index 000000000..f3e6424ca --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/reference.rs @@ -0,0 +1,3 @@ +// opaque type over `ExternRef`? +#[allow(non_camel_case_types)] +pub struct wasm_ref_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 new file mode 100644 index 000000000..beb37b659 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/table.rs @@ -0,0 +1,79 @@ +use super::{wasm_externtype_t, wasm_limits_t, wasm_valtype_delete, wasm_valtype_t}; +use wasmer::{ExternType, TableType}; + +#[allow(non_camel_case_types)] +pub type wasm_table_size_t = u32; + +#[derive(Clone, Debug)] +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct wasm_tabletype_t { + pub(crate) extern_: wasm_externtype_t, +} + +wasm_declare_vec!(tabletype); + +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`" + ); + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_tabletype_new( + // own + valtype: Box, + limits: &wasm_limits_t, +) -> Box { + // TODO: investigate if `0` is in fact a sentinel value here + let max_elements = if limits.max == 0 { + 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, + )), + }, + }); + wasm_valtype_delete(Some(valtype)); + + out +} + +// 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, +) -> *const wasm_limits_t { + let tt = tabletype.as_tabletype(); + Box::into_raw(Box::new(wasm_limits_t { + min: tt.minimum as _, + max: tt.maximum.unwrap_or(0), + })) +} + +// 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_element( + tabletype: &wasm_tabletype_t, +) -> *const wasm_valtype_t { + let tt = tabletype.as_tabletype(); + + Box::into_raw(Box::new(tt.ty.into())) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_tabletype_delete(_tabletype: Option>) {} diff --git a/lib/c-api/src/wasm_c_api/types/value.rs b/lib/c-api/src/wasm_c_api/types/value.rs new file mode 100644 index 000000000..c7f0fa549 --- /dev/null +++ b/lib/c-api/src/wasm_c_api/types/value.rs @@ -0,0 +1,92 @@ +use super::super::value::wasm_valkind_t; +use std::convert::TryInto; +use wasmer::ValType; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[allow(non_camel_case_types)] +#[repr(u8)] +pub enum wasm_valkind_enum { + WASM_I32 = 0, + WASM_I64 = 1, + WASM_F32 = 2, + WASM_F64 = 3, + WASM_ANYREF = 128, + WASM_FUNCREF = 129, +} + +impl From for wasm_valkind_enum { + fn from(other: ValType) -> Self { + match other { + ValType::I32 => Self::WASM_I32, + ValType::I64 => Self::WASM_I64, + ValType::F32 => Self::WASM_F32, + ValType::F64 => Self::WASM_F64, + ValType::V128 => todo!("no v128 type in Wasm C API yet!"), + ValType::ExternRef => Self::WASM_ANYREF, + ValType::FuncRef => Self::WASM_FUNCREF, + } + } +} + +impl From for ValType { + fn from(other: wasm_valkind_enum) -> Self { + use wasm_valkind_enum::*; + match other { + WASM_I32 => ValType::I32, + WASM_I64 => ValType::I64, + WASM_F32 => ValType::F32, + WASM_F64 => ValType::F64, + WASM_ANYREF => ValType::ExternRef, + WASM_FUNCREF => ValType::FuncRef, + } + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct wasm_valtype_t { + valkind: wasm_valkind_enum, +} + +impl Default for wasm_valtype_t { + fn default() -> Self { + Self { + valkind: wasm_valkind_enum::WASM_I32, + } + } +} + +wasm_declare_boxed_vec!(valtype); + +impl From for ValType { + fn from(other: wasm_valtype_t) -> Self { + other.valkind.into() + } +} + +impl From for wasm_valtype_t { + fn from(other: ValType) -> Self { + Self { + valkind: other.into(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_valtype_new(kind: wasm_valkind_t) -> Option> { + let kind_enum = kind.try_into().ok()?; + let valtype = wasm_valtype_t { valkind: kind_enum }; + Some(Box::new(valtype)) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_valtype_delete(_valtype: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn wasm_valtype_kind(valtype: *const wasm_valtype_t) -> wasm_valkind_t { + if valtype.is_null() { + // TODO: handle error + panic!("wasm_valtype_kind: argument is null pointer"); + } + return (*valtype).valkind as wasm_valkind_t; +} diff --git a/lib/c-api/src/wasm_c_api/utils.rs b/lib/c-api/src/wasm_c_api/utils.rs deleted file mode 100644 index fa041ee70..000000000 --- a/lib/c-api/src/wasm_c_api/utils.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[macro_export] -macro_rules! c_try { - ($expr:expr) => {{ - let res: Result<_, _> = $expr; - match res { - Ok(val) => val, - Err(err) => { - crate::error::update_last_error(err); - return None; - } - } - }}; - ($expr:expr, $e:expr) => {{ - let opt: Option<_> = $expr; - c_try!(opt.ok_or_else(|| $e)) - }}; -} diff --git a/lib/c-api/src/wasm_c_api/value.rs b/lib/c-api/src/wasm_c_api/value.rs index 0fc7071ad..03cc48e52 100644 --- a/lib/c-api/src/wasm_c_api/value.rs +++ b/lib/c-api/src/wasm_c_api/value.rs @@ -1,4 +1,4 @@ -use super::{wasm_ref_t, wasm_valkind_enum}; +use super::types::{wasm_ref_t, wasm_valkind_enum}; use std::convert::{TryFrom, TryInto}; use std::ptr::NonNull; use wasmer::Val; diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 066c00694..3ea267463 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -12,7 +12,6 @@ use super::{ }; // required due to really weird Rust resolution rules for macros // https://github.com/rust-lang/rust/issues/57966 -use crate::c_try; use crate::error::{update_last_error, CApiError}; use std::convert::TryFrom; use std::ffi::CStr;