From 5b920b7953872817e71c9b6aad7b1c20910caaa6 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Tue, 18 Dec 2018 20:28:15 -0500 Subject: [PATCH] More backing work --- Cargo.lock | 7 + Cargo.toml | 1 + src/lib.rs | 2 + src/webassembly/backing.rs | 182 ++++++++++++++++++++ src/webassembly/instance.rs | 139 ++------------- src/webassembly/memory.rs | 8 + src/webassembly/mod.rs | 2 + src/webassembly/module.rs | 2 +- src/webassembly/table.rs | 54 ++++++ src/webassembly/vm.rs | 333 +++++++++++++++++++++++++++++------- 10 files changed, 542 insertions(+), 188 deletions(-) create mode 100644 src/webassembly/backing.rs create mode 100644 src/webassembly/table.rs diff --git a/Cargo.lock b/Cargo.lock index 547737a60ee..1ead438a676 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,6 +300,11 @@ dependencies = [ "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "field-offset" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -888,6 +893,7 @@ dependencies = [ "docopt 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.44 (git+https://github.com/rust-lang/libc)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -967,6 +973,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7" "checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596" +"checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" diff --git a/Cargo.toml b/Cargo.toml index 2a61b1524d0..53f25180065 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ rayon = "1.0.3" byteorder = "1" indicatif = "0.10" console = "0.7.1" +field-offset = "0.1.1" [build-dependencies] wabt = "0.7.2" diff --git a/src/lib.rs b/src/lib.rs index 2d5809a6e63..0649128382a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,8 @@ pub extern crate nix; // re-exported for usage in macros extern crate rayon; #[cfg(windows)] extern crate winapi; +#[cfg_attr(test, macro_use)] +extern crate field_offset; #[macro_use] mod macros; diff --git a/src/webassembly/backing.rs b/src/webassembly/backing.rs new file mode 100644 index 00000000000..8082a538f1a --- /dev/null +++ b/src/webassembly/backing.rs @@ -0,0 +1,182 @@ +use super::vm; +use super::module::Module; +use super::table::{TableBacking, TableScheme}; +use super::memory::LinearMemory; +use super::instance::{InstanceOptions, InstanceABI}; +use super::ImportObject; +use cranelift_entity::EntityRef; + +#[derive(Debug)] +pub struct Backing { + memories: Box<[LinearMemory]>, + tables: Box<[TableBacking]>, + + vm_memories: Box<[vm::LocalMemory]>, + vm_tables: Box<[vm::LocalTable]>, + vm_globals: Box<[vm::LocalGlobal]>, +} + +impl Backing { + pub fn new(module: &Module, options: &InstanceOptions, imports: &ImportObject) -> Self { + let memories = Backing::generate_memories(module, options); + let tables = Backing::generate_tables(module, options); + + Backing { + memories, + tables, + + vm_memories: Backing::finalize_memories(module, &memories, options), + vm_tables: Backing::finalize_tables(module, &tables, options, imports), + vm_globals: Backing::generate_globals(module), + } + } + + fn generate_memories(module: &Module, options: &InstanceOptions) -> Box<[LinearMemory]> { + let memories = Vec::with_capacity(module.info.memories.len()); + + for mem in &module.info.memories { + let memory = mem.entity; + // If we use emscripten, we set a fixed initial and maximum + debug!( + "Instance - init memory ({}, {:?})", + memory.minimum, memory.maximum + ); + let memory = if options.abi == InstanceABI::Emscripten { + // We use MAX_PAGES, so at the end the result is: + // (initial * LinearMemory::PAGE_SIZE) == LinearMemory::DEFAULT_HEAP_SIZE + // However, it should be: (initial * LinearMemory::PAGE_SIZE) == 16777216 + LinearMemory::new(LinearMemory::MAX_PAGES, None) + } else { + LinearMemory::new(memory.minimum, memory.maximum.map(|m| m as u32)) + }; + memories.push(memory); + } + + memories.into_boxed_slice() + } + + fn finalize_memories(module: &Module, memories: &[LinearMemory], options: &InstanceOptions) -> Box<[vm::LocalMemory]> { + for init in &module.info.data_initializers { + debug_assert!(init.base.is_none(), "globalvar base not supported yet"); + let offset = init.offset; + let mem: &mut LinearMemory = &mut memories[init.memory_index.index()]; + let end_of_init = offset + init.data.len(); + if end_of_init > mem.current_size() { + let grow_pages = (end_of_init / LinearMemory::PAGE_SIZE as usize) + 1; + mem.grow(grow_pages as u32) + .expect("failed to grow memory for data initializers"); + } + let to_init = &mut mem[offset..offset + init.data.len()]; + to_init.copy_from_slice(&init.data); + } + + if options.abi == InstanceABI::Emscripten { + debug!("emscripten::setup memory"); + crate::apis::emscripten::emscripten_set_up_memory(&mut memories[0]); + debug!("emscripten::finish setup memory"); + } + + memories.iter().map(|mem| mem.into_vm_memory()).collect::>().into_boxed_slice() + } + + fn generate_tables(module: &Module, options: &InstanceOptions) -> Box<[TableBacking]> { + let mut tables = Vec::with_capacity(module.info.tables.len()); + + for table in &module.info.tables { + let scheme = TableScheme::from_table(table.entity); + let table_backing = TableBacking::new(&scheme); + tables.push(table_backing); + } + + tables.into_boxed_slice() + } + + fn finalize_tables(module: &Module, tables: &[TableBacking], options: &InstanceOptions, imports: &ImportObject) -> Box<[vm::LocalTable]> { + tables.iter().map(|table| table.into_vm_table()).collect::>().into_boxed_slice() + } + + fn generate_globals(module: &Module) -> Box<[vm::LocalGlobal]> { + let mut globals = Vec::with_capacity(module.info.globals.len()); + + for global in module.info.globals.iter().map(|mem| mem.entity) { + + } + + globals.into_boxed_slice() + } + + // fn generate_tables(module: &Module, _options: &InstanceOptions) -> (Box<[TableBacking]>, Box<[vm::LocalTable]>) { + // let mut tables = Vec::new(); + // // Reserve space for tables + // tables.reserve_exact(module.info.tables.len()); + + // // Get tables in module + // for table in &module.info.tables { + // let table: Vec = match table.import_name.as_ref() { + // Some((module_name, field_name)) => { + // let imported = + // import_object.get(&module_name.as_str(), &field_name.as_str()); + // match imported { + // Some(ImportValue::Table(t)) => t.to_vec(), + // None => { + // if options.mock_missing_tables { + // debug!( + // "The Imported table {}.{} is not provided, therefore will be mocked.", + // module_name, field_name + // ); + // let len = table.entity.minimum as usize; + // let mut v = Vec::with_capacity(len); + // v.resize(len, 0); + // v + // } else { + // panic!( + // "Imported table value was not provided ({}.{})", + // module_name, field_name + // ) + // } + // } + // _ => panic!( + // "Expected global table, but received {:?} ({}.{})", + // imported, module_name, field_name + // ), + // } + // } + // None => { + // let len = table.entity.minimum as usize; + // let mut v = Vec::with_capacity(len); + // v.resize(len, 0); + // v + // } + // }; + // tables.push(table); + // } + + // // instantiate tables + // for table_element in &module.info.table_elements { + // let base = match table_element.base { + // Some(global_index) => globals_data[global_index.index()] as usize, + // None => 0, + // }; + + // let table = &mut tables[table_element.table_index.index()]; + // for (i, func_index) in table_element.elements.iter().enumerate() { + // // since the table just contains functions in the MVP + // // we get the address of the specified function indexes + // // to populate the table. + + // // let func_index = *elem_index - module.info.imported_funcs.len() as u32; + // // let func_addr = functions[func_index.index()].as_ptr(); + // let func_addr = get_function_addr(&func_index, &import_functions, &functions); + // table[base + table_element.offset + i] = func_addr as _; + // } + // } + // } +} + +#[derive(Debug)] +pub struct ImportsBacking { + functions: Box<[vm::ImportedFunc]>, + memories: Box<[vm::ImportedMemory]>, + tables: Box<[vm::ImportedTable]>, + globals: Box<[vm::ImportedGlobal]>, +} \ No newline at end of file diff --git a/src/webassembly/instance.rs b/src/webassembly/instance.rs index b7f17e1bcec..ce22443b805 100644 --- a/src/webassembly/instance.rs +++ b/src/webassembly/instance.rs @@ -20,7 +20,6 @@ use std::iter::FromIterator; use std::iter::Iterator; use std::mem::size_of; use std::ptr::write_unaligned; -use std::sync::Arc; use std::{fmt, mem, slice}; use super::super::common::slice::{BoundedSlice, UncheckedSlice}; @@ -30,6 +29,8 @@ use super::libcalls; use super::memory::LinearMemory; use super::module::{Export, ImportableExportable, Module}; use super::relocation::{Reloc, RelocSink, RelocationType}; +use super::vm; +use super::backing::{Backing, ImportsBacking}; type TablesSlice = UncheckedSlice>; // TODO: this should be `type MemoriesSlice = UncheckedSlice>;`, but that crashes for some reason. @@ -98,22 +99,12 @@ pub struct Instance { // C-like pointers to data (heaps, globals, tables) pub data_pointers: DataPointers, - /// WebAssembly table data - // pub tables: Arc>>>, - pub tables: Arc>>, - - /// WebAssembly linear memory data - pub memories: Arc>, - - /// WebAssembly global variable data - pub globals: Vec, - /// Webassembly functions - // functions: Vec, - functions: Vec>, + finalized_funcs: Box<[*const vm::Func]>, - /// Imported functions - import_functions: Vec<*const u8>, + backing: Backing, + + imports: ImportsBacking, /// The module start function pub start_func: Option, @@ -421,114 +412,13 @@ impl Instance { debug!("Instance - Instantiating tables"); // Instantiate tables { - // Reserve space for tables - tables.reserve_exact(module.info.tables.len()); - - // Get tables in module - for table in &module.info.tables { - let table: Vec = match table.import_name.as_ref() { - Some((module_name, field_name)) => { - let imported = - import_object.get(&module_name.as_str(), &field_name.as_str()); - match imported { - Some(ImportValue::Table(t)) => t.to_vec(), - None => { - if options.mock_missing_tables { - debug!( - "The Imported table {}.{} is not provided, therefore will be mocked.", - module_name, field_name - ); - let len = table.entity.minimum as usize; - let mut v = Vec::with_capacity(len); - v.resize(len, 0); - v - } else { - panic!( - "Imported table value was not provided ({}.{})", - module_name, field_name - ) - } - } - _ => panic!( - "Expected global table, but received {:?} ({}.{})", - imported, module_name, field_name - ), - } - } - None => { - let len = table.entity.minimum as usize; - let mut v = Vec::with_capacity(len); - v.resize(len, 0); - v - } - }; - tables.push(table); - } - - // instantiate tables - for table_element in &module.info.table_elements { - let base = match table_element.base { - Some(global_index) => globals_data[global_index.index()] as usize, - None => 0, - }; - - let table = &mut tables[table_element.table_index.index()]; - for (i, func_index) in table_element.elements.iter().enumerate() { - // since the table just contains functions in the MVP - // we get the address of the specified function indexes - // to populate the table. - - // let func_index = *elem_index - module.info.imported_funcs.len() as u32; - // let func_addr = functions[func_index.index()].as_ptr(); - let func_addr = get_function_addr(&func_index, &import_functions, &functions); - table[base + table_element.offset + i] = func_addr as _; - } - } + } debug!("Instance - Instantiating memories"); // Instantiate memories { - // Reserve space for memories - memories.reserve_exact(module.info.memories.len()); - - // Get memories in module - for memory in &module.info.memories { - let memory = memory.entity; - // If we use emscripten, we set a fixed initial and maximum - debug!( - "Instance - init memory ({}, {:?})", - memory.minimum, memory.maximum - ); - let memory = if options.abi == InstanceABI::Emscripten { - // We use MAX_PAGES, so at the end the result is: - // (initial * LinearMemory::PAGE_SIZE) == LinearMemory::DEFAULT_HEAP_SIZE - // However, it should be: (initial * LinearMemory::PAGE_SIZE) == 16777216 - LinearMemory::new(LinearMemory::MAX_PAGES, None) - } else { - LinearMemory::new(memory.minimum, memory.maximum.map(|m| m as u32)) - }; - memories.push(memory); - } - - for init in &module.info.data_initializers { - debug_assert!(init.base.is_none(), "globalvar base not supported yet"); - let offset = init.offset; - let mem = &mut memories[init.memory_index.index()]; - let end_of_init = offset + init.data.len(); - if end_of_init > mem.current_size() { - let grow_pages = (end_of_init / LinearMemory::PAGE_SIZE as usize) + 1; - mem.grow(grow_pages as u32) - .expect("failed to grow memory for data initializers"); - } - let to_init = &mut mem[offset..offset + init.data.len()]; - to_init.copy_from_slice(&init.data); - } - if options.abi == InstanceABI::Emscripten { - debug!("emscripten::setup memory"); - crate::apis::emscripten::emscripten_set_up_memory(&mut memories[0]); - debug!("emscripten::finish setup memory"); - } + } let start_func: Option = @@ -615,8 +505,8 @@ impl Instance { Ok(Instance { data_pointers, - tables: Arc::new(tables.into_iter().collect()), // tables.into_iter().map(|table| RwLock::new(table)).collect()), - memories: Arc::new(memories.into_iter().collect()), + tables: tables.into_iter().collect(), + memories: memories.into_iter().collect(), globals, functions, import_functions, @@ -626,18 +516,11 @@ impl Instance { } pub fn memory_mut(&mut self, memory_index: usize) -> &mut LinearMemory { - let memories = Arc::get_mut(&mut self.memories).unwrap_or_else(|| { - panic!("Can't get memories as a mutable pointer (there might exist more mutable pointers to the memories)") - }); - memories + self.memories .get_mut(memory_index) .unwrap_or_else(|| panic!("no memory for index {}", memory_index)) } - pub fn memories(&self) -> Arc> { - self.memories.clone() - } - pub fn get_function_pointer(&self, func_index: FuncIndex) -> *const u8 { get_function_addr(&func_index, &self.import_functions, &self.functions) } diff --git a/src/webassembly/memory.rs b/src/webassembly/memory.rs index cc69a66f2bf..207dd9953ad 100644 --- a/src/webassembly/memory.rs +++ b/src/webassembly/memory.rs @@ -8,6 +8,7 @@ use std::ops::{Deref, DerefMut}; use std::slice; use crate::common::mmap::Mmap; +use super::vm::LocalMemory; /// A linear memory instance. #[derive(Debug)] @@ -104,6 +105,13 @@ impl LinearMemory { self.maximum.unwrap_or(Self::MAX_PAGES) } + pub fn into_vm_memory(&mut self) -> LocalMemory { + LocalMemory { + base: self.base(), + size: self.current_size(), + } + } + /// Grow memory by the specified amount of pages. /// /// Returns `None` if memory can't be grown by the specified amount diff --git a/src/webassembly/mod.rs b/src/webassembly/mod.rs index ca405d8f467..4036628c886 100644 --- a/src/webassembly/mod.rs +++ b/src/webassembly/mod.rs @@ -7,6 +7,8 @@ pub mod module; pub mod relocation; pub mod utils; pub mod vm; +pub mod table; +pub mod backing; use cranelift_codegen::{ isa, diff --git a/src/webassembly/module.rs b/src/webassembly/module.rs index e5c4b69e20c..84440a13713 100644 --- a/src/webassembly/module.rs +++ b/src/webassembly/module.rs @@ -199,7 +199,7 @@ pub struct DataInitializer { #[derive(Clone, Debug)] pub enum TableElement { /// A element that, if called, produces a trap. - Trap(), + Trap, /// A function. Function(FuncIndex), } diff --git a/src/webassembly/table.rs b/src/webassembly/table.rs new file mode 100644 index 00000000000..f56cbab0b70 --- /dev/null +++ b/src/webassembly/table.rs @@ -0,0 +1,54 @@ +use super::vm::{CCAnyfunc, LocalTable}; +use cranelift_wasm::{ + Table as ClifTable, + TableElementType, +}; + +pub struct TableScheme { + table: ClifTable, + info: TableInfo, +} + +impl TableScheme { + pub fn from_table(table: ClifTable) -> Self { + Self { + table, + info: match table.ty { + TableElementType::Func => TableInfo::CallerChecks, + TableElementType::Val(_) => unimplemented!(), + }, + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum TableInfo { + CallerChecks, +} + +#[derive(Debug)] +pub struct TableBacking { + pub elements: Box<[CCAnyfunc]>, + pub max: Option, +} + +impl TableBacking { + pub fn new(scheme: &TableScheme) -> Self { + match (scheme.table.ty, scheme.info) { + (TableElementType::Func, TableInfo::CallerChecks) => { + TableBacking { + elements: vec![CCAnyfunc::null(); scheme.table.minimum as usize].into(), + max: scheme.table.maximum, + } + }, + (TableElementType::Val(_), _) => unimplemented!(), + } + } + + pub fn into_vm_table(&mut self) -> LocalTable { + LocalTable { + base: self.elements.as_mut_ptr() as *mut u8, + current_elements: self.elements.len(), + } + } +} \ No newline at end of file diff --git a/src/webassembly/vm.rs b/src/webassembly/vm.rs index fc2bcf132d6..1f25c103c55 100644 --- a/src/webassembly/vm.rs +++ b/src/webassembly/vm.rs @@ -1,4 +1,4 @@ - +use std::{ptr, mem}; use crate::common::slice::IndexedSlice; use cranelift_wasm::{ TableIndex, MemoryIndex, GlobalIndex, FuncIndex, @@ -6,41 +6,87 @@ use cranelift_wasm::{ SignatureIndex, }; +#[derive(Debug)] #[repr(C)] pub struct VmCtx { - /// A pointer to an array of locally-defined tables, indexed by `DefinedTableIndex`. - tables: IndexedSlice, - /// A pointer to an array of locally-defined memories, indexed by `DefinedMemoryIndex`. - memories: IndexedSlice, + pub(in crate::webassembly) memories: IndexedSlice, + + /// A pointer to an array of locally-defined tables, indexed by `DefinedTableIndex`. + pub(in crate::webassembly) tables: IndexedSlice, /// A pointer to an array of locally-defined globals, indexed by `DefinedGlobalIndex`. - globals: IndexedSlice, + pub(in crate::webassembly) globals: IndexedSlice, - /// A pointer to an array of imported functions, indexed by `FuncIndex`. - imported_funcs: IndexedSlice, + /// A pointer to an array of imported memories, indexed by `MemoryIndex, + pub(in crate::webassembly) imported_memories: IndexedSlice, /// A pointer to an array of imported tables, indexed by `TableIndex`. - imported_tables: IndexedSlice, - - /// A pointer to an array of imported memories, indexed by `MemoryIndex, - imported_memories: IndexedSlice, + pub(in crate::webassembly) imported_tables: IndexedSlice, /// A pointer to an array of imported globals, indexed by `GlobalIndex`. - imported_globals: IndexedSlice, + pub(in crate::webassembly) imported_globals: IndexedSlice, + + /// A pointer to an array of imported functions, indexed by `FuncIndex`. + pub(in crate::webassembly) imported_funcs: IndexedSlice, /// Signature identifiers for signature-checked indirect calls. - signature_ids: IndexedSlice, + pub(in crate::webassembly) sig_ids: IndexedSlice, } -#[derive(Copy, Clone)] -pub struct Offsets { - ptr_size: u8, -} +impl VmCtx { + pub fn new( + memories: *mut LocalMemory, + tables: *mut LocalTable, + globals: *mut LocalGlobal, + imported_memories: *mut ImportedMemory, + imported_tables: *mut ImportedTable, + imported_globals: *mut ImportedGlobal, + imported_funcs: *mut ImportedFunc, + sig_ids: *mut SigId, + ) -> Self { + Self { + memories: IndexedSlice::new(memories), + tables: IndexedSlice::new(tables), + globals: IndexedSlice::new(globals), + imported_memories: IndexedSlice::new(imported_memories), + imported_tables: IndexedSlice::new(imported_tables), + imported_globals: IndexedSlice::new(imported_globals), + imported_funcs: IndexedSlice::new(imported_funcs), + sig_ids: IndexedSlice::new(sig_ids), + } + } + + pub fn offset_memories() -> u8 { + 0 * (mem::size_of::() as u8) + } -impl Offsets { - pub fn new(ptr_size: u8) -> Self { - Self { ptr_size } + pub fn offset_tables() -> u8 { + 1 * (mem::size_of::() as u8) + } + + pub fn offset_globals() -> u8 { + 2 * (mem::size_of::() as u8) + } + + pub fn offset_imported_memories() -> u8 { + 3 * (mem::size_of::() as u8) + } + + pub fn offset_imported_tables() -> u8 { + 4 * (mem::size_of::() as u8) + } + + pub fn offset_imported_globals() -> u8 { + 5 * (mem::size_of::() as u8) + } + + pub fn offset_imported_funcs() -> u8 { + 6 * (mem::size_of::() as u8) + } + + pub fn offset_sig_ids() -> u8 { + 7 * (mem::size_of::() as u8) } } @@ -50,7 +96,7 @@ impl Offsets { pub enum Func {} /// An imported function, which contains the vmctx that owns this function. -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct ImportedFunc { pub func: *const Func, @@ -58,17 +104,17 @@ pub struct ImportedFunc { } impl ImportedFunc { - pub fn offset_func(offsets: &Offsets) -> u8 { - 0 * offsets.ptr_size + pub fn offset_func() -> u8 { + 0 * (mem::size_of::() as u8) } - pub fn offset_vmctx(offsets: &Offsets) -> u8 { - 1 * offsets.ptr_size + pub fn offset_vmctx() -> u8 { + 1 * (mem::size_of::() as u8) } } /// Definition of a table used by the VM. (obviously) -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct LocalTable { /// pointer to the elements in the table. @@ -78,16 +124,16 @@ pub struct LocalTable { } impl LocalTable { - pub fn offset_base(offsets: &Offsets) -> u8 { - 0 * offsets.ptr_size + pub fn offset_base() -> u8 { + 0 * (mem::size_of::() as u8) } - pub fn offset_current_elements(offsets: &Offsets) -> u8 { - 1 * offsets.ptr_size + pub fn offset_current_elements() -> u8 { + 1 * (mem::size_of::() as u8) } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct ImportedTable { /// A pointer to the table definition. @@ -97,17 +143,17 @@ pub struct ImportedTable { } impl ImportedTable { - pub fn offset_table(offsets: &Offsets) -> u8 { - 0 * offsets.ptr_size + pub fn offset_table() -> u8 { + 0 * (mem::size_of::() as u8) } - pub fn offset_vmctx(offsets: &Offsets) -> u8 { - 1 * offsets.ptr_size + pub fn offset_vmctx() -> u8 { + 1 * (mem::size_of::() as u8) } } /// Definition of a memory used by the VM. -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct LocalMemory { /// Pointer to the bottom of linear memory. @@ -117,16 +163,16 @@ pub struct LocalMemory { } impl LocalMemory { - pub fn offset_base(offsets: &Offsets) -> u8 { - 0 * offsets.ptr_size + pub fn offset_base() -> u8 { + 0 * (mem::size_of::() as u8) } - pub fn offset_size(offsets: &Offsets) -> u8 { - 1 * offsets.ptr_size + pub fn offset_size() -> u8 { + 1 * (mem::size_of::() as u8) } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct ImportedMemory { /// A pointer to the memory definition. @@ -134,51 +180,220 @@ pub struct ImportedMemory { } impl ImportedMemory { - pub fn offset_memory(offsets: &Offsets) -> u8 { - 0 * offsets.ptr_size + pub fn offset_memory() -> u8 { + 0 * (mem::size_of::() as u8) } } /// Definition of a global used by the VM. -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct LocalGlobal { pub data: [u8; 8], } -#[derive(Debug)] +impl LocalGlobal { + pub fn offset_data() -> u8 { + 0 * (mem::size_of::() as u8) + } +} + +#[derive(Debug, Clone)] #[repr(C)] pub struct ImportedGlobal { - pub globals: *mut LocalGlobal, + pub global: *mut LocalGlobal, } impl ImportedGlobal { - pub fn offset_globals(offsets: &Offsets) -> u8 { - 0 * offsets.ptr_size + pub fn offset_global() -> u8 { + 0 * (mem::size_of::() as u8) } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(transparent)] pub struct SigId(u32); -#[derive(Debug)] +/// Caller-checked anyfunc +#[derive(Debug, Clone)] #[repr(C)] -pub struct CallerVerifiedAnyFunc { +pub struct CCAnyfunc { pub func_data: ImportedFunc, pub sig_id: SigId, } -impl CallerVerifiedAnyFunc { - pub fn offset_func(offsets: &Offsets) -> u8 { - 0 * offsets.ptr_size +impl CCAnyfunc { + pub fn null() -> Self { + Self { + func_data: ImportedFunc { + func: ptr::null(), + vmctx: ptr::null_mut(), + }, + sig_id: SigId(u32::max_value()), + } + } + + pub fn offset_func() -> u8 { + 0 * (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) + } +} + +#[cfg(test)] +mod vm_offset_tests { + use super::{ + VmCtx, + ImportedFunc, + LocalTable, + ImportedTable, + LocalMemory, + ImportedMemory, + LocalGlobal, + ImportedGlobal, + CCAnyfunc, + }; + + #[test] + fn vmctx() { + assert_eq!( + VmCtx::offset_memories() as usize, + offset_of!(VmCtx => memories).get_byte_offset(), + ); + + assert_eq!( + VmCtx::offset_tables() as usize, + offset_of!(VmCtx => tables).get_byte_offset(), + ); + + assert_eq!( + VmCtx::offset_globals() as usize, + offset_of!(VmCtx => globals).get_byte_offset(), + ); + + assert_eq!( + VmCtx::offset_imported_memories() as usize, + offset_of!(VmCtx => imported_memories).get_byte_offset(), + ); + + assert_eq!( + VmCtx::offset_imported_tables() as usize, + offset_of!(VmCtx => imported_tables).get_byte_offset(), + ); + + assert_eq!( + VmCtx::offset_imported_globals() as usize, + offset_of!(VmCtx => imported_globals).get_byte_offset(), + ); + + assert_eq!( + VmCtx::offset_imported_funcs() as usize, + offset_of!(VmCtx => imported_funcs).get_byte_offset(), + ); + + assert_eq!( + VmCtx::offset_sig_ids() as usize, + offset_of!(VmCtx => sig_ids).get_byte_offset(), + ); + } + + #[test] + fn imported_func() { + assert_eq!( + ImportedFunc::offset_func() as usize, + offset_of!(ImportedFunc => func).get_byte_offset(), + ); + + assert_eq!( + ImportedFunc::offset_vmctx() as usize, + offset_of!(ImportedFunc => vmctx).get_byte_offset(), + ); + } + + #[test] + fn local_table() { + assert_eq!( + LocalTable::offset_base() as usize, + offset_of!(LocalTable => base).get_byte_offset(), + ); + + 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(), + ); + } + + #[test] + fn local_memory() { + assert_eq!( + LocalMemory::offset_base() as usize, + offset_of!(LocalMemory => base).get_byte_offset(), + ); + + assert_eq!( + LocalMemory::offset_size() as usize, + offset_of!(LocalMemory => size).get_byte_offset(), + ); + } + + #[test] + fn imported_memory() { + assert_eq!( + ImportedMemory::offset_memory() as usize, + offset_of!(ImportedMemory => memory).get_byte_offset(), + ); + } + + #[test] + fn local_global() { + assert_eq!( + LocalGlobal::offset_data() as usize, + offset_of!(LocalGlobal => data).get_byte_offset(), + ); } - pub fn offset_vmctx(offsets: &Offsets) -> u8 { - 1 * offsets.ptr_size + #[test] + fn imported_global() { + assert_eq!( + ImportedGlobal::offset_global() as usize, + offset_of!(ImportedGlobal => global).get_byte_offset(), + ); } - pub fn offset_sig_id(offsets: &Offsets) -> u8 { - 2 * offsets.ptr_size + #[test] + fn cc_anyfunc() { + assert_eq!( + CCAnyfunc::offset_func() as usize, + offset_of!(CCAnyfunc => func_data: ImportedFunc => func).get_byte_offset(), + ); + + assert_eq!( + CCAnyfunc::offset_vmctx() as usize, + offset_of!(CCAnyfunc => func_data: ImportedFunc => vmctx).get_byte_offset(), + ); + + assert_eq!( + CCAnyfunc::offset_sig_id() as usize, + offset_of!(CCAnyfunc => sig_id).get_byte_offset(), + ); } } \ No newline at end of file