Remove use of offset_of! from wasmtime-environ.

wasmtime-environ is meant to support cross compilation, so it shouldn't
have dependencies on target layout of structs. This moves the layout
back into wasmtime-execute, and adds a system of asserts for checking
that wasmtime-environ's offsets stay in sync.
This commit is contained in:
Dan Gohman
2018-11-30 16:50:05 -08:00
parent 099f85f821
commit fe1643733b
10 changed files with 355 additions and 66 deletions

View File

@@ -15,17 +15,15 @@ use module::{
DataInitializer, Export, LazyContents, MemoryPlan, MemoryStyle, Module, TableElements,
};
use std::clone::Clone;
use std::mem;
use std::string::String;
use std::vec::Vec;
use tunables::Tunables;
use vmcontext;
use vmoffsets::VMOffsets;
use WASM_PAGE_SIZE;
/// Compute a `ir::ExternalName` for a given wasm function index.
pub fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
debug_assert!(FuncIndex::new(func_index.index() as u32 as usize) == func_index);
ir::ExternalName::user(0, func_index.index() as u32)
ir::ExternalName::user(0, func_index.as_u32())
}
/// Object containing the standalone environment information. To be passed after creation as
@@ -104,6 +102,9 @@ pub struct FuncEnvironment<'module_environment> {
/// The external function declaration for implementing wasm's `grow_memory`.
grow_memory_extfunc: Option<FuncRef>,
/// Offsets to struct fields accessed by JIT code.
offsets: VMOffsets,
}
impl<'module_environment> FuncEnvironment<'module_environment> {
@@ -120,6 +121,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
globals_base: None,
current_memory_extfunc: None,
grow_memory_extfunc: None,
offsets: VMOffsets::new(isa.frontend_config().pointer_bytes()),
}
}
@@ -149,10 +151,6 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
impl<'data, 'module> cranelift_wasm::ModuleEnvironment<'data>
for ModuleEnvironment<'data, 'module>
{
fn get_func_name(&self, func_index: FuncIndex) -> ir::ExternalName {
get_func_name(func_index)
}
fn target_config(&self) -> isa::TargetFrontendConfig {
self.isa.frontend_config()
}
@@ -302,19 +300,16 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
let globals_base = self.globals_base.unwrap_or_else(|| {
let new_base = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: Offset32::new(offset_of!(vmcontext::VMContext, globals) as i32),
offset: Offset32::new(i32::from(self.offsets.vmctx_globals())),
global_type: self.pointer_type(),
readonly: true,
});
self.globals_base = Some(new_base);
new_base
});
// 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: Imm64::new(offset as i64),
offset: Imm64::new(i64::from(self.offsets.index_vmglobal(index.as_u32()))),
global_type: self.pointer_type(),
});
GlobalVariable::Memory {
@@ -328,16 +323,13 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
let memories_base = self.memories_base.unwrap_or_else(|| {
let new_base = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: Offset32::new(offset_of!(vmcontext::VMContext, memories) as i32),
offset: Offset32::new(i32::from(self.offsets.vmctx_memories())),
global_type: self.pointer_type(),
readonly: true,
});
self.memories_base = Some(new_base);
new_base
});
let offset = index.index() * mem::size_of::<vmcontext::VMMemory>();
let offset32 = offset as i32;
debug_assert_eq!(offset32 as usize, offset);
// If we have a declared maximum, we can make this a "static" heap, which is
// allocated up front and never moved.
let (offset_guard_size, heap_style, readonly_base) = match self.module.memory_plans[index] {
@@ -349,7 +341,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
let heap_bound = func.create_global_value(ir::GlobalValueData::Load {
base: memories_base,
offset: Offset32::new(
offset32 + offset_of!(vmcontext::VMMemory, current_length) as i32,
self.offsets.index_vmmemory_current_length(index.as_u32()),
),
global_type: I32,
readonly: false,
@@ -377,7 +369,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
let heap_base = func.create_global_value(ir::GlobalValueData::Load {
base: memories_base,
offset: Offset32::new(offset32 + offset_of!(vmcontext::VMMemory, base) as i32),
offset: Offset32::new(self.offsets.index_vmmemory_base(index.as_u32())),
global_type: self.pointer_type(),
readonly: readonly_base,
});
@@ -395,27 +387,22 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
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),
offset: Offset32::new(i32::from(self.offsets.vmctx_tables())),
global_type: self.pointer_type(),
readonly: true,
});
self.tables_base = Some(new_base);
new_base
});
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),
offset: Offset32::new(self.offsets.index_vmtable_base(index.as_u32())),
global_type: self.pointer_type(),
readonly: false,
});
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,
),
offset: Offset32::new(self.offsets.index_vmtable_current_elements(index.as_u32())),
global_type: I32,
readonly: false,
});

View File

