Update to Cranelift 0.22.

This commit is contained in:
Dan Gohman
2018-11-16 10:49:37 -08:00
parent 9e56ed5aad
commit 0a0108f959
9 changed files with 171 additions and 70 deletions

View File

@@ -18,8 +18,8 @@ name = "wasm2obj"
path = "src/wasm2obj.rs"
[dependencies]
cranelift-codegen = "0.20.0"
cranelift-native = "0.20.0"
cranelift-codegen = "0.22.0"
cranelift-native = "0.22.0"
wasmtime-environ = { path = "lib/environ" }
wasmtime-execute = { path = "lib/execute" }
wasmtime-obj = { path = "lib/obj" }

View File

@@ -10,9 +10,9 @@ cargo-fuzz = true
[dependencies]
wasmtime-environ = { path = "../lib/environ" }
wasmtime-execute = { path = "../lib/execute" }
cranelift-codegen = "0.20.0"
cranelift-wasm = "0.20.1"
cranelift-native = "0.20.0"
cranelift-codegen = "0.22.0"
cranelift-wasm = "0.22.0"
cranelift-native = "0.22.0"
libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" }
wasmparser = { version = "0.17.2", default-features = false }

View File

@@ -10,10 +10,11 @@ license = "Apache-2.0 WITH LLVM-exception"
readme = "README.md"
[dependencies]
cranelift-codegen = "0.20.0"
cranelift-entity = "0.20.1"
cranelift-wasm = "0.20.1"
cranelift-codegen = "0.22.0"
cranelift-entity = "0.22.0"
cranelift-wasm = "0.22.0"
target-lexicon = "0.0.3"
memoffset = "0.2.1"
[badges]
maintenance = { status = "experimental" }

View File

