diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index 8dd6353b8..4b098e190 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -120,6 +120,11 @@ impl Table { exported: wasmer_export, } } + + /// Returns whether or not these two tables refer to the same data. + pub fn same(&self, other: &Self) -> bool { + self.exported.same(&other.exported) + } } impl<'a> Exportable<'a> for Table { diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 4437e5f99..f9673812b 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -7,6 +7,7 @@ mod import_object; mod instance; mod memory_view; mod module; +mod ordered_resolver; mod ptr; mod store; mod tunables; @@ -18,6 +19,7 @@ pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace pub use crate::instance::Instance; pub use crate::memory_view::{Atomically, MemoryView}; pub use crate::module::Module; +pub use crate::ordered_resolver::OrderedResolver; pub use crate::ptr::{Array, Item, WasmPtr}; pub use crate::store::{Store, StoreObject}; pub use crate::tunables::Tunables; diff --git a/lib/c-api/src/wasm_c_api.rs b/lib/c-api/src/wasm_c_api.rs index 9f9a09698..150e7798b 100644 --- a/lib/c-api/src/wasm_c_api.rs +++ b/lib/c-api/src/wasm_c_api.rs @@ -1,6 +1,5 @@ //! entrypoints for the standard C API -use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::ffi::c_void; use std::mem; @@ -9,11 +8,30 @@ use std::slice; use std::sync::Arc; use wasmer::{ - CompilerConfig, Engine, Exports, Extern, ExternType, Function, FunctionType, Global, - GlobalType, ImportObject, Instance, JITEngine, Memory, MemoryType, Module, Mutability, Pages, - RuntimeError, Store, Tunables, Val, ValType, + CompilerConfig, Engine, Extern, Function, FunctionType, Global, GlobalType, Instance, + JITEngine, Memory, MemoryType, Module, Mutability, OrderedResolver, Pages, RuntimeError, Store, + Table, TableType, Tunables, Val, ValType, }; +use crate::error::update_last_error; + +macro_rules! c_try { + ($expr:expr) => {{ + let res: Result<_, _> = $expr; + match res { + Ok(val) => val, + Err(err) => { + update_last_error(err); + return None; + } + } + }}; + ($expr:expr, $e:expr) => {{ + let opt: Option<_> = $expr; + c_try!(opt.ok_or_else(|| $e)) + }}; +} + /// this can be a wasmer-specific type with wasmer-specific functions for manipulating it #[repr(C)] pub struct wasm_config_t {} @@ -78,58 +96,14 @@ pub unsafe extern "C" fn wasm_instance_new( let module_imports = wasm_module.imports(); let module_import_count = module_imports.len(); let imports = argument_import_iter(imports); - let mut imports_processed = 0; - let mut org_map: HashMap = HashMap::new(); - for (import_type, import) in module_imports.into_iter().zip(imports) { - imports_processed += 1; - let entry = org_map - .entry(import_type.module().to_string()) - .or_insert_with(Exports::new); - - match (import_type.ty(), &import.inner) { - (ExternType::Function(expected_signature), Extern::Function(f)) => { - if expected_signature != f.ty() { - // TODO: report error - return None; - } - } - (ExternType::Global(global_ty), Extern::Global(extern_global)) => { - if global_ty != extern_global.ty() { - // TODO: report error - return None; - } - } - (ExternType::Memory(memory_ty), Extern::Memory(extern_memory)) => { - if memory_ty != extern_memory.ty() { - // TODO: report error - return None; - } - } - (ExternType::Table(table_ty), Extern::Table(extern_table)) => { - if table_ty != extern_table.ty() { - // TODO: report error - return None; - } - } - _ => { - // type mismatch: report error here - return None; - } - } - entry.insert(import_type.name(), import.inner.clone()) - } - if module_import_count != imports_processed { - // handle this error - return None; - } - - let mut import_object = ImportObject::new(); - for (ns, exports) in org_map { - import_object.register(ns, exports); - } + let resolver: OrderedResolver = imports + .map(|imp| &imp.inner) + .take(module_import_count) + .cloned() + .collect(); let instance = Arc::new( - Instance::new(wasm_module, &import_object) + Instance::new(wasm_module, &resolver) .expect("failed to instantiate: TODO handle this error"), ); Some(Box::new(wasm_instance_t { inner: instance })) @@ -356,6 +330,20 @@ pub unsafe extern "C" fn wasm_memory_as_extern( })) } +#[no_mangle] +pub unsafe extern "C" fn wasm_table_as_extern( + table_ptr: Option>, +) -> Option> { + let table_ptr = table_ptr?; + let table = table_ptr.as_ref(); + + Some(Box::new(wasm_extern_t { + // update this if global does hold onto an `instance` + instance: None, + inner: Extern::Table(table.inner.clone()), + })) +} + #[no_mangle] pub unsafe extern "C" fn wasm_extern_as_func( extern_ptr: Option>, @@ -398,6 +386,19 @@ pub unsafe extern "C" fn wasm_extern_as_memory( } } +#[no_mangle] +pub unsafe extern "C" fn wasm_extern_as_table( + extern_ptr: Option>, +) -> Option> { + let extern_ptr = extern_ptr?; + let r#extern = extern_ptr.as_ref(); + if let Extern::Table(t) = &r#extern.inner { + Some(Box::new(wasm_table_t { inner: t.clone() })) + } else { + None + } +} + #[allow(non_camel_case_types)] pub type wasm_mutability_t = u8; @@ -785,16 +786,13 @@ pub struct wasm_memory_t { pub unsafe extern "C" fn wasm_memory_new( store_ptr: Option>, mt_ptr: *const wasm_memorytype_t, -) -> Option> { +) -> Option> { let md = (&*(mt_ptr as *const MemoryType)).clone(); let store_ptr: NonNull = store_ptr?.cast::(); let store = store_ptr.as_ref(); - // TODO: report this error - let memory = Memory::new(store, md).ok()?; - Some(NonNull::new_unchecked(Box::into_raw(Box::new( - wasm_memory_t { inner: memory }, - )))) + let memory = c_try!(Memory::new(store, md)); + Some(Box::new(wasm_memory_t { inner: memory })) } #[no_mangle] @@ -847,6 +845,52 @@ pub unsafe extern "C" fn wasm_memory_same( wasm_memory1.inner.same(&wasm_memory2.inner) } +#[repr(C)] +pub struct wasm_table_t { + // maybe needs to hold onto instance + inner: Table, +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_new( + store_ptr: Option>, + mt_ptr: *const wasm_tabletype_t, + init: *const wasm_ref_t, +) -> Option> { + let tt = (&*(mt_ptr as *const TableType)).clone(); + let store_ptr: NonNull = store_ptr?.cast::(); + let store = store_ptr.as_ref(); + + let init_val = todo!("get val from init somehow"); + + let table = c_try!(Table::new(store, tt, init_val)); + Some(Box::new(wasm_table_t { inner: table })) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_delete(_table: Option>) {} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_copy(wasm_table: &wasm_table_t) -> Box { + // do shallow copy + Box::new(wasm_table_t { + inner: wasm_table.inner.clone(), + }) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_same( + wasm_table1: &wasm_table_t, + wasm_table2: &wasm_table_t, +) -> bool { + wasm_table1.inner.same(&wasm_table2.inner) +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_table_size(wasm_table: &wasm_table_t) -> usize { + wasm_table.inner.size() as _ +} + macro_rules! wasm_declare_own { ($name:ident) => { paste::item! { @@ -1095,6 +1139,41 @@ unsafe fn wasm_globaltype_new_inner( )) } +// opaque type wrapping `GlobalType` +#[repr(C)] +pub struct wasm_tabletype_t {} + +wasm_declare_vec!(tabletype); + +#[no_mangle] +pub unsafe extern "C" fn wasm_tabletype_new( + // own + valtype: Box, + limits: &wasm_limits_t, +) -> NonNull { + // TODO: investigate if `0` is in fact a sentinel value here + let max_elements = if limits.max == 0 { + None + } else { + Some(limits.max as _) + }; + let out = NonNull::new_unchecked(Box::into_raw(Box::new(TableType::new( + (*valtype).into(), + limits.min as _, + max_elements, + ))) as *mut wasm_tabletype_t); + wasm_valtype_delete(Some(valtype)); + + out +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_tabletype_delete(tabletype: Option>) { + if let Some(g_inner) = tabletype { + let _ = Box::from_raw(g_inner.cast::().as_ptr()); + } +} + // opaque type wrapping `MemoryType` #[repr(C)] pub struct wasm_memorytype_t {} @@ -1109,10 +1188,7 @@ pub struct wasm_limits_t { } #[no_mangle] -pub unsafe extern "C" fn wasm_memorytype_new( - limits: *const wasm_limits_t, -) -> NonNull { - let limits = *limits; +pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> NonNull { let min_pages = Pages(limits.min as _); // TODO: investigate if `0` is in fact a sentinel value here let max_pages = if limits.max == 0 { diff --git a/lib/c-api/tests/CMakeLists.txt b/lib/c-api/tests/CMakeLists.txt index af0ec0b3c..ba4545e38 100644 --- a/lib/c-api/tests/CMakeLists.txt +++ b/lib/c-api/tests/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(test-module-import-instantiate test-module-import-instantiate.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-global wasm-c-api/example/global.c) +#add_executable(wasm-c-api-table wasm-c-api/example/table.c) add_executable(wasm-c-api-serialize wasm-c-api/example/serialize.c) if (DEFINED WASI_TESTS) @@ -162,6 +163,13 @@ add_test(NAME wasm-c-api-global WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example ) +#target_link_libraries(wasm-c-api-table general ${WASMER_LIB}) +#target_compile_options(wasm-c-api-table PRIVATE ${COMPILER_OPTIONS}) +#add_test(NAME wasm-c-api-table +# COMMAND wasm-c-api-table +# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wasm-c-api/example +#) + target_link_libraries(wasm-c-api-serialize general ${WASMER_LIB}) target_compile_options(wasm-c-api-serialize PRIVATE ${COMPILER_OPTIONS}) add_test(NAME wasm-c-api-serialize diff --git a/lib/runtime/src/export.rs b/lib/runtime/src/export.rs index cea1d5404..a278fe676 100644 --- a/lib/runtime/src/export.rs +++ b/lib/runtime/src/export.rs @@ -56,6 +56,11 @@ impl ExportTable { pub fn plan(&self) -> &TablePlan { unsafe { self.from.as_ref().unwrap() }.plan() } + + /// Returns whether or not the two `ExportTable`s refer to the same Memory. + pub fn same(&self, other: &Self) -> bool { + self.definition == other.definition && self.from == other.from + } } impl From for Export {