Get Wasm C API Hello World working

This commit is contained in:
Mark McCaskey
2020-05-29 13:39:24 -07:00
parent 027e26c1b4
commit 342b2cf927
6 changed files with 337 additions and 296 deletions

View File

@@ -108,6 +108,11 @@ impl Global {
exported: wasmer_export, exported: wasmer_export,
} }
} }
/// Returns whether or not these two globals refer to the same data.
pub fn same(&self, other: &Global) -> bool {
self.exported.same(&other.exported)
}
} }
impl fmt::Debug for Global { impl fmt::Debug for Global {

View File

@@ -126,6 +126,11 @@ impl Memory {
exported: wasmer_export, exported: wasmer_export,
} }
} }
/// Returns whether or not these two globals refer to the same data.
pub fn same(&self, other: &Memory) -> bool {
self.exported.same(&other.exported)
}
} }
impl<'a> Exportable<'a> for Memory { impl<'a> Exportable<'a> for Memory {

View File

@@ -51,6 +51,7 @@ If you wish to use more than one compiler, you can simply import it from it's ow
use wasmer::{Store, Engine}; use wasmer::{Store, Engine};
use wasmer_compiler_singlepass::SinglepassConfig; use wasmer_compiler_singlepass::SinglepassConfig;
// TODO: update this, this is now out of date:
let engine = Engine::new(SinglepassConfig::default()); let engine = Engine::new(SinglepassConfig::default());
let store = Store::new_config(&engine); let store = Store::new_config(&engine);
```"# ```"#

View File

@@ -1,5 +1,6 @@
//! entrypoints for the standard C API //! entrypoints for the standard C API
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use std::ffi::c_void; use std::ffi::c_void;
use std::mem; use std::mem;
@@ -8,9 +9,9 @@ use std::slice;
use std::sync::Arc; use std::sync::Arc;
use wasmer::{ use wasmer::{
Extern, ExternType, Function, FunctionType, Global, GlobalType, ImportObject, Instance, CompilerConfig, Engine, Exports, Extern, ExternType, Function, FunctionType, Global,
LikeNamespace, Memory, MemoryType, Module, Mutability, Pages, RuntimeError, Store, Val, GlobalType, ImportObject, Instance, JITEngine, Memory, MemoryType, Module, Mutability, Pages,
ValType, RuntimeError, Store, Tunables, Val, ValType,
}; };
// TODO: remove delete from macro generation, need to do that manually // TODO: remove delete from macro generation, need to do that manually
@@ -41,29 +42,44 @@ pub extern "C" fn wasm_config_new() -> *mut wasm_config_t {
} }
#[repr(C)] #[repr(C)]
pub struct wasm_engine_t {} pub struct wasm_engine_t {
inner: Arc<dyn Engine + Send + Sync>,
}
#[no_mangle] fn get_default_compiler_config() -> Box<dyn CompilerConfig> {
pub extern "C" fn wasm_engine_new() -> *mut wasm_engine_t { // TODO: use cfg-if
let mut wasmer_heap_string = "WASMER ENGINE".to_string(); #[cfg(feature = "cranelift-backend")]
wasmer_heap_string.shrink_to_fit(); Box::new(wasmer::CraneliftConfig::default())
let boxed_string: Box<String> = Box::new(wasmer_heap_string); /*
Box::into_raw(boxed_string) as *mut wasm_engine_t #[cfg(feature = "singlepass-backend")]
Box::new(wasmer::SinglepassConfig::default())
#[cfg(feature = "llvm-backend")]
Box::new(wasmer::LLVMConfig::default())
*/
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_engine_delete(wasm_engine_address: *mut wasm_engine_t) { pub extern "C" fn wasm_engine_new() -> NonNull<wasm_engine_t> {
if !wasm_engine_address.is_null() { let compiler_config: Box<dyn CompilerConfig> = get_default_compiler_config();
// this should not leak memory: let tunables = Tunables::default();
// we should double check it to make sure though let engine: Arc<dyn Engine + Send + Sync> = Arc::new(JITEngine::new(compiler_config, tunables));
let _boxed_str: Box<String> = unsafe { Box::from_raw(wasm_engine_address as *mut String) }; let wasm_engine = Box::new(wasm_engine_t { inner: engine });
unsafe { NonNull::new_unchecked(Box::into_raw(wasm_engine)).cast::<wasm_engine_t>() }
}
#[no_mangle]
pub unsafe extern "C" fn wasm_engine_delete(wasm_engine_address: Option<NonNull<wasm_engine_t>>) {
if let Some(e_inner) = wasm_engine_address {
// this should probably be a no-op
Box::from_raw(e_inner.as_ptr());
} }
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_engine_new_with_config( pub extern "C" fn wasm_engine_new_with_config(
_config_ptr: *mut wasm_config_t, _config_ptr: *mut wasm_config_t,
) -> *mut wasm_engine_t { ) -> NonNull<wasm_engine_t> {
wasm_engine_new() wasm_engine_new()
} }
@@ -80,42 +96,26 @@ pub unsafe extern "C" fn wasm_instance_new(
// own // own
_traps: *mut *mut wasm_trap_t, _traps: *mut *mut wasm_trap_t,
) -> Option<NonNull<wasm_instance_t>> { ) -> Option<NonNull<wasm_instance_t>> {
let module = &(&*module).inner; let wasm_module = &(&*module).inner;
let module_imports = module.imports(); let module_imports = wasm_module.imports();
let module_import_count = module_imports.len(); let module_import_count = module_imports.len();
let imports = argument_import_iter(imports); let imports = argument_import_iter(imports);
let mut import_object = ImportObject::new();
let mut imports_processed = 0; let mut imports_processed = 0;
/* let mut org_map: HashMap<String, Exports> = HashMap::new();
for ( for (import_type, import) in module_imports.into_iter().zip(imports) {
ImportDescriptor {
namespace,
name,
ty,
},
import,
) in module_imports.into_iter().zip(imports)
{
imports_processed += 1; imports_processed += 1;
// TODO: review this code and consider doing it without internal mutation (build up external data Namespaces and then register them with the ImportObject) let entry = org_map
if import_object.with_namespace(&namespace, |_| ()).is_none() { .entry(import_type.module().to_string())
import_object.register(&namespace, Namespace::new()); .or_insert_with(Exports::new);
}
match (ty, import.export.clone()) { let extrn = match (import_type.ty(), &import.inner) {
(ExternType::Function(expected_signature), Extern::Function(f)) => { (ExternType::Function(expected_signature), Extern::Function(f)) => {
if expected_signature != f.ty() { if expected_signature != f.ty() {
// TODO: report error // TODO: report error
return None; return None;
} }
import_object entry.insert(import_type.name(), import.inner.clone())
.with_namespace_mut(
&namespace,
|ns: &mut (dyn LikeNamespace + Send)| -> Option<()> {
ns.maybe_insert(&name, import.export.clone())
},
)
.expect("failed to modify namespace: TODO handle this error");
} }
(ExternType::Global(global_ty), Extern::Global(extern_global)) => { (ExternType::Global(global_ty), Extern::Global(extern_global)) => {
if global_ty != extern_global.ty() { if global_ty != extern_global.ty() {
@@ -123,14 +123,7 @@ pub unsafe extern "C" fn wasm_instance_new(
return None; return None;
} }
import_object entry.insert(import_type.name(), import.inner.clone())
.with_namespace_mut(
&namespace,
|ns: &mut (dyn LikeNamespace + Send)| -> Option<()> {
ns.maybe_insert(&name, import.export.clone())
},
)
.expect("failed to modify namespace");
} }
(ExternType::Memory(_), Extern::Memory(_)) => todo!("memory"), (ExternType::Memory(_), Extern::Memory(_)) => todo!("memory"),
(ExternType::Table(_), Extern::Table(_)) => todo!("table"), (ExternType::Table(_), Extern::Table(_)) => todo!("table"),
@@ -138,20 +131,25 @@ pub unsafe extern "C" fn wasm_instance_new(
// type mismatch: report error here // type mismatch: report error here
return None; return None;
} }
};
} }
}
*/
todo!("instance new");
if module_import_count != imports_processed { if module_import_count != imports_processed {
// handle this error // handle this error
return None; return None;
} }
let mut import_object = ImportObject::new();
for (ns, exports) in org_map {
import_object.register(ns, exports);
}
let instance = Arc::new( let instance = Arc::new(
Instance::new(module, &import_object) Instance::new(wasm_module, &import_object)
.expect("failed to instantiate: TODO handle this error"), .expect("failed to instantiate: TODO handle this error"),
); );
NonNull::new(Box::into_raw(Box::new(wasm_instance_t { inner: instance }))) Some(NonNull::new_unchecked(Box::into_raw(Box::new(
wasm_instance_t { inner: instance },
))))
} }
#[no_mangle] #[no_mangle]
@@ -210,7 +208,7 @@ pub unsafe extern "C" fn wasm_instance_exports(
.iter() .iter()
.map(|(name, r#extern)| { .map(|(name, r#extern)| {
let function = if let Extern::Function { .. } = r#extern { let function = if let Extern::Function { .. } = r#extern {
instance.exports.get(&name).ok().cloned() instance.exports.get_function(&name).ok().cloned()
/*let sig_idx = SigRegistry::lookup_sig_index(signature); /*let sig_idx = SigRegistry::lookup_sig_index(signature);
let trampoline = instance.module.runnable_module.get_trampoline(&instance.module.info, sig_idx).expect("wasm trampoline"); let trampoline = instance.module.runnable_module.get_trampoline(&instance.module.info, sig_idx).expect("wasm trampoline");
@@ -220,8 +218,7 @@ pub unsafe extern "C" fn wasm_instance_exports(
}; };
Box::into_raw(Box::new(wasm_extern_t { Box::into_raw(Box::new(wasm_extern_t {
instance: Some(Arc::clone(instance)), instance: Some(Arc::clone(instance)),
function, inner: r#extern.clone(),
inner: *r#extern,
})) }))
}) })
.collect::<Vec<*mut wasm_extern_t>>(); .collect::<Vec<*mut wasm_extern_t>>();
@@ -246,7 +243,8 @@ pub unsafe extern "C" fn wasm_module_new(
let bytes = &*bytes; let bytes = &*bytes;
// TODO: review lifetime of byte slice // TODO: review lifetime of byte slice
let wasm_byte_slice: &[u8] = slice::from_raw_parts_mut(bytes.data, bytes.size); let wasm_byte_slice: &[u8] = slice::from_raw_parts_mut(bytes.data, bytes.size);
let store: &Store = store_ptr?.cast::<Store>().as_ref(); let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
let store = store_ptr.as_ref();
let result = Module::from_binary(store, wasm_byte_slice); let result = Module::from_binary(store, wasm_byte_slice);
let module = match result { let module = match result {
Ok(module) => module, Ok(module) => module,
@@ -256,9 +254,11 @@ pub unsafe extern "C" fn wasm_module_new(
} }
}; };
NonNull::new(Box::into_raw(Box::new(wasm_module_t { Some(NonNull::new_unchecked(Box::into_raw(Box::new(
wasm_module_t {
inner: Arc::new(module), inner: Arc::new(module),
}))) },
))))
} }
#[no_mangle] #[no_mangle]
@@ -282,7 +282,8 @@ pub unsafe extern "C" fn wasm_module_deserialize(
(&*bytes).into_slice().unwrap() (&*bytes).into_slice().unwrap()
}; };
let store: &Store = store_ptr?.cast::<Store>().as_ref(); let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
let store = store_ptr.as_ref();
let module = if let Ok(module) = Module::deserialize(store, byte_slice) { let module = if let Ok(module) = Module::deserialize(store, byte_slice) {
module module
} else { } else {
@@ -290,9 +291,11 @@ pub unsafe extern "C" fn wasm_module_deserialize(
return None; return None;
}; };
NonNull::new(Box::into_raw(Box::new(wasm_module_t { Some(NonNull::new_unchecked(Box::into_raw(Box::new(
wasm_module_t {
inner: Arc::new(module), inner: Arc::new(module),
}))) },
))))
} }
#[no_mangle] #[no_mangle]
@@ -321,124 +324,112 @@ pub unsafe extern "C" fn wasm_module_serialize(
pub struct wasm_store_t {} pub struct wasm_store_t {}
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_store_new(_wasm_engine: *mut wasm_engine_t) -> *mut wasm_store_t { pub unsafe extern "C" fn wasm_store_new(
let mut wasmer_heap_string = "WASMER STORE".to_string(); wasm_engine_ptr: Option<NonNull<wasm_engine_t>>,
wasmer_heap_string.shrink_to_fit(); ) -> Option<NonNull<wasm_store_t>> {
let boxed_string: Box<String> = Box::new(wasmer_heap_string); let wasm_engine_ptr = wasm_engine_ptr?;
Box::into_raw(boxed_string) as *mut wasm_store_t let wasm_engine = wasm_engine_ptr.as_ref();
let store = Store::new(wasm_engine.inner.clone());
Some(NonNull::new_unchecked(
Box::into_raw(Box::new(store)) as *mut wasm_store_t
))
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn wasm_store_delete(wasm_store_address: *mut wasm_store_t) { pub unsafe extern "C" fn wasm_store_delete(wasm_store: Option<NonNull<wasm_store_t>>) {
if !wasm_store_address.is_null() { if let Some(s_inner) = wasm_store {
// this should not leak memory: // this should not leak memory:
// we should double check it to make sure though // we should double check it to make sure though
let _boxed_str: Box<String> = unsafe { Box::from_raw(wasm_store_address as *mut String) }; let _: Box<Store> = Box::from_raw(s_inner.cast::<Store>().as_ptr());
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_as_extern(func_ptr: *mut wasm_func_t) -> *mut wasm_extern_t { pub unsafe extern "C" fn wasm_func_as_extern(
let func = &*func_ptr; func_ptr: Option<NonNull<wasm_func_t>>,
/*match func.callback { ) -> Option<NonNull<wasm_extern_t>> {
CallbackType::WithEnv { .. } => todo!("wasm_func_as_extern for funcs with envs"), let func_ptr = func_ptr?;
CallbackType::WithoutEnv(callback) => { let func = func_ptr.as_ref();
let r#extern = Extern::Function {
func: FuncPointer::new(callback as *const _),
// TODO: figure out how to use `Context` correctly here
ctx: Context::Internal,
signature: Arc::clone(&func.functype),
};
Box::into_raw(Box::new(wasm_extern_t { let r#extern = Box::new(wasm_extern_t {
instance: func.instance.clone(), instance: func.instance.clone(),
function: None, inner: Extern::Function(func.inner.clone()),
inner: r#extern, });
})) Some(NonNull::new_unchecked(Box::into_raw(r#extern)))
}
}*/
todo!("func as extern");
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_as_extern( pub unsafe extern "C" fn wasm_global_as_extern(
global_ptr: *mut wasm_global_t, global_ptr: Option<NonNull<wasm_global_t>>,
) -> *mut wasm_extern_t { ) -> Option<NonNull<wasm_extern_t>> {
let global = &*global_ptr; let global_ptr = global_ptr?;
Box::into_raw(Box::new(wasm_extern_t { let global = global_ptr.as_ref();
let r#extern = Box::new(wasm_extern_t {
// update this if global does hold onto an `instance` // update this if global does hold onto an `instance`
instance: None, instance: None,
function: None, inner: Extern::Global(global.inner.clone()),
inner: Extern::Global(global.global.clone()), });
})) Some(NonNull::new_unchecked(Box::into_raw(r#extern)))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_as_extern( pub unsafe extern "C" fn wasm_memory_as_extern(
memory_ptr: *mut wasm_memory_t, memory_ptr: Option<NonNull<wasm_memory_t>>,
) -> *mut wasm_extern_t { ) -> Option<NonNull<wasm_extern_t>> {
let memory = &*memory_ptr; let memory_ptr = memory_ptr?;
Box::into_raw(Box::new(wasm_extern_t { let memory = memory_ptr.as_ref();
let r#extern = Box::new(wasm_extern_t {
// update this if global does hold onto an `instance` // update this if global does hold onto an `instance`
instance: None, instance: None,
function: None, inner: Extern::Memory(memory.inner.clone()),
inner: Extern::Memory(memory.memory.clone()),
}))
}
#[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_func(extrn: *mut wasm_extern_t) -> *mut wasm_func_t {
let extrn = &*extrn;
/*
match &extrn.inner {
Extern::Function(f) => {
let func = Box::new(wasm_func_t {
instance: extrn.instance.clone(),
function: extrn.function.as_ref().map(|r| r as *const _),
functype: Arc::clone(signature),
callback: match ctx {
Context::Internal => CallbackType::WithoutEnv(
// TOOD: fix this transmute, this isn't safe because the struct isn't transparent
mem::transmute(func),
),
// this is probably doubly wrong: understand `External` better
Context::External(_) => CallbackType::WithoutEnv(
// TOOD: fix this transmute, this isn't safe because the struct isn't transparent
mem::transmute(func),
),
unhandled_context => todo!(
"Handle other types of wasm Context: {:?}",
unhandled_context
),
},
}); });
Box::into_raw(func) Some(NonNull::new_unchecked(Box::into_raw(r#extern)))
}
_ => return ptr::null_mut(),
}
*/
todo!("extern as func");
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_global(extrn: *mut wasm_extern_t) -> *mut wasm_global_t { pub unsafe extern "C" fn wasm_extern_as_func(
let extrn = &*extrn; extern_ptr: Option<NonNull<wasm_extern_t>>,
match &extrn.inner { ) -> Option<NonNull<wasm_func_t>> {
Extern::Global(global) => Box::into_raw(Box::new(wasm_global_t { let extern_ptr = extern_ptr?;
global: global.clone(), let r#extern = extern_ptr.as_ref();
})), if let Extern::Function(f) = &r#extern.inner {
_ => ptr::null_mut(), let wasm_func = Box::new(wasm_func_t {
inner: f.clone(),
instance: r#extern.instance.clone(),
});
Some(NonNull::new_unchecked(Box::into_raw(wasm_func)))
} else {
None
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_memory(extrn: *mut wasm_extern_t) -> *mut wasm_memory_t { pub unsafe extern "C" fn wasm_extern_as_global(
let extrn = &*extrn; extern_ptr: Option<NonNull<wasm_extern_t>>,
match &extrn.inner { ) -> Option<NonNull<wasm_global_t>> {
Extern::Memory(memory) => Box::into_raw(Box::new(wasm_memory_t { let extern_ptr = extern_ptr?;
memory: memory.clone(), let r#extern = extern_ptr.as_ref();
})), if let Extern::Global(g) = &r#extern.inner {
_ => ptr::null_mut(), let wasm_global = Box::new(wasm_global_t { inner: g.clone() });
Some(NonNull::new_unchecked(Box::into_raw(wasm_global)))
} else {
None
}
}
#[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_memory(
extern_ptr: Option<NonNull<wasm_extern_t>>,
) -> Option<NonNull<wasm_memory_t>> {
let extern_ptr = extern_ptr?;
let r#extern = extern_ptr.as_ref();
if let Extern::Memory(m) = &r#extern.inner {
let wasm_memory = Box::new(wasm_memory_t { inner: m.clone() });
Some(NonNull::new_unchecked(Box::into_raw(wasm_memory)))
} else {
None
} }
} }
@@ -454,6 +445,7 @@ enum wasm_mutability_enum {
} }
impl wasm_mutability_enum { impl wasm_mutability_enum {
#[allow(dead_code)]
fn is_mutable(self) -> bool { fn is_mutable(self) -> bool {
self == Self::WASM_VAR self == Self::WASM_VAR
} }
@@ -516,6 +508,7 @@ pub enum wasm_valkind_enum {
} }
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)]
pub union wasm_val_inner { pub union wasm_val_inner {
int32_t: i32, int32_t: i32,
int64_t: i64, int64_t: i64,
@@ -530,6 +523,15 @@ pub struct wasm_val_t {
of: wasm_val_inner, of: wasm_val_inner,
} }
impl Clone for wasm_val_t {
fn clone(&self) -> Self {
wasm_val_t {
kind: self.kind,
of: self.of.clone(),
}
}
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_val_copy(out_ptr: *mut wasm_val_t, val: *const wasm_val_t) { pub unsafe extern "C" fn wasm_val_copy(out_ptr: *mut wasm_val_t, val: *const wasm_val_t) {
let val = &*val; let val = &*val;
@@ -597,7 +599,15 @@ impl TryFrom<Val> for wasm_val_t {
type Error = &'static str; type Error = &'static str;
fn try_from(item: Val) -> Result<Self, Self::Error> { fn try_from(item: Val) -> Result<Self, Self::Error> {
Ok(match item { wasm_val_t::try_from(&item)
}
}
impl TryFrom<&Val> for wasm_val_t {
type Error = &'static str;
fn try_from(item: &Val) -> Result<Self, Self::Error> {
Ok(match *item {
Val::I32(v) => wasm_val_t { Val::I32(v) => wasm_val_t {
of: wasm_val_inner { int32_t: v }, of: wasm_val_inner { int32_t: v },
kind: wasm_valkind_enum::WASM_I32 as _, kind: wasm_valkind_enum::WASM_I32 as _,
@@ -615,6 +625,7 @@ impl TryFrom<Val> for wasm_val_t {
kind: wasm_valkind_enum::WASM_F64 as _, kind: wasm_valkind_enum::WASM_F64 as _,
}, },
Val::V128(_) => return Err("128bit SIMD types not yet supported in Wasm C API"), Val::V128(_) => return Err("128bit SIMD types not yet supported in Wasm C API"),
_ => todo!("Handle these values in TryFrom<Val> for wasm_val_t"),
}) })
} }
} }
@@ -633,43 +644,56 @@ pub type wasm_func_callback_with_env_t = unsafe extern "C" fn(
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void); pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void);
#[allow(dead_code)]
#[repr(C)]
enum CallbackType {
WithoutEnv(wasm_func_callback_t),
WithEnv {
callback: wasm_func_callback_with_env_t,
env: c_void,
finalizer: wasm_env_finalizer_t,
},
}
#[repr(C)] #[repr(C)]
pub struct wasm_func_t { pub struct wasm_func_t {
// hack to make it just work for now inner: Function,
inner: Option<*const Function>,
// this is how we ensure the instance stays alive // this is how we ensure the instance stays alive
instance: Option<Arc<Instance>>, instance: Option<Arc<Instance>>,
functype: Arc<FunctionType>,
callback: CallbackType,
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_new( pub unsafe extern "C" fn wasm_func_new(
_store: *mut wasm_store_t, store: Option<NonNull<wasm_store_t>>,
ft: *const wasm_functype_t, ft: *const wasm_functype_t,
callback: wasm_func_callback_t, callback: wasm_func_callback_t,
) -> *mut wasm_func_t { ) -> Option<NonNull<wasm_func_t>> {
// TODO: handle null pointers? // TODO: handle null pointers?
let store_ptr = store?.cast::<Store>();
let store = store_ptr.as_ref();
let new_ft = wasm_functype_copy(ft as *mut _); let new_ft = wasm_functype_copy(ft as *mut _);
let func_sig = functype_to_real_type(new_ft); let func_sig = functype_to_real_type(new_ft);
let num_rets = func_sig.results().len();
let inner_callback = move |args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
let processed_args = args
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<wasm_val_t>, _>>()
.expect("Argument conversion failed");
let mut results = vec![
wasm_val_t {
kind: wasm_valkind_enum::WASM_I64 as _,
of: wasm_val_inner { int64_t: 0 },
};
num_rets
];
let _traps = callback(processed_args.as_ptr(), results.as_mut_ptr());
// TODO: do something with `traps`
let processed_results = results
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Val>, _>>()
.expect("Result conversion failed");
Ok(processed_results)
};
let f = Function::new_dynamic(store, &func_sig, inner_callback);
let wasm_func = Box::new(wasm_func_t { let wasm_func = Box::new(wasm_func_t {
instance: None, instance: None,
inner: None, inner: f,
functype: func_sig,
callback: CallbackType::WithoutEnv(callback),
}); });
Box::into_raw(wasm_func) Some(NonNull::new_unchecked(Box::into_raw(wasm_func)))
} }
#[no_mangle] #[no_mangle]
@@ -680,6 +704,8 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
env: c_void, env: c_void,
finalizer: wasm_env_finalizer_t, finalizer: wasm_env_finalizer_t,
) -> *mut wasm_func_t { ) -> *mut wasm_func_t {
todo!("wasm_func_new_with_env")
/*
// TODO: handle null pointers? // TODO: handle null pointers?
let new_ft = wasm_functype_copy(ft as *mut _); let new_ft = wasm_functype_copy(ft as *mut _);
let func_sig = functype_to_real_type(new_ft); let func_sig = functype_to_real_type(new_ft);
@@ -687,13 +713,9 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
instance: None, instance: None,
inner: None, inner: None,
functype: func_sig, functype: func_sig,
callback: CallbackType::WithEnv {
callback,
env,
finalizer,
},
}); });
Box::into_raw(wasm_func) Box::into_raw(wasm_func)
*/
} }
#[no_mangle] #[no_mangle]
@@ -712,10 +734,8 @@ pub unsafe extern "C" fn wasm_func_call(
let func = &*func; let func = &*func;
let wasm_traps; let wasm_traps;
if let Some(dynfunc) = func.inner {
let dynfunc = &*dynfunc;
let mut params = vec![]; let mut params = vec![];
for (i, param) in func.functype.params().iter().enumerate() { for (i, param) in func.inner.ty().params().iter().enumerate() {
let arg = &(*args.add(i)); let arg = &(*args.add(i));
match param { match param {
@@ -752,7 +772,7 @@ pub unsafe extern "C" fn wasm_func_call(
} }
} }
match dynfunc.call(&params) { match func.inner.call(&params) {
Ok(wasm_results) => { Ok(wasm_results) => {
for (i, actual_result) in wasm_results.iter().enumerate() { for (i, actual_result) in wasm_results.iter().enumerate() {
let result_loc = &mut (*results.add(i)); let result_loc = &mut (*results.add(i));
@@ -774,6 +794,7 @@ pub unsafe extern "C" fn wasm_func_call(
result_loc.kind = wasm_valkind_enum::WASM_F64 as u8; result_loc.kind = wasm_valkind_enum::WASM_F64 as u8;
} }
Val::V128(_) => todo!("Handle v128 case in wasm_func_call"), Val::V128(_) => todo!("Handle v128 case in wasm_func_call"),
_ => todo!("handle other vals"),
} }
} }
wasm_traps = ptr::null_mut(); wasm_traps = ptr::null_mut();
@@ -789,12 +810,6 @@ pub unsafe extern "C" fn wasm_func_call(
panic!("resolve error!"); panic!("resolve error!");
} }
} }
} else {
wasm_traps = match func.callback {
CallbackType::WithoutEnv(fp) => fp(args, results),
_ => unimplemented!("Host calls with `wasm_func_call`"),
};
}
wasm_traps wasm_traps
} }
@@ -802,19 +817,19 @@ pub unsafe extern "C" fn wasm_func_call(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_param_arity(func: *const wasm_func_t) -> usize { pub unsafe extern "C" fn wasm_func_param_arity(func: *const wasm_func_t) -> usize {
let func = &*func; let func = &*func;
func.functype.params().len() func.inner.ty().params().len()
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_func_result_arity(func: *const wasm_func_t) -> usize { pub unsafe extern "C" fn wasm_func_result_arity(func: *const wasm_func_t) -> usize {
let func = &*func; let func = &*func;
func.functype.results().len() func.inner.ty().results().len()
} }
#[repr(C)] #[repr(C)]
pub struct wasm_global_t { pub struct wasm_global_t {
// maybe needs to hold onto instance // maybe needs to hold onto instance
global: Global, inner: Global,
} }
#[no_mangle] #[no_mangle]
@@ -826,14 +841,17 @@ pub unsafe extern "C" fn wasm_global_new(
let gt = &*(gt_ptr as *const GlobalType); let gt = &*(gt_ptr as *const GlobalType);
let val = &*val_ptr; let val = &*val_ptr;
let wasm_val = val.try_into().ok()?; let wasm_val = val.try_into().ok()?;
let store: &Store = store_ptr?.cast::<Store>().as_ref(); let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
let store = store_ptr.as_ref();
let global = if gt.mutability.is_mutable() { let global = if gt.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)
}; };
NonNull::new(Box::into_raw(Box::new(wasm_global_t { global }))) Some(NonNull::new_unchecked(Box::into_raw(Box::new(
wasm_global_t { inner: global },
))))
} }
#[no_mangle] #[no_mangle]
@@ -851,14 +869,14 @@ pub unsafe extern "C" fn wasm_global_copy(global_ptr: *const wasm_global_t) -> *
// do shallow copy // do shallow copy
Box::into_raw(Box::new(wasm_global_t { Box::into_raw(Box::new(wasm_global_t {
global: wasm_global.global.clone(), inner: wasm_global.inner.clone(),
})) }))
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_global_get(global_ptr: *const wasm_global_t, out: *mut wasm_val_t) { pub unsafe extern "C" fn wasm_global_get(global_ptr: *const wasm_global_t, out: *mut wasm_val_t) {
let wasm_global = &*global_ptr; let wasm_global = &*global_ptr;
let value = wasm_global.global.get(); let value = wasm_global.inner.get();
*out = value.try_into().unwrap(); *out = value.try_into().unwrap();
} }
@@ -870,7 +888,7 @@ pub unsafe extern "C" fn wasm_global_set(
let wasm_global: &mut wasm_global_t = &mut *global_ptr; let wasm_global: &mut wasm_global_t = &mut *global_ptr;
let val: &wasm_val_t = &*val_ptr; let val: &wasm_val_t = &*val_ptr;
let value: Val = val.try_into().unwrap(); let value: Val = val.try_into().unwrap();
wasm_global.global.set(value); wasm_global.inner.set(value);
} }
#[no_mangle] #[no_mangle]
@@ -881,13 +899,13 @@ pub unsafe extern "C" fn wasm_global_same(
let wasm_global1 = &*global_ptr1; let wasm_global1 = &*global_ptr1;
let wasm_global2 = &*global_ptr2; let wasm_global2 = &*global_ptr2;
wasm_global1.global.same(&wasm_global2.global) wasm_global1.inner.same(&wasm_global2.inner)
} }
#[repr(C)] #[repr(C)]
pub struct wasm_memory_t { pub struct wasm_memory_t {
// maybe needs to hold onto instance // maybe needs to hold onto instance
memory: Memory, inner: Memory,
} }
#[no_mangle] #[no_mangle]
@@ -896,11 +914,14 @@ pub unsafe extern "C" fn wasm_memory_new(
mt_ptr: *const wasm_memorytype_t, mt_ptr: *const wasm_memorytype_t,
) -> Option<NonNull<wasm_memory_t>> { ) -> Option<NonNull<wasm_memory_t>> {
let md = (&*(mt_ptr as *const MemoryType)).clone(); let md = (&*(mt_ptr as *const MemoryType)).clone();
let store: &Store = store_ptr?.cast::<Store>().as_ref(); let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
let store = store_ptr.as_ref();
// TODO: report this error // TODO: report this error
let memory = Memory::new(store, md).ok()?; let memory = Memory::new(store, md).ok()?;
NonNull::new(Box::into_raw(Box::new(wasm_memory_t { memory }))) Some(NonNull::new_unchecked(Box::into_raw(Box::new(
wasm_memory_t { inner: memory },
))))
} }
#[no_mangle] #[no_mangle]
@@ -918,7 +939,7 @@ pub unsafe extern "C" fn wasm_memory_copy(memory_ptr: *const wasm_memory_t) -> *
// do shallow copy // do shallow copy
Box::into_raw(Box::new(wasm_memory_t { Box::into_raw(Box::new(wasm_memory_t {
memory: wasm_memory.memory.clone(), inner: wasm_memory.inner.clone(),
})) }))
} }
@@ -933,7 +954,7 @@ pub unsafe extern "C" fn wasm_memory_type(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_data(memory_ptr: *mut wasm_memory_t) -> *mut u8 { pub unsafe extern "C" fn wasm_memory_data(memory_ptr: *mut wasm_memory_t) -> *mut u8 {
let memory = &mut *memory_ptr; let memory = &mut *memory_ptr;
mem::transmute::<&[std::cell::Cell<u8>], &[u8]>(&memory.memory.view()[..]) as *const [u8] mem::transmute::<&[std::cell::Cell<u8>], &[u8]>(&memory.inner.view()[..]) as *const [u8]
as *const u8 as *mut u8 as *const u8 as *mut u8
} }
@@ -941,21 +962,21 @@ pub unsafe extern "C" fn wasm_memory_data(memory_ptr: *mut wasm_memory_t) -> *mu
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_data_size(memory_ptr: *const wasm_memory_t) -> usize { pub unsafe extern "C" fn wasm_memory_data_size(memory_ptr: *const wasm_memory_t) -> usize {
let memory = &*memory_ptr; let memory = &*memory_ptr;
memory.memory.size().bytes().0 memory.inner.size().bytes().0
} }
// size in pages // size in pages
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_size(memory_ptr: *const wasm_memory_t) -> u32 { pub unsafe extern "C" fn wasm_memory_size(memory_ptr: *const wasm_memory_t) -> u32 {
let memory = &*memory_ptr; let memory = &*memory_ptr;
memory.memory.size().0 as _ memory.inner.size().0 as _
} }
// delta is in pages // delta is in pages
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memory_grow(memory_ptr: *mut wasm_memory_t, delta: u32) -> bool { pub unsafe extern "C" fn wasm_memory_grow(memory_ptr: *mut wasm_memory_t, delta: u32) -> bool {
let memory = &mut *memory_ptr; let memory = &mut *memory_ptr;
memory.memory.grow(Pages(delta)).is_ok() memory.inner.grow(Pages(delta)).is_ok()
} }
#[no_mangle] #[no_mangle]
@@ -966,7 +987,7 @@ pub unsafe extern "C" fn wasm_memory_same(
let wasm_memory1 = &*memory_ptr1; let wasm_memory1 = &*memory_ptr1;
let wasm_memory2 = &*memory_ptr2; let wasm_memory2 = &*memory_ptr2;
wasm_memory1.memory.same(&wasm_memory2.memory) wasm_memory1.inner.same(&wasm_memory2.inner)
} }
macro_rules! wasm_declare_own { macro_rules! wasm_declare_own {
@@ -1145,8 +1166,6 @@ pub unsafe extern "C" fn wasm_trap_trace(trap: *const wasm_trap_t, out_ptr: *mut
#[repr(C)] #[repr(C)]
pub struct wasm_extern_t { pub struct wasm_extern_t {
// Hack for Wasm functions: TODO clean this up
function: Option<Function>,
// this is how we ensure the instance stays alive // this is how we ensure the instance stays alive
instance: Option<Arc<Instance>>, instance: Option<Arc<Instance>>,
inner: Extern, inner: Extern,
@@ -1284,21 +1303,21 @@ wasm_declare_vec!(functype);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_new( pub unsafe extern "C" fn wasm_functype_new(
// own // own
params: *mut wasm_valtype_vec_t, params: Option<NonNull<wasm_valtype_vec_t>>,
// own // own
results: *mut wasm_valtype_vec_t, results: Option<NonNull<wasm_valtype_vec_t>>,
) -> *mut wasm_functype_t { ) -> Option<NonNull<wasm_functype_t>> {
wasm_functype_new_inner(params, results).unwrap_or(ptr::null_mut()) wasm_functype_new_inner(params?, results?)
} }
unsafe fn wasm_functype_new_inner( unsafe fn wasm_functype_new_inner(
// own // own
params: *mut wasm_valtype_vec_t, params: NonNull<wasm_valtype_vec_t>,
// own // own
results: *mut wasm_valtype_vec_t, results: NonNull<wasm_valtype_vec_t>,
) -> Option<*mut wasm_functype_t> { ) -> Option<NonNull<wasm_functype_t>> {
let params = &*params; let params = params.as_ref();
let results = &*results; let results = results.as_ref();
let params: Vec<ValType> = params let params: Vec<ValType> = params
.into_slice()? .into_slice()?
.iter() .iter()
@@ -1313,7 +1332,9 @@ unsafe fn wasm_functype_new_inner(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let funcsig = Arc::new(FunctionType::new(params, results)); let funcsig = Arc::new(FunctionType::new(params, results));
Some(Arc::into_raw(funcsig) as *mut wasm_functype_t) Some(NonNull::new_unchecked(
Arc::into_raw(funcsig) as *mut wasm_functype_t
))
} }
#[no_mangle] #[no_mangle]

View File

@@ -21,8 +21,7 @@ add_executable(test-context test-context.c)
add_executable(test-module-import-instantiate test-module-import-instantiate.c) add_executable(test-module-import-instantiate test-module-import-instantiate.c)
# Wasm C API tests # Wasm C API tests
# Commented out until we can find a solution to the exported function problem add_executable(wasm-c-api-hello wasm-c-api/example/hello.c)
#add_executable(wasm-c-api-hello wasm-c-api/example/hello.c)
#add_executable(wasm-c-api-memory wasm-c-api/example/memory.c) #add_executable(wasm-c-api-memory wasm-c-api/example/memory.c)
#add_executable(wasm-c-api-global wasm-c-api/example/global.c) #add_executable(wasm-c-api-global wasm-c-api/example/global.c)
#add_executable(wasm-c-api-serialize wasm-c-api/example/serialize.c) #add_executable(wasm-c-api-serialize wasm-c-api/example/serialize.c)
@@ -142,15 +141,13 @@ target_link_libraries(test-module-import-instantiate general ${WASMER_LIB})
target_compile_options(test-module-import-instantiate PRIVATE ${COMPILER_OPTIONS}) target_compile_options(test-module-import-instantiate PRIVATE ${COMPILER_OPTIONS})
add_test(test-module-import-instantiate test-module-import-instantiate) add_test(test-module-import-instantiate test-module-import-instantiate)
# Commented out until we can find a solution to the exported function problem target_link_libraries(wasm-c-api-hello general ${WASMER_LIB})
# target_compile_options(wasm-c-api-hello PRIVATE ${COMPILER_OPTIONS})
#target_link_libraries(wasm-c-api-hello general ${WASMER_LIB}) add_test(NAME wasm-c-api-hello
#target_compile_options(wasm-c-api-hello PRIVATE ${COMPILER_OPTIONS}) COMMAND wasm-c-api-hello
#add_test(NAME wasm-c-api-hello WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example
# COMMAND wasm-c-api-hello )
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example
#)
#
#target_link_libraries(wasm-c-api-memory general ${WASMER_LIB}) #target_link_libraries(wasm-c-api-memory general ${WASMER_LIB})
#target_compile_options(wasm-c-api-memory PRIVATE ${COMPILER_OPTIONS}) #target_compile_options(wasm-c-api-memory PRIVATE ${COMPILER_OPTIONS})
#add_test(NAME wasm-c-api-memory #add_test(NAME wasm-c-api-memory

View File

@@ -78,6 +78,11 @@ impl ExportMemory {
pub fn plan(&self) -> &MemoryPlan { pub fn plan(&self) -> &MemoryPlan {
unsafe { self.from.as_ref().unwrap() }.plan() unsafe { self.from.as_ref().unwrap() }.plan()
} }
/// Returns whether or not the two `ExportMemory`s refer to the same Memory.
pub fn same(&self, other: &ExportMemory) -> bool {
self.definition == other.definition && self.from == other.from
}
} }
impl From<ExportMemory> for Export { impl From<ExportMemory> for Export {
@@ -95,6 +100,13 @@ pub struct ExportGlobal {
pub global: GlobalType, pub global: GlobalType,
} }
impl ExportGlobal {
/// Returns whether or not the two `ExportGlobal`s refer to the same Global.
pub fn same(&self, other: &ExportGlobal) -> bool {
self.definition == other.definition && self.global == other.global
}
}
impl From<ExportGlobal> for Export { impl From<ExportGlobal> for Export {
fn from(global: ExportGlobal) -> Self { fn from(global: ExportGlobal) -> Self {
Self::Global(global) Self::Global(global)