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:
Dan Gohman
2019-01-03 06:59:46 -08:00
parent 450a279e18
commit 7592c99f3b
46 changed files with 1225 additions and 1073 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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