Add support for tables

This commit is contained in:
Lachlan Sneff 2018-12-26 22:29:42 -05:00
parent 20342c74b9
commit 74f0ff444a
7 changed files with 92 additions and 32 deletions

View File

@ -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<Arc<Module>, String>;
}
pub trait FuncResolver {
fn resolve(&self, module: &Module, name: &str) -> Option<NonNull<vm::Func>>;
}

View File

@ -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()
}

View File

@ -22,10 +22,10 @@ pub struct Instance {
impl Instance {
pub fn new(module: Arc<Module>, imports: &Imports) -> Result<Box<Instance>, 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(),

View File

@ -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;

View File

@ -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<dyn FuncResolver>,
pub function_resolver: Box<dyn Fn(&Module, FuncIndex) -> Option<NonNull<vm::Func>>>,
pub memories: Map<Memory, MemoryIndex>,
pub globals: Map<Global, GlobalIndex>,
pub tables: Map<Table, TableIndex>,
@ -20,12 +23,19 @@ pub struct Module {
pub exports: HashMap<String, Export>,
pub data_initializers: Vec<DataInitializer>,
pub table_initializers: Vec<TableInitializer>,
pub start_func: FuncIndex,
pub signature_assoc: Map<SigIndex, FuncIndex>,
pub signatures: Map<FuncSig, SigIndex>,
}
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<u8>,
}
/// 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<GlobalIndex>,
/// The offset to add to the base.
pub offset: usize,
/// The values to write into the table elements.
pub elements: Vec<FuncIndex>,
}

View File

@ -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);
}
}

View File

@ -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<Type>,
pub returns: Vec<Type>,