More backing work

This commit is contained in:
Lachlan Sneff
2018-12-18 20:28:15 -05:00
parent e4dab88efd
commit 5b920b7953
10 changed files with 548 additions and 194 deletions

7
Cargo.lock generated
View File

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

View File

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

View File

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

182
src/webassembly/backing.rs Normal file
View File

@ -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::<Vec<_>>().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::<Vec<_>>().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<usize> = 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]>,
}

View File

@ -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<BoundedSlice<usize>>;
// TODO: this should be `type MemoriesSlice = UncheckedSlice<UncheckedSlice<u8>>;`, 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<Vec<RwLock<Vec<usize>>>>,
pub tables: Arc<Vec<Vec<usize>>>,
/// WebAssembly linear memory data
pub memories: Arc<Vec<LinearMemory>>,
/// WebAssembly global variable data
pub globals: Vec<u8>,
/// Webassembly functions
// functions: Vec<usize>,
functions: Vec<Vec<u8>>,
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<FuncIndex>,
@ -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<usize> = 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<FuncIndex> =
@ -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<Vec<LinearMemory>> {
self.memories.clone()
}
pub fn get_function_pointer(&self, func_index: FuncIndex) -> *const u8 {
get_function_addr(&func_index, &self.import_functions, &self.functions)
}

View File

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

View File

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

View File

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

54
src/webassembly/table.rs Normal file
View File

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

View File

@ -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<LocalTable, DefinedTableIndex>,
/// A pointer to an array of locally-defined memories, indexed by `DefinedMemoryIndex`.
memories: IndexedSlice<LocalMemory, DefinedMemoryIndex>,
pub(in crate::webassembly) memories: IndexedSlice<LocalMemory, DefinedMemoryIndex>,
/// A pointer to an array of locally-defined tables, indexed by `DefinedTableIndex`.
pub(in crate::webassembly) tables: IndexedSlice<LocalTable, DefinedTableIndex>,
/// A pointer to an array of locally-defined globals, indexed by `DefinedGlobalIndex`.
globals: IndexedSlice<LocalGlobal, DefinedGlobalIndex>,
/// A pointer to an array of imported functions, indexed by `FuncIndex`.
imported_funcs: IndexedSlice<ImportedFunc, FuncIndex>,
/// A pointer to an array of imported tables, indexed by `TableIndex`.
imported_tables: IndexedSlice<ImportedTable, TableIndex>,
pub(in crate::webassembly) globals: IndexedSlice<LocalGlobal, DefinedGlobalIndex>,
/// A pointer to an array of imported memories, indexed by `MemoryIndex,
imported_memories: IndexedSlice<ImportedMemory, MemoryIndex>,
pub(in crate::webassembly) imported_memories: IndexedSlice<ImportedMemory, MemoryIndex>,
/// A pointer to an array of imported tables, indexed by `TableIndex`.
pub(in crate::webassembly) imported_tables: IndexedSlice<ImportedTable, TableIndex>,
/// A pointer to an array of imported globals, indexed by `GlobalIndex`.
imported_globals: IndexedSlice<ImportedGlobal, GlobalIndex>,
pub(in crate::webassembly) imported_globals: IndexedSlice<ImportedGlobal, GlobalIndex>,
/// A pointer to an array of imported functions, indexed by `FuncIndex`.
pub(in crate::webassembly) imported_funcs: IndexedSlice<ImportedFunc, FuncIndex>,
/// Signature identifiers for signature-checked indirect calls.
signature_ids: IndexedSlice<SigId, SignatureIndex>,
pub(in crate::webassembly) sig_ids: IndexedSlice<SigId, SignatureIndex>,
}
#[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),
}
}
impl Offsets {
pub fn new(ptr_size: u8) -> Self {
Self { ptr_size }
pub fn offset_memories() -> u8 {
0 * (mem::size_of::<usize>() as u8)
}
pub fn offset_tables() -> u8 {
1 * (mem::size_of::<usize>() as u8)
}
pub fn offset_globals() -> u8 {
2 * (mem::size_of::<usize>() as u8)
}
pub fn offset_imported_memories() -> u8 {
3 * (mem::size_of::<usize>() as u8)
}
pub fn offset_imported_tables() -> u8 {
4 * (mem::size_of::<usize>() as u8)
}
pub fn offset_imported_globals() -> u8 {
5 * (mem::size_of::<usize>() as u8)
}
pub fn offset_imported_funcs() -> u8 {
6 * (mem::size_of::<usize>() as u8)
}
pub fn offset_sig_ids() -> u8 {
7 * (mem::size_of::<usize>() 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::<usize>() as u8)
}
pub fn offset_vmctx(offsets: &Offsets) -> u8 {
1 * offsets.ptr_size
pub fn offset_vmctx() -> u8 {
1 * (mem::size_of::<usize>() 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::<usize>() as u8)
}
pub fn offset_current_elements(offsets: &Offsets) -> u8 {
1 * offsets.ptr_size
pub fn offset_current_elements() -> u8 {
1 * (mem::size_of::<usize>() 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::<usize>() as u8)
}
pub fn offset_vmctx(offsets: &Offsets) -> u8 {
1 * offsets.ptr_size
pub fn offset_vmctx() -> u8 {
1 * (mem::size_of::<usize>() 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::<usize>() as u8)
}
pub fn offset_size(offsets: &Offsets) -> u8 {
1 * offsets.ptr_size
pub fn offset_size() -> u8 {
1 * (mem::size_of::<usize>() 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::<usize>() 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)]
#[repr(C)]
pub struct ImportedGlobal {
pub globals: *mut LocalGlobal,
}
impl ImportedGlobal {
pub fn offset_globals(offsets: &Offsets) -> u8 {
0 * offsets.ptr_size
impl LocalGlobal {
pub fn offset_data() -> u8 {
0 * (mem::size_of::<usize>() as u8)
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
#[repr(C)]
pub struct ImportedGlobal {
pub global: *mut LocalGlobal,
}
impl ImportedGlobal {
pub fn offset_global() -> u8 {
0 * (mem::size_of::<usize>() as u8)
}
}
#[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_vmctx(offsets: &Offsets) -> u8 {
1 * offsets.ptr_size
pub fn offset_func() -> u8 {
0 * (mem::size_of::<usize>() as u8)
}
pub fn offset_sig_id(offsets: &Offsets) -> u8 {
2 * offsets.ptr_size
pub fn offset_vmctx() -> u8 {
1 * (mem::size_of::<usize>() as u8)
}
pub fn offset_sig_id() -> u8 {
2 * (mem::size_of::<usize>() 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(),
);
}
#[test]
fn imported_global() {
assert_eq!(
ImportedGlobal::offset_global() as usize,
offset_of!(ImportedGlobal => global).get_byte_offset(),
);
}
#[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(),
);
}
}