Improve infrastructure.
Do more encapsulation of raw pointers, use more PrimaryMaps instead of Vecs, add a table.rs for managing table storage.
This commit is contained in:
@@ -52,10 +52,10 @@ impl binemit::RelocSink for RelocSink {
|
|||||||
let reloc_target = if let ExternalName::User { namespace, index } = *name {
|
let reloc_target = if let ExternalName::User { namespace, index } = *name {
|
||||||
debug_assert!(namespace == 0);
|
debug_assert!(namespace == 0);
|
||||||
RelocationTarget::UserFunc(FuncIndex::new(index as usize))
|
RelocationTarget::UserFunc(FuncIndex::new(index as usize))
|
||||||
} else if *name == ExternalName::testcase("grow_memory") {
|
} else if *name == ExternalName::testcase("wasmtime_memory_grow") {
|
||||||
RelocationTarget::GrowMemory
|
RelocationTarget::MemoryGrow
|
||||||
} else if *name == ExternalName::testcase("current_memory") {
|
} else if *name == ExternalName::testcase("wasmtime_memory_size") {
|
||||||
RelocationTarget::CurrentMemory
|
RelocationTarget::MemorySize
|
||||||
} else {
|
} else {
|
||||||
panic!("unrecognized external name")
|
panic!("unrecognized external name")
|
||||||
};
|
};
|
||||||
@@ -104,9 +104,9 @@ pub enum RelocationTarget {
|
|||||||
/// The user function index.
|
/// The user function index.
|
||||||
UserFunc(FuncIndex),
|
UserFunc(FuncIndex),
|
||||||
/// Function for growing the default memory by the specified amount of pages.
|
/// Function for growing the default memory by the specified amount of pages.
|
||||||
GrowMemory,
|
MemoryGrow,
|
||||||
/// Function for query current size of the default linear memory.
|
/// Function for query current size of the default linear memory.
|
||||||
CurrentMemory,
|
MemorySize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Relocations to apply to function bodies.
|
/// Relocations to apply to function bodies.
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ pub struct Module {
|
|||||||
pub signatures: PrimaryMap<SignatureIndex, ir::Signature>,
|
pub signatures: PrimaryMap<SignatureIndex, ir::Signature>,
|
||||||
|
|
||||||
/// Names of imported functions.
|
/// Names of imported functions.
|
||||||
pub imported_funcs: Vec<(String, String)>,
|
pub imported_funcs: PrimaryMap<FuncIndex, (String, String)>,
|
||||||
|
|
||||||
/// Types of functions, imported and local.
|
/// Types of functions, imported and local.
|
||||||
pub functions: PrimaryMap<FuncIndex, SignatureIndex>,
|
pub functions: PrimaryMap<FuncIndex, SignatureIndex>,
|
||||||
@@ -127,7 +127,7 @@ impl Module {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
signatures: PrimaryMap::new(),
|
signatures: PrimaryMap::new(),
|
||||||
imported_funcs: Vec::new(),
|
imported_funcs: PrimaryMap::new(),
|
||||||
functions: PrimaryMap::new(),
|
functions: PrimaryMap::new(),
|
||||||
tables: PrimaryMap::new(),
|
tables: PrimaryMap::new(),
|
||||||
memory_plans: PrimaryMap::new(),
|
memory_plans: PrimaryMap::new(),
|
||||||
|
|||||||
@@ -20,15 +20,13 @@ lazy_static = "1.2.0"
|
|||||||
libc = { version = "0.2.44", default-features = false }
|
libc = { version = "0.2.44", default-features = false }
|
||||||
errno = "0.2.4"
|
errno = "0.2.4"
|
||||||
cast = { version = "0.2.2", default-features = false }
|
cast = { version = "0.2.2", default-features = false }
|
||||||
|
memoffset = "0.2.1"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cmake = "0.1.35"
|
cmake = "0.1.35"
|
||||||
bindgen = "0.44.0"
|
bindgen = "0.44.0"
|
||||||
regex = "1.0.6"
|
regex = "1.0.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
memoffset = "0.2.1"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["cranelift-codegen/std", "cranelift-wasm/std"]
|
std = ["cranelift-codegen/std", "cranelift-wasm/std"]
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ use code::Code;
|
|||||||
use cranelift_codegen::binemit::Reloc;
|
use cranelift_codegen::binemit::Reloc;
|
||||||
use cranelift_codegen::isa::TargetIsa;
|
use cranelift_codegen::isa::TargetIsa;
|
||||||
use cranelift_entity::{EntityRef, PrimaryMap};
|
use cranelift_entity::{EntityRef, PrimaryMap};
|
||||||
use cranelift_wasm::{DefinedFuncIndex, MemoryIndex, TableIndex};
|
use cranelift_wasm::{DefinedFuncIndex, MemoryIndex};
|
||||||
use instance::Instance;
|
use instance::Instance;
|
||||||
use invoke::{invoke_by_index, InvokeOutcome};
|
use invoke::{invoke_by_index, InvokeOutcome};
|
||||||
use memory::LinearMemory;
|
|
||||||
use region::protect;
|
use region::protect;
|
||||||
use region::Protection;
|
use region::Protection;
|
||||||
use std::ptr::{self, write_unaligned};
|
use std::ptr::write_unaligned;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
use vmcontext::VMContext;
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
compile_module, Compilation, Module, ModuleTranslation, Relocation, RelocationTarget,
|
compile_module, Compilation, Module, ModuleTranslation, Relocation, RelocationTarget,
|
||||||
};
|
};
|
||||||
@@ -53,7 +53,7 @@ fn relocate<F>(
|
|||||||
RelocationTarget::UserFunc(index) => match module.defined_func_index(index) {
|
RelocationTarget::UserFunc(index) => match module.defined_func_index(index) {
|
||||||
Some(f) => compilation.functions[f].as_ptr() as usize,
|
Some(f) => compilation.functions[f].as_ptr() as usize,
|
||||||
None => {
|
None => {
|
||||||
let func = &module.imported_funcs[index.index()];
|
let func = &module.imported_funcs[index];
|
||||||
match imports(&func.0, &func.1) {
|
match imports(&func.0, &func.1) {
|
||||||
Some(ptr) => ptr,
|
Some(ptr) => ptr,
|
||||||
None => {
|
None => {
|
||||||
@@ -62,8 +62,8 @@ fn relocate<F>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
RelocationTarget::GrowMemory => grow_memory as usize,
|
RelocationTarget::MemoryGrow => wasmtime_memory_grow as usize,
|
||||||
RelocationTarget::CurrentMemory => current_memory as usize,
|
RelocationTarget::MemorySize => wasmtime_memory_size as usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = &mut compilation.functions[i];
|
let body = &mut compilation.functions[i];
|
||||||
@@ -93,52 +93,20 @@ fn relocate<F>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: *mut *mut u8) -> u32 {
|
extern "C" fn wasmtime_memory_grow(size: u32, memory_index: u32, vmctx: *mut VMContext) -> u32 {
|
||||||
unsafe {
|
let instance = unsafe { (&mut *vmctx).instance() };
|
||||||
// FIXME: update the VMMemory's size
|
let memory_index = MemoryIndex::new(memory_index as usize);
|
||||||
let instance = (*vmctx.offset(4)) as *mut Instance;
|
|
||||||
(*instance)
|
instance
|
||||||
.memory_mut(MemoryIndex::new(memory_index as usize))
|
.memory_grow(memory_index, size)
|
||||||
.grow(size)
|
|
||||||
.unwrap_or(u32::max_value())
|
.unwrap_or(u32::max_value())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn current_memory(memory_index: u32, vmctx: *mut *mut u8) -> u32 {
|
extern "C" fn wasmtime_memory_size(memory_index: u32, vmctx: *mut VMContext) -> u32 {
|
||||||
unsafe {
|
let instance = unsafe { (&mut *vmctx).instance() };
|
||||||
// FIXME: read the VMMemory's size instead
|
let memory_index = MemoryIndex::new(memory_index as usize);
|
||||||
let instance = (*vmctx.offset(4)) as *mut Instance;
|
|
||||||
(*instance)
|
|
||||||
.memory_mut(MemoryIndex::new(memory_index as usize))
|
|
||||||
.current_size()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create the VmCtx data structure for the JIT'd code to use. This must
|
instance.memory_size(memory_index)
|
||||||
/// match the VmCtx layout in the environment.
|
|
||||||
fn make_vmctx(instance: &mut Instance) -> Vec<*mut u8> {
|
|
||||||
debug_assert!(
|
|
||||||
instance.tables.len() <= 1,
|
|
||||||
"non-default tables is not supported"
|
|
||||||
);
|
|
||||||
|
|
||||||
let (default_table_ptr, default_table_len) = instance
|
|
||||||
.tables
|
|
||||||
.get_mut(TableIndex::new(0))
|
|
||||||
.map(|table| (table.as_mut_ptr() as *mut u8, table.len()))
|
|
||||||
.unwrap_or((ptr::null_mut(), 0));
|
|
||||||
|
|
||||||
// FIXME: Actually use environ's VMContext struct
|
|
||||||
let mut vmctx = Vec::new();
|
|
||||||
vmctx.push(instance.globals.as_mut_ptr());
|
|
||||||
// FIXME: These need to be VMMemory now
|
|
||||||
vmctx.push(instance.mem_base_addrs.as_mut_ptr() as *mut u8);
|
|
||||||
// FIXME: These need to be VMTable now
|
|
||||||
vmctx.push(default_table_ptr);
|
|
||||||
vmctx.push(default_table_len as *mut u8);
|
|
||||||
vmctx.push(instance as *mut Instance as *mut u8);
|
|
||||||
|
|
||||||
vmctx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// prepares the execution context
|
/// prepares the execution context
|
||||||
@@ -148,7 +116,7 @@ pub fn finish_instantiation(
|
|||||||
module: &Module,
|
module: &Module,
|
||||||
compilation: &Compilation,
|
compilation: &Compilation,
|
||||||
instance: &mut Instance,
|
instance: &mut Instance,
|
||||||
) -> Result<Vec<*mut u8>, String> {
|
) -> Result<(), String> {
|
||||||
// TODO: Put all the function bodies into a page-aligned memory region, and
|
// TODO: Put all the function bodies into a page-aligned memory region, and
|
||||||
// then make them ReadExecute rather than ReadWriteExecute.
|
// then make them ReadExecute rather than ReadWriteExecute.
|
||||||
for code_buf in compilation.functions.values() {
|
for code_buf in compilation.functions.values() {
|
||||||
@@ -169,17 +137,9 @@ pub fn finish_instantiation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect all memory base addresses and Vec.
|
|
||||||
instance.mem_base_addrs = instance
|
|
||||||
.memories
|
|
||||||
.values_mut()
|
|
||||||
.map(LinearMemory::base_addr)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let mut vmctx = make_vmctx(instance);
|
|
||||||
|
|
||||||
if let Some(start_index) = module.start_func {
|
if let Some(start_index) = module.start_func {
|
||||||
let result = invoke_by_index(code, isa, module, compilation, &mut vmctx, start_index, &[])?;
|
let vmctx = instance.vmctx();
|
||||||
|
let result = invoke_by_index(code, isa, module, compilation, vmctx, start_index, &[])?;
|
||||||
match result {
|
match result {
|
||||||
InvokeOutcome::Returned { values } => {
|
InvokeOutcome::Returned { values } => {
|
||||||
assert!(values.is_empty());
|
assert!(values.is_empty());
|
||||||
@@ -190,5 +150,5 @@ pub fn finish_instantiation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(vmctx)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,35 @@
|
|||||||
//! An `Instance` contains all the runtime state used by execution of a wasm
|
//! An `Instance` contains all the runtime state used by execution of a wasm
|
||||||
//! module.
|
//! module.
|
||||||
|
|
||||||
use cranelift_codegen::ir;
|
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
use cranelift_entity::PrimaryMap;
|
use cranelift_entity::PrimaryMap;
|
||||||
use cranelift_wasm::{GlobalIndex, MemoryIndex, TableIndex};
|
use cranelift_wasm::{GlobalIndex, MemoryIndex, TableIndex};
|
||||||
use memory::LinearMemory;
|
use memory::LinearMemory;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::vec::Vec;
|
use table::{AnyFunc, Table};
|
||||||
use wasmtime_environ::{Compilation, DataInitializer, Module, TableElements};
|
use vmcontext::{VMContext, VMGlobal, VMMemory, VMTable};
|
||||||
|
use wasmtime_environ::{Compilation, DataInitializer, Module};
|
||||||
|
|
||||||
/// An Instance of a WebAssemby module.
|
/// An Instance of a WebAssemby module.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
/// WebAssembly table data.
|
|
||||||
pub tables: PrimaryMap<TableIndex, Vec<usize>>,
|
|
||||||
|
|
||||||
/// WebAssembly linear memory data.
|
/// WebAssembly linear memory data.
|
||||||
pub memories: PrimaryMap<MemoryIndex, LinearMemory>,
|
memories: PrimaryMap<MemoryIndex, LinearMemory>,
|
||||||
|
|
||||||
/// WebAssembly global variable data.
|
/// WebAssembly table data.
|
||||||
pub globals: Vec<u8>,
|
tables: PrimaryMap<TableIndex, Table>,
|
||||||
|
|
||||||
/// Memory base address vector pointed to by vmctx.
|
/// Memory base address vector pointed to by vmctx.
|
||||||
pub mem_base_addrs: Vec<*mut u8>,
|
vmctx_memories: PrimaryMap<MemoryIndex, VMMemory>,
|
||||||
|
|
||||||
|
/// WebAssembly global variable data.
|
||||||
|
vmctx_globals: PrimaryMap<GlobalIndex, VMGlobal>,
|
||||||
|
|
||||||
|
/// Table storage base address vector pointed to by vmctx.
|
||||||
|
vmctx_tables: PrimaryMap<TableIndex, VMTable>,
|
||||||
|
|
||||||
|
/// Context pointer used by JIT code.
|
||||||
|
vmctx: VMContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
@@ -33,82 +39,68 @@ impl Instance {
|
|||||||
compilation: &Compilation,
|
compilation: &Compilation,
|
||||||
data_initializers: &[DataInitializer],
|
data_initializers: &[DataInitializer],
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, String> {
|
||||||
let mut result = Self {
|
let mut memories = instantiate_memories(module, data_initializers)?;
|
||||||
tables: PrimaryMap::new(),
|
let mut tables = instantiate_tables(module, compilation);
|
||||||
memories: PrimaryMap::new(),
|
|
||||||
globals: Vec::new(),
|
let mut vmctx_memories = memories
|
||||||
mem_base_addrs: Vec::new(),
|
.values_mut()
|
||||||
};
|
.map(LinearMemory::vmmemory)
|
||||||
result.instantiate_tables(module, compilation, &module.table_elements);
|
.collect::<PrimaryMap<MemoryIndex, _>>();
|
||||||
result.instantiate_memories(module, data_initializers)?;
|
|
||||||
result.instantiate_globals(module);
|
let mut vmctx_globals = instantiate_globals(module);
|
||||||
Ok(result)
|
|
||||||
|
let mut vmctx_tables = tables
|
||||||
|
.values_mut()
|
||||||
|
.map(Table::vmtable)
|
||||||
|
.collect::<PrimaryMap<TableIndex, _>>();
|
||||||
|
|
||||||
|
let vmctx_memories_ptr = vmctx_memories.values_mut().into_slice().as_mut_ptr();
|
||||||
|
let vmctx_globals_ptr = vmctx_globals.values_mut().into_slice().as_mut_ptr();
|
||||||
|
let vmctx_tables_ptr = vmctx_tables.values_mut().into_slice().as_mut_ptr();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
memories,
|
||||||
|
tables,
|
||||||
|
vmctx_memories,
|
||||||
|
vmctx_globals,
|
||||||
|
vmctx_tables,
|
||||||
|
vmctx: VMContext::new(vmctx_memories_ptr, vmctx_globals_ptr, vmctx_tables_ptr),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate memory in `self` for just the tables of the current module.
|
/// Return the vmctx pointer to be passed into JIT code.
|
||||||
fn instantiate_tables(
|
pub fn vmctx(&mut self) -> *mut VMContext {
|
||||||
&mut self,
|
&mut self.vmctx as *mut VMContext
|
||||||
module: &Module,
|
|
||||||
compilation: &Compilation,
|
|
||||||
table_initializers: &[TableElements],
|
|
||||||
) {
|
|
||||||
debug_assert!(self.tables.is_empty());
|
|
||||||
self.tables.reserve_exact(module.tables.len());
|
|
||||||
for table in module.tables.values() {
|
|
||||||
let len = table.minimum as usize;
|
|
||||||
let mut v = Vec::with_capacity(len);
|
|
||||||
v.resize(len, 0);
|
|
||||||
self.tables.push(v);
|
|
||||||
}
|
|
||||||
for init in table_initializers {
|
|
||||||
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
|
||||||
let to_init =
|
|
||||||
&mut self.tables[init.table_index][init.offset..init.offset + init.elements.len()];
|
|
||||||
for (i, func_idx) in init.elements.iter().enumerate() {
|
|
||||||
let code_buf = &compilation.functions[module.defined_func_index(*func_idx).expect(
|
|
||||||
"table element initializer with imported function not supported yet",
|
|
||||||
)];
|
|
||||||
to_init[i] = code_buf.as_ptr() as usize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate memory in `instance` for just the memories of the current module.
|
/// Return the offset from the vmctx pointer to its containing Instance.
|
||||||
fn instantiate_memories(
|
pub fn vmctx_offset() -> isize {
|
||||||
&mut self,
|
offset_of!(Instance, vmctx) as isize
|
||||||
module: &Module,
|
|
||||||
data_initializers: &[DataInitializer],
|
|
||||||
) -> Result<(), String> {
|
|
||||||
debug_assert!(self.memories.is_empty());
|
|
||||||
// Allocate the underlying memory and initialize it to all zeros.
|
|
||||||
self.memories.reserve_exact(module.memory_plans.len());
|
|
||||||
for plan in module.memory_plans.values() {
|
|
||||||
let v = LinearMemory::new(&plan)?;
|
|
||||||
self.memories.push(v);
|
|
||||||
}
|
|
||||||
for init in data_initializers {
|
|
||||||
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
|
||||||
let mem_mut = self.memories[init.memory_index].as_mut();
|
|
||||||
let to_init = &mut mem_mut[init.offset..init.offset + init.data.len()];
|
|
||||||
to_init.copy_from_slice(init.data);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate memory in `instance` for just the globals of the current module,
|
/// Grow memory by the specified amount of pages.
|
||||||
/// without any initializers applied yet.
|
///
|
||||||
fn instantiate_globals(&mut self, module: &Module) {
|
/// Returns `None` if memory can't be grown by the specified amount
|
||||||
debug_assert!(self.globals.is_empty());
|
/// of pages.
|
||||||
// Allocate the underlying memory and initialize it to all zeros.
|
pub fn memory_grow(&mut self, memory_index: MemoryIndex, delta: u32) -> Option<u32> {
|
||||||
let globals_data_size = module.globals.len() * 8;
|
let result = self
|
||||||
self.globals.resize(globals_data_size, 0);
|
.memories
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a mutable reference to a linear memory under the specified index.
|
|
||||||
pub fn memory_mut(&mut self, memory_index: MemoryIndex) -> &mut LinearMemory {
|
|
||||||
self.memories
|
|
||||||
.get_mut(memory_index)
|
.get_mut(memory_index)
|
||||||
.unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
|
.unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
|
||||||
|
.grow(delta);
|
||||||
|
|
||||||
|
// Keep current the VMContext pointers used by JIT code.
|
||||||
|
self.vmctx_memories[memory_index] = self.memories[memory_index].vmmemory();
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of allocated wasm pages.
|
||||||
|
pub fn memory_size(&mut self, memory_index: MemoryIndex) -> u32 {
|
||||||
|
self.memories
|
||||||
|
.get(memory_index)
|
||||||
|
.unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
|
||||||
|
.size()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a slice of the contents of allocated linear memory.
|
/// Returns a slice of the contents of allocated linear memory.
|
||||||
@@ -121,9 +113,64 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the value of a global variable.
|
/// Shows the value of a global variable.
|
||||||
pub fn inspect_global(&self, global_index: GlobalIndex, ty: ir::Type) -> &[u8] {
|
pub fn inspect_global(&self, global_index: GlobalIndex) -> &VMGlobal {
|
||||||
let offset = global_index.index() * 8;
|
&self.vmctx_globals[global_index]
|
||||||
let len = ty.bytes() as usize;
|
|
||||||
&self.globals[offset..offset + len]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocate memory for just the memories of the current module.
|
||||||
|
fn instantiate_memories(
|
||||||
|
module: &Module,
|
||||||
|
data_initializers: &[DataInitializer],
|
||||||
|
) -> Result<PrimaryMap<MemoryIndex, LinearMemory>, String> {
|
||||||
|
let mut memories = PrimaryMap::with_capacity(module.memory_plans.len());
|
||||||
|
for plan in module.memory_plans.values() {
|
||||||
|
memories.push(LinearMemory::new(&plan)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
for init in data_initializers {
|
||||||
|
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
||||||
|
let mem_mut = memories[init.memory_index].as_mut();
|
||||||
|
let to_init = &mut mem_mut[init.offset..init.offset + init.data.len()];
|
||||||
|
to_init.copy_from_slice(init.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(memories)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate memory for just the tables of the current module.
|
||||||
|
fn instantiate_tables(module: &Module, compilation: &Compilation) -> PrimaryMap<TableIndex, Table> {
|
||||||
|
let mut tables = PrimaryMap::with_capacity(module.tables.len());
|
||||||
|
for table in module.tables.values() {
|
||||||
|
tables.push(Table::new(table));
|
||||||
|
}
|
||||||
|
|
||||||
|
for init in &module.table_elements {
|
||||||
|
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
||||||
|
let slice = &mut tables[init.table_index].as_mut();
|
||||||
|
let subslice = &mut slice[init.offset..init.offset + init.elements.len()];
|
||||||
|
for (i, func_idx) in init.elements.iter().enumerate() {
|
||||||
|
let code_buf = &compilation.functions[module.defined_func_index(*func_idx).expect(
|
||||||
|
"table element initializer with imported function not supported yet",
|
||||||
|
)];
|
||||||
|
subslice[i] = AnyFunc {
|
||||||
|
func_ptr: code_buf.as_ptr(),
|
||||||
|
type_id: 0, // TODO: Implement signature checking.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tables
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate memory for just the globals of the current module,
|
||||||
|
/// without any initializers applied yet.
|
||||||
|
fn instantiate_globals(module: &Module) -> PrimaryMap<GlobalIndex, VMGlobal> {
|
||||||
|
let mut vmctx_globals = PrimaryMap::with_capacity(module.globals.len());
|
||||||
|
|
||||||
|
for _ in 0..module.globals.len() {
|
||||||
|
vmctx_globals.push(VMGlobal::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
vmctx_globals
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use std::ptr;
|
|||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use traphandlers::call_wasm;
|
use traphandlers::call_wasm;
|
||||||
|
use vmcontext::VMContext;
|
||||||
use wasmtime_environ::{Compilation, Export, Module, RelocSink};
|
use wasmtime_environ::{Compilation, Export, Module, RelocSink};
|
||||||
|
|
||||||
/// A runtime value.
|
/// A runtime value.
|
||||||
@@ -91,7 +92,7 @@ pub fn invoke(
|
|||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
compilation: &Compilation,
|
compilation: &Compilation,
|
||||||
vmctx: &mut Vec<*mut u8>,
|
vmctx: *mut VMContext,
|
||||||
function: &str,
|
function: &str,
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
) -> Result<InvokeOutcome, String> {
|
) -> Result<InvokeOutcome, String> {
|
||||||
@@ -109,7 +110,7 @@ pub fn invoke_by_index(
|
|||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
compilation: &Compilation,
|
compilation: &Compilation,
|
||||||
vmctx: &mut Vec<*mut u8>,
|
vmctx: *mut VMContext,
|
||||||
fn_index: FuncIndex,
|
fn_index: FuncIndex,
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
) -> Result<InvokeOutcome, String> {
|
) -> Result<InvokeOutcome, String> {
|
||||||
@@ -138,21 +139,14 @@ pub fn invoke_by_index(
|
|||||||
return Err("failed to install signal handlers".to_string());
|
return Err("failed to install signal handlers".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
call_through_wrapper(
|
call_through_wrapper(code, isa, exec_code_buf as usize, vmctx, args, &sig)
|
||||||
code,
|
|
||||||
isa,
|
|
||||||
exec_code_buf as usize,
|
|
||||||
vmctx.as_ptr() as usize,
|
|
||||||
args,
|
|
||||||
&sig,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_through_wrapper(
|
fn call_through_wrapper(
|
||||||
code: &mut Code,
|
code: &mut Code,
|
||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
callee: usize,
|
callee: usize,
|
||||||
vmctx: usize,
|
vmctx: *mut VMContext,
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
sig: &ir::Signature,
|
sig: &ir::Signature,
|
||||||
) -> Result<InvokeOutcome, String> {
|
) -> Result<InvokeOutcome, String> {
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ extern crate alloc;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
#[cfg(test)]
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate memoffset;
|
extern crate memoffset;
|
||||||
extern crate cast;
|
extern crate cast;
|
||||||
@@ -52,13 +51,16 @@ mod invoke;
|
|||||||
mod memory;
|
mod memory;
|
||||||
mod mmap;
|
mod mmap;
|
||||||
mod signalhandlers;
|
mod signalhandlers;
|
||||||
|
mod table;
|
||||||
mod traphandlers;
|
mod traphandlers;
|
||||||
|
mod vmcontext;
|
||||||
|
|
||||||
pub use code::Code;
|
pub use code::Code;
|
||||||
pub use execute::{compile_and_link_module, finish_instantiation};
|
pub use execute::{compile_and_link_module, finish_instantiation};
|
||||||
pub use instance::Instance;
|
pub use instance::Instance;
|
||||||
pub use invoke::{invoke, InvokeOutcome, Value};
|
pub use invoke::{invoke, InvokeOutcome, Value};
|
||||||
pub use traphandlers::{call_wasm, LookupCodeSegment, RecordTrap, Unwind};
|
pub use traphandlers::{call_wasm, LookupCodeSegment, RecordTrap, Unwind};
|
||||||
|
pub use vmcontext::VMContext;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
mod std {
|
mod std {
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
//! Memory management for linear memory.
|
//! Memory management for linear memories.
|
||||||
|
//!
|
||||||
|
//! `LinearMemory` is to WebAssembly linear memories what `Table` is to WebAssembly tables.
|
||||||
|
|
||||||
use cast;
|
use cast;
|
||||||
use mmap::Mmap;
|
use mmap::Mmap;
|
||||||
use region;
|
use region;
|
||||||
use std::fmt;
|
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
use vmcontext::VMMemory;
|
||||||
use wasmtime_environ::{MemoryPlan, MemoryStyle, WASM_MAX_PAGES, WASM_PAGE_SIZE};
|
use wasmtime_environ::{MemoryPlan, MemoryStyle, WASM_MAX_PAGES, WASM_PAGE_SIZE};
|
||||||
|
|
||||||
/// A linear memory instance.
|
/// A linear memory instance.
|
||||||
///
|
#[derive(Debug)]
|
||||||
/// This linear memory has a stable base address and at the same time allows
|
|
||||||
/// for dynamical growing.
|
|
||||||
pub struct LinearMemory {
|
pub struct LinearMemory {
|
||||||
mmap: Mmap,
|
mmap: Mmap,
|
||||||
current: u32,
|
current: u32,
|
||||||
@@ -61,13 +61,8 @@ impl LinearMemory {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an base address of this linear memory.
|
/// Returns the number of allocated wasm pages.
|
||||||
pub fn base_addr(&mut self) -> *mut u8 {
|
pub fn size(&self) -> u32 {
|
||||||
self.mmap.as_mut_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a number of allocated wasm pages.
|
|
||||||
pub fn current_size(&self) -> u32 {
|
|
||||||
assert_eq!(self.mmap.len() % WASM_PAGE_SIZE as usize, 0);
|
assert_eq!(self.mmap.len() % WASM_PAGE_SIZE as usize, 0);
|
||||||
let num_pages = self.mmap.len() / WASM_PAGE_SIZE as usize;
|
let num_pages = self.mmap.len() / WASM_PAGE_SIZE as usize;
|
||||||
cast::u32(num_pages).unwrap()
|
cast::u32(num_pages).unwrap()
|
||||||
@@ -131,14 +126,9 @@ impl LinearMemory {
|
|||||||
|
|
||||||
Some(prev_pages)
|
Some(prev_pages)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for LinearMemory {
|
pub fn vmmemory(&mut self) -> VMMemory {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
VMMemory::new(self.mmap.as_mut_ptr(), self.mmap.len())
|
||||||
f.debug_struct("LinearMemory")
|
|
||||||
.field("current", &self.current)
|
|
||||||
.field("maximum", &self.maximum)
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
|
|||||||
|
|
||||||
/// A simple struct consisting of a page-aligned pointer to page-aligned
|
/// A simple struct consisting of a page-aligned pointer to page-aligned
|
||||||
/// and initially-zeroed memory and a length.
|
/// and initially-zeroed memory and a length.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Mmap {
|
pub struct Mmap {
|
||||||
ptr: *mut u8,
|
ptr: *mut u8,
|
||||||
len: usize,
|
len: usize,
|
||||||
|
|||||||
65
lib/execute/src/table.rs
Normal file
65
lib/execute/src/table.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
//! Memory management for tables.
|
||||||
|
//!
|
||||||
|
//! `Table` is to WebAssembly tables what `LinearMemory` is to WebAssembly linear memories.
|
||||||
|
|
||||||
|
use cranelift_wasm::{self, TableElementType};
|
||||||
|
use std::ptr;
|
||||||
|
use vmcontext::VMTable;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AnyFunc {
|
||||||
|
pub func_ptr: *const u8,
|
||||||
|
pub type_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AnyFunc {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
func_ptr: ptr::null(),
|
||||||
|
type_id: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A table instance.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Table {
|
||||||
|
vec: Vec<AnyFunc>,
|
||||||
|
maximum: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Table {
|
||||||
|
/// Create a new table instance with specified minimum and maximum number of pages.
|
||||||
|
pub fn new(table: &cranelift_wasm::Table) -> Self {
|
||||||
|
match table.ty {
|
||||||
|
TableElementType::Func => (),
|
||||||
|
TableElementType::Val(ty) => {
|
||||||
|
unimplemented!("tables of types other than anyfunc ({})", ty)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
vec.resize(table.minimum as usize, AnyFunc::default());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
vec,
|
||||||
|
maximum: table.maximum,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vmtable(&mut self) -> VMTable {
|
||||||
|
VMTable::new(self.vec.as_mut_ptr() as *mut u8, self.vec.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[AnyFunc]> for Table {
|
||||||
|
fn as_ref(&self) -> &[AnyFunc] {
|
||||||
|
self.vec.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[AnyFunc]> for Table {
|
||||||
|
fn as_mut(&mut self) -> &mut [AnyFunc] {
|
||||||
|
self.vec.as_mut_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,10 +74,9 @@ impl ScopeGuard {
|
|||||||
impl Drop for ScopeGuard {
|
impl Drop for ScopeGuard {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let orig_num_bufs = self.orig_num_bufs;
|
let orig_num_bufs = self.orig_num_bufs;
|
||||||
// TODO: Use `shrink_to` once it stablizes.
|
|
||||||
JMP_BUFS.with(|bufs| {
|
JMP_BUFS.with(|bufs| {
|
||||||
bufs.borrow_mut()
|
bufs.borrow_mut()
|
||||||
.resize(orig_num_bufs, unsafe { mem::uninitialized() })
|
.resize(orig_num_bufs, unsafe { mem::zeroed() })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
//! This file declares `VMContext` and several related structs which contain
|
//! This file declares `VMContext` and several related structs which contain
|
||||||
//! fields that JIT code accesses directly.
|
//! fields that JIT code accesses directly.
|
||||||
|
|
||||||
use std::ptr::{size_of, align_of};
|
use cranelift_entity::EntityRef;
|
||||||
|
use cranelift_wasm::{GlobalIndex, MemoryIndex, TableIndex};
|
||||||
|
use instance::Instance;
|
||||||
|
use std::mem::size_of;
|
||||||
|
use std::slice;
|
||||||
|
|
||||||
/// The main fields a JIT needs to access to utilize a WebAssembly linear,
|
/// The main fields a JIT needs to access to utilize a WebAssembly linear,
|
||||||
/// memory, namely the start address and the size in bytes.
|
/// memory, namely the start address and the size in bytes.
|
||||||
#[repr(C, packed)]
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct VMMemory {
|
pub struct VMMemory {
|
||||||
pub base: *mut u8,
|
base: *mut u8,
|
||||||
pub current_length: usize,
|
current_length: usize,
|
||||||
// If more elements are added here, remember to add offset_of tests below!
|
// If more elements are added here, remember to add offset_of tests below!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,14 +23,24 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_vmmemory_offsets() {
|
fn check_vmmemory_offsets() {
|
||||||
let offsets = VMOffsets::new(size_of<*mut u8>());
|
let offsets = VMOffsets::new(size_of::<*mut u8>());
|
||||||
assert_eq!(size_of<VMMemory>(), offsets.size_of_vmmemory());
|
assert_eq!(size_of::<VMMemory>(), offsets.size_of_vmmemory());
|
||||||
assert_eq!(offset_of!(VMMemory, base), offsets.vmmemory_base());
|
assert_eq!(offset_of!(VMMemory, base), offsets.vmmemory_base());
|
||||||
assert_eq!(offset_of!(VMMemory, current_length), offsets.vmmemory_current_length());
|
assert_eq!(
|
||||||
|
offset_of!(VMMemory, current_length),
|
||||||
|
offsets.vmmemory_current_length()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VMMemory {
|
impl VMMemory {
|
||||||
|
pub fn new(base: *mut u8, current_length: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
base,
|
||||||
|
current_length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
unsafe { slice::from_raw_parts(self.base, self.current_length) }
|
unsafe { slice::from_raw_parts(self.base, self.current_length) }
|
||||||
}
|
}
|
||||||
@@ -47,38 +62,50 @@ impl VMMemory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed, align(8))]
|
/// The storage for a WebAssembly global.
|
||||||
|
///
|
||||||
|
/// TODO: Pack the globals more densely, rather than using the same size
|
||||||
|
/// for every type.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C, align(8))]
|
||||||
pub struct VMGlobal {
|
pub struct VMGlobal {
|
||||||
pub storage: [u8; 8],
|
storage: [u8; 8],
|
||||||
// If more elements are added here, remember to add offset_of tests below!
|
// If more elements are added here, remember to add offset_of tests below!
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The storage for a WebAssembly global.
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use std::mem::align_of;
|
||||||
use wasmtime_environ::VMOffsets;
|
use wasmtime_environ::VMOffsets;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_vmglobal_alignment() {
|
fn check_vmglobal_alignment() {
|
||||||
assert!(align_of<VMGlobal>() <= align_of<i32>());
|
assert!(align_of::<VMGlobal>() <= align_of::<i32>());
|
||||||
assert!(align_of<VMGlobal>() >= align_of<i64>());
|
assert!(align_of::<VMGlobal>() >= align_of::<i64>());
|
||||||
assert!(align_of<VMGlobal>() >= align_of<f32>());
|
assert!(align_of::<VMGlobal>() >= align_of::<f32>());
|
||||||
assert!(align_of<VMGlobal>() >= align_of<f64>());
|
assert!(align_of::<VMGlobal>() >= align_of::<f64>());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_vmglobal_offsets() {
|
fn check_vmglobal_offsets() {
|
||||||
let offsets = VMOffsets::new(size_of<*mut u8>());
|
let offsets = VMOffsets::new(size_of::<*mut u8>());
|
||||||
assert_eq!(size_of<VMGlobal>(), offsets.size_of_vmglobal());
|
assert_eq!(size_of::<VMGlobal>(), offsets.size_of_vmglobal());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for VMGlobal {
|
||||||
|
fn default() -> Self {
|
||||||
|
VMGlobal { storage: [0; 8] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
/// The main fields a JIT needs to access to utilize a WebAssembly table,
|
/// The main fields a JIT needs to access to utilize a WebAssembly table,
|
||||||
/// namely the start address and the number of elements.
|
/// namely the start address and the number of elements.
|
||||||
#[repr(C, packed)]
|
#[repr(C)]
|
||||||
pub struct VMTableStorage {
|
pub struct VMTable {
|
||||||
pub base: *mut u8,
|
base: *mut u8,
|
||||||
pub current_elements: usize,
|
current_elements: usize,
|
||||||
// If more elements are added here, remember to add offset_of tests below!
|
// If more elements are added here, remember to add offset_of tests below!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,20 +115,30 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_vmtable_offsets() {
|
fn check_vmtable_offsets() {
|
||||||
let offsets = VMOffsets::new(size_of<*mut u8>());
|
let offsets = VMOffsets::new(size_of::<*mut u8>());
|
||||||
assert_eq!(size_of<VMTableStorage>(), offsets.size_of_vmtable());
|
assert_eq!(size_of::<VMTable>(), offsets.size_of_vmtable());
|
||||||
assert_eq!(offset_of!(VMTableStorage, base), offsets.vmtable_base());
|
assert_eq!(offset_of!(VMTable, base), offsets.vmtable_base());
|
||||||
assert_eq!(offset_of!(VMTableStorage, current_elements), offsets.vmtable_current_elements());
|
assert_eq!(
|
||||||
|
offset_of!(VMTable, current_elements),
|
||||||
|
offsets.vmtable_current_elements()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VMTable {
|
||||||
|
pub fn new(base: *mut u8, current_elements: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
base,
|
||||||
|
current_elements,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VMTableStorage {
|
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
unsafe { slice::from_raw_parts(self.base, self.current_length) }
|
unsafe { slice::from_raw_parts(self.base, self.current_elements) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||||
unsafe { slice::from_raw_parts_mut(self.base, self.current_length) }
|
unsafe { slice::from_raw_parts_mut(self.base, self.current_elements) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ptr(&self) -> *const u8 {
|
pub fn as_ptr(&self) -> *const u8 {
|
||||||
@@ -113,26 +150,24 @@ impl VMTableStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.current_length
|
self.current_elements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
|
/// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
|
||||||
/// This has pointers to the globals, memories, tables, and other runtime
|
/// This has pointers to the globals, memories, tables, and other runtime
|
||||||
/// state associated with the current instance.
|
/// state associated with the current instance.
|
||||||
#[repr(C, packed)]
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct VMContext {
|
pub struct VMContext {
|
||||||
/// A pointer to an array of `VMMemory` instances, indexed by
|
/// A pointer to an array of `VMMemory` instances, indexed by
|
||||||
/// WebAssembly memory index.
|
/// WebAssembly memory index.
|
||||||
pub memories: *mut VMMemory,
|
memories: *mut VMMemory,
|
||||||
/// A pointer to an array of globals.
|
/// A pointer to an array of globals.
|
||||||
pub globals: *mut u8,
|
globals: *mut VMGlobal,
|
||||||
/// A pointer to an array of `VMTableStorage` instances, indexed by
|
/// A pointer to an array of `VMTable` instances, indexed by
|
||||||
/// WebAssembly table index.
|
/// WebAssembly table index.
|
||||||
pub tables: *mut VMTableStorage,
|
tables: *mut VMTable,
|
||||||
/// A pointer to extra runtime state that isn't directly accessed
|
|
||||||
/// from JIT code.
|
|
||||||
pub instance: *mut u8,
|
|
||||||
// If more elements are added here, remember to add offset_of tests below!
|
// If more elements are added here, remember to add offset_of tests below!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,41 +177,63 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_vmctx_offsets() {
|
fn check_vmctx_offsets() {
|
||||||
let offsets = VMOffsets::new(size_of<*mut u8>());
|
let offsets = VMOffsets::new(size_of::<*mut u8>());
|
||||||
assert_eq!(size_of<VMContext>(), offsets.size_of_vmctx());
|
assert_eq!(size_of::<VMContext>(), offsets.size_of_vmctx());
|
||||||
assert_eq!(offset_of!(VMContext, globals), offsets.vmctx_globals());
|
|
||||||
assert_eq!(offset_of!(VMContext, memories), offsets.vmctx_memories());
|
assert_eq!(offset_of!(VMContext, memories), offsets.vmctx_memories());
|
||||||
|
assert_eq!(offset_of!(VMContext, globals), offsets.vmctx_globals());
|
||||||
assert_eq!(offset_of!(VMContext, tables), offsets.vmctx_tables());
|
assert_eq!(offset_of!(VMContext, tables), offsets.vmctx_tables());
|
||||||
assert_eq!(offset_of!(VMContext, instance), offsets.vmctx_instance());
|
assert_eq!(offset_of!(VMContext, instance), offsets.vmctx_instance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VMContext {
|
impl VMContext {
|
||||||
unsafe pub fn global_storage(&mut self, index: usize) -> *mut u8 {
|
/// Create a new `VMContext` instance.
|
||||||
globals.add(index * global_size)
|
pub fn new(memories: *mut VMMemory, globals: *mut VMGlobal, tables: *mut VMTable) -> Self {
|
||||||
|
Self {
|
||||||
|
memories,
|
||||||
|
globals,
|
||||||
|
tables,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe pub fn global_i32(&mut self, index: usize) -> &mut i32 {
|
/// Return the base pointer of the globals array.
|
||||||
self.global_storage(index) as &mut i32
|
pub unsafe fn global_storage(&mut self, index: GlobalIndex) -> *mut VMGlobal {
|
||||||
|
self.globals.add(index.index() * size_of::<VMGlobal>())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe pub fn global_i64(&mut self, index: usize) -> &mut i64 {
|
/// Return a mutable reference to global `index` which has type i32.
|
||||||
self.global_storage(index) as &mut i64
|
pub unsafe fn global_i32(&mut self, index: GlobalIndex) -> &mut i32 {
|
||||||
|
&mut *(self.global_storage(index) as *mut i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe pub fn global_f32(&mut self, index: usize) -> &mut f32 {
|
/// Return a mutable reference to global `index` which has type i64.
|
||||||
self.global_storage(index) as &mut f32
|
pub unsafe fn global_i64(&mut self, index: GlobalIndex) -> &mut i64 {
|
||||||
|
&mut *(self.global_storage(index) as *mut i64)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe pub fn global_f64(&mut self, index: usize) -> &mut f64 {
|
/// Return a mutable reference to global `index` which has type f32.
|
||||||
self.global_storage(index) as &mut f64
|
pub unsafe fn global_f32(&mut self, index: GlobalIndex) -> &mut f32 {
|
||||||
|
&mut *(self.global_storage(index) as *mut f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe pub fn memory(&mut self, index: usize) -> &mut VMMemory {
|
/// Return a mutable reference to global `index` which has type f64.
|
||||||
memories.add(index) as &mut VMMemory
|
pub unsafe fn global_f64(&mut self, index: GlobalIndex) -> &mut f64 {
|
||||||
|
&mut *(self.global_storage(index) as *mut f64)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe pub fn table(&mut self, index: usize) -> &mut VMTableStorage {
|
/// Return a mutable reference to linear memory `index`.
|
||||||
tables.add(index) as &mut VMTableStorage
|
pub unsafe fn memory(&mut self, index: MemoryIndex) -> &mut VMMemory {
|
||||||
|
&mut *self.memories.add(index.index())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a mutable reference to table `index`.
|
||||||
|
pub unsafe fn table(&mut self, index: TableIndex) -> &mut VMTable {
|
||||||
|
&mut *self.tables.add(index.index())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a mutable reference to the associated `Instance`.
|
||||||
|
pub unsafe fn instance(&mut self) -> &mut Instance {
|
||||||
|
&mut *((self as *mut VMContext as *mut u8).offset(-Instance::vmctx_offset())
|
||||||
|
as *mut Instance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ fn handle_module(args: &Args, path: PathBuf, isa: &TargetIsa) -> Result<(), Stri
|
|||||||
&translation.lazy.data_initializers,
|
&translation.lazy.data_initializers,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut context = finish_instantiation(
|
finish_instantiation(
|
||||||
&mut code,
|
&mut code,
|
||||||
isa,
|
isa,
|
||||||
&translation.module,
|
&translation.module,
|
||||||
@@ -181,7 +181,7 @@ fn handle_module(args: &Args, path: PathBuf, isa: &TargetIsa) -> Result<(), Stri
|
|||||||
isa,
|
isa,
|
||||||
&translation.module,
|
&translation.module,
|
||||||
&compilation,
|
&compilation,
|
||||||
&mut context,
|
instance.vmctx(),
|
||||||
&f,
|
&f,
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ use wasmtime_execute::{
|
|||||||
|
|
||||||
struct InstanceWorld {
|
struct InstanceWorld {
|
||||||
module: Module,
|
module: Module,
|
||||||
context: Vec<*mut u8>,
|
|
||||||
// FIXME
|
|
||||||
#[allow(dead_code)]
|
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
compilation: Compilation,
|
compilation: Compilation,
|
||||||
}
|
}
|
||||||
@@ -30,7 +27,7 @@ impl InstanceWorld {
|
|||||||
fn new(code: &mut Code, isa: &isa::TargetIsa, data: &[u8]) -> Result<Self, String> {
|
fn new(code: &mut Code, isa: &isa::TargetIsa, data: &[u8]) -> Result<Self, String> {
|
||||||
let mut module = Module::new();
|
let mut module = Module::new();
|
||||||
let tunables = Tunables::default();
|
let tunables = Tunables::default();
|
||||||
let (context, instance, compilation) = {
|
let (instance, compilation) = {
|
||||||
let translation = {
|
let translation = {
|
||||||
let environ = ModuleEnvironment::new(isa, &mut module, tunables);
|
let environ = ModuleEnvironment::new(isa, &mut module, tunables);
|
||||||
|
|
||||||
@@ -46,16 +43,13 @@ impl InstanceWorld {
|
|||||||
&translation.lazy.data_initializers,
|
&translation.lazy.data_initializers,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
(
|
finish_instantiation(code, isa, &translation.module, &compilation, &mut instance)?;
|
||||||
finish_instantiation(code, isa, &translation.module, &compilation, &mut instance)?,
|
|
||||||
instance,
|
(instance, compilation)
|
||||||
compilation,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
module,
|
module,
|
||||||
context,
|
|
||||||
instance,
|
instance,
|
||||||
compilation,
|
compilation,
|
||||||
})
|
})
|
||||||
@@ -73,7 +67,7 @@ impl InstanceWorld {
|
|||||||
isa,
|
isa,
|
||||||
&self.module,
|
&self.module,
|
||||||
&self.compilation,
|
&self.compilation,
|
||||||
&mut self.context,
|
self.instance.vmctx(),
|
||||||
&f,
|
&f,
|
||||||
args,
|
args,
|
||||||
).map_err(|e| e.to_string())
|
).map_err(|e| e.to_string())
|
||||||
|
|||||||
Reference in New Issue
Block a user