diff --git a/src/common/slice.rs b/src/common/slice.rs index bb82a64c2..471b3b059 100644 --- a/src/common/slice.rs +++ b/src/common/slice.rs @@ -1,7 +1,5 @@ use std::ops::{Index, IndexMut}; use std::ptr::NonNull; -use std::marker::PhantomData; -use crate::runtime::types::MapIndex; #[derive(Copy, Clone, Debug)] #[repr(transparent)] @@ -105,41 +103,4 @@ impl<'a, T> From<&'a [T]> for BoundedSlice { len: slice.len(), } } -} - -#[derive(Debug)] -#[repr(transparent)] -pub struct IndexedSlice<'a, T, I> { - ptr: NonNull, - _phantom: PhantomData, -} - -impl<'a, T: 'a, I> IndexedSlice -where - I: MapIndex, -{ - pub(crate) fn new(ptr: *mut T) -> Self { - Self { - ptr: NonNull::new(ptr).unwrap(), - _phantom: PhantomData, - } - } - - pub unsafe fn get(&self, index: I) -> &T { - let ptr = self.as_ptr(); - &*ptr.add(index.index()) - } - - pub unsafe fn get_mut(&mut self, index: I) -> &mut T { - let ptr = self.as_mut_ptr(); - &mut *ptr.add(index.index()) - } - - pub fn as_ptr(&self) -> *const T { - self.ptr.as_ptr() - } - - pub fn as_mut_ptr(&mut self) -> *mut T { - self.ptr.as_ptr() - } } \ No newline at end of file diff --git a/src/runtime/backend.rs b/src/runtime/backend.rs index c48f41415..5d227166c 100644 --- a/src/runtime/backend.rs +++ b/src/runtime/backend.rs @@ -1,5 +1,4 @@ -use crate::runtime::module::Module; -use crate::runtime::types::FuncIndex; + use crate::runtime::{ vm, module::Module, @@ -12,5 +11,5 @@ pub trait Compiler { } pub trait FuncResolver { - pub fn resolve(&self, index: FuncIndex) -> Option<*const vm::Func>; + fn resolve(&self, index: FuncIndex) -> Option<*const vm::Func>; } \ No newline at end of file diff --git a/src/runtime/backing.rs b/src/runtime/backing.rs index dae840c6a..f6ffb8220 100644 --- a/src/runtime/backing.rs +++ b/src/runtime/backing.rs @@ -2,11 +2,10 @@ use crate::runtime::{ vm, module::Module, table::TableBacking, - types::{Val, GlobalInit}, + types::{Val, GlobalInit, MapIndex}, memory::LinearMemory, instance::{Imports, Import}, }; -use std::{ptr, mem}; #[derive(Debug)] @@ -14,9 +13,9 @@ pub struct LocalBacking { memories: Box<[LinearMemory]>, tables: Box<[TableBacking]>, - vm_memories: Box<[vm::LocalMemory]>, - vm_tables: Box<[vm::LocalTable]>, - vm_globals: Box<[vm::LocalGlobal]>, + pub vm_memories: Box<[vm::LocalMemory]>, + pub vm_tables: Box<[vm::LocalTable]>, + pub vm_globals: Box<[vm::LocalGlobal]>, } impl LocalBacking { @@ -29,8 +28,8 @@ impl LocalBacking { memories, tables, - vm_memories: Self::finalize_memories(module, &mut memories[..], options), - vm_tables: Self::finalize_tables(module, &mut tables[..], options), + vm_memories: Self::finalize_memories(module, &mut memories[..]), + vm_tables: Self::finalize_tables(module, &mut tables[..]), vm_globals: Self::finalize_globals(module, imports, globals), } } @@ -42,7 +41,7 @@ impl LocalBacking { // If we use emscripten, we set a fixed initial and maximum debug!( "Instance - init memory ({}, {:?})", - memory.min, memory.max + mem.min, mem.max ); // let memory = if options.abi == InstanceABI::Emscripten { // // We use MAX_PAGES, so at the end the result is: @@ -80,7 +79,7 @@ impl LocalBacking { fn generate_tables(module: &Module) -> Box<[TableBacking]> { let mut tables = Vec::with_capacity(module.tables.len()); - for table in &module.tables { + for (_, table) in &module.tables { let table_backing = TableBacking::new(table); tables.push(table_backing); } @@ -99,13 +98,13 @@ impl LocalBacking { } fn finalize_globals(module: &Module, imports: &ImportBacking, globals: Box<[vm::LocalGlobal]>) -> Box<[vm::LocalGlobal]> { - for (to, from) in globals.iter_mut().zip(module.globals.iter()) { - *to = match from.init { + for (to, (_, from)) in globals.iter_mut().zip(module.globals.into_iter()) { + to.data = match from.init { GlobalInit::Val(Val::I32(x)) => x as u64, GlobalInit::Val(Val::I64(x)) => x as u64, GlobalInit::Val(Val::F32(x)) => x as u64, GlobalInit::Val(Val::F64(x)) => x, - GlobalInit::GetGlobal(index) => unsafe { (*imports.globals[index.index()].global).data }, + GlobalInit::GetGlobal(index) => unsafe { (imports.globals[index.index()].global).data }, }; } @@ -182,10 +181,10 @@ impl LocalBacking { #[derive(Debug)] pub struct ImportBacking { - functions: Box<[vm::ImportedFunc]>, - memories: Box<[vm::ImportedMemory]>, - tables: Box<[vm::ImportedTable]>, - globals: Box<[vm::ImportedGlobal]>, + pub functions: Box<[vm::ImportedFunc]>, + pub memories: Box<[vm::ImportedMemory]>, + pub tables: Box<[vm::ImportedTable]>, + pub globals: Box<[vm::ImportedGlobal]>, } impl ImportBacking { @@ -195,42 +194,43 @@ impl ImportBacking { let mut functions = Vec::with_capacity(module.imported_functions.len()); for (index, (mod_name, item_name)) in &module.imported_functions { - let expected_sig = module.signatures[index]; + let expected_sig_index = module.signature_assoc[index]; + let expected_sig = module.signatures[expected_sig_index]; let import = imports.get(mod_name, item_name); - if let Import::Func(func, signature) = import { - if expected_sig == signature { + if let Some(Import::Func(func, signature)) = import { + if &expected_sig == signature { functions.push(vm::ImportedFunc { - func, - vmctx: ptr::null_mut(), + func: *func, + // vmctx: ptr::null_mut(), }); } else { - return Err(format!("unexpected signature for {}:{}", mod_name, item_name)); + return Err(format!("unexpected signature for {:?}:{:?}", mod_name, item_name)); } } else { - return Err(format!("incorrect type for {}:{}", mod_name, item_name)); + return Err(format!("incorrect type for {:?}:{:?}", mod_name, item_name)); } } let mut globals = Vec::with_capacity(module.imported_globals.len()); for (_, ((mod_name, item_name), global_desc)) in &module.imported_globals { let import = imports.get(mod_name, item_name); - if let Import::Global(val) = import { + if let Some(Import::Global(val)) = import { if val.ty() == global_desc.ty { globals.push(vm::ImportedGlobal { global: vm::LocalGlobal { data: match val { - Val::I32(n) => n as u64, - Val::I64(n) => n as u64, - Val::F32(n) => n as u64, - Val::F64(n) => n, + Val::I32(n) => *n as u64, + Val::I64(n) => *n as u64, + Val::F32(n) => *n as u64, + Val::F64(n) => *n, }, }, }); } else { - return Err(format!("unexpected global type for {}:{}", mod_name, item_name)); + return Err(format!("unexpected global type for {:?}:{:?}", mod_name, item_name)); } } else { - return Err(format!("incorrect type for {}:{}", mod_name, item_name)); + return Err(format!("incorrect type for {:?}:{:?}", mod_name, item_name)); } } diff --git a/src/runtime/instance.rs b/src/runtime/instance.rs index aa6bb2ac2..4bb3b98f4 100644 --- a/src/runtime/instance.rs +++ b/src/runtime/instance.rs @@ -1,21 +1,24 @@ use crate::runtime::{ vm, backing::{LocalBacking, ImportBacking}, - module::{ModuleName, ItemName}, - types::{Val, Memory, Table, Global, FuncSig}, + module::{Module, ModuleName, ItemName}, + types::{Val, Memory, Table, FuncSig}, table::TableBacking, memory::LinearMemory, + sig_registry::SigRegistry, }; use std::sync::Arc; -use hashbrown::{HashMap, Entry}; +use hashbrown::HashMap; pub struct Instance { pub vmctx: vm::Ctx, backing: LocalBacking, - imports: ImportBacking, + import_backing: ImportBacking, pub module: Arc, + + pub sig_registry: SigRegistry, } impl Instance { @@ -23,18 +26,21 @@ impl Instance { let mut import_backing = ImportBacking::new(&*module, imports)?; let mut backing = LocalBacking::new(&*module, &import_backing); - let vmctx = vm::Ctx::new(&mut backing, &mut imports); + let sig_registry = SigRegistry::new(); + + let vmctx = vm::Ctx::new(&mut backing, &mut import_backing, &sig_registry); Ok(Box::new(Instance { vmctx, backing, import_backing, module, + sig_registry, })) } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug)] pub enum Import { Func(*const vm::Func, FuncSig), Table(Arc, Table), @@ -54,10 +60,10 @@ impl Imports { } pub fn add(&mut self, module: ModuleName, name: ItemName, import: Import) { - self.map.entry(module).or_insert(HashMap::new()).insert(name, import) + self.map.entry(module).or_insert(HashMap::new()).insert(name, import); } - pub fn get(&self, module: ModuleName, name: ItemName) -> Option<&Import> { - self.map.get().and_then(|m| m.get(name)) + pub fn get(&self, module: &[u8], name: &[u8]) -> Option<&Import> { + self.map.get(module).and_then(|m| m.get(name)) } } \ No newline at end of file diff --git a/src/runtime/memory.rs b/src/runtime/memory.rs index 8ccc0a51a..a09caa9f3 100644 --- a/src/runtime/memory.rs +++ b/src/runtime/memory.rs @@ -10,7 +10,7 @@ use std::slice; use crate::common::mmap::Mmap; use crate::runtime::{ vm::LocalMemory, - types::{Memory, Map, FuncIndex}, + types::Memory, }; /// A linear memory instance. @@ -62,7 +62,7 @@ impl LinearMemory { assert!(!mem.shared, "shared memories must have a maximum size."); (mem.min as usize * Self::PAGE_SIZE as usize, mem.min, 0, false) - } + }; let mut mmap = Mmap::with_size(mmap_size).unwrap(); @@ -103,7 +103,7 @@ impl LinearMemory { /// Returns the maximum number of wasm pages allowed. pub fn maximum_size(&self) -> u32 { - self.maximum.unwrap_or(Self::MAX_PAGES) + self.max.unwrap_or(Self::MAX_PAGES) } pub fn into_vm_memory(&mut self) -> LocalMemory { @@ -131,7 +131,7 @@ impl LinearMemory { None => return None, }; - if let Some(val) = self.maximum { + if let Some(val) = self.max { if new_pages > val { return None; } @@ -147,7 +147,7 @@ impl LinearMemory { if new_bytes > self.mmap.len() - self.offset_guard_size { let mmap_size = new_bytes.checked_add(self.offset_guard_size)?; - let mut new_mmap = Mmap::with_size(request_bytes).ok()?; + let mut new_mmap = Mmap::with_size(mmap_size).ok()?; unsafe { region::protect( @@ -158,7 +158,7 @@ impl LinearMemory { } let copy_size = self.mmap.len() - self.offset_guard_size; - new_mmap.as_mut_slice()[..copy_size].copy_from_slice(self.mmap.as_slice()[..copy_size]); + new_mmap.as_mut_slice()[..copy_size].copy_from_slice(&self.mmap.as_slice()[..copy_size]); self.mmap = new_mmap; } @@ -182,7 +182,7 @@ impl LinearMemory { None => return None, }; - if let Some(val) = self.maximum { + if let Some(val) = self.max { if new_pages > val { return None; } @@ -213,7 +213,7 @@ impl LinearMemory { // Not comparing based on memory content. That would be inefficient. impl PartialEq for LinearMemory { fn eq(&self, other: &LinearMemory) -> bool { - self.current == other.current && self.maximum == other.maximum + self.current == other.current && self.max == other.max } } diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 4b47b0e4e..a43f01bf7 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -9,9 +9,9 @@ mod instance; mod table; mod sig_registry; -pub use backend::Compiler; -pub use instance::{Instance, Imports, Import}; -pub use module::{ModuleName, ItemName, Module}; +pub use self::backend::Compiler; +pub use self::instance::{Instance, Imports, Import}; +pub use self::module::{ModuleName, ItemName, Module}; /// Compile a webassembly module using the provided compiler and linked with the provided imports. pub fn compile(compiler: &dyn Compiler, wasm: &[u8], imports: &Imports) -> Result, String> { diff --git a/src/runtime/module.rs b/src/runtime/module.rs index 110a7e6ed..84828e6b6 100644 --- a/src/runtime/module.rs +++ b/src/runtime/module.rs @@ -1,12 +1,11 @@ use crate::runtime::types::{ Map, - FuncIndex, MemoryIndex, TableIndex, GlobalIndex, - Memory, Globals, GlobalDesc, FuncSig, Table, + FuncIndex, MemoryIndex, TableIndex, GlobalIndex, SigIndex, + Memory, Global, GlobalDesc, FuncSig, Table, }; use crate::runtime::backend::FuncResolver; /// This is used to instantiate a new webassembly module. -#[derive(Debug)] pub struct Module { pub functions: Box, pub memories: Map, @@ -23,7 +22,8 @@ pub struct Module { pub data_initializers: Vec, pub start_func: FuncIndex, - pub signatures: Map, + pub signature_assoc: Map, + pub signatures: Map, } pub type ModuleName = Vec; diff --git a/src/runtime/sig_registry.rs b/src/runtime/sig_registry.rs index cf9256ab1..949d2547e 100644 --- a/src/runtime/sig_registry.rs +++ b/src/runtime/sig_registry.rs @@ -1,5 +1,32 @@ +use hashbrown::HashMap; +use crate::runtime::{ + types::{Map, SigIndex, FuncSig}, + vm, +}; -pub struct SignatureRegistry { - +pub struct SigRegistry { + sig_set: HashMap, + signatures: Map, +} + +impl SigRegistry { + pub fn new() -> Self { + Self { + sig_set: HashMap::new(), + signatures: Map::new(), + } + } + + pub fn into_vm_signatures(&self) -> *const vm::SigId { + self.signatures.as_ptr() + } + + pub fn register(&mut self, signature: FuncSig, sig_index: SigIndex) { + let index = self.sig_set.len(); + let vm_sig_id = *self.sig_set.entry(signature).or_insert_with(|| { + vm::SigId(index as u32) + }); + self.signatures.push(vm_sig_id); + } } \ No newline at end of file diff --git a/src/runtime/table.rs b/src/runtime/table.rs index 3c72290ab..10c237a6b 100644 --- a/src/runtime/table.rs +++ b/src/runtime/table.rs @@ -1,7 +1,7 @@ use super::vm; use crate::runtime::types::{ElementType, Table}; -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] enum TableElements { /// This is intended to be a caller-checked Anyfunc. Anyfunc(Box<[vm::Anyfunc]>), @@ -18,7 +18,7 @@ impl TableBacking { match table.ty { ElementType::Anyfunc => { Self { - elements: TableElements::Anyfunc(vec![vm::Anyfunc::null(); table.min].into_boxed_slice()), + elements: TableElements::Anyfunc(vec![vm::Anyfunc::null(); table.min as usize].into_boxed_slice()), max: table.max, } } diff --git a/src/runtime/types.rs b/src/runtime/types.rs index 9fe58bd2a..0c31485ae 100644 --- a/src/runtime/types.rs +++ b/src/runtime/types.rs @@ -1,7 +1,10 @@ use std::marker::PhantomData; -use std::{slice, iter}; +use std::{ + slice, iter, + ops::{Index, IndexMut}, +}; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Type { /// The `i32` type. I32, @@ -38,25 +41,25 @@ impl Val { impl From for Val { fn from(n: i32) -> Self { - Self::I32(n) + Val::I32(n) } } impl From for Val { fn from(n: i64) -> Self { - Self::I64(n) + Val::I64(n) } } impl From for Val { fn from(n: f32) -> Self { - Self::F32(n.to_bits()) + Val::F32(n.to_bits()) } } impl From for Val { fn from(n: f64) -> Self { - Self::I64(n.to_bits()) + Val::F64(n.to_bits()) } } @@ -116,7 +119,7 @@ impl Memory { } /// A wasm func. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct FuncSig { pub params: Vec, pub returns: Vec, @@ -137,7 +140,10 @@ where _marker: PhantomData, } -impl Map { +impl Map +where + I: MapIndex, +{ pub fn new() -> Self { Self { elems: Vec::new(), @@ -165,6 +171,10 @@ impl Map { self.elems.push(value); I::new(len) } + + pub fn as_ptr(&self) -> *const T { + self.elems.as_ptr() + } } impl Index for Map @@ -206,13 +216,13 @@ where type IntoIter = IterMut<'a, T, I>; fn into_iter(self) -> Self::IntoIter { - Iter::new(self.elems.iter_mut()) + IterMut::new(self.elems.iter_mut()) } } pub struct Iter<'a, T: 'a, I: MapIndex> { - enumerated: iter::Enumerate>, - _marker: PhantomData, + enumerated: iter::Enumerate>, + _marker: PhantomData, } impl<'a, T: 'a, I: MapIndex> Iter<'a, T, I> { @@ -227,18 +237,18 @@ impl<'a, T: 'a, I: MapIndex> Iter<'a, T, I> { impl<'a, T: 'a, I: MapIndex> Iterator for Iter<'a, T, I> { type Item = (I, &'a T); - fn next(&mut self) -> Self::Item { - self.enumerated.next().map(|i, v| (I::new(i), v)) + fn next(&mut self) -> Option { + self.enumerated.next().map(|(i, v)| (I::new(i), v)) } } pub struct IterMut<'a, T: 'a, I: MapIndex> { - enumerated: iter::Enumerate>, - _marker: PhantomData, + enumerated: iter::Enumerate>, + _marker: PhantomData, } impl<'a, T: 'a, I: MapIndex> IterMut<'a, T, I> { - fn new(iter: slice::Iter<'a, T>) -> Self { + fn new(iter: slice::IterMut<'a, T>) -> Self { Self { enumerated: iter.enumerate(), _marker: PhantomData, @@ -249,8 +259,8 @@ impl<'a, T: 'a, I: MapIndex> IterMut<'a, T, I> { impl<'a, T: 'a, I: MapIndex> Iterator for IterMut<'a, T, I> { type Item = (I, &'a mut T); - fn next(&mut self) -> Self::Item { - self.enumerated.next().map(|i, v| (I::new(i), v)) + fn next(&mut self) -> Option { + self.enumerated.next().map(|(i, v)| (I::new(i), v)) } } @@ -268,7 +278,7 @@ macro_rules! define_map_index { } } }; - ($($ty:ident),*) => { + ($($ty:ident,)*) => { $( define_map_index!($ty); )* @@ -277,5 +287,5 @@ macro_rules! define_map_index { define_map_index![ FuncIndex, MemoryIndex, GlobalIndex, TableIndex, - SignatureIndex, + SigIndex, ]; \ No newline at end of file diff --git a/src/runtime/vm.rs b/src/runtime/vm.rs index 56100e183..b622768c2 100644 --- a/src/runtime/vm.rs +++ b/src/runtime/vm.rs @@ -1,15 +1,16 @@ use std::{ptr, mem}; use crate::runtime::{ - types::{ - MemoryIndex, TableIndex, GlobalIndex, FuncIndex, - SignatureIndex, - }, + // types::{ + // MemoryIndex, TableIndex, GlobalIndex, FuncIndex, + // SigIndex, + // }, backing::{LocalBacking, ImportBacking}, + sig_registry::SigRegistry, }; #[derive(Debug)] #[repr(C)] -pub struct Ctx<'a> { +pub struct Ctx { /// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`. pub memories: *mut LocalMemory, @@ -32,14 +33,14 @@ pub struct Ctx<'a> { pub imported_funcs: *mut ImportedFunc, /// Signature identifiers for signature-checked indirect calls. - pub sig_ids: *mut SigId, + pub signatures: *const SigId, } impl Ctx { pub fn new( local_backing: &mut LocalBacking, import_backing: &mut ImportBacking, - sig_ids: *mut SigId, + sig_registry: &SigRegistry, ) -> Self { Self { memories: local_backing.vm_memories.as_mut_ptr(), @@ -48,9 +49,10 @@ impl Ctx { imported_memories: import_backing.memories.as_mut_ptr(), imported_tables: import_backing.tables.as_mut_ptr(), + imported_globals: import_backing.globals.as_mut_ptr(), imported_funcs: import_backing.functions.as_mut_ptr(), - - sig_ids, + + signatures: sig_registry.into_vm_signatures(), } } @@ -82,7 +84,7 @@ impl Ctx { 6 * (mem::size_of::() as u8) } - pub fn offset_sig_ids() -> u8 { + pub fn offset_signatures() -> u8 { 7 * (mem::size_of::() as u8) } } @@ -210,7 +212,7 @@ impl ImportedGlobal { #[derive(Debug, Clone)] #[repr(transparent)] -pub struct SigId(u32); +pub struct SigId(pub u32); /// Caller-checked anyfunc #[derive(Debug, Clone)] @@ -225,7 +227,6 @@ impl Anyfunc { Self { func_data: ImportedFunc { func: ptr::null(), - vmctx: ptr::null_mut(), }, sig_id: SigId(u32::max_value()), } @@ -235,9 +236,9 @@ impl Anyfunc { 0 * (mem::size_of::() as u8) } - pub fn offset_vmctx() -> u8 { - 1 * (mem::size_of::() as u8) - } + // pub fn offset_vmctx() -> u8 { + // 1 * (mem::size_of::() as u8) + // } pub fn offset_sig_id() -> u8 { 2 * (mem::size_of::() as u8) @@ -296,8 +297,8 @@ mod vm_offset_tests { ); assert_eq!( - Ctx::offset_sig_ids() as usize, - offset_of!(Ctx => sig_ids).get_byte_offset(), + Ctx::offset_signatures() as usize, + offset_of!(Ctx => signatures).get_byte_offset(), ); } @@ -384,10 +385,10 @@ mod vm_offset_tests { offset_of!(Anyfunc => func_data: ImportedFunc => func).get_byte_offset(), ); - assert_eq!( - Anyfunc::offset_vmctx() as usize, - offset_of!(Anyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(), - ); + // assert_eq!( + // Anyfunc::offset_vmctx() as usize, + // offset_of!(Anyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(), + // ); assert_eq!( Anyfunc::offset_sig_id() as usize,