diff --git a/src/runtime/backend.rs b/src/runtime/backend.rs index ba8ecf9c0..93f536322 100644 --- a/src/runtime/backend.rs +++ b/src/runtime/backend.rs @@ -1,11 +1,6 @@ -use crate::runtime::{module::Module, vm}; -use std::ptr::NonNull; +use crate::runtime::module::Module; use std::sync::Arc; pub trait Compiler { fn compile(&self, wasm: &[u8]) -> Result, String>; } - -pub trait FuncResolver { - fn resolve(&self, module: &Module, name: &str) -> Option>; -} diff --git a/src/runtime/backing.rs b/src/runtime/backing.rs index 6c2780385..a12ccc3e8 100644 --- a/src/runtime/backing.rs +++ b/src/runtime/backing.rs @@ -2,7 +2,8 @@ use crate::runtime::{ instance::{Import, Imports}, memory::LinearMemory, module::{ImportName, Module}, - table::TableBacking, + sig_registry::SigRegistry, + table::{TableBacking, TableElements}, types::{GlobalInit, MapIndex, Val}, vm, }; @@ -18,13 +19,13 @@ pub struct LocalBacking { } impl LocalBacking { - pub fn new(module: &Module, imports: &ImportBacking) -> Self { + pub fn new(module: &Module, imports: &ImportBacking, sig_registry: &SigRegistry) -> Self { let mut memories = Self::generate_memories(module); let mut tables = Self::generate_tables(module); let globals = Self::generate_globals(module); let vm_memories = Self::finalize_memories(module, &mut memories[..]); - let vm_tables = Self::finalize_tables(module, &mut tables[..]); + let vm_tables = Self::finalize_tables(module, imports, &mut tables[..], sig_registry); let vm_globals = Self::finalize_globals(module, imports, globals); Self { @@ -60,7 +61,7 @@ impl LocalBacking { fn finalize_memories(module: &Module, memories: &mut [LinearMemory]) -> Box<[vm::LocalMemory]> { for init in &module.data_initializers { - assert!(init.base.is_none(), "globalvar base not supported yet"); + assert!(init.base.is_none(), "global base not supported yet"); assert!( init.offset + init.data.len() <= memories[init.memory_index.index()].current_size() ); @@ -94,8 +95,40 @@ impl LocalBacking { tables.into_boxed_slice() } - // TODO: Actually finish this - fn finalize_tables(_module: &Module, tables: &mut [TableBacking]) -> Box<[vm::LocalTable]> { + fn finalize_tables( + module: &Module, + imports: &ImportBacking, + tables: &mut [TableBacking], + sig_registry: &SigRegistry, + ) -> Box<[vm::LocalTable]> { + for init in &module.table_initializers { + assert!(init.base.is_none(), "global base not supported yet"); + let table = &mut tables[init.table_index.index()]; + match table.elements { + TableElements::Anyfunc(ref mut elements) => { + for (i, &func_index) in init.elements.iter().enumerate() { + let sig_index = module.signature_assoc[func_index]; + let vm_sig_id = sig_registry.get_vm_id(sig_index); + + let func_data = if module.is_imported_function(func_index) { + imports.functions[func_index.index()].clone() + } else { + vm::ImportedFunc { + func: (module.function_resolver)(module, func_index) + .unwrap() + .as_ptr(), + } + }; + + elements[init.offset + i] = vm::Anyfunc { + func_data, + sig_id: vm_sig_id, + }; + } + } + } + } + tables .iter_mut() .map(|table| table.into_vm_table()) @@ -103,9 +136,8 @@ impl LocalBacking { .into_boxed_slice() } - // TODO: Actually finish this fn generate_globals(module: &Module) -> Box<[vm::LocalGlobal]> { - let mut globals = vec![vm::LocalGlobal::null(); module.globals.len()]; + let globals = vec![vm::LocalGlobal::null(); module.globals.len()]; globals.into_boxed_slice() } diff --git a/src/runtime/instance.rs b/src/runtime/instance.rs index ef31b1761..14d5cc827 100644 --- a/src/runtime/instance.rs +++ b/src/runtime/instance.rs @@ -22,10 +22,10 @@ pub struct Instance { impl Instance { pub fn new(module: Arc, imports: &Imports) -> Result, String> { - let import_backing = ImportBacking::new(&*module, imports)?; - let backing = LocalBacking::new(&*module, &import_backing); + let sig_registry = SigRegistry::new(&*module); - let sig_registry = SigRegistry::new(); + let import_backing = ImportBacking::new(&*module, imports)?; + let backing = LocalBacking::new(&*module, &import_backing, &sig_registry); Ok(Box::new(Instance { backing, @@ -90,9 +90,7 @@ impl Instance { .collect(); let func_ptr = CodePtr::from_ptr( - self.module - .functions - .resolve(&*self.module, name) + (self.module.function_resolver)(&*self.module, func_index) .expect("broken invariant, func resolver not synced with module.exports") .cast() .as_ptr(), diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 6491a82e8..ac5e3941b 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -8,7 +8,7 @@ mod table; pub mod types; pub mod vm; -pub use self::backend::{Compiler, FuncResolver}; +pub use self::backend::Compiler; pub use self::instance::{Import, Imports, Instance}; pub use self::module::Module; diff --git a/src/runtime/module.rs b/src/runtime/module.rs index c5cc82638..3894e6142 100644 --- a/src/runtime/module.rs +++ b/src/runtime/module.rs @@ -1,13 +1,16 @@ -use crate::runtime::backend::FuncResolver; -use crate::runtime::types::{ - FuncIndex, FuncSig, Global, GlobalDesc, GlobalIndex, Map, Memory, MemoryIndex, SigIndex, Table, - TableIndex, +use crate::runtime::{ + types::{ + FuncIndex, FuncSig, Global, GlobalDesc, GlobalIndex, Map, MapIndex, Memory, MemoryIndex, + SigIndex, Table, TableIndex, + }, + vm, }; use hashbrown::HashMap; +use std::ptr::NonNull; /// This is used to instantiate a new webassembly module. pub struct Module { - pub functions: Box, + pub function_resolver: Box Option>>, pub memories: Map, pub globals: Map, pub tables: Map, @@ -20,12 +23,19 @@ pub struct Module { pub exports: HashMap, pub data_initializers: Vec, + pub table_initializers: Vec, pub start_func: FuncIndex, pub signature_assoc: Map, pub signatures: Map, } +impl Module { + pub(in crate::runtime) fn is_imported_function(&self, func_index: FuncIndex) -> bool { + func_index.index() < self.imported_functions.len() + } +} + #[derive(Debug, Clone)] pub struct ImportName { pub module: String, @@ -52,3 +62,16 @@ pub struct DataInitializer { /// The initialization data. pub data: Vec, } + +/// A WebAssembly table initializer. +#[derive(Clone, Debug)] +pub struct TableInitializer { + /// The index of a table to initialize. + pub table_index: TableIndex, + /// Optionally, a global variable giving a base index. + pub base: Option, + /// The offset to add to the base. + pub offset: usize, + /// The values to write into the table elements. + pub elements: Vec, +} diff --git a/src/runtime/sig_registry.rs b/src/runtime/sig_registry.rs index cc3236c5e..1912211fb 100644 --- a/src/runtime/sig_registry.rs +++ b/src/runtime/sig_registry.rs @@ -1,4 +1,5 @@ use crate::runtime::{ + module::Module, types::{FuncSig, Map, SigIndex}, vm, }; @@ -10,23 +11,34 @@ pub struct SigRegistry { } impl SigRegistry { - pub fn new() -> Self { - Self { + pub fn new(module: &Module) -> Self { + let mut registry = Self { sig_set: HashMap::new(), signatures: Map::new(), + }; + + for (_, &sig_index) in &module.signature_assoc { + let func_sig = module.signatures[sig_index].clone(); + registry.register(func_sig); } + + registry } pub fn into_vm_signatures(&self) -> *const vm::SigId { self.signatures.as_ptr() } - pub fn register(&mut self, signature: FuncSig) { + pub fn get_vm_id(&self, sig_index: SigIndex) -> vm::SigId { + self.signatures[sig_index] + } + + fn register(&mut self, signature: FuncSig) { let index = self.sig_set.len(); - let vm_sig_id = self + let vm_sig_id = *self .sig_set .entry(signature) .or_insert_with(|| vm::SigId(index as u32)); - self.signatures.push(*vm_sig_id); + self.signatures.push(vm_sig_id); } } diff --git a/src/runtime/types.rs b/src/runtime/types.rs index 026f096a8..34e3e39eb 100644 --- a/src/runtime/types.rs +++ b/src/runtime/types.rs @@ -120,7 +120,7 @@ impl Memory { } /// A wasm func. -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FuncSig { pub params: Vec, pub returns: Vec,