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.
This commit is contained in:
Ivan Enderlin
2020-11-09 15:04:22 +01:00
parent 19fe6e482c
commit adb84e2bf6
11 changed files with 386 additions and 294 deletions

View File

@@ -33,11 +33,11 @@ pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_new( pub unsafe extern "C" fn wasm_func_new(
store: &wasm_store_t, store: &wasm_store_t,
ft: &wasm_functype_t, function_type: &wasm_functype_t,
callback: wasm_func_callback_t, callback: wasm_func_callback_t,
) -> Option<Box<wasm_func_t>> { ) -> Option<Box<wasm_func_t>> {
// TODO: handle null pointers? // 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 num_rets = func_sig.results().len();
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> { let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
let processed_args: wasm_val_vec_t = args let processed_args: wasm_val_vec_t = args
@@ -85,13 +85,13 @@ pub unsafe extern "C" fn wasm_func_new(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_new_with_env( pub unsafe extern "C" fn wasm_func_new_with_env(
store: &wasm_store_t, store: &wasm_store_t,
ft: &wasm_functype_t, function_type: &wasm_functype_t,
callback: wasm_func_callback_with_env_t, callback: wasm_func_callback_with_env_t,
env: *mut c_void, env: *mut c_void,
finalizer: wasm_env_finalizer_t, finalizer: wasm_env_finalizer_t,
) -> Option<Box<wasm_func_t>> { ) -> Option<Box<wasm_func_t>> {
// TODO: handle null pointers? // 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 num_rets = func_sig.results().len();
let inner_callback = let inner_callback =
move |env: &mut *mut c_void, args: &[Val]| -> Result<Vec<Val>, RuntimeError> { move |env: &mut *mut c_void, args: &[Val]| -> Result<Vec<Val>, RuntimeError> {

View File

@@ -13,13 +13,13 @@ pub struct wasm_global_t {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_new( pub unsafe extern "C" fn wasm_global_new(
store: &wasm_store_t, store: &wasm_store_t,
gt: &wasm_globaltype_t, global_type: &wasm_globaltype_t,
val: &wasm_val_t, val: &wasm_val_t,
) -> Option<Box<wasm_global_t>> { ) -> Option<Box<wasm_global_t>> {
let gt = gt.as_globaltype(); let global_type = &global_type.inner().global_type;
let wasm_val = val.try_into().ok()?; let wasm_val = val.try_into().ok()?;
let store = &store.inner; 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) Global::new_mut(store, wasm_val)
} else { } else {
Global::new(store, wasm_val) Global::new(store, wasm_val)

View File

@@ -12,10 +12,10 @@ pub struct wasm_memory_t {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_new( pub unsafe extern "C" fn wasm_memory_new(
store: &wasm_store_t, store: &wasm_store_t,
mt: &wasm_memorytype_t, memory_type: &wasm_memorytype_t,
) -> Option<Box<wasm_memory_t>> { ) -> Option<Box<wasm_memory_t>> {
let md = mt.as_memorytype().clone(); let memory_type = memory_type.inner().memory_type.clone();
let memory = c_try!(Memory::new(&store.inner, md)); let memory = c_try!(Memory::new(&store.inner, memory_type));
Some(Box::new(wasm_memory_t { inner: memory })) Some(Box::new(wasm_memory_t { inner: memory }))
} }

View File

@@ -11,12 +11,12 @@ pub struct wasm_table_t {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_table_new( pub unsafe extern "C" fn wasm_table_new(
store: &wasm_store_t, store: &wasm_store_t,
tt: &wasm_tabletype_t, table_type: &wasm_tabletype_t,
init: *const wasm_ref_t, init: *const wasm_ref_t,
) -> Option<Box<wasm_table_t>> { ) -> Option<Box<wasm_table_t>> {
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 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 })) Some(Box::new(wasm_table_t { inner: table }))
} }

View File

@@ -17,6 +17,7 @@ macro_rules! wasm_declare_vec_inner {
macro_rules! wasm_declare_vec { macro_rules! wasm_declare_vec {
($name:ident) => { ($name:ident) => {
paste::item! { paste::item! {
#[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct [<wasm_ $name _vec_t>] { pub struct [<wasm_ $name _vec_t>] {
pub size: usize, pub size: usize,
@@ -108,6 +109,7 @@ macro_rules! wasm_declare_vec {
macro_rules! wasm_declare_boxed_vec { macro_rules! wasm_declare_boxed_vec {
($name:ident) => { ($name:ident) => {
paste::item! { paste::item! {
#[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct [<wasm_ $name _vec_t>] { pub struct [<wasm_ $name _vec_t>] {
pub size: usize, pub size: usize,

View File

@@ -259,11 +259,9 @@ mod tests {
wasmer_assert(func_params->size == 2); 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[0]) == WASM_I32);
wasmer_assert(wasm_valtype_kind(func_params->data[1]) == WASM_I64); 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); const wasm_valtype_vec_t* func_results = wasm_functype_results(func_type);
wasmer_assert(func_results->size == 0); 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); const wasm_valtype_vec_t* func_params = wasm_functype_params(func_type);
wasmer_assert(func_params->size == 0); 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); const wasm_valtype_vec_t* func_results = wasm_functype_results(func_type);
wasmer_assert(func_results->size == 0); wasmer_assert(func_results->size == 0);
wasm_valtype_vec_delete((wasm_valtype_vec_t*) func_results);
} }
{ {

View File

@@ -1,47 +1,13 @@
use super::super::externals::wasm_extern_t; 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::convert::{TryFrom, TryInto};
use std::mem; use std::mem;
use thiserror::Error; use thiserror::Error;
use wasmer::ExternType; 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<wasm_externtype_t> {
Box::new(wasm_externtype_t {
inner: e.inner.ty(),
})
}
#[no_mangle]
pub unsafe extern "C" fn wasm_externtype_delete(_et: Option<Box<wasm_externtype_t>>) {}
#[no_mangle]
pub extern "C" fn wasm_externtype_copy(
wasm_externtype: &wasm_externtype_t,
) -> Box<wasm_externtype_t> {
Box::new(wasm_externtype_t {
inner: wasm_externtype.inner.clone(),
})
}
impl From<ExternType> 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)] #[allow(non_camel_case_types)]
type wasm_externkind_t = u8; type wasm_externkind_t = u8;
@@ -54,11 +20,6 @@ pub enum wasm_externkind_enum {
WASM_EXTERN_MEMORY = 3, 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<ExternType> for wasm_externkind_enum { impl From<ExternType> for wasm_externkind_enum {
fn from(other: ExternType) -> Self { fn from(other: ExternType) -> Self {
(&other).into() (&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<ExternType> 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] #[no_mangle]
pub unsafe extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkind_t { pub unsafe extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
wasm_externkind_enum::from(&et.inner) as wasm_externkind_t 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<Box<wasm_externtype_t>>) {}
#[no_mangle]
pub extern "C" fn wasm_externtype_copy(externtype: &wasm_externtype_t) -> Box<wasm_externtype_t> {
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)] #[derive(Debug, Clone, Error)]
@@ -94,7 +127,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_functype_t {
type Error = ExternTypeConversionError; type Error = ExternTypeConversionError;
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> { fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
if let ExternType::Function(_) = other.inner { if let WasmExternType::Function(_) = other.inner {
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
} else { } else {
Err(ExternTypeConversionError("Wrong type: expected function")) Err(ExternTypeConversionError("Wrong type: expected function"))
@@ -106,7 +139,7 @@ impl TryFrom<&'static wasm_externtype_t> for &'static wasm_globaltype_t {
type Error = ExternTypeConversionError; type Error = ExternTypeConversionError;
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> { fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
if let ExternType::Global(_) = other.inner { if let WasmExternType::Global(_) = other.inner {
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
} else { } else {
Err(ExternTypeConversionError("Wrong type: expected global")) 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<Self, Self::Error> {
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 { impl TryFrom<&'static wasm_externtype_t> for &'static wasm_tabletype_t {
type Error = ExternTypeConversionError; type Error = ExternTypeConversionError;
fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> { fn try_from(other: &'static wasm_externtype_t) -> Result<Self, Self::Error> {
if let ExternType::Table(_) = other.inner { if let WasmExternType::Table(_) = other.inner {
Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) }) Ok(unsafe { mem::transmute::<&'static wasm_externtype_t, Self>(other) })
} else { } else {
Err(ExternTypeConversionError("Wrong type: expected table")) 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<Self, Self::Error> {
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] #[no_mangle]
pub unsafe extern "C" fn wasm_externtype_as_functype_const( 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> { ) -> Option<&'static wasm_functype_t> {
Some(c_try!(et.try_into())) Some(c_try!(extern_type.try_into()))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_externtype_as_functype( 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> { ) -> Option<&'static wasm_functype_t> {
Some(c_try!(et.try_into())) Some(c_try!(extern_type.try_into()))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_as_externtype_const( 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 { ) -> &'static wasm_externtype_t {
&ft.extern_ &function_type.extern_type
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_as_externtype( pub unsafe extern "C" fn wasm_functype_as_externtype(
ft: &'static wasm_functype_t, function_type: &'static wasm_functype_t,
) -> &'static wasm_externtype_t { ) -> &'static wasm_externtype_t {
&ft.extern_ &function_type.extern_type
}
#[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] #[no_mangle]
pub unsafe extern "C" fn wasm_externtype_as_globaltype_const( 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> { ) -> Option<&'static wasm_globaltype_t> {
Some(c_try!(et.try_into())) Some(c_try!(extern_type.try_into()))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_externtype_as_globaltype( 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> { ) -> Option<&'static wasm_globaltype_t> {
Some(c_try!(et.try_into())) Some(c_try!(extern_type.try_into()))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_as_externtype_const( 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 { ) -> &'static wasm_externtype_t {
&gt.extern_ &global_type.extern_type
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_as_externtype( pub unsafe extern "C" fn wasm_globaltype_as_externtype(
gt: &'static wasm_globaltype_t, global_type: &'static wasm_globaltype_t,
) -> &'static wasm_externtype_t { ) -> &'static wasm_externtype_t {
&gt.extern_ &global_type.extern_type
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_externtype_as_tabletype_const( 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> { ) -> Option<&'static wasm_tabletype_t> {
Some(c_try!(et.try_into())) Some(c_try!(extern_type.try_into()))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_externtype_as_tabletype( 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> { ) -> Option<&'static wasm_tabletype_t> {
Some(c_try!(et.try_into())) Some(c_try!(extern_type.try_into()))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_as_externtype_const( 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 { ) -> &'static wasm_externtype_t {
&tt.extern_ &table_type.extern_type
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_as_externtype( pub unsafe extern "C" fn wasm_tabletype_as_externtype(
tt: &'static wasm_tabletype_t, table_type: &'static wasm_tabletype_t,
) -> &'static wasm_externtype_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
} }

View File

@@ -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::mem;
use std::ptr::NonNull; use std::ptr::NonNull;
use wasmer::{ExternType, FunctionType, ValType}; use wasmer::{ExternType, FunctionType, ValType};
#[derive(Debug)]
pub(crate) struct WasmFunctionType {
pub(crate) function_type: FunctionType,
params: Box<wasm_valtype_vec_t>,
results: Box<wasm_valtype_vec_t>,
}
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::<Vec<*mut wasm_valtype_t>>();
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::<Vec<*mut wasm_valtype_t>>();
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)] #[allow(non_camel_case_types)]
#[derive(Clone, Debug)] #[derive(Debug)]
#[repr(transparent)]
pub struct wasm_functype_t { pub struct wasm_functype_t {
pub(crate) extern_: wasm_externtype_t, pub(crate) extern_type: wasm_externtype_t,
} }
impl wasm_functype_t { impl wasm_functype_t {
pub(crate) fn sig(&self) -> &FunctionType { pub(crate) fn new(function_type: FunctionType) -> Self {
if let ExternType::Function(ref f) = self.extern_.inner { Self {
f extern_type: wasm_externtype_t::new(ExternType::Function(function_type)),
} else {
unreachable!("data corruption: `wasm_functype_t` does not contain a function")
} }
} }
pub(crate) fn new(function_type: FunctionType) -> Self { pub(crate) fn inner(&self) -> &WasmFunctionType {
Self { match &self.extern_type.inner {
extern_: wasm_externtype_t { WasmExternType::Function(wasm_function_type) => &wasm_function_type,
inner: ExternType::Function(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 // own
results: Option<NonNull<wasm_valtype_vec_t>>, results: Option<NonNull<wasm_valtype_vec_t>>,
) -> Option<Box<wasm_functype_t>> { ) -> Option<Box<wasm_functype_t>> {
wasm_functype_new_inner(params?, results?) let params = params?;
} let results = results?;
unsafe fn wasm_functype_new_inner(
// own
params: NonNull<wasm_valtype_vec_t>,
// own
results: NonNull<wasm_valtype_vec_t>,
) -> Option<Box<wasm_functype_t>> {
let params = params.as_ref();
let results = results.as_ref();
let params: Vec<ValType> = params let params: Vec<ValType> = params
.as_ref()
.into_slice()? .into_slice()?
.iter() .iter()
.map(|ptr| **ptr) .map(|ptr| **ptr)
.map(Into::into) .map(Into::into)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let results: Vec<ValType> = results let results: Vec<ValType> = results
.as_ref()
.into_slice()? .into_slice()?
.iter() .iter()
.map(|ptr| **ptr) .map(|ptr| **ptr)
@@ -66,51 +122,29 @@ unsafe fn wasm_functype_new_inner(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_delete(_ft: Option<Box<wasm_functype_t>>) {} pub unsafe extern "C" fn wasm_functype_delete(_function_type: Option<Box<wasm_functype_t>>) {}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_copy( pub unsafe extern "C" fn wasm_functype_copy(
arg: Option<NonNull<wasm_functype_t>>, function_type: Option<NonNull<wasm_functype_t>>,
) -> Option<Box<wasm_functype_t>> { ) -> Option<Box<wasm_functype_t>> {
let arg = arg?; let function_type = function_type?;
let funcsig = arg.as_ref();
Some(Box::new(funcsig.clone())) Some(Box::new(wasm_functype_t::new(
function_type.as_ref().inner().function_type.clone(),
)))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_params(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t { pub unsafe extern "C" fn wasm_functype_params(
let mut valtypes = ft function_type: &wasm_functype_t,
.sig() ) -> *const wasm_valtype_vec_t {
.params() function_type.inner().params.as_ref() as *const _
.iter()
.cloned()
.map(Into::into)
.map(Box::new)
.map(Box::into_raw)
.collect::<Vec<*mut wasm_valtype_t>>();
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 _
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_results(ft: &wasm_functype_t) -> *const wasm_valtype_vec_t { pub unsafe extern "C" fn wasm_functype_results(
let mut valtypes = ft function_type: &wasm_functype_t,
.sig() ) -> *const wasm_valtype_vec_t {
.results() function_type.inner().results.as_ref() as *const _
.iter()
.cloned()
.map(Into::into)
.map(Box::new)
.map(Box::into_raw)
.collect::<Vec<*mut wasm_valtype_t>>();
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 _
} }

View File

@@ -1,31 +1,41 @@
use super::{ 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 std::convert::TryInto;
use wasmer::{ExternType, GlobalType}; 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)] #[allow(non_camel_case_types)]
#[derive(Clone, Debug)] #[derive(Debug)]
#[repr(transparent)]
pub struct wasm_globaltype_t { pub struct wasm_globaltype_t {
pub(crate) extern_: wasm_externtype_t, pub(crate) extern_type: wasm_externtype_t,
} }
impl wasm_globaltype_t { impl wasm_globaltype_t {
pub(crate) fn as_globaltype(&self) -> &GlobalType { pub(crate) fn new(global_type: GlobalType) -> Self {
if let ExternType::Global(ref g) = self.extern_.inner { Self {
g extern_type: wasm_externtype_t::new(ExternType::Global(global_type)),
} else {
unreachable!(
"Data corruption detected: `wasm_globaltype_t` does not contain a `GlobalType`"
);
} }
} }
pub(crate) fn new(global_type: GlobalType) -> Self { pub(crate) fn inner(&self) -> &WasmGlobalType {
Self { match &self.extern_type.inner {
extern_: wasm_externtype_t { WasmExternType::Global(wasm_global_type) => &wasm_global_type,
inner: ExternType::Global(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<Box<wasm_valtype_t>>, valtype: Option<Box<wasm_valtype_t>>,
mutability: wasm_mutability_t, mutability: wasm_mutability_t,
) -> Option<Box<wasm_globaltype_t>> { ) -> Option<Box<wasm_globaltype_t>> {
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] #[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_delete(_globaltype: Option<Box<wasm_globaltype_t>>) {} pub unsafe extern "C" fn wasm_globaltype_delete(_global_type: Option<Box<wasm_globaltype_t>>) {}
unsafe fn wasm_globaltype_new_inner(
// own
valtype: Box<wasm_valtype_t>,
mutability: wasm_mutability_t,
) -> Option<Box<wasm_globaltype_t>> {
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)
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_mutability( pub unsafe extern "C" fn wasm_globaltype_mutability(
globaltype: &wasm_globaltype_t, global_type: &wasm_globaltype_t,
) -> wasm_mutability_t { ) -> wasm_mutability_t {
let gt = globaltype.as_globaltype(); wasm_mutability_enum::from(global_type.inner().global_type.mutability).into()
wasm_mutability_enum::from(gt.mutability).into()
} }
// TODO: fix memory leak // TODO: fix memory leak
// this function leaks memory because the returned limits pointer is not owned // this function leaks memory because the returned limits pointer is not owned
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_content( pub unsafe extern "C" fn wasm_globaltype_content(
globaltype: &wasm_globaltype_t, global_type: &wasm_globaltype_t,
) -> *const wasm_valtype_t { ) -> *const wasm_valtype_t {
let gt = globaltype.as_globaltype(); let global_type = global_type.inner().global_type;
Box::into_raw(Box::new(gt.ty.into()))
Box::into_raw(Box::new(global_type.ty.into()))
} }

View File

@@ -1,49 +1,46 @@
use super::wasm_externtype_t; use super::{wasm_externtype_t, WasmExternType};
use wasmer::{ExternType, MemoryType, Pages}; 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)] #[allow(non_camel_case_types)]
#[derive(Clone, Debug)] #[derive(Debug)]
#[repr(transparent)]
pub struct wasm_memorytype_t { pub struct wasm_memorytype_t {
pub(crate) extern_: wasm_externtype_t, pub(crate) extern_type: wasm_externtype_t,
} }
impl wasm_memorytype_t { impl wasm_memorytype_t {
pub(crate) fn as_memorytype(&self) -> &MemoryType { pub(crate) fn new(memory_type: MemoryType) -> Self {
if let ExternType::Memory(ref mt) = self.extern_.inner { Self {
mt extern_type: wasm_externtype_t::new(ExternType::Memory(memory_type)),
} else {
unreachable!(
"Data corruption detected: `wasm_memorytype_t` does not contain a `MemoryType`"
);
} }
} }
pub(crate) fn new(memory_type: MemoryType) -> Self { pub(crate) fn inner(&self) -> &WasmMemoryType {
Self { match &self.extern_type.inner {
extern_: wasm_externtype_t { WasmExternType::Memory(wasm_memory_type) => &wasm_memory_type,
inner: ExternType::Memory(memory_type), _ => {
}, unreachable!("Data corruption: `wasm_memorytype_t` does not contain a memory type")
}
} }
} }
} }
wasm_declare_vec!(memorytype); 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] #[no_mangle]
pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> { pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> {
let min_pages = Pages(limits.min as _); 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 { let max_pages = if limits.max == LIMITS_MAX_SENTINEL {
None None
} else { } else {
@@ -56,17 +53,29 @@ pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memorytype_delete(_memorytype: Option<Box<wasm_memorytype_t>>) {} pub unsafe extern "C" fn wasm_memorytype_delete(_memory_type: Option<Box<wasm_memorytype_t>>) {}
#[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 // TODO: fix memory leak
// this function leaks memory because the returned limits pointer is not owned // this function leaks memory because the returned limits pointer is not owned
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memorytype_limits(mt: &wasm_memorytype_t) -> *const wasm_limits_t { pub unsafe extern "C" fn wasm_memorytype_limits(
let md = mt.as_memorytype(); 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 { Box::into_raw(Box::new(wasm_limits_t {
min: md.minimum.0 as _, min: memory_type.minimum.0 as _,
max: md max: memory_type
.maximum .maximum
.map(|max| max.0 as _) .map(|max| max.0 as _)
.unwrap_or(LIMITS_MAX_SENTINEL), .unwrap_or(LIMITS_MAX_SENTINEL),

View File

@@ -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}; use wasmer::{ExternType, TableType};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type wasm_table_size_t = u32; pub type wasm_table_size_t = u32;
#[allow(non_camel_case_types)] const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
#[derive(Clone, Debug)]
#[repr(C)] #[derive(Debug, Clone)]
pub struct wasm_tabletype_t { pub(crate) struct WasmTableType {
pub(crate) extern_: wasm_externtype_t, 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 { impl wasm_tabletype_t {
pub(crate) fn as_tabletype(&self) -> &TableType { pub(crate) fn new(table_type: TableType) -> Self {
if let ExternType::Table(ref t) = self.extern_.inner { Self {
t extern_type: wasm_externtype_t::new(ExternType::Table(table_type)),
} else { }
unreachable!( }
"Data corruption detected: `wasm_tabletype_t` does not contain a `TableType`"
); 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] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_new( pub unsafe extern "C" fn wasm_tabletype_new(
// own // own
valtype: Box<wasm_valtype_t>, valtype: Option<Box<wasm_valtype_t>>,
limits: &wasm_limits_t, limits: &wasm_limits_t,
) -> Box<wasm_tabletype_t> { ) -> Option<Box<wasm_tabletype_t>> {
let valtype = valtype?;
let max_elements = if limits.max == LIMITS_MAX_SENTINEL { let max_elements = if limits.max == LIMITS_MAX_SENTINEL {
None None
} else { } else {
Some(limits.max as _) Some(limits.max as _)
}; };
let out = Box::new(wasm_tabletype_t { let table_type = Box::new(wasm_tabletype_t::new(TableType::new(
extern_: wasm_externtype_t { (*valtype).into(),
inner: ExternType::Table(TableType::new( limits.min as _,
(*valtype).into(), max_elements,
limits.min as _, )));
max_elements,
)),
},
});
wasm_valtype_delete(Some(valtype)); wasm_valtype_delete(Some(valtype));
out Some(table_type)
} }
// TODO: fix memory leak // TODO: fix memory leak
// this function leaks memory because the returned limits pointer is not owned // this function leaks memory because the returned limits pointer is not owned
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_limits( pub unsafe extern "C" fn wasm_tabletype_limits(
tabletype: &wasm_tabletype_t, table_type: &wasm_tabletype_t,
) -> *const wasm_limits_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 { Box::into_raw(Box::new(wasm_limits_t {
min: tt.minimum as _, min: table_type.minimum as _,
max: tt.maximum.unwrap_or(LIMITS_MAX_SENTINEL), 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 // this function leaks memory because the returned limits pointer is not owned
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_element( pub unsafe extern "C" fn wasm_tabletype_element(
tabletype: &wasm_tabletype_t, table_type: &wasm_tabletype_t,
) -> *const wasm_valtype_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] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_delete(_tabletype: Option<Box<wasm_tabletype_t>>) {} pub unsafe extern "C" fn wasm_tabletype_delete(_table_type: Option<Box<wasm_tabletype_t>>) {}