@@ -33,8 +33,6 @@
extern crate cranelift_codegen;
extern crate cranelift_entity;
extern crate cranelift_wasm;
#[macro_use]
extern crate memoffset;
#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;
@@ -43,7 +41,7 @@ mod compilation;
mod environ;
mod module;
mod tunables;
mod vmcontext;
mod vmoffsets;
pub use compilation::{
compile_module, Compilation, RelocSink, Relocation, RelocationTarget, Relocations,

View File

@@ -1,33 +0,0 @@
/// 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

@@ -0,0 +1,145 @@
/// This class computes offsets to fields within `VMContext` and other
/// related structs that JIT code accesses directly.
pub struct VMOffsets {
pointer_size: u8,
}
impl VMOffsets {
/// Return a new `VMOffsets` instance, for a given pointer size.
pub fn new(pointer_size: u8) -> Self {
Self { pointer_size }
}
}
/// Offsets for `wasmtime_execute::VMMemory`.
impl VMOffsets {
/// The offset of the `base` field.
pub fn vmmemory_base(&self) -> u8 {
0 * self.pointer_size
}
/// The offset of the `current_length` field.
pub fn vmmemory_current_length(&self) -> u8 {
1 * self.pointer_size
}
/// Return the size of `VMMemory`.
pub fn size_of_vmmemory(&self) -> u8 {
2 * self.pointer_size
}
}
/// Offsets for `wasmtime_execute::VMGlobal`.
impl VMOffsets {
/// Return the size of `VMGlobal`.
pub fn size_of_vmglobal(&self) -> u8 {
8
}
}
/// Offsets for `wasmtime_execute::VMTable`.
impl VMOffsets {
/// The offset of the `base` field.
pub fn vmtable_base(&self) -> u8 {
0 * self.pointer_size
}
/// The offset of the `current_elements` field.
pub fn vmtable_current_elements(&self) -> u8 {
1 * self.pointer_size
}
/// Return the size of `VMTable`.
pub fn size_of_vmtable(&self) -> u8 {
2 * self.pointer_size
}
}
/// Offsets for `wasmtime_execute::VMContext`.
impl VMOffsets {
/// The offset of the `memories` field.
pub fn vmctx_memories(&self) -> u8 {
0 * self.pointer_size
}
/// The offset of the `globals` field.
pub fn vmctx_globals(&self) -> u8 {
1 * self.pointer_size
}
/// The offset of the `tables` field.
pub fn vmctx_tables(&self) -> u8 {
2 * self.pointer_size
}
/// The offset of the `instance` field.
#[allow(dead_code)]
pub fn vmctx_instance(&self) -> u8 {
3 * self.pointer_size
}
/// Return the size of `VMContext`.
#[allow(dead_code)]
pub fn size_of_vmctx(&self) -> u8 {
4 * self.pointer_size
}
/// Return the offset from the `memories` pointer to `VMMemory` index `index`.
pub fn index_vmmemory(&self, index: u32) -> i32 {
cast::i32(
index
.checked_mul(u32::from(self.size_of_vmmemory()))
.unwrap(),
).unwrap()
}
/// Return the offset from the `globals` pointer to `VMGlobal` index `index`.
pub fn index_vmglobal(&self, index: u32) -> i32 {
cast::i32(
index
.checked_mul(u32::from(self.size_of_vmglobal()))
.unwrap(),
).unwrap()
}
/// Return the offset from the `tables` pointer to `VMTable` index `index`.
pub fn index_vmtable(&self, index: u32) -> i32 {
cast::i32(
index
.checked_mul(u32::from(self.size_of_vmtable()))
.unwrap(),
).unwrap()
}
/// Return the offset from the `memories` pointer to the `base` field in
/// `VMMemory` index `index`.
pub fn index_vmmemory_base(&self, index: u32) -> i32 {
self.index_vmmemory(index)
.checked_add(i32::from(self.vmmemory_base()))
.unwrap()
}
/// Return the offset from the `memories` pointer to the `current_length` field in
/// `VMMemory` index `index`.
pub fn index_vmmemory_current_length(&self, index: u32) -> i32 {
self.index_vmmemory(index)
.checked_add(i32::from(self.vmmemory_current_length()))
.unwrap()
}
/// Return the offset from the `tables` pointer to the `base` field in
/// `VMTable` index `index`.
pub fn index_vmtable_base(&self, index: u32) -> i32 {
self.index_vmtable(index)
.checked_add(i32::from(self.vmtable_base()))
.unwrap()
}
/// Return the offset from the `tables` pointer to the `current_elements` field in
/// `VMTable` index `index`.
pub fn index_vmtable_current_elements(&self, index: u32) -> i32 {
self.index_vmtable(index)
.checked_add(i32::from(self.vmtable_current_elements()))
.unwrap()
}
}