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 8d1abdedd..77e76f1c7 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -2,17 +2,27 @@ 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, wasm_val_vec_t}; +use super::CApiExternTag; use std::convert::TryInto; use std::ffi::c_void; use std::sync::Arc; -use wasmer::{Function, Instance, RuntimeError, Val}; +use wasmer::{Function, RuntimeError, Val}; #[derive(Debug)] #[allow(non_camel_case_types)] +#[repr(C)] pub struct wasm_func_t { - pub(crate) inner: Function, - // this is how we ensure the instance stays alive - pub(crate) instance: Option>, + pub(crate) tag: CApiExternTag, + pub(crate) inner: Box, +} + +impl wasm_func_t { + pub(crate) fn new(function: Function) -> Self { + Self { + tag: CApiExternTag::Function, + inner: Box::new(function), + } + } } #[allow(non_camel_case_types)] @@ -80,10 +90,7 @@ pub unsafe extern "C" fn wasm_func_new( }; let function = Function::new(&store.inner, func_sig, inner_callback); - Some(Box::new(wasm_func_t { - instance: None, - inner: function, - })) + Some(Box::new(wasm_func_t { inner: function })) } #[no_mangle] @@ -172,10 +179,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( trampoline, ); - Some(Box::new(wasm_func_t { - instance: None, - inner: function, - })) + Some(Box::new(wasm_func_t { inner: function })) } #[no_mangle] 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 624d4620f..1504784cd 100644 --- a/lib/c-api/src/wasm_c_api/externals/global.rs +++ b/lib/c-api/src/wasm_c_api/externals/global.rs @@ -1,14 +1,25 @@ use super::super::store::wasm_store_t; use super::super::types::wasm_globaltype_t; use super::super::value::wasm_val_t; +use super::CApiExternTag; use crate::error::update_last_error; use std::convert::TryInto; use wasmer::{Global, Val}; #[allow(non_camel_case_types)] +#[repr(C)] pub struct wasm_global_t { - // maybe needs to hold onto instance - pub(crate) inner: Global, + pub(crate) tag: CApiExternTag, + pub(crate) inner: Box, +} + +impl wasm_global_t { + pub(crate) fn new(global: Global) -> Self { + Self { + tag: CApiExternTag::Global, + inner: Box::new(global), + } + } } #[no_mangle] 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 e43db12ee..e8b65a0b6 100644 --- a/lib/c-api/src/wasm_c_api/externals/memory.rs +++ b/lib/c-api/src/wasm_c_api/externals/memory.rs @@ -1,12 +1,23 @@ use super::super::store::wasm_store_t; use super::super::types::wasm_memorytype_t; +use super::CApiExternTag; use std::mem; use wasmer::{Memory, Pages}; #[allow(non_camel_case_types)] +#[repr(C)] pub struct wasm_memory_t { - // maybe needs to hold onto instance - pub(crate) inner: Memory, + pub(crate) tag: CApiExternTag, + pub(crate) inner: Box, +} + +impl wasm_memory_t { + pub(crate) fn new(memory: Memory) -> Self { + Self { + tag: CApiExternTag::Memory, + inner: Box::new(memory), + } + } } #[no_mangle] diff --git a/lib/c-api/src/wasm_c_api/externals/mod.rs b/lib/c-api/src/wasm_c_api/externals/mod.rs index 869ae4b6e..7548ff3c4 100644 --- a/lib/c-api/src/wasm_c_api/externals/mod.rs +++ b/lib/c-api/src/wasm_c_api/externals/mod.rs @@ -12,10 +12,94 @@ use wasmer::{Extern, Instance}; #[allow(non_camel_case_types)] #[derive(Clone)] +#[repr(transparent)] pub struct wasm_extern_t { - // this is how we ensure the instance stays alive - pub(crate) instance: Option>, - pub(crate) inner: Extern, + pub(crate) inner: wasm_extern_inner, +} + +/// All elements in this union must be `repr(C)` and have a +/// `CApiExternTag` as their first element. +pub(crate) union wasm_extern_inner { + function: wasm_func_t, + memory: wasm_memory_t, + global: wasm_global_t, + table: wasm_table_t, +} + +#[cfg(test)] +mod extern_tests { + use super::*; + + #[test] + fn externs_are_the_same_size() { + use std::mem::size_of; + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + } +} + +impl wasm_extern_t { + pub(crate) fn get_tag(&self) -> CApiExternTag { + unsafe { self.inner.function.tag } + } + + pub(crate) fn ty(&self) -> ExternType { + match self.get_tag() { + CApiExternTag::Function => unsafe { self.inner.function.inner.ty() }, + CApiExternTag::Memory => unsafe { self.inner.memory.inner.ty() }, + CApiExternTag::Global => unsafe { self.inner.global.inner.ty() }, + CApiExternTag::Table => unsafe { self.inner.table.inner.ty() }, + } + } +} + +impl From for wasm_extern_t { + fn from(other: Extern) -> Self { + match other { + Extern::Function(function) => Self { + inner: wasm_extern_inner { + function: wasm_func_t::new(function), + }, + }, + Extern::Memory(memory) => Self { + inner: wasm_extern_inner { + memory: wasm_memory_t::new(memory), + }, + }, + Extern::Table(table) => Self { + inner: wasm_extern_inner { + table: wasm_table_t::new(table), + }, + }, + Extern::Global(global) => Self { + inner: wasm_extern_inner { + global: wasm_global_t::new(global), + }, + }, + } + } +} + +impl From for Extern { + fn from(other: wasm_extern_t) -> Self { + match other.get_tag() { + CApiExternTag::Function => unsafe { self.inner.function.inner.clone().into() }, + CApiExternTag::Memory => unsafe { self.inner.memory.inner.clone().into() }, + CApiExternTag::Table => unsafe { self.inner.table.inner.clone().into() }, + CApiExternTag::Global => unsafe { self.inner.global.inner.clone().into() }, + } + } +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub(crate) enum CApiExternTag { + Function, + Global, + Table, + Memory, } wasm_declare_boxed_vec!(extern); 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 d2b23f5fa..775b84f63 100644 --- a/lib/c-api/src/wasm_c_api/externals/table.rs +++ b/lib/c-api/src/wasm_c_api/externals/table.rs @@ -1,11 +1,22 @@ use super::super::store::wasm_store_t; use super::super::types::{wasm_ref_t, wasm_table_size_t, wasm_tabletype_t}; +use super::CApiExternTag; use wasmer::Table; #[allow(non_camel_case_types)] +#[repr(C)] pub struct wasm_table_t { - // maybe needs to hold onto instance - pub(crate) inner: Table, + pub(crate) tag: CApiExternTag, + pub(crate) inner: Box, +} + +impl wasm_table_t { + pub(crate) fn new(table: Table) -> Self { + Self { + tag: CApiExternTag::Table, + inner: Box::new(table), + } + } } #[no_mangle] diff --git a/lib/c-api/src/wasm_c_api/instance.rs b/lib/c-api/src/wasm_c_api/instance.rs index 9f7bc3842..d440d81d7 100644 --- a/lib/c-api/src/wasm_c_api/instance.rs +++ b/lib/c-api/src/wasm_c_api/instance.rs @@ -192,10 +192,7 @@ pub unsafe extern "C" fn wasm_instance_exports( None }; - Box::into_raw(Box::new(wasm_extern_t { - instance: Some(Arc::clone(instance)), - inner: r#extern.clone(), - })) + Box::into_raw(Box::new(r#extern.clone().into())) }) .collect::>(); extern_vec.shrink_to_fit(); diff --git a/lib/c-api/src/wasm_c_api/types/extern_.rs b/lib/c-api/src/wasm_c_api/types/extern_.rs index 4ef1f8cb6..cdf2abca9 100644 --- a/lib/c-api/src/wasm_c_api/types/extern_.rs +++ b/lib/c-api/src/wasm_c_api/types/extern_.rs @@ -85,12 +85,12 @@ impl From<&ExternType> for wasm_externtype_t { #[no_mangle] pub unsafe extern "C" fn wasm_extern_type(r#extern: &wasm_extern_t) -> Box { - Box::new(wasm_externtype_t::new(r#extern.inner.ty())) + Box::new(wasm_externtype_t::new(r#extern.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 + wasm_externkind_enum::from(r#extern.ty()) as wasm_externkind_t } #[no_mangle] diff --git a/lib/c-api/src/wasm_c_api/unstable/wasi.rs b/lib/c-api/src/wasm_c_api/unstable/wasi.rs index 8eb0a5fa2..53aa8173b 100644 --- a/lib/c-api/src/wasm_c_api/unstable/wasi.rs +++ b/lib/c-api/src/wasm_c_api/unstable/wasi.rs @@ -186,10 +186,7 @@ fn wasi_get_unordered_imports_inner( Box::new(wasmer_named_extern_t { module, name, - r#extern: Box::new(wasm_extern_t { - instance: None, - inner: extern_inner, - }), + r#extern: Box::new(extern_inner.into()), }) }) .collect::>() 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 5d16fabb0..190c6cbac 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -390,10 +390,7 @@ fn wasi_get_imports_inner( })); let inner = Extern::from_vm_export(store, export); - Some(Box::new(wasm_extern_t { - instance: None, - inner, - })) + Some(Box::new(inner.into())) }) .collect::>>()? .into(); @@ -407,10 +404,7 @@ pub unsafe extern "C" fn wasi_get_start_function( ) -> Option> { let start = c_try!(instance.inner.exports.get_function("_start")); - Some(Box::new(wasm_func_t { - inner: start.clone(), - instance: Some(instance.inner.clone()), - })) + Some(Box::new(wasm_func_t::new(start.clone()))) } #[cfg(test)]