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:
@@ -13,7 +13,7 @@ readme = "README.md"
|
|||||||
cranelift-codegen = { git = "https://github.com/sunfishcode/cranelift.git", branch = "guard-offset" }
|
cranelift-codegen = { git = "https://github.com/sunfishcode/cranelift.git", branch = "guard-offset" }
|
||||||
cranelift-entity = { git = "https://github.com/sunfishcode/cranelift.git", branch = "guard-offset" }
|
cranelift-entity = { git = "https://github.com/sunfishcode/cranelift.git", branch = "guard-offset" }
|
||||||
cranelift-wasm = { git = "https://github.com/sunfishcode/cranelift.git", branch = "guard-offset" }
|
cranelift-wasm = { git = "https://github.com/sunfishcode/cranelift.git", branch = "guard-offset" }
|
||||||
memoffset = "0.2.1"
|
cast = { version = "0.2.2", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -15,17 +15,15 @@ use module::{
|
|||||||
DataInitializer, Export, LazyContents, MemoryPlan, MemoryStyle, Module, TableElements,
|
DataInitializer, Export, LazyContents, MemoryPlan, MemoryStyle, Module, TableElements,
|
||||||
};
|
};
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::mem;
|
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use tunables::Tunables;
|
use tunables::Tunables;
|
||||||
use vmcontext;
|
use vmoffsets::VMOffsets;
|
||||||
use WASM_PAGE_SIZE;
|
use WASM_PAGE_SIZE;
|
||||||
|
|
||||||
/// Compute a `ir::ExternalName` for a given wasm function index.
|
/// Compute a `ir::ExternalName` for a given wasm function index.
|
||||||
pub fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
|
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.as_u32())
|
||||||
ir::ExternalName::user(0, func_index.index() as u32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Object containing the standalone environment information. To be passed after creation as
|
/// 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`.
|
/// The external function declaration for implementing wasm's `grow_memory`.
|
||||||
grow_memory_extfunc: Option<FuncRef>,
|
grow_memory_extfunc: Option<FuncRef>,
|
||||||
|
|
||||||
|
/// Offsets to struct fields accessed by JIT code.
|
||||||
|
offsets: VMOffsets,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'module_environment> FuncEnvironment<'module_environment> {
|
impl<'module_environment> FuncEnvironment<'module_environment> {
|
||||||
@@ -120,6 +121,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
|
|||||||
globals_base: None,
|
globals_base: None,
|
||||||
current_memory_extfunc: None,
|
current_memory_extfunc: None,
|
||||||
grow_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>
|
impl<'data, 'module> cranelift_wasm::ModuleEnvironment<'data>
|
||||||
for ModuleEnvironment<'data, 'module>
|
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 {
|
fn target_config(&self) -> isa::TargetFrontendConfig {
|
||||||
self.isa.frontend_config()
|
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 globals_base = self.globals_base.unwrap_or_else(|| {
|
||||||
let new_base = func.create_global_value(ir::GlobalValueData::Load {
|
let new_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: vmctx,
|
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(),
|
global_type: self.pointer_type(),
|
||||||
readonly: true,
|
readonly: true,
|
||||||
});
|
});
|
||||||
self.globals_base = Some(new_base);
|
self.globals_base = Some(new_base);
|
||||||
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 {
|
let gv = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||||
base: globals_base,
|
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(),
|
global_type: self.pointer_type(),
|
||||||
});
|
});
|
||||||
GlobalVariable::Memory {
|
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 memories_base = self.memories_base.unwrap_or_else(|| {
|
||||||
let new_base = func.create_global_value(ir::GlobalValueData::Load {
|
let new_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: vmctx,
|
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(),
|
global_type: self.pointer_type(),
|
||||||
readonly: true,
|
readonly: true,
|
||||||
});
|
});
|
||||||
self.memories_base = Some(new_base);
|
self.memories_base = Some(new_base);
|
||||||
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
|
// If we have a declared maximum, we can make this a "static" heap, which is
|
||||||
// allocated up front and never moved.
|
// allocated up front and never moved.
|
||||||
let (offset_guard_size, heap_style, readonly_base) = match self.module.memory_plans[index] {
|
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 {
|
let heap_bound = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: memories_base,
|
base: memories_base,
|
||||||
offset: Offset32::new(
|
offset: Offset32::new(
|
||||||
offset32 + offset_of!(vmcontext::VMMemory, current_length) as i32,
|
self.offsets.index_vmmemory_current_length(index.as_u32()),
|
||||||
),
|
),
|
||||||
global_type: I32,
|
global_type: I32,
|
||||||
readonly: false,
|
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 {
|
let heap_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: memories_base,
|
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(),
|
global_type: self.pointer_type(),
|
||||||
readonly: readonly_base,
|
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 tables_base = self.tables_base.unwrap_or_else(|| {
|
||||||
let new_base = func.create_global_value(ir::GlobalValueData::Load {
|
let new_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: vmctx,
|
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(),
|
global_type: self.pointer_type(),
|
||||||
readonly: true,
|
readonly: true,
|
||||||
});
|
});
|
||||||
self.tables_base = Some(new_base);
|
self.tables_base = Some(new_base);
|
||||||
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 {
|
let base_gv = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: tables_base,
|
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(),
|
global_type: self.pointer_type(),
|
||||||
readonly: false,
|
readonly: false,
|
||||||
});
|
});
|
||||||
let bound_gv = func.create_global_value(ir::GlobalValueData::Load {
|
let bound_gv = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: tables_base,
|
base: tables_base,
|
||||||
offset: Offset32::new(
|
offset: Offset32::new(self.offsets.index_vmtable_current_elements(index.as_u32())),
|
||||||
offset32 + offset_of!(vmcontext::VMTable, current_num_elements) as i32,
|
|
||||||
),
|
|
||||||
global_type: I32,
|
global_type: I32,
|
||||||
readonly: false,
|
readonly: false,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -33,8 +33,6 @@
|
|||||||
extern crate cranelift_codegen;
|
extern crate cranelift_codegen;
|
||||||
extern crate cranelift_entity;
|
extern crate cranelift_entity;
|
||||||
extern crate cranelift_wasm;
|
extern crate cranelift_wasm;
|
||||||
#[macro_use]
|
|
||||||
extern crate memoffset;
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
@@ -43,7 +41,7 @@ mod compilation;
|
|||||||
mod environ;
|
mod environ;
|
||||||
mod module;
|
mod module;
|
||||||
mod tunables;
|
mod tunables;
|
||||||
mod vmcontext;
|
mod vmoffsets;
|
||||||
|
|
||||||
pub use compilation::{
|
pub use compilation::{
|
||||||
compile_module, Compilation, RelocSink, Relocation, RelocationTarget, Relocations,
|
compile_module, Compilation, RelocSink, Relocation, RelocationTarget, Relocations,
|
||||||
|
|||||||
@@ -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,
|
|
||||||
}
|
|
||||||
145
lib/environ/src/vmoffsets.rs
Normal file
145
lib/environ/src/vmoffsets.rs
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,12 +19,16 @@ region = "1.0.0"
|
|||||||
lazy_static = "1.2.0"
|
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 }
|
||||||
|
|
||||||
[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"]
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ fn relocate<F>(
|
|||||||
|
|
||||||
let body = &mut compilation.functions[i];
|
let body = &mut compilation.functions[i];
|
||||||
match r.reloc {
|
match r.reloc {
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
Reloc::Abs8 => unsafe {
|
Reloc::Abs8 => unsafe {
|
||||||
let reloc_address = body.as_mut_ptr().add(r.offset as usize) as usize;
|
let reloc_address = body.as_mut_ptr().add(r.offset as usize) as usize;
|
||||||
let reloc_addend = r.addend as isize;
|
let reloc_addend = r.addend as isize;
|
||||||
@@ -76,6 +77,7 @@ fn relocate<F>(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
write_unaligned(reloc_address as *mut u64, reloc_abs);
|
write_unaligned(reloc_address as *mut u64, reloc_abs);
|
||||||
},
|
},
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
Reloc::X86PCRel4 => unsafe {
|
Reloc::X86PCRel4 => unsafe {
|
||||||
let reloc_address = body.as_mut_ptr().add(r.offset as usize) as usize;
|
let reloc_address = body.as_mut_ptr().add(r.offset as usize) as usize;
|
||||||
let reloc_addend = r.addend as isize;
|
let reloc_addend = r.addend as isize;
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ 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]
|
||||||
|
extern crate memoffset;
|
||||||
|
extern crate cast;
|
||||||
|
|
||||||
mod code;
|
mod code;
|
||||||
mod execute;
|
mod execute;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//! Memory management for linear memory.
|
//! Memory management for linear memory.
|
||||||
|
|
||||||
|
use cast;
|
||||||
use mmap::Mmap;
|
use mmap::Mmap;
|
||||||
use region;
|
use region;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -69,8 +70,7 @@ impl LinearMemory {
|
|||||||
pub fn current_size(&self) -> u32 {
|
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;
|
||||||
assert_eq!(num_pages as u32 as usize, num_pages);
|
cast::u32(num_pages).unwrap()
|
||||||
num_pages as u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grow memory by the specified amount of pages.
|
/// Grow memory by the specified amount of pages.
|
||||||
|
|||||||
182
lib/execute/src/vmcontext.rs
Normal file
182
lib/execute/src/vmcontext.rs
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
//! This file declares `VMContext` and several related structs which contain
|
||||||
|
//! fields that JIT code accesses directly.
|
||||||
|
|
||||||
|
use std::ptr::{size_of, align_of};
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
// If more elements are added here, remember to add offset_of tests below!
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use wasmtime_environ::VMOffsets;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_vmmemory_offsets() {
|
||||||
|
let offsets = VMOffsets::new(size_of<*mut u8>());
|
||||||
|
assert_eq!(size_of<VMMemory>(), offsets.size_of_vmmemory());
|
||||||
|
assert_eq!(offset_of!(VMMemory, base), offsets.vmmemory_base());
|
||||||
|
assert_eq!(offset_of!(VMMemory, current_length), offsets.vmmemory_current_length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VMMemory {
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
unsafe { slice::from_raw_parts(self.base, self.current_length) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||||
|
unsafe { slice::from_raw_parts_mut(self.base, self.current_length) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const u8 {
|
||||||
|
self.base
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||||
|
self.base
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.current_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed, align(8))]
|
||||||
|
pub struct VMGlobal {
|
||||||
|
pub storage: [u8; 8],
|
||||||
|
// If more elements are added here, remember to add offset_of tests below!
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The storage for a WebAssembly global.
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use wasmtime_environ::VMOffsets;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_vmglobal_alignment() {
|
||||||
|
assert!(align_of<VMGlobal>() <= align_of<i32>());
|
||||||
|
assert!(align_of<VMGlobal>() >= align_of<i64>());
|
||||||
|
assert!(align_of<VMGlobal>() >= align_of<f32>());
|
||||||
|
assert!(align_of<VMGlobal>() >= align_of<f64>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_vmglobal_offsets() {
|
||||||
|
let offsets = VMOffsets::new(size_of<*mut u8>());
|
||||||
|
assert_eq!(size_of<VMGlobal>(), offsets.size_of_vmglobal());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 VMTableStorage {
|
||||||
|
pub base: *mut u8,
|
||||||
|
pub current_elements: usize,
|
||||||
|
// If more elements are added here, remember to add offset_of tests below!
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use wasmtime_environ::VMOffsets;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_vmtable_offsets() {
|
||||||
|
let offsets = VMOffsets::new(size_of<*mut u8>());
|
||||||
|
assert_eq!(size_of<VMTableStorage>(), offsets.size_of_vmtable());
|
||||||
|
assert_eq!(offset_of!(VMTableStorage, base), offsets.vmtable_base());
|
||||||
|
assert_eq!(offset_of!(VMTableStorage, current_elements), offsets.vmtable_current_elements());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VMTableStorage {
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
unsafe { slice::from_raw_parts(self.base, self.current_length) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||||
|
unsafe { slice::from_raw_parts_mut(self.base, self.current_length) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const u8 {
|
||||||
|
self.base
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||||
|
self.base
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.current_length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 `VMMemory` instances, indexed by
|
||||||
|
/// WebAssembly memory index.
|
||||||
|
pub memories: *mut VMMemory,
|
||||||
|
/// A pointer to an array of globals.
|
||||||
|
pub globals: *mut u8,
|
||||||
|
/// A pointer to an array of `VMTableStorage` instances, indexed by
|
||||||
|
/// WebAssembly table index.
|
||||||
|
pub tables: *mut VMTableStorage,
|
||||||
|
/// 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!
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use wasmtime_environ::VMOffsets;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_vmctx_offsets() {
|
||||||
|
let offsets = VMOffsets::new(size_of<*mut u8>());
|
||||||
|
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, tables), offsets.vmctx_tables());
|
||||||
|
assert_eq!(offset_of!(VMContext, instance), offsets.vmctx_instance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VMContext {
|
||||||
|
unsafe pub fn global_storage(&mut self, index: usize) -> *mut u8 {
|
||||||
|
globals.add(index * global_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe pub fn global_i32(&mut self, index: usize) -> &mut i32 {
|
||||||
|
self.global_storage(index) as &mut i32
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe pub fn global_i64(&mut self, index: usize) -> &mut i64 {
|
||||||
|
self.global_storage(index) as &mut i64
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe pub fn global_f32(&mut self, index: usize) -> &mut f32 {
|
||||||
|
self.global_storage(index) as &mut f32
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe pub fn global_f64(&mut self, index: usize) -> &mut f64 {
|
||||||
|
self.global_storage(index) as &mut f64
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe pub fn memory(&mut self, index: usize) -> &mut VMMemory {
|
||||||
|
memories.add(index) as &mut VMMemory
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe pub fn table(&mut self, index: usize) -> &mut VMTableStorage {
|
||||||
|
tables.add(index) as &mut VMTableStorage
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user