mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-13 00:51:20 +00:00
Get table imports working
This commit is contained in:
@ -6,24 +6,23 @@ use crate::{
|
||||
memory::{Memory, WASM_PAGE_SIZE},
|
||||
module::{ImportName, ModuleInner},
|
||||
structures::{BoxedMap, Map, SliceMap, TypedIndex},
|
||||
table::{TableBacking, TableElements},
|
||||
table::Table,
|
||||
types::{
|
||||
ElementType, ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex,
|
||||
ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex, LocalOrImport,
|
||||
LocalTableIndex, Value,
|
||||
ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex, ImportedTableIndex,
|
||||
Initializer, LocalGlobalIndex, LocalMemoryIndex, LocalOrImport, LocalTableIndex, Value,
|
||||
},
|
||||
vm,
|
||||
};
|
||||
use std::{mem, slice};
|
||||
use std::slice;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LocalBacking {
|
||||
pub(crate) memories: BoxedMap<LocalMemoryIndex, Memory>,
|
||||
pub(crate) tables: BoxedMap<LocalTableIndex, TableBacking>,
|
||||
pub(crate) tables: BoxedMap<LocalTableIndex, Table>,
|
||||
pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>,
|
||||
|
||||
pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory>,
|
||||
pub(crate) vm_tables: BoxedMap<LocalTableIndex, vm::LocalTable>,
|
||||
pub(crate) vm_tables: BoxedMap<LocalTableIndex, *mut vm::LocalTable>,
|
||||
pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal>,
|
||||
}
|
||||
|
||||
@ -133,12 +132,12 @@ impl LocalBacking {
|
||||
.into_boxed_map()
|
||||
}
|
||||
|
||||
fn generate_tables(module: &ModuleInner) -> BoxedMap<LocalTableIndex, TableBacking> {
|
||||
fn generate_tables(module: &ModuleInner) -> BoxedMap<LocalTableIndex, Table> {
|
||||
let mut tables = Map::with_capacity(module.tables.len());
|
||||
|
||||
for (_, &table) in &module.tables {
|
||||
let table_backing = TableBacking::new(table);
|
||||
tables.push(table_backing);
|
||||
for (_, &table_desc) in module.tables.iter() {
|
||||
let table = Table::new(table_desc).unwrap();
|
||||
tables.push(table);
|
||||
}
|
||||
|
||||
tables.into_boxed_map()
|
||||
@ -148,9 +147,9 @@ impl LocalBacking {
|
||||
fn finalize_tables(
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
tables: &mut SliceMap<LocalTableIndex, TableBacking>,
|
||||
tables: &mut SliceMap<LocalTableIndex, Table>,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> BoxedMap<LocalTableIndex, vm::LocalTable> {
|
||||
) -> BoxedMap<LocalTableIndex, *mut vm::LocalTable> {
|
||||
for init in &module.elem_initializers {
|
||||
let init_base = match init.base {
|
||||
Initializer::Const(Value::I32(offset)) => offset as u32,
|
||||
@ -166,100 +165,83 @@ impl LocalBacking {
|
||||
|
||||
match init.table_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let table = &mut tables[local_table_index];
|
||||
match table.elements {
|
||||
TableElements::Anyfunc(ref mut elements) => {
|
||||
if elements.len() < init_base + init.elements.len() {
|
||||
// Grow the table if it's too small.
|
||||
elements
|
||||
.resize(init_base + init.elements.len(), vm::Anyfunc::null());
|
||||
}
|
||||
let table = &tables[local_table_index];
|
||||
|
||||
for (i, &func_index) in init.elements.iter().enumerate() {
|
||||
let sig_index = module.func_assoc[func_index];
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
|
||||
let func_data = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => vm::ImportedFunc {
|
||||
func: module
|
||||
.func_resolver
|
||||
.get(module, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
vmctx,
|
||||
},
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
imports.vm_functions[imported_func_index].clone()
|
||||
}
|
||||
};
|
||||
|
||||
elements[init_base + i] = vm::Anyfunc { func_data, sig_id };
|
||||
}
|
||||
}
|
||||
if (table.current_size() as usize) < init_base + init.elements.len() {
|
||||
let delta =
|
||||
(init_base + init.elements.len()) - table.current_size() as usize;
|
||||
// Grow the table if it's too small.
|
||||
table.grow(delta as u32).expect("couldn't grow table");
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(imported_table_index) => {
|
||||
let (_, table_description) = module.imported_tables[imported_table_index];
|
||||
match table_description.ty {
|
||||
ElementType::Anyfunc => {
|
||||
let imported_table = &imports.vm_tables[imported_table_index];
|
||||
let imported_local_table = (*imported_table).table;
|
||||
|
||||
let mut elements = unsafe {
|
||||
Vec::from_raw_parts(
|
||||
(*imported_local_table).base as *mut vm::Anyfunc,
|
||||
(*imported_local_table).current_elements,
|
||||
(*imported_local_table).capacity,
|
||||
)
|
||||
table.anyfunc_direct_access_mut(|elements| {
|
||||
for (i, &func_index) in init.elements.iter().enumerate() {
|
||||
let sig_index = module.func_assoc[func_index];
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
|
||||
let (func, ctx) = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
.get(module, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr()
|
||||
as *const vm::Func,
|
||||
vmctx,
|
||||
),
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
let vm::ImportedFunc { func, vmctx } =
|
||||
imports.vm_functions[imported_func_index];
|
||||
(func, vmctx)
|
||||
}
|
||||
};
|
||||
|
||||
if elements.len() < init_base + init.elements.len() {
|
||||
// Grow the table if it's too small.
|
||||
elements
|
||||
.resize(init_base + init.elements.len(), vm::Anyfunc::null());
|
||||
// Since the vector may have changed location after reallocating,
|
||||
// we must fix the base, current_elements, and capacity fields.
|
||||
unsafe {
|
||||
(*imported_local_table).base = elements.as_mut_ptr() as *mut u8;
|
||||
(*imported_local_table).current_elements = elements.len();
|
||||
(*imported_local_table).capacity = elements.capacity();
|
||||
}
|
||||
}
|
||||
|
||||
for (i, &func_index) in init.elements.iter().enumerate() {
|
||||
let sig_index = module.func_assoc[func_index];
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
|
||||
let func_data = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => vm::ImportedFunc {
|
||||
func: module
|
||||
.func_resolver
|
||||
.get(module, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
vmctx,
|
||||
},
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
imports.vm_functions[imported_func_index].clone()
|
||||
}
|
||||
};
|
||||
|
||||
elements[init_base + i] = vm::Anyfunc { func_data, sig_id };
|
||||
}
|
||||
|
||||
// println!("imported elements: {:#?}", elements);
|
||||
|
||||
// THIS IS EXTREMELY IMPORTANT.
|
||||
mem::forget(elements);
|
||||
elements[init_base + i] = vm::Anyfunc { func, ctx, sig_id };
|
||||
}
|
||||
});
|
||||
}
|
||||
LocalOrImport::Import(import_table_index) => {
|
||||
let table = &imports.tables[import_table_index];
|
||||
|
||||
if (table.current_size() as usize) < init_base + init.elements.len() {
|
||||
let delta =
|
||||
(init_base + init.elements.len()) - table.current_size() as usize;
|
||||
// Grow the table if it's too small.
|
||||
table.grow(delta as u32).expect("couldn't grow table");
|
||||
}
|
||||
|
||||
table.anyfunc_direct_access_mut(|elements| {
|
||||
for (i, &func_index) in init.elements.iter().enumerate() {
|
||||
let sig_index = module.func_assoc[func_index];
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
|
||||
let (func, ctx) = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
.get(module, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr()
|
||||
as *const vm::Func,
|
||||
vmctx,
|
||||
),
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
let vm::ImportedFunc { func, vmctx } =
|
||||
imports.vm_functions[imported_func_index];
|
||||
(func, vmctx)
|
||||
}
|
||||
};
|
||||
|
||||
elements[init_base + i] = vm::Anyfunc { func, ctx, sig_id };
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tables
|
||||
.iter_mut()
|
||||
.map(|(_, table)| table.into_vm_table())
|
||||
.map(|(_, table)| table.vm_local_table())
|
||||
.collect::<Map<_, _>>()
|
||||
.into_boxed_map()
|
||||
}
|
||||
@ -304,11 +286,12 @@ impl LocalBacking {
|
||||
#[derive(Debug)]
|
||||
pub struct ImportBacking {
|
||||
pub(crate) memories: BoxedMap<ImportedMemoryIndex, Memory>,
|
||||
pub(crate) tables: BoxedMap<ImportedTableIndex, Table>,
|
||||
pub(crate) globals: BoxedMap<ImportedGlobalIndex, Global>,
|
||||
|
||||
pub(crate) vm_functions: BoxedMap<ImportedFuncIndex, vm::ImportedFunc>,
|
||||
pub(crate) vm_memories: BoxedMap<ImportedMemoryIndex, *mut vm::LocalMemory>,
|
||||
pub(crate) vm_tables: BoxedMap<ImportedTableIndex, vm::ImportedTable>,
|
||||
pub(crate) vm_tables: BoxedMap<ImportedTableIndex, *mut vm::LocalTable>,
|
||||
pub(crate) vm_globals: BoxedMap<ImportedGlobalIndex, *mut vm::LocalGlobal>,
|
||||
}
|
||||
|
||||
@ -333,10 +316,10 @@ impl ImportBacking {
|
||||
(Map::new().into_boxed_map(), Map::new().into_boxed_map())
|
||||
});
|
||||
|
||||
let vm_tables = import_tables(module, imports, vmctx).unwrap_or_else(|le| {
|
||||
let (tables, vm_tables) = import_tables(module, imports).unwrap_or_else(|le| {
|
||||
failed = true;
|
||||
link_errors.extend(le);
|
||||
Map::new().into_boxed_map()
|
||||
(Map::new().into_boxed_map(), Map::new().into_boxed_map())
|
||||
});
|
||||
|
||||
let (globals, vm_globals) = import_globals(module, imports).unwrap_or_else(|le| {
|
||||
@ -350,6 +333,7 @@ impl ImportBacking {
|
||||
} else {
|
||||
Ok(ImportBacking {
|
||||
memories,
|
||||
tables,
|
||||
globals,
|
||||
|
||||
vm_functions,
|
||||
@ -374,7 +358,7 @@ fn import_functions(
|
||||
let mut functions = Map::with_capacity(module.imported_functions.len());
|
||||
for (index, ImportName { namespace, name }) in &module.imported_functions {
|
||||
let sig_index = module.func_assoc[index.convert_up(module)];
|
||||
let expected_sig = module.sig_registry.lookup_func_sig(sig_index);
|
||||
let expected_sig = module.sig_registry.lookup_signature(sig_index);
|
||||
let import = imports
|
||||
.get_namespace(namespace)
|
||||
.and_then(|namespace| namespace.get_export(name));
|
||||
@ -384,7 +368,7 @@ fn import_functions(
|
||||
ctx,
|
||||
signature,
|
||||
}) => {
|
||||
if expected_sig == &signature {
|
||||
if expected_sig == signature {
|
||||
functions.push(vm::ImportedFunc {
|
||||
func: func.inner(),
|
||||
vmctx: match ctx {
|
||||
@ -496,34 +480,28 @@ fn import_memories(
|
||||
fn import_tables(
|
||||
module: &ModuleInner,
|
||||
imports: &mut ImportObject,
|
||||
vmctx: *mut vm::Ctx,
|
||||
) -> LinkResult<BoxedMap<ImportedTableIndex, vm::ImportedTable>> {
|
||||
) -> LinkResult<(
|
||||
BoxedMap<ImportedTableIndex, Table>,
|
||||
BoxedMap<ImportedTableIndex, *mut vm::LocalTable>,
|
||||
)> {
|
||||
let mut link_errors = vec![];
|
||||
let mut tables = Map::with_capacity(module.imported_tables.len());
|
||||
let mut vm_tables = Map::with_capacity(module.imported_tables.len());
|
||||
for (_index, (ImportName { namespace, name }, expected_table_desc)) in &module.imported_tables {
|
||||
let table_import = imports
|
||||
.get_namespace(&namespace)
|
||||
.and_then(|namespace| namespace.get_export(&name));
|
||||
match table_import {
|
||||
Some(Export::Table {
|
||||
local,
|
||||
ctx,
|
||||
desc: table_desc,
|
||||
}) => {
|
||||
if expected_table_desc.fits_in_imported(&table_desc) {
|
||||
tables.push(vm::ImportedTable {
|
||||
table: local.inner(),
|
||||
vmctx: match ctx {
|
||||
Context::External(ctx) => ctx,
|
||||
Context::Internal => vmctx,
|
||||
},
|
||||
});
|
||||
Some(Export::Table(mut table)) => {
|
||||
if expected_table_desc.fits_in_imported(table.description()) {
|
||||
vm_tables.push(table.vm_local_table());
|
||||
tables.push(table);
|
||||
} else {
|
||||
link_errors.push(LinkError::IncorrectTableDescription {
|
||||
namespace: namespace.clone(),
|
||||
name: name.clone(),
|
||||
expected: expected_table_desc.clone(),
|
||||
found: table_desc.clone(),
|
||||
expected: *expected_table_desc,
|
||||
found: table.description(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -554,7 +532,7 @@ fn import_tables(
|
||||
if link_errors.len() > 0 {
|
||||
Err(link_errors)
|
||||
} else {
|
||||
Ok(tables.into_boxed_map())
|
||||
Ok((tables.into_boxed_map(), vm_tables.into_boxed_map()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::types::{FuncSig, GlobalDesc, MemoryDesc, MemoryIndex, TableDesc, TableIndex, Type};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Box<Error>>;
|
||||
pub type CompileResult<T> = std::result::Result<T, Box<CompileError>>;
|
||||
@ -39,8 +40,8 @@ pub enum LinkError {
|
||||
IncorrectImportSignature {
|
||||
namespace: String,
|
||||
name: String,
|
||||
expected: FuncSig,
|
||||
found: FuncSig,
|
||||
expected: Arc<FuncSig>,
|
||||
found: Arc<FuncSig>,
|
||||
},
|
||||
ImportNotFound {
|
||||
namespace: String,
|
||||
@ -100,9 +101,16 @@ impl PartialEq for RuntimeError {
|
||||
/// Comparing two `ResolveError`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ResolveError {
|
||||
Signature { expected: FuncSig, found: Vec<Type> },
|
||||
ExportNotFound { name: String },
|
||||
ExportWrongType { name: String },
|
||||
Signature {
|
||||
expected: Arc<FuncSig>,
|
||||
found: Vec<Type>,
|
||||
},
|
||||
ExportNotFound {
|
||||
name: String,
|
||||
},
|
||||
ExportWrongType {
|
||||
name: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl PartialEq for ResolveError {
|
||||
|
@ -1,13 +1,9 @@
|
||||
use crate::{
|
||||
global::Global,
|
||||
instance::InstanceInner,
|
||||
memory::Memory,
|
||||
module::ExportIndex,
|
||||
module::ModuleInner,
|
||||
types::{FuncSig, TableDesc},
|
||||
vm,
|
||||
global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex,
|
||||
module::ModuleInner, table::Table, types::FuncSig, vm,
|
||||
};
|
||||
use hashbrown::hash_map;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Context {
|
||||
@ -20,14 +16,10 @@ pub enum Export {
|
||||
Function {
|
||||
func: FuncPointer,
|
||||
ctx: Context,
|
||||
signature: FuncSig,
|
||||
signature: Arc<FuncSig>,
|
||||
},
|
||||
Memory(Memory),
|
||||
Table {
|
||||
local: TablePointer,
|
||||
ctx: Context,
|
||||
desc: TableDesc,
|
||||
},
|
||||
Table(Table),
|
||||
Global(Global),
|
||||
}
|
||||
|
||||
@ -47,22 +39,6 @@ impl FuncPointer {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TablePointer(*mut vm::LocalTable);
|
||||
|
||||
impl TablePointer {
|
||||
/// This needs to be unsafe because there is
|
||||
/// no way to check whether the passed function
|
||||
/// is valid and has the right signature.
|
||||
pub unsafe fn new(f: *mut vm::LocalTable) -> Self {
|
||||
TablePointer(f)
|
||||
}
|
||||
|
||||
pub(crate) fn inner(&self) -> *mut vm::LocalTable {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExportIter<'a> {
|
||||
inner: &'a mut InstanceInner,
|
||||
iter: hash_map::Iter<'a, String, ExportIndex>,
|
||||
|
@ -2,14 +2,13 @@ use crate::{
|
||||
backend::Token,
|
||||
backing::{ImportBacking, LocalBacking},
|
||||
error::{CallError, CallResult, ResolveError, ResolveResult, Result},
|
||||
export::{Context, Export, ExportIter, FuncPointer, TablePointer},
|
||||
export::{Context, Export, ExportIter, FuncPointer},
|
||||
global::Global,
|
||||
import::{ImportObject, LikeNamespace},
|
||||
memory::Memory,
|
||||
module::{ExportIndex, Module, ModuleInner},
|
||||
types::{
|
||||
FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableDesc, TableIndex, Value,
|
||||
},
|
||||
table::Table,
|
||||
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
|
||||
vm,
|
||||
};
|
||||
use std::{mem, sync::Arc};
|
||||
@ -18,7 +17,14 @@ pub(crate) struct InstanceInner {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) backing: LocalBacking,
|
||||
import_backing: ImportBacking,
|
||||
vmctx: Box<vm::Ctx>,
|
||||
pub(crate) vmctx: *mut vm::Ctx,
|
||||
}
|
||||
|
||||
impl Drop for InstanceInner {
|
||||
fn drop(&mut self) {
|
||||
// Drop the vmctx.
|
||||
unsafe { Box::from_raw(self.vmctx) };
|
||||
}
|
||||
}
|
||||
|
||||
/// An instantiated WebAssembly module.
|
||||
@ -52,15 +58,16 @@ impl Instance {
|
||||
let mut inner = Box::new(InstanceInner {
|
||||
backing,
|
||||
import_backing,
|
||||
vmctx,
|
||||
vmctx: Box::leak(vmctx),
|
||||
});
|
||||
|
||||
// Initialize the vm::Ctx in-place after the backing
|
||||
// has been boxed.
|
||||
*inner.vmctx =
|
||||
unsafe { vm::Ctx::new(&mut inner.backing, &mut inner.import_backing, &module) };
|
||||
unsafe {
|
||||
*inner.vmctx = vm::Ctx::new(&mut inner.backing, &mut inner.import_backing, &module)
|
||||
};
|
||||
|
||||
let mut instance = Instance {
|
||||
let instance = Instance {
|
||||
module,
|
||||
inner,
|
||||
imports,
|
||||
@ -87,7 +94,7 @@ impl Instance {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn func(&mut self, name: &str) -> ResolveResult<Function> {
|
||||
pub fn func(&self, name: &str) -> ResolveResult<Function> {
|
||||
let export_index =
|
||||
self.module
|
||||
.exports
|
||||
@ -102,12 +109,12 @@ impl Instance {
|
||||
.func_assoc
|
||||
.get(*func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
|
||||
let signature = self.module.sig_registry.lookup_signature(sig_index);
|
||||
|
||||
Ok(Function {
|
||||
signature,
|
||||
module: &self.module,
|
||||
instance_inner: &mut self.inner,
|
||||
instance_inner: &self.inner,
|
||||
func_index: *func_index,
|
||||
})
|
||||
} else {
|
||||
@ -140,7 +147,7 @@ impl Instance {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn call(&mut self, name: &str, args: &[Value]) -> CallResult<Vec<Value>> {
|
||||
pub fn call(&self, name: &str, args: &[Value]) -> CallResult<Vec<Value>> {
|
||||
let export_index =
|
||||
self.module
|
||||
.exports
|
||||
@ -166,7 +173,7 @@ impl Instance {
|
||||
///
|
||||
/// [`Ctx`]: struct.Ctx.html
|
||||
pub fn context(&self) -> &vm::Ctx {
|
||||
&self.inner.vmctx
|
||||
unsafe { &*self.inner.vmctx }
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the
|
||||
@ -174,7 +181,7 @@ impl Instance {
|
||||
///
|
||||
/// [`Ctx`]: struct.Ctx.html
|
||||
pub fn context_mut(&mut self) -> &mut vm::Ctx {
|
||||
&mut self.inner.vmctx
|
||||
unsafe { &mut *self.inner.vmctx }
|
||||
}
|
||||
|
||||
/// Returns a iterator over all of the items
|
||||
@ -190,15 +197,15 @@ impl Instance {
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
fn call_with_index(&mut self, func_index: FuncIndex, args: &[Value]) -> CallResult<Vec<Value>> {
|
||||
fn call_with_index(&self, func_index: FuncIndex, args: &[Value]) -> CallResult<Vec<Value>> {
|
||||
let sig_index = *self
|
||||
.module
|
||||
.func_assoc
|
||||
.get(func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
|
||||
let signature = self.module.sig_registry.lookup_signature(sig_index);
|
||||
|
||||
if !signature.check_sig(args) {
|
||||
if !signature.check_param_value_types(args) {
|
||||
Err(ResolveError::Signature {
|
||||
expected: signature.clone(),
|
||||
found: args.iter().map(|val| val.ty()).collect(),
|
||||
@ -206,7 +213,7 @@ impl Instance {
|
||||
}
|
||||
|
||||
let vmctx = match func_index.local_or_import(&self.module) {
|
||||
LocalOrImport::Local(_) => &mut *self.inner.vmctx,
|
||||
LocalOrImport::Local(_) => self.inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||
}
|
||||
@ -229,7 +236,7 @@ impl Instance {
|
||||
|
||||
impl InstanceInner {
|
||||
pub(crate) fn get_export_from_index(
|
||||
&mut self,
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
export_index: &ExportIndex,
|
||||
) -> Export {
|
||||
@ -240,7 +247,7 @@ impl InstanceInner {
|
||||
Export::Function {
|
||||
func,
|
||||
ctx: match ctx {
|
||||
Context::Internal => Context::External(&mut *self.vmctx),
|
||||
Context::Internal => Context::External(self.vmctx),
|
||||
ctx @ Context::External(_) => ctx,
|
||||
},
|
||||
signature,
|
||||
@ -255,24 +262,17 @@ impl InstanceInner {
|
||||
Export::Global(global)
|
||||
}
|
||||
ExportIndex::Table(table_index) => {
|
||||
let (local, ctx, desc) = self.get_table_from_index(module, *table_index);
|
||||
Export::Table {
|
||||
local,
|
||||
ctx: match ctx {
|
||||
Context::Internal => Context::External(&mut *self.vmctx),
|
||||
ctx @ Context::External(_) => ctx,
|
||||
},
|
||||
desc,
|
||||
}
|
||||
let table = self.get_table_from_index(module, *table_index);
|
||||
Export::Table(table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_func_from_index(
|
||||
&mut self,
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
func_index: FuncIndex,
|
||||
) -> (FuncPointer, Context, FuncSig) {
|
||||
) -> (FuncPointer, Context, Arc<FuncSig>) {
|
||||
let sig_index = *module
|
||||
.func_assoc
|
||||
.get(func_index)
|
||||
@ -297,12 +297,12 @@ impl InstanceInner {
|
||||
}
|
||||
};
|
||||
|
||||
let signature = module.sig_registry.lookup_func_sig(sig_index).clone();
|
||||
let signature = module.sig_registry.lookup_signature(sig_index);
|
||||
|
||||
(unsafe { FuncPointer::new(func_ptr) }, ctx, signature)
|
||||
}
|
||||
|
||||
fn get_memory_from_index(&mut self, module: &ModuleInner, mem_index: MemoryIndex) -> Memory {
|
||||
fn get_memory_from_index(&self, module: &ModuleInner, mem_index: MemoryIndex) -> Memory {
|
||||
match mem_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_mem_index) => self.backing.memories[local_mem_index].clone(),
|
||||
LocalOrImport::Import(imported_mem_index) => {
|
||||
@ -311,7 +311,7 @@ impl InstanceInner {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_global_from_index(&mut self, module: &ModuleInner, global_index: GlobalIndex) -> Global {
|
||||
fn get_global_from_index(&self, module: &ModuleInner, global_index: GlobalIndex) -> Global {
|
||||
match global_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_global_index) => {
|
||||
self.backing.globals[local_global_index].clone()
|
||||
@ -322,35 +322,13 @@ impl InstanceInner {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_table_from_index(
|
||||
&mut self,
|
||||
module: &ModuleInner,
|
||||
table_index: TableIndex,
|
||||
) -> (TablePointer, Context, TableDesc) {
|
||||
fn get_table_from_index(&self, module: &ModuleInner, table_index: TableIndex) -> Table {
|
||||
match table_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let vm_table = &mut self.backing.vm_tables[local_table_index];
|
||||
(
|
||||
unsafe { TablePointer::new(vm_table) },
|
||||
Context::Internal,
|
||||
*module
|
||||
.tables
|
||||
.get(local_table_index)
|
||||
.expect("broken invariant, tables"),
|
||||
)
|
||||
self.backing.tables[local_table_index].clone()
|
||||
}
|
||||
LocalOrImport::Import(imported_table_index) => {
|
||||
let &(_, desc) = &module
|
||||
.imported_tables
|
||||
.get(imported_table_index)
|
||||
.expect("missing imported table index");
|
||||
let vm::ImportedTable { table, vmctx } =
|
||||
&self.import_backing.vm_tables[imported_table_index];
|
||||
(
|
||||
unsafe { TablePointer::new(*table) },
|
||||
Context::External(*vmctx),
|
||||
*desc,
|
||||
)
|
||||
self.import_backing.tables[imported_table_index].clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -366,9 +344,9 @@ impl LikeNamespace for Instance {
|
||||
|
||||
/// A representation of an exported WebAssembly function.
|
||||
pub struct Function<'a> {
|
||||
signature: &'a FuncSig,
|
||||
pub(crate) signature: Arc<FuncSig>,
|
||||
module: &'a ModuleInner,
|
||||
instance_inner: &'a mut InstanceInner,
|
||||
pub(crate) instance_inner: &'a InstanceInner,
|
||||
func_index: FuncIndex,
|
||||
}
|
||||
|
||||
@ -396,7 +374,7 @@ impl<'a> Function<'a> {
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn call(&mut self, params: &[Value]) -> CallResult<Vec<Value>> {
|
||||
if !self.signature.check_sig(params) {
|
||||
if !self.signature.check_param_value_types(params) {
|
||||
Err(ResolveError::Signature {
|
||||
expected: self.signature.clone(),
|
||||
found: params.iter().map(|val| val.ty()).collect(),
|
||||
@ -404,7 +382,7 @@ impl<'a> Function<'a> {
|
||||
}
|
||||
|
||||
let vmctx = match self.func_index.local_or_import(self.module) {
|
||||
LocalOrImport::Local(_) => &mut *self.instance_inner.vmctx,
|
||||
LocalOrImport::Local(_) => self.instance_inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.instance_inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||
}
|
||||
@ -425,7 +403,7 @@ impl<'a> Function<'a> {
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> &FuncSig {
|
||||
self.signature
|
||||
&*self.signature
|
||||
}
|
||||
|
||||
pub fn raw(&self) -> *const vm::Func {
|
||||
|
@ -19,10 +19,10 @@ macro_rules! func {
|
||||
Export::Function {
|
||||
func: unsafe { FuncPointer::new(func as _) },
|
||||
ctx: Context::Internal,
|
||||
signature: FuncSig {
|
||||
params: vec![$($crate::__export_func_convert_type!($params),)*],
|
||||
returns: vec![$($crate::__export_func_convert_type!($returns),)*],
|
||||
},
|
||||
signature: FuncSig::new(
|
||||
&[$($crate::__export_func_convert_type!($params),)*] as &[Type],
|
||||
&[$($crate::__export_func_convert_type!($returns),)*] as &[Type],
|
||||
).into(),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
@ -3,39 +3,50 @@ use crate::{
|
||||
types::{FuncSig, SigIndex},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SigRegistry {
|
||||
func_table: HashMap<FuncSig, SigIndex>,
|
||||
sig_assoc: Map<SigIndex, FuncSig>,
|
||||
duplicated_sig_assoc: Map<SigIndex, SigIndex>,
|
||||
}
|
||||
|
||||
impl SigRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
lazy_static! {
|
||||
static ref GLOBAL_SIG_REGISTRY: RwLock<GlobalSigRegistry> = {
|
||||
let registry = GlobalSigRegistry {
|
||||
func_table: HashMap::new(),
|
||||
sig_assoc: Map::new(),
|
||||
duplicated_sig_assoc: Map::new(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RwLock::new(registry)
|
||||
};
|
||||
}
|
||||
|
||||
struct GlobalSigRegistry {
|
||||
func_table: HashMap<Arc<FuncSig>, SigIndex>,
|
||||
sig_assoc: Map<SigIndex, Arc<FuncSig>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SigRegistry;
|
||||
|
||||
impl SigRegistry {
|
||||
pub fn lookup_sigindex<Sig>(&self, func_sig: Sig) -> SigIndex
|
||||
where
|
||||
Sig: Into<Arc<FuncSig>>,
|
||||
{
|
||||
let func_sig = func_sig.into();
|
||||
let mut global = (*GLOBAL_SIG_REGISTRY).write();
|
||||
let global = &mut *global;
|
||||
|
||||
let func_table = &mut global.func_table;
|
||||
let sig_assoc = &mut global.sig_assoc;
|
||||
|
||||
pub fn register(&mut self, func_sig: FuncSig) -> SigIndex {
|
||||
// self.sig_assoc.push(func_sig)
|
||||
let func_table = &mut self.func_table;
|
||||
let sig_assoc = &mut self.sig_assoc;
|
||||
let sig_index = *func_table
|
||||
.entry(func_sig.clone())
|
||||
.entry(Arc::clone(&func_sig))
|
||||
.or_insert_with(|| sig_assoc.push(func_sig));
|
||||
self.duplicated_sig_assoc.push(sig_index);
|
||||
|
||||
sig_index
|
||||
}
|
||||
|
||||
pub fn lookup_deduplicated_sigindex(&self, sig_index: SigIndex) -> SigIndex {
|
||||
self.duplicated_sig_assoc[sig_index]
|
||||
}
|
||||
|
||||
pub fn lookup_func_sig(&self, sig_index: SigIndex) -> &FuncSig {
|
||||
&self.sig_assoc[sig_index]
|
||||
pub fn lookup_signature(&self, sig_index: SigIndex) -> Arc<FuncSig> {
|
||||
let global = (*GLOBAL_SIG_REGISTRY).read();
|
||||
Arc::clone(&global.sig_assoc[sig_index])
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
use super::vm;
|
||||
use crate::types::{ElementType, TableDesc};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TableElements {
|
||||
/// This is intended to be a caller-checked Anyfunc.
|
||||
Anyfunc(Vec<vm::Anyfunc>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TableBacking {
|
||||
pub elements: TableElements,
|
||||
pub max: Option<u32>,
|
||||
}
|
||||
|
||||
impl TableBacking {
|
||||
pub fn new(table: TableDesc) -> Self {
|
||||
match table.ty {
|
||||
ElementType::Anyfunc => {
|
||||
let initial_table_backing_len = match table.max {
|
||||
Some(max) => max,
|
||||
None => table.min,
|
||||
} as usize;
|
||||
|
||||
Self {
|
||||
elements: TableElements::Anyfunc(vec![
|
||||
vm::Anyfunc::null();
|
||||
initial_table_backing_len
|
||||
]),
|
||||
max: table.max,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_vm_table(&mut self) -> vm::LocalTable {
|
||||
match self.elements {
|
||||
TableElements::Anyfunc(ref mut funcs) => vm::LocalTable {
|
||||
base: funcs.as_mut_ptr() as *mut u8,
|
||||
current_elements: funcs.len(),
|
||||
capacity: funcs.capacity(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
137
lib/runtime-core/src/table/anyfunc.rs
Normal file
137
lib/runtime-core/src/table/anyfunc.rs
Normal file
@ -0,0 +1,137 @@
|
||||
use crate::{
|
||||
instance::Function,
|
||||
sig_registry::SigRegistry,
|
||||
structures::TypedIndex,
|
||||
types::{FuncSig, TableDesc},
|
||||
vm,
|
||||
};
|
||||
|
||||
use std::{ptr, sync::Arc};
|
||||
|
||||
enum AnyfuncInner<'a> {
|
||||
Host {
|
||||
ptr: *const vm::Func,
|
||||
signature: Arc<FuncSig>,
|
||||
},
|
||||
Managed(Function<'a>),
|
||||
}
|
||||
|
||||
pub struct Anyfunc<'a> {
|
||||
inner: AnyfuncInner<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Anyfunc<'a> {
|
||||
pub unsafe fn new<Sig>(func: *const vm::Func, signature: Sig) -> Self
|
||||
where
|
||||
Sig: Into<Arc<FuncSig>>,
|
||||
{
|
||||
Self {
|
||||
inner: AnyfuncInner::Host {
|
||||
ptr: func as _,
|
||||
signature: signature.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn raw(&self) -> *const vm::Func {
|
||||
match self.inner {
|
||||
AnyfuncInner::Host { ptr, .. } => ptr,
|
||||
AnyfuncInner::Managed(ref func) => func.raw(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Function<'a>> for Anyfunc<'a> {
|
||||
fn from(function: Function<'a>) -> Self {
|
||||
Anyfunc {
|
||||
inner: AnyfuncInner::Managed(function),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AnyfuncTable {
|
||||
backing: Vec<vm::Anyfunc>,
|
||||
max: Option<u32>,
|
||||
}
|
||||
|
||||
impl AnyfuncTable {
|
||||
pub fn new(desc: TableDesc, local: &mut vm::LocalTable) -> Result<Box<Self>, ()> {
|
||||
let initial_table_backing_len = match desc.max {
|
||||
Some(max) => max,
|
||||
None => desc.min,
|
||||
} as usize;
|
||||
|
||||
let mut storage = Box::new(AnyfuncTable {
|
||||
backing: vec![vm::Anyfunc::null(); initial_table_backing_len],
|
||||
max: desc.max,
|
||||
});
|
||||
|
||||
let storage_ptr: *mut AnyfuncTable = &mut *storage;
|
||||
|
||||
local.base = storage.backing.as_mut_ptr() as *mut u8;
|
||||
local.count = storage.backing.len();
|
||||
local.table = storage_ptr as *mut ();
|
||||
|
||||
Ok(storage)
|
||||
}
|
||||
|
||||
pub fn current_size(&self) -> u32 {
|
||||
self.backing.len() as u32
|
||||
}
|
||||
|
||||
pub fn internal_buffer(&mut self) -> &mut [vm::Anyfunc] {
|
||||
&mut self.backing
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, delta: u32, local: &mut vm::LocalTable) -> Option<u32> {
|
||||
let starting_len = self.backing.len() as u32;
|
||||
|
||||
let new_len = starting_len.checked_add(delta)?;
|
||||
|
||||
if let Some(max) = self.max {
|
||||
if new_len > max {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
self.backing.resize(new_len as usize, vm::Anyfunc::null());
|
||||
|
||||
local.base = self.backing.as_mut_ptr() as *mut u8;
|
||||
local.count = self.backing.len();
|
||||
|
||||
Some(starting_len)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, index: u32, element: Anyfunc) -> Result<(), ()> {
|
||||
if let Some(slot) = self.backing.get_mut(index as usize) {
|
||||
let anyfunc = match element.inner {
|
||||
AnyfuncInner::Host { ptr, signature } => {
|
||||
let sig_index = SigRegistry.lookup_sigindex(signature);
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
|
||||
vm::Anyfunc {
|
||||
func: ptr,
|
||||
ctx: ptr::null_mut(),
|
||||
sig_id,
|
||||
}
|
||||
}
|
||||
AnyfuncInner::Managed(ref func) => {
|
||||
let sig_index = SigRegistry.lookup_sigindex(Arc::clone(&func.signature));
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
|
||||
vm::Anyfunc {
|
||||
func: func.raw(),
|
||||
ctx: func.instance_inner.vmctx,
|
||||
sig_id,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
*slot = anyfunc;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
113
lib/runtime-core/src/table/mod.rs
Normal file
113
lib/runtime-core/src/table/mod.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use crate::{
|
||||
export::Export,
|
||||
import::IsExport,
|
||||
types::{ElementType, TableDesc},
|
||||
vm,
|
||||
};
|
||||
use std::{cell::RefCell, fmt, ptr, rc::Rc};
|
||||
|
||||
mod anyfunc;
|
||||
|
||||
pub use self::anyfunc::Anyfunc;
|
||||
use self::anyfunc::AnyfuncTable;
|
||||
|
||||
pub enum Element<'a> {
|
||||
Anyfunc(Anyfunc<'a>),
|
||||
}
|
||||
|
||||
// #[derive(Debug)]
|
||||
pub enum TableStorage {
|
||||
/// This is intended to be a caller-checked Anyfunc.
|
||||
Anyfunc(Box<AnyfuncTable>),
|
||||
}
|
||||
|
||||
pub struct Table {
|
||||
desc: TableDesc,
|
||||
storage: Rc<RefCell<(TableStorage, vm::LocalTable)>>,
|
||||
}
|
||||
|
||||
impl Table {
|
||||
pub fn new(desc: TableDesc) -> Result<Self, ()> {
|
||||
let mut local = vm::LocalTable {
|
||||
base: ptr::null_mut(),
|
||||
count: 0,
|
||||
table: ptr::null_mut(),
|
||||
};
|
||||
|
||||
let storage = match desc.ty {
|
||||
ElementType::Anyfunc => TableStorage::Anyfunc(AnyfuncTable::new(desc, &mut local)?),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
desc,
|
||||
storage: Rc::new(RefCell::new((storage, local))),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn description(&self) -> TableDesc {
|
||||
self.desc
|
||||
}
|
||||
|
||||
pub fn set(&self, index: u32, element: Element) -> Result<(), ()> {
|
||||
match &mut *self.storage.borrow_mut() {
|
||||
(TableStorage::Anyfunc(ref mut anyfunc_table), _) => {
|
||||
match element {
|
||||
Element::Anyfunc(anyfunc) => anyfunc_table.set(index, anyfunc),
|
||||
// _ => panic!("wrong element type for anyfunc table"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn anyfunc_direct_access_mut<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [vm::Anyfunc]) -> R,
|
||||
{
|
||||
match &mut *self.storage.borrow_mut() {
|
||||
(TableStorage::Anyfunc(ref mut anyfunc_table), _) => f(anyfunc_table.internal_buffer()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_size(&self) -> u32 {
|
||||
match &*self.storage.borrow() {
|
||||
(TableStorage::Anyfunc(ref anyfunc_table), _) => anyfunc_table.current_size(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn grow(&self, delta: u32) -> Option<u32> {
|
||||
if delta == 0 {
|
||||
return Some(self.current_size());
|
||||
}
|
||||
|
||||
match &mut *self.storage.borrow_mut() {
|
||||
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => {
|
||||
anyfunc_table.grow(delta, local)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn vm_local_table(&mut self) -> *mut vm::LocalTable {
|
||||
&mut self.storage.borrow_mut().1
|
||||
}
|
||||
}
|
||||
|
||||
impl IsExport for Table {
|
||||
fn to_export(&mut self) -> Export {
|
||||
Export::Table(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Table {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
desc: self.desc,
|
||||
storage: Rc::clone(&self.storage),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Table {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Table").field("desc", &self.desc).finish()
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::{memory::MemoryType, module::ModuleInner, structures::TypedIndex};
|
||||
use std::mem;
|
||||
use std::{borrow::Cow, mem};
|
||||
|
||||
/// Represents a WebAssembly type.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@ -138,7 +138,7 @@ pub struct TableDesc {
|
||||
}
|
||||
|
||||
impl TableDesc {
|
||||
pub(crate) fn fits_in_imported(&self, imported: &TableDesc) -> bool {
|
||||
pub(crate) fn fits_in_imported(&self, imported: TableDesc) -> bool {
|
||||
// TODO: We should define implementation limits.
|
||||
let imported_max = imported.max.unwrap_or(u32::max_value());
|
||||
let self_max = self.max.unwrap_or(u32::max_value());
|
||||
@ -203,12 +203,31 @@ impl MemoryDesc {
|
||||
/// in a wasm module or exposed to wasm by the host.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FuncSig {
|
||||
pub params: Vec<Type>,
|
||||
pub returns: Vec<Type>,
|
||||
params: Cow<'static, [Type]>,
|
||||
returns: Cow<'static, [Type]>,
|
||||
}
|
||||
|
||||
impl FuncSig {
|
||||
pub fn check_sig(&self, params: &[Value]) -> bool {
|
||||
pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
|
||||
where
|
||||
Params: Into<Cow<'static, [Type]>>,
|
||||
Returns: Into<Cow<'static, [Type]>>,
|
||||
{
|
||||
Self {
|
||||
params: params.into(),
|
||||
returns: returns.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn params(&self) -> &[Type] {
|
||||
&self.params
|
||||
}
|
||||
|
||||
pub fn returns(&self) -> &[Type] {
|
||||
&self.returns
|
||||
}
|
||||
|
||||
pub fn check_param_value_types(&self, params: &[Value]) -> bool {
|
||||
self.params.len() == params.len()
|
||||
&& self
|
||||
.params
|
||||
|
@ -16,7 +16,7 @@ pub struct Ctx {
|
||||
pub(crate) memories: *mut *mut LocalMemory,
|
||||
|
||||
/// A pointer to an array of locally-defined tables, indexed by `TableIndex`.
|
||||
pub(crate) tables: *mut LocalTable,
|
||||
pub(crate) tables: *mut *mut LocalTable,
|
||||
|
||||
/// A pointer to an array of locally-defined globals, indexed by `GlobalIndex`.
|
||||
pub(crate) globals: *mut *mut LocalGlobal,
|
||||
@ -25,7 +25,7 @@ pub struct Ctx {
|
||||
pub(crate) imported_memories: *mut *mut LocalMemory,
|
||||
|
||||
/// A pointer to an array of imported tables, indexed by `TableIndex`.
|
||||
pub(crate) imported_tables: *mut ImportedTable,
|
||||
pub(crate) imported_tables: *mut *mut LocalTable,
|
||||
|
||||
/// A pointer to an array of imported globals, indexed by `GlobalIndex`.
|
||||
pub(crate) imported_globals: *mut *mut LocalGlobal,
|
||||
@ -234,9 +234,9 @@ pub struct LocalTable {
|
||||
/// pointer to the elements in the table.
|
||||
pub base: *mut u8,
|
||||
/// Number of elements in the table (NOT necessarily the size of the table in bytes!).
|
||||
pub current_elements: usize,
|
||||
/// The number of elements that can fit into the memory allocated for this table.
|
||||
pub capacity: usize,
|
||||
pub count: usize,
|
||||
/// The table that this represents. At the moment, this can only be `*mut AnyfuncTable`.
|
||||
pub table: *mut (),
|
||||
}
|
||||
|
||||
impl LocalTable {
|
||||
@ -245,31 +245,7 @@ impl LocalTable {
|
||||
0 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn offset_current_elements() -> u8 {
|
||||
1 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn size() -> u8 {
|
||||
mem::size_of::<Self>() as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct ImportedTable {
|
||||
/// A pointer to the table definition.
|
||||
pub table: *mut LocalTable,
|
||||
/// A pointer to the vmcontext that owns this table definition.
|
||||
pub vmctx: *mut Ctx,
|
||||
}
|
||||
|
||||
impl ImportedTable {
|
||||
#[allow(clippy::erasing_op)] // TODO
|
||||
pub fn offset_table() -> u8 {
|
||||
0 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
pub fn offset_vmctx() -> u8 {
|
||||
pub fn offset_count() -> u8 {
|
||||
1 * (mem::size_of::<usize>() as u8)
|
||||
}
|
||||
|
||||
@ -337,17 +313,16 @@ pub struct SigId(pub u32);
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct Anyfunc {
|
||||
pub func_data: ImportedFunc,
|
||||
pub func: *const Func,
|
||||
pub ctx: *mut Ctx,
|
||||
pub sig_id: SigId,
|
||||
}
|
||||
|
||||
impl Anyfunc {
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
func_data: ImportedFunc {
|
||||
func: ptr::null(),
|
||||
vmctx: ptr::null_mut(),
|
||||
},
|
||||
func: ptr::null(),
|
||||
ctx: ptr::null_mut(),
|
||||
sig_id: SigId(u32::max_value()),
|
||||
}
|
||||
}
|
||||
@ -372,7 +347,7 @@ impl Anyfunc {
|
||||
|
||||
#[cfg(test)]
|
||||
mod vm_offset_tests {
|
||||
use super::{Anyfunc, Ctx, ImportedFunc, ImportedTable, LocalGlobal, LocalMemory, LocalTable};
|
||||
use super::{Anyfunc, Ctx, ImportedFunc, LocalGlobal, LocalMemory, LocalTable};
|
||||
|
||||
#[test]
|
||||
fn vmctx() {
|
||||
@ -433,21 +408,8 @@ mod vm_offset_tests {
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
LocalTable::offset_current_elements() as usize,
|
||||
offset_of!(LocalTable => current_elements).get_byte_offset(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imported_table() {
|
||||
assert_eq!(
|
||||
ImportedTable::offset_table() as usize,
|
||||
offset_of!(ImportedTable => table).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
ImportedTable::offset_vmctx() as usize,
|
||||
offset_of!(ImportedTable => vmctx).get_byte_offset(),
|
||||
LocalTable::offset_count() as usize,
|
||||
offset_of!(LocalTable => count).get_byte_offset(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -476,12 +438,12 @@ mod vm_offset_tests {
|
||||
fn cc_anyfunc() {
|
||||
assert_eq!(
|
||||
Anyfunc::offset_func() as usize,
|
||||
offset_of!(Anyfunc => func_data: ImportedFunc => func).get_byte_offset(),
|
||||
offset_of!(Anyfunc => func).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Anyfunc::offset_vmctx() as usize,
|
||||
offset_of!(Anyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(),
|
||||
offset_of!(Anyfunc => ctx).get_byte_offset(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@ -531,6 +493,7 @@ mod vm_ctx_tests {
|
||||
};
|
||||
let mut import_backing = ImportBacking {
|
||||
memories: Map::new().into_boxed_map(),
|
||||
tables: Map::new().into_boxed_map(),
|
||||
globals: Map::new().into_boxed_map(),
|
||||
|
||||
vm_functions: Map::new().into_boxed_map(),
|
||||
@ -613,7 +576,7 @@ mod vm_ctx_tests {
|
||||
start_func: None,
|
||||
|
||||
func_assoc: Map::new(),
|
||||
sig_registry: SigRegistry::new(),
|
||||
sig_registry: SigRegistry,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user