mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-28 08:01:33 +00:00
More backing work
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
182
src/webassembly/backing.rs
Normal 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]>,
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
54
src/webassembly/table.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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)]
|
||||
impl LocalGlobal {
|
||||
pub fn offset_data() -> u8 {
|
||||
0 * (mem::size_of::<usize>() 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::<usize>() 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_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(),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user