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]
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<Box<wasm_func_t>> {
// 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<Vec<Val>, 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<Box<wasm_func_t>> {
// 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<Vec<Val>, RuntimeError> {

View File

@@ -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<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 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)

View File

@@ -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<Box<wasm_memory_t>> {
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 }))
}

View File

@@ -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<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 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 }))
}

View File

@@ -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 [<wasm_ $name _vec_t>] {
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 [<wasm_ $name _vec_t>] {
pub size: usize,

View File

@@ -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);
}
{

View File

@@ -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<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)]
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<ExternType> 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<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]
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<wasm_externtype_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)]
@@ -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<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) })
} 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<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) })
} 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<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 {
type Error = ExternTypeConversionError;
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) })
} 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<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]
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 {
&gt.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 {
&gt.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
}

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::ptr::NonNull;
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)]
#[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<NonNull<wasm_valtype_vec_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
.as_ref()
.into_slice()?
.iter()
.map(|ptr| **ptr)
.map(Into::into)
.collect::<Vec<_>>();
let results: Vec<ValType> = 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<Box<wasm_functype_t>>) {}
pub unsafe extern "C" fn wasm_functype_delete(_function_type: Option<Box<wasm_functype_t>>) {}
#[no_mangle]
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>> {
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::<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 _
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::<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 _
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 _
}

View File

@@ -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<Box<wasm_valtype_t>>,
mutability: wasm_mutability_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]
pub unsafe extern "C" fn wasm_globaltype_delete(_globaltype: 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)
}
pub unsafe extern "C" fn wasm_globaltype_delete(_global_type: Option<Box<wasm_globaltype_t>>) {}
#[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()))
}

View File

@@ -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<wasm_memorytype_t> {
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<wasm
}
#[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
// 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),

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};
#[allow(non_camel_case_types)]
pub type wasm_table_size_t = u32;
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
#[derive(Debug, Clone)]
pub(crate) struct WasmTableType {
pub(crate) table_type: TableType,
}
impl WasmTableType {
pub(crate) fn new(table_type: TableType) -> Self {
Self { table_type }
}
}
#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
#[repr(C)]
#[derive(Debug)]
#[repr(transparent)]
pub struct wasm_tabletype_t {
pub(crate) extern_: wasm_externtype_t,
pub(crate) extern_type: wasm_externtype_t,
}
impl wasm_tabletype_t {
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"),
}
}
}
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`"
);
}
}
}
const LIMITS_MAX_SENTINEL: u32 = u32::max_value();
#[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_new(
// own
valtype: Box<wasm_valtype_t>,
valtype: Option<Box<wasm_valtype_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 {
None
} else {
Some(limits.max as _)
};
let out = Box::new(wasm_tabletype_t {
extern_: wasm_externtype_t {
inner: ExternType::Table(TableType::new(
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<Box<wasm_tabletype_t>>) {}
pub unsafe extern "C" fn wasm_tabletype_delete(_table_type: Option<Box<wasm_tabletype_t>>) {}