@@ -6,14 +6,14 @@ use cranelift_codegen::ir::{
AbiParam, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, Function, InstBuilder, Signature,
};
use cranelift_codegen::isa;
use cranelift_codegen::settings;
use cranelift_entity::EntityRef;
use cranelift_wasm::{
self, translate_module, FuncIndex, Global, GlobalIndex, GlobalVariable, Memory, MemoryIndex,
SignatureIndex, Table, TableIndex, WasmResult,
};
use module::{DataInitializer, Export, LazyContents, Module, TableElements};
use target_lexicon::Triple;
use std::mem;
use vmcontext;
/// Compute a `ir::ExternalName` for a given wasm function index.
pub fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
@@ -32,6 +32,9 @@ pub struct ModuleEnvironment<'data, 'module> {
/// References to information to be decoded later.
pub lazy: LazyContents<'data>,
/// The ISA's target front-end configuration.
frontend_config: isa::TargetFrontendConfig,
}
impl<'data, 'module> ModuleEnvironment<'data, 'module> {
@@ -41,6 +44,7 @@ impl<'data, 'module> ModuleEnvironment<'data, 'module> {
isa,
module,
lazy: LazyContents::new(),
frontend_config: isa.frontend_config(),
}
}
@@ -76,9 +80,15 @@ pub struct FuncEnvironment<'module_environment> {
/// The module-level environment which this function-level environment belongs to.
pub module: &'module_environment Module,
/// The Cranelift global holding the vmctx address.
pub vmctx: Option<ir::GlobalValue>,
/// The Cranelift global holding the base address of the memories vector.
pub memories_base: Option<ir::GlobalValue>,
/// The Cranelift global holding the base address of the tables vector.
pub tables_base: Option<ir::GlobalValue>,
/// The Cranelift global holding the base address of the globals vector.
pub globals_base: Option<ir::GlobalValue>,
@@ -97,7 +107,9 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
Self {
isa,
module,
vmctx: None,
memories_base: None,
tables_base: None,
globals_base: None,
current_memory_extfunc: None,
grow_memory_extfunc: None,
@@ -115,6 +127,14 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
fn pointer_bytes(&self) -> usize {
usize::from(self.isa.pointer_bytes())
}
fn vmctx(&mut self, func: &mut Function) -> ir::GlobalValue {
self.vmctx.unwrap_or_else(|| {
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
self.vmctx = Some(vmctx);
vmctx
})
}
}
/// This trait is useful for `translate_module` because it tells how to translate
@@ -126,8 +146,8 @@ impl<'data, 'module> cranelift_wasm::ModuleEnvironment<'data>
get_func_name(func_index)
}
fn flags(&self) -> &settings::Flags {
self.isa.flags()
fn target_config(&self) -> &isa::TargetFrontendConfig {
&self.frontend_config
}
fn declare_signature(&mut self, sig: &ir::Signature) {
@@ -253,30 +273,29 @@ impl<'data, 'module> cranelift_wasm::ModuleEnvironment<'data>
}
impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> {
fn flags(&self) -> &settings::Flags {
&self.isa.flags()
}
fn triple(&self) -> &Triple {
self.isa.triple()
fn target_config(&self) -> isa::TargetFrontendConfig {
self.isa.frontend_config()
}
fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable {
let pointer_bytes = self.pointer_bytes();
let vmctx = self.vmctx(func);
let globals_base = self.globals_base.unwrap_or_else(|| {
let new_base = func.create_global_value(ir::GlobalValueData::VMContext {
offset: Offset32::new(0),
let new_base = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: Offset32::new(offset_of!(vmcontext::VMContext, globals) as i32),
global_type: self.pointer_type(),
readonly: true,
});
self.globals_base = Some(new_base);
new_base
});
let offset = index * pointer_bytes;
let offset32 = offset as i32;
debug_assert_eq!(offset32 as usize, offset);
let gv = func.create_global_value(ir::GlobalValueData::Deref {
// For now, give each global gets a pointer-sized region of
// storage, regardless of its type.
let offset = index.index() * mem::size_of::<*mut u8>();
let gv = func.create_global_value(ir::GlobalValueData::IAddImm {
base: globals_base,
offset: Offset32::new(offset32),
memory_type: self.pointer_type(),
offset: Imm64::new(offset as i64),
global_type: self.pointer_type(),
});
GlobalVariable::Memory {
gv,
@@ -285,55 +304,91 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
}
fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> ir::Heap {
let pointer_bytes = self.pointer_bytes();
let vmctx = self.vmctx(func);
let memories_base = self.memories_base.unwrap_or_else(|| {
let new_base = func.create_global_value(ir::GlobalValueData::VMContext {
offset: Offset32::new(pointer_bytes as i32),
let new_base = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: Offset32::new(offset_of!(vmcontext::VMContext, memories) as i32),
global_type: self.pointer_type(),
readonly: true,
});
self.memories_base = Some(new_base);
new_base
});
let offset = index * pointer_bytes;
let offset = index.index() * mem::size_of::<vmcontext::VMMemory>();
let offset32 = offset as i32;
debug_assert_eq!(offset32 as usize, offset);
let heap_base_addr = func.create_global_value(ir::GlobalValueData::Deref {
// If we have a declared maximum, we can make this a "static" heap, which is
// allocated up front and never moved.
let (guard_size, heap_style, readonly_base) =
if self.module.memories[index].maximum.is_some() {
(
0x8000_0000.into(),
ir::HeapStyle::Static {
bound: 0x1_0000_0000.into(),
},
true,
)
} else {
let heap_bound = func.create_global_value(ir::GlobalValueData::Load {
base: memories_base,
offset: Offset32::new(offset32),
memory_type: self.pointer_type(),
offset: Offset32::new(
offset32 + offset_of!(vmcontext::VMMemory, current_length) as i32,
),
global_type: self.pointer_type(),
readonly: false,
});
let heap_base = func.create_global_value(ir::GlobalValueData::Deref {
base: heap_base_addr,
offset: Offset32::new(0),
memory_type: self.pointer_type(),
(
0.into(),
ir::HeapStyle::Dynamic {
bound_gv: heap_bound,
},
false,
)
};
let heap_base = func.create_global_value(ir::GlobalValueData::Load {
base: memories_base,
offset: Offset32::new(offset32 + offset_of!(vmcontext::VMMemory, base) as i32),
global_type: self.pointer_type(),
readonly: readonly_base,
});
func.create_heap(ir::HeapData {
base: heap_base,
min_size: 0.into(),
guard_size: 0x8000_0000.into(),
style: ir::HeapStyle::Static {
bound: 0x1_0000_0000.into(),
},
guard_size,
style: heap_style,
index_type: I32,
})
}
fn make_table(&mut self, func: &mut ir::Function, _index: TableIndex) -> ir::Table {
let pointer_bytes = self.pointer_bytes();
let base_gv_addr = func.create_global_value(ir::GlobalValueData::VMContext {
offset: Offset32::new(pointer_bytes as i32 * 2),
fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> ir::Table {
let vmctx = self.vmctx(func);
let tables_base = self.tables_base.unwrap_or_else(|| {
let new_base = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: Offset32::new(offset_of!(vmcontext::VMContext, tables) as i32),
global_type: self.pointer_type(),
readonly: true,
});
let base_gv = func.create_global_value(ir::GlobalValueData::Deref {
base: base_gv_addr,
offset: 0.into(),
memory_type: self.pointer_type(),
self.tables_base = Some(new_base);
new_base
});
let bound_gv_addr = func.create_global_value(ir::GlobalValueData::VMContext {
offset: Offset32::new(pointer_bytes as i32 * 3),
let offset = index.index() * mem::size_of::<vmcontext::VMTable>();
let offset32 = offset as i32;
debug_assert_eq!(offset32 as usize, offset);
let base_gv = func.create_global_value(ir::GlobalValueData::Load {
base: tables_base,
offset: Offset32::new(offset32 + offset_of!(vmcontext::VMTable, base) as i32),
global_type: self.pointer_type(),
readonly: false,
});
let bound_gv = func.create_global_value(ir::GlobalValueData::Deref {
base: bound_gv_addr,
offset: 0.into(),
memory_type: I32,
let bound_gv = func.create_global_value(ir::GlobalValueData::Load {
base: tables_base,
offset: Offset32::new(
offset32 + offset_of!(vmcontext::VMTable, current_num_elements) as i32,
),
global_type: I32,
readonly: false,
});
func.create_table(ir::TableData {
@@ -375,7 +430,11 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
) -> WasmResult<ir::Inst> {
// TODO: Cranelift's call_indirect doesn't implement signature checking,
// so we need to implement it ourselves.
debug_assert_eq!(table_index, 0, "non-default tables not supported yet");
debug_assert_eq!(
table_index.index(),
0,
"non-default tables not supported yet"
);
let table_entry_addr = pos.ins().table_addr(I64, table, callee, 0);
@@ -411,7 +470,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
) -> WasmResult<ir::Value> {
let grow_mem_func = self.grow_memory_extfunc.unwrap_or_else(|| {
let sig_ref = pos.func.import_signature(Signature {
call_conv: self.isa.flags().call_conv(),
call_conv: self.isa.frontend_config().default_call_conv,
params: vec![
AbiParam::new(I32),
AbiParam::new(I32),
@@ -430,7 +489,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
})
});
self.grow_memory_extfunc = Some(grow_mem_func);
let memory_index = pos.ins().iconst(I32, index as i64);
let memory_index = pos.ins().iconst(I32, index.index() as i64);
let vmctx = pos.func.special_param(ArgumentPurpose::VMContext).unwrap();
let call_inst = pos.ins().call(grow_mem_func, &[val, memory_index, vmctx]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
@@ -444,7 +503,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
) -> WasmResult<ir::Value> {
let cur_mem_func = self.current_memory_extfunc.unwrap_or_else(|| {
let sig_ref = pos.func.import_signature(Signature {
call_conv: self.isa.flags().call_conv(),
call_conv: self.isa.frontend_config().default_call_conv,
params: vec![
AbiParam::new(I32),
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
@@ -462,7 +521,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
})
});
self.current_memory_extfunc = Some(cur_mem_func);
let memory_index = pos.ins().iconst(I32, index as i64);
let memory_index = pos.ins().iconst(I32, index.index() as i64);
let vmctx = pos.func.special_param(ArgumentPurpose::VMContext).unwrap();
let call_inst = pos.ins().call(cur_mem_func, &[memory_index, vmctx]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())

View File

@@ -36,10 +36,13 @@ extern crate cranelift_codegen;
extern crate cranelift_entity;
extern crate cranelift_wasm;
extern crate target_lexicon;
#[macro_use]
extern crate memoffset;
mod compilation;
mod environ;
mod module;
mod vmcontext;
pub use compilation::{compile_module, Compilation, Relocation, RelocationTarget, Relocations};
pub use environ::{ModuleEnvironment, ModuleTranslation};

View File

@@ -0,0 +1,33 @@
/// The main fields a JIT needs to access to utilize a WebAssembly linear,
/// memory, namely the start address and the size in bytes.
#[repr(C, packed)]
pub struct VMMemory {
pub base: *mut u8,
pub current_length: usize,
}
/// The main fields a JIT needs to access to utilize a WebAssembly table,
/// namely the start address and the number of elements.
#[repr(C, packed)]
pub struct VMTable {
pub base: *mut u8,
pub current_num_elements: usize,
}
/// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
/// This has pointers to the globals, memories, tables, and other runtime
/// state associated with the current instance.
#[repr(C, packed)]
pub struct VMContext {
/// A pointer to an array of globals.
pub globals: *mut u8,
/// A pointer to an array of `VMMemory` instances, indexed by
/// WebAssembly memory index.
pub memories: *mut VMMemory,
/// A pointer to an array of `VMTable` instances, indexed by
/// WebAssembly table index.
pub tables: *mut VMTable,
/// A pointer to extra runtime state that isn't directly accessed
/// from JIT code.
pub instance: *mut u8,
}

View File

@@ -9,9 +9,9 @@ repository = "https://github.com/CraneStation/wasmtime"
license = "Apache-2.0 WITH LLVM-exception"
[dependencies]
cranelift-codegen = "0.20.0"
cranelift-entity = "0.20.1"
cranelift-wasm = "0.20.1"
cranelift-codegen = "0.22.0"
cranelift-entity = "0.22.0"
cranelift-wasm = "0.22.0"
region = "0.3.0"
wasmtime-environ = { path = "../environ" }
memmap = "0.6.2"
memmap = "0.7.0"

View File

@@ -84,6 +84,7 @@ fn relocate<F>(
extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: *mut *mut u8) -> u32 {
unsafe {
// FIXME: update the VMMemory's size
let instance = (*vmctx.offset(4)) as *mut Instance;
(*instance)
.memory_mut(memory_index as MemoryIndex)
@@ -94,6 +95,7 @@ extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: *mut *mut u8) ->
extern "C" fn current_memory(memory_index: u32, vmctx: *mut *mut u8) -> u32 {
unsafe {
// FIXME: read the VMMemory's size instead
let instance = (*vmctx.offset(4)) as *mut Instance;
(*instance)
.memory_mut(memory_index as MemoryIndex)
@@ -115,9 +117,12 @@ fn make_vmctx(instance: &mut Instance, mem_base_addrs: &mut [*mut u8]) -> Vec<*m
.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(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);
@@ -134,7 +139,7 @@ pub fn execute(
let start_index = module
.start_func
.ok_or_else(|| String::from("No start function defined, aborting execution"))?;
// TODO: Put all the function bodies into a page-aligned memory region, and
// FIXME: Put all the function bodies into a page-aligned memory region, and
// then make them ReadExecute rather than ReadWriteExecute.
for code_buf in compilation.functions.values() {
match unsafe {

View File

@@ -8,7 +8,7 @@ categories = ["wasm"]
license = "Apache-2.0 WITH LLVM-exception"
[dependencies]
cranelift-codegen = "0.20.0"
cranelift-entity = "0.20.1"
cranelift-codegen = "0.22.0"
cranelift-entity = "0.22.0"
wasmtime-environ = { path = "../environ" }
faerie = "0.5.0"