Refactor the compilation and instantiation pipeline.
wasmtime-execute is now wasmtime-jit. Move `JITCode` and the TargetIsa into a new `Compiler` type. `InstancePlus` is no more, with trampoline functionality now handled by `Compiler`.
This commit is contained in:
@@ -3,7 +3,7 @@ use cranelift_wasm::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex};
|
||||
use vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
|
||||
|
||||
/// Resolved import pointers.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Imports {
|
||||
/// Resolved addresses for imported functions.
|
||||
pub functions: BoxedSlice<FuncIndex, VMFunctionImport>,
|
||||
|
||||
@@ -23,6 +23,9 @@ use vmcontext::{
|
||||
use wasmtime_environ::{DataInitializer, Module};
|
||||
|
||||
/// An Instance of a WebAssemby module.
|
||||
///
|
||||
/// Note that compiled wasm code passes around raw pointers to `Instance`, so
|
||||
/// this shouldn't be moved.
|
||||
#[derive(Debug)]
|
||||
pub struct Instance {
|
||||
/// The `Module` this `Instance` was instantiated from.
|
||||
@@ -53,7 +56,7 @@ pub struct Instance {
|
||||
/// WebAssembly global variable data.
|
||||
vmctx_globals: BoxedSlice<DefinedGlobalIndex, VMGlobalDefinition>,
|
||||
|
||||
/// Context pointer used by JIT code.
|
||||
/// Context pointer used by compiled wasm code.
|
||||
vmctx: VMContext,
|
||||
}
|
||||
|
||||
@@ -63,7 +66,7 @@ impl Instance {
|
||||
module: Rc<Module>,
|
||||
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
||||
mut vmctx_imports: Imports,
|
||||
data_initializers: Vec<DataInitializer>,
|
||||
data_initializers: &[DataInitializer],
|
||||
) -> Result<Box<Self>, InstantiationError> {
|
||||
let mut sig_registry = create_and_initialize_signatures(&module);
|
||||
let mut tables = create_tables(&module);
|
||||
@@ -125,7 +128,7 @@ impl Instance {
|
||||
|
||||
// Check initializer bounds before initializing anything.
|
||||
check_table_init_bounds(&mut *result)?;
|
||||
check_memory_init_bounds(&mut *result, &data_initializers)?;
|
||||
check_memory_init_bounds(&mut *result, data_initializers)?;
|
||||
|
||||
// Apply the initializers.
|
||||
initialize_tables(&mut *result)?;
|
||||
@@ -148,22 +151,22 @@ impl Instance {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Return a reference to the vmctx used by JIT code.
|
||||
/// Return a reference to the vmctx used by compiled wasm code.
|
||||
pub fn vmctx(&self) -> &VMContext {
|
||||
&self.vmctx
|
||||
}
|
||||
|
||||
/// Return a raw pointer to the vmctx used by JIT code.
|
||||
/// Return a raw pointer to the vmctx used by compiled wasm code.
|
||||
pub fn vmctx_ptr(&self) -> *const VMContext {
|
||||
self.vmctx()
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the vmctx used by JIT code.
|
||||
/// Return a mutable reference to the vmctx used by compiled wasm code.
|
||||
pub fn vmctx_mut(&mut self) -> &mut VMContext {
|
||||
&mut self.vmctx
|
||||
}
|
||||
|
||||
/// Return a mutable raw pointer to the vmctx used by JIT code.
|
||||
/// Return a mutable raw pointer to the vmctx used by compiled wasm code.
|
||||
pub fn vmctx_mut_ptr(&mut self) -> *mut VMContext {
|
||||
self.vmctx_mut()
|
||||
}
|
||||
@@ -184,7 +187,7 @@ impl Instance {
|
||||
.unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
|
||||
.grow(delta);
|
||||
|
||||
// Keep current the VMContext pointers used by JIT code.
|
||||
// Keep current the VMContext pointers used by compiled wasm code.
|
||||
self.vmctx_memories[memory_index] = self.memories[memory_index].vmmemory();
|
||||
|
||||
result
|
||||
@@ -314,7 +317,7 @@ impl Instance {
|
||||
/// This requirement is not enforced in the type system, so this function is
|
||||
/// unsafe.
|
||||
pub unsafe fn lookup_immutable(&self, field: &str) -> Option<Export> {
|
||||
let temporary_mut = &mut *(self as *const Instance as *mut Instance);
|
||||
let temporary_mut = &mut *(self as *const Self as *mut Self);
|
||||
temporary_mut.lookup(field)
|
||||
}
|
||||
}
|
||||
@@ -346,9 +349,9 @@ fn check_table_init_bounds(instance: &mut Instance) -> Result<(), InstantiationE
|
||||
};
|
||||
|
||||
if slice.get_mut(start..start + init.elements.len()).is_none() {
|
||||
return Err(InstantiationError::Link(
|
||||
return Err(InstantiationError::Link(LinkError(
|
||||
"elements segment does not fit".to_owned(),
|
||||
));
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,8 +364,8 @@ fn check_memory_init_bounds(
|
||||
) -> Result<(), InstantiationError> {
|
||||
for init in data_initializers {
|
||||
// TODO: Refactor this.
|
||||
let mut start = init.offset;
|
||||
if let Some(base) = init.base {
|
||||
let mut start = init.location.offset;
|
||||
if let Some(base) = init.location.base {
|
||||
let global = if let Some(def_index) = instance.module.defined_global_index(base) {
|
||||
unsafe { instance.vmctx.global_mut(def_index) }
|
||||
} else {
|
||||
@@ -372,12 +375,13 @@ fn check_memory_init_bounds(
|
||||
}
|
||||
|
||||
// TODO: Refactor this.
|
||||
let memory = if let Some(defined_memory_index) =
|
||||
instance.module.defined_memory_index(init.memory_index)
|
||||
let memory = if let Some(defined_memory_index) = instance
|
||||
.module
|
||||
.defined_memory_index(init.location.memory_index)
|
||||
{
|
||||
unsafe { instance.vmctx.memory(defined_memory_index) }
|
||||
} else {
|
||||
let import = &instance.vmctx_imports.memories[init.memory_index];
|
||||
let import = &instance.vmctx_imports.memories[init.location.memory_index];
|
||||
let foreign_instance = unsafe { (&mut *(import).vmctx).instance() };
|
||||
let foreign_memory = unsafe { &mut *(import).from };
|
||||
let foreign_index = foreign_instance.vmctx().memory_index(foreign_memory);
|
||||
@@ -386,9 +390,9 @@ fn check_memory_init_bounds(
|
||||
let mem_slice = unsafe { slice::from_raw_parts_mut(memory.base, memory.current_length) };
|
||||
|
||||
if mem_slice.get_mut(start..start + init.data.len()).is_none() {
|
||||
return Err(InstantiationError::Link(
|
||||
return Err(InstantiationError::Link(LinkError(
|
||||
"data segment does not fit".to_owned(),
|
||||
));
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,9 +461,9 @@ fn initialize_tables(instance: &mut Instance) -> Result<(), InstantiationError>
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return Err(InstantiationError::Link(
|
||||
return Err(InstantiationError::Link(LinkError(
|
||||
"elements segment does not fit".to_owned(),
|
||||
));
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,11 +486,11 @@ fn create_memories(
|
||||
/// Initialize the table memory from the provided initializers.
|
||||
fn initialize_memories(
|
||||
instance: &mut Instance,
|
||||
data_initializers: Vec<DataInitializer>,
|
||||
data_initializers: &[DataInitializer],
|
||||
) -> Result<(), InstantiationError> {
|
||||
for init in data_initializers {
|
||||
let mut start = init.offset;
|
||||
if let Some(base) = init.base {
|
||||
let mut start = init.location.offset;
|
||||
if let Some(base) = init.location.base {
|
||||
let global = if let Some(def_index) = instance.module.defined_global_index(base) {
|
||||
unsafe { instance.vmctx.global_mut(def_index) }
|
||||
} else {
|
||||
@@ -495,12 +499,13 @@ fn initialize_memories(
|
||||
start += unsafe { *(&*global).as_i32() } as u32 as usize;
|
||||
}
|
||||
|
||||
let memory = if let Some(defined_memory_index) =
|
||||
instance.module.defined_memory_index(init.memory_index)
|
||||
let memory = if let Some(defined_memory_index) = instance
|
||||
.module
|
||||
.defined_memory_index(init.location.memory_index)
|
||||
{
|
||||
unsafe { instance.vmctx.memory(defined_memory_index) }
|
||||
} else {
|
||||
let import = &instance.vmctx_imports.memories[init.memory_index];
|
||||
let import = &instance.vmctx_imports.memories[init.location.memory_index];
|
||||
let foreign_instance = unsafe { (&mut *(import).vmctx).instance() };
|
||||
let foreign_memory = unsafe { &mut *(import).from };
|
||||
let foreign_index = foreign_instance.vmctx().memory_index(foreign_memory);
|
||||
@@ -510,9 +515,9 @@ fn initialize_memories(
|
||||
if let Some(to_init) = mem_slice.get_mut(start..start + init.data.len()) {
|
||||
to_init.copy_from_slice(init.data);
|
||||
} else {
|
||||
return Err(InstantiationError::Link(
|
||||
return Err(InstantiationError::Link(LinkError(
|
||||
"data segment does not fit".to_owned(),
|
||||
));
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,6 +560,11 @@ fn initialize_globals(instance: &mut Instance) {
|
||||
}
|
||||
}
|
||||
|
||||
/// An link error while instantiating a module.
|
||||
#[derive(Fail, Debug)]
|
||||
#[fail(display = "Link error: {}", _0)]
|
||||
pub struct LinkError(pub String);
|
||||
|
||||
/// An error while instantiating a module.
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum InstantiationError {
|
||||
@@ -562,9 +572,9 @@ pub enum InstantiationError {
|
||||
#[fail(display = "Insufficient resources: {}", _0)]
|
||||
Resource(String),
|
||||
|
||||
/// A wasm translation error occured.
|
||||
#[fail(display = "Link error: {}", _0)]
|
||||
Link(String),
|
||||
/// A wasm link error occured.
|
||||
#[fail(display = "{}", _0)]
|
||||
Link(LinkError),
|
||||
|
||||
/// A compilation error occured.
|
||||
#[fail(display = "Trap occurred while invoking start function: {}", _0)]
|
||||
|
||||
@@ -60,7 +60,7 @@ pub mod libcalls;
|
||||
|
||||
pub use export::Export;
|
||||
pub use imports::Imports;
|
||||
pub use instance::{Instance, InstantiationError};
|
||||
pub use instance::{Instance, InstantiationError, LinkError};
|
||||
pub use mmap::Mmap;
|
||||
pub use signalhandlers::{wasmtime_init_eager, wasmtime_init_finish};
|
||||
pub use traphandlers::{wasmtime_call, wasmtime_call_trampoline};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Runtime library calls. Note that the JIT may sometimes perform these inline
|
||||
//! rather than calling them, particularly when CPUs have special instructions
|
||||
//! which compute them directly.
|
||||
//! Runtime library calls. Note that wasm compilers may sometimes perform these
|
||||
//! inline rather than calling them, particularly when CPUs have special
|
||||
//! instructions which compute them directly.
|
||||
|
||||
use cranelift_wasm::{DefinedMemoryIndex, MemoryIndex};
|
||||
use vmcontext::VMContext;
|
||||
|
||||
@@ -148,7 +148,7 @@ impl LinearMemory {
|
||||
Some(prev_pages)
|
||||
}
|
||||
|
||||
/// Return a `VMMemoryDefinition` for exposing the memory to JIT code.
|
||||
/// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code.
|
||||
pub fn vmmemory(&mut self) -> VMMemoryDefinition {
|
||||
VMMemoryDefinition {
|
||||
base: self.mmap.as_mut_ptr(),
|
||||
|
||||
@@ -110,7 +110,7 @@ impl Mmap {
|
||||
self.ptr
|
||||
}
|
||||
|
||||
/// Return the lengthof the allocated memory.
|
||||
/// Return the length of the allocated memory.
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a `VMTableDefinition` for exposing the table to JIT code.
|
||||
/// Return a `VMTableDefinition` for exposing the table to compiled wasm code.
|
||||
pub fn vmtable(&mut self) -> VMTableDefinition {
|
||||
VMTableDefinition {
|
||||
base: self.vec.as_mut_ptr() as *mut u8,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! This file declares `VMContext` and several related structs which contain
|
||||
//! fields that JIT code accesses directly.
|
||||
//! fields that compiled wasm code accesses directly.
|
||||
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_wasm::{
|
||||
@@ -62,7 +62,7 @@ mod test_vmfunction_body {
|
||||
}
|
||||
}
|
||||
|
||||
/// The fields a JIT needs to access to utilize a WebAssembly table
|
||||
/// The fields compiled code needs to access to utilize a WebAssembly table
|
||||
/// imported from another instance.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
@@ -98,7 +98,7 @@ mod test_vmtable_import {
|
||||
}
|
||||
}
|
||||
|
||||
/// The fields a JIT needs to access to utilize a WebAssembly linear
|
||||
/// The fields compiled code needs to access to utilize a WebAssembly linear
|
||||
/// memory imported from another instance.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
@@ -134,7 +134,7 @@ mod test_vmmemory_import {
|
||||
}
|
||||
}
|
||||
|
||||
/// The fields a JIT needs to access to utilize a WebAssembly global
|
||||
/// The fields compiled code needs to access to utilize a WebAssembly global
|
||||
/// variable imported from another instance.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
@@ -163,7 +163,7 @@ mod test_vmglobal_import {
|
||||
}
|
||||
}
|
||||
|
||||
/// The fields a JIT needs to access to utilize a WebAssembly linear
|
||||
/// The fields compiled code needs to access to utilize a WebAssembly linear
|
||||
/// memory defined within the instance, namely the start address and the
|
||||
/// size in bytes.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@@ -206,7 +206,7 @@ mod test_vmmemory_definition {
|
||||
}
|
||||
}
|
||||
|
||||
/// The fields a JIT needs to access to utilize a WebAssembly table
|
||||
/// The fields compiled code needs to access to utilize a WebAssembly table
|
||||
/// defined within the instance.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
|
||||
Reference in New Issue
Block a user