Add Tables to C API; clean up

This commit is contained in:
Mark McCaskey
2020-05-29 17:14:17 -07:00
parent 4d3b95d674
commit e45a5b5af9
5 changed files with 160 additions and 64 deletions

View File

@@ -120,6 +120,11 @@ impl Table {
exported: wasmer_export, 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 { impl<'a> Exportable<'a> for Table {

View File

@@ -7,6 +7,7 @@ mod import_object;
mod instance; mod instance;
mod memory_view; mod memory_view;
mod module; mod module;
mod ordered_resolver;
mod ptr; mod ptr;
mod store; mod store;
mod tunables; mod tunables;
@@ -18,6 +19,7 @@ pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace
pub use crate::instance::Instance; pub use crate::instance::Instance;
pub use crate::memory_view::{Atomically, MemoryView}; pub use crate::memory_view::{Atomically, MemoryView};
pub use crate::module::Module; pub use crate::module::Module;
pub use crate::ordered_resolver::OrderedResolver;
pub use crate::ptr::{Array, Item, WasmPtr}; pub use crate::ptr::{Array, Item, WasmPtr};
pub use crate::store::{Store, StoreObject}; pub use crate::store::{Store, StoreObject};
pub use crate::tunables::Tunables; pub use crate::tunables::Tunables;

View File

@@ -1,6 +1,5 @@
//! 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;
@@ -9,11 +8,30 @@ use std::slice;
use std::sync::Arc; use std::sync::Arc;
use wasmer::{ use wasmer::{
CompilerConfig, Engine, Exports, Extern, ExternType, Function, FunctionType, Global, CompilerConfig, Engine, Extern, Function, FunctionType, Global, GlobalType, Instance,
GlobalType, ImportObject, Instance, JITEngine, Memory, MemoryType, Module, Mutability, Pages, JITEngine, Memory, MemoryType, Module, Mutability, OrderedResolver, Pages, RuntimeError, Store,
RuntimeError, Store, Tunables, Val, ValType, 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 /// this can be a wasmer-specific type with wasmer-specific functions for manipulating it
#[repr(C)] #[repr(C)]
pub struct wasm_config_t {} 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_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 imports_processed = 0; let resolver: OrderedResolver = imports
let mut org_map: HashMap<String, Exports> = HashMap::new(); .map(|imp| &imp.inner)
for (import_type, import) in module_imports.into_iter().zip(imports) { .take(module_import_count)
imports_processed += 1; .cloned()
let entry = org_map .collect();
.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 instance = Arc::new( let instance = Arc::new(
Instance::new(wasm_module, &import_object) Instance::new(wasm_module, &resolver)
.expect("failed to instantiate: TODO handle this error"), .expect("failed to instantiate: TODO handle this error"),
); );
Some(Box::new(wasm_instance_t { inner: instance })) 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<NonNull<wasm_table_t>>,
) -> Option<Box<wasm_extern_t>> {
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] #[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_func( pub unsafe extern "C" fn wasm_extern_as_func(
extern_ptr: Option<NonNull<wasm_extern_t>>, extern_ptr: Option<NonNull<wasm_extern_t>>,
@@ -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<NonNull<wasm_extern_t>>,
) -> Option<Box<wasm_table_t>> {
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)] #[allow(non_camel_case_types)]
pub type wasm_mutability_t = u8; pub type wasm_mutability_t = u8;
@@ -785,16 +786,13 @@ pub struct wasm_memory_t {
pub unsafe extern "C" fn wasm_memory_new( pub unsafe extern "C" fn wasm_memory_new(
store_ptr: Option<NonNull<wasm_store_t>>, store_ptr: Option<NonNull<wasm_store_t>>,
mt_ptr: *const wasm_memorytype_t, mt_ptr: *const wasm_memorytype_t,
) -> Option<NonNull<wasm_memory_t>> { ) -> Option<Box<wasm_memory_t>> {
let md = (&*(mt_ptr as *const MemoryType)).clone(); let md = (&*(mt_ptr as *const MemoryType)).clone();
let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>(); let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
let store = store_ptr.as_ref(); let store = store_ptr.as_ref();
// TODO: report this error let memory = c_try!(Memory::new(store, md));
let memory = Memory::new(store, md).ok()?; Some(Box::new(wasm_memory_t { inner: memory }))
Some(NonNull::new_unchecked(Box::into_raw(Box::new(
wasm_memory_t { inner: memory },
))))
} }
#[no_mangle] #[no_mangle]
@@ -847,6 +845,52 @@ pub unsafe extern "C" fn wasm_memory_same(
wasm_memory1.inner.same(&wasm_memory2.inner) 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<NonNull<wasm_store_t>>,
mt_ptr: *const wasm_tabletype_t,
init: *const wasm_ref_t,
) -> Option<Box<wasm_table_t>> {
let tt = (&*(mt_ptr as *const TableType)).clone();
let store_ptr: NonNull<Store> = store_ptr?.cast::<Store>();
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<Box<wasm_table_t>>) {}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_copy(wasm_table: &wasm_table_t) -> Box<wasm_table_t> {
// 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 { macro_rules! wasm_declare_own {
($name:ident) => { ($name:ident) => {
paste::item! { 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<wasm_valtype_t>,
limits: &wasm_limits_t,
) -> NonNull<wasm_tabletype_t> {
// 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<NonNull<wasm_tabletype_t>>) {
if let Some(g_inner) = tabletype {
let _ = Box::from_raw(g_inner.cast::<TableType>().as_ptr());
}
}
// opaque type wrapping `MemoryType` // opaque type wrapping `MemoryType`
#[repr(C)] #[repr(C)]
pub struct wasm_memorytype_t {} pub struct wasm_memorytype_t {}
@@ -1109,10 +1188,7 @@ pub struct wasm_limits_t {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memorytype_new( pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> NonNull<wasm_memorytype_t> {
limits: *const wasm_limits_t,
) -> NonNull<wasm_memorytype_t> {
let limits = *limits;
let min_pages = Pages(limits.min as _); let min_pages = Pages(limits.min as _);
// TODO: investigate if `0` is in fact a sentinel value here // TODO: investigate if `0` is in fact a sentinel value here
let max_pages = if limits.max == 0 { let max_pages = if limits.max == 0 {

View File

@@ -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-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-table wasm-c-api/example/table.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)
if (DEFINED WASI_TESTS) 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 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_link_libraries(wasm-c-api-serialize general ${WASMER_LIB})
target_compile_options(wasm-c-api-serialize PRIVATE ${COMPILER_OPTIONS}) target_compile_options(wasm-c-api-serialize PRIVATE ${COMPILER_OPTIONS})
add_test(NAME wasm-c-api-serialize add_test(NAME wasm-c-api-serialize

View File

@@ -56,6 +56,11 @@ impl ExportTable {
pub fn plan(&self) -> &TablePlan { pub fn plan(&self) -> &TablePlan {
unsafe { self.from.as_ref().unwrap() }.plan() 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<ExportTable> for Export { impl From<ExportTable> for Export {