Add a type parameter to VMOffsets for pointer size (#3020)

* Add a type parameter to `VMOffsets` for pointer size

This commit adds a type parameter to `VMOffsets` representing the
pointer size to improve computations in `wasmtime-runtime` which always
use a constant value of the host's pointer size. The type parameter is
`u8` for `wasmtime-cranelift`'s use case where cross-compilation may be
involved.

* fix lightbeam
This commit is contained in:
Alex Crichton
2021-07-13 09:52:27 -05:00
committed by GitHub
parent 75e5219792
commit 992d85ae8b
7 changed files with 111 additions and 78 deletions

View File

@@ -120,7 +120,7 @@ pub struct FuncEnvironment<'module_environment> {
builtin_function_signatures: BuiltinFunctionSignatures,
/// Offsets to struct fields accessed by JIT code.
pub(crate) offsets: VMOffsets,
pub(crate) offsets: VMOffsets<u8>,
tunables: &'module_environment Tunables,
@@ -288,7 +288,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
// If this changes that's ok, the `atomic_rmw` below just needs to be
// preceded with an add instruction of `externref` and the offset.
assert_eq!(VMOffsets::vm_extern_data_ref_count(), 0);
assert_eq!(self.offsets.vm_extern_data_ref_count(), 0);
let delta = builder.ins().iconst(pointer_type, delta);
builder.ins().atomic_rmw(
pointer_type,

View File

@@ -52,9 +52,9 @@ fn align(offset: u32, width: u32) -> u32 {
/// This class computes offsets to fields within `VMContext` and other
/// related structs that JIT code accesses directly.
#[derive(Debug, Clone, Copy)]
pub struct VMOffsets {
pub struct VMOffsets<P> {
/// The size in bytes of a pointer on the target.
pub pointer_size: u8,
pub ptr: P,
/// The number of signature declarations in the module.
pub num_signature_ids: u32,
/// The number of imported functions in the module.
@@ -91,11 +91,34 @@ pub struct VMOffsets {
size: u32,
}
/// Trait used for the `ptr` representation of the field of `VMOffsets`
pub trait PtrSize {
/// Returns the pointer size, in bytes, for the target.
fn size(&self) -> u8;
}
/// Type representing the size of a pointer for the current compilation host
pub struct HostPtr;
impl PtrSize for HostPtr {
#[inline]
fn size(&self) -> u8 {
std::mem::size_of::<usize>() as u8
}
}
impl PtrSize for u8 {
#[inline]
fn size(&self) -> u8 {
*self
}
}
/// Used to construct a `VMOffsets`
#[derive(Debug, Clone, Copy)]
pub struct VMOffsetsFields {
pub struct VMOffsetsFields<P> {
/// The size in bytes of a pointer on the target.
pub pointer_size: u8,
pub ptr: P,
/// The number of signature declarations in the module.
pub num_signature_ids: u32,
/// The number of imported functions in the module.
@@ -116,11 +139,11 @@ pub struct VMOffsetsFields {
pub num_defined_globals: u32,
}
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// Return a new `VMOffsets` instance, for a given pointer size.
pub fn new(pointer_size: u8, module: &Module) -> Self {
pub fn new(ptr: P, module: &Module) -> Self {
VMOffsets::from(VMOffsetsFields {
pointer_size,
ptr,
num_signature_ids: cast_to_u32(module.types.len()),
num_imported_functions: cast_to_u32(module.num_imported_funcs),
num_imported_tables: cast_to_u32(module.num_imported_tables),
@@ -132,12 +155,18 @@ impl VMOffsets {
num_defined_globals: cast_to_u32(module.globals.len()),
})
}
/// Returns the size, in bytes, of the target
#[inline]
pub fn pointer_size(&self) -> u8 {
self.ptr.size()
}
}
impl From<VMOffsetsFields> for VMOffsets {
fn from(fields: VMOffsetsFields) -> VMOffsets {
impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {
fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {
let mut ret = Self {
pointer_size: fields.pointer_size,
ptr: fields.ptr,
num_signature_ids: fields.num_signature_ids,
num_imported_functions: fields.num_imported_functions,
num_imported_tables: fields.num_imported_tables,
@@ -166,15 +195,15 @@ impl From<VMOffsetsFields> for VMOffsets {
ret.interrupts = 0;
ret.externref_activations_table = ret
.interrupts
.checked_add(u32::from(fields.pointer_size))
.checked_add(u32::from(ret.ptr.size()))
.unwrap();
ret.store = ret
.externref_activations_table
.checked_add(u32::from(fields.pointer_size))
.checked_add(u32::from(ret.ptr.size()))
.unwrap();
ret.signature_ids = ret
.store
.checked_add(u32::from(fields.pointer_size * 2))
.checked_add(u32::from(ret.ptr.size() * 2))
.unwrap();
ret.imported_functions = ret
.signature_ids
@@ -257,7 +286,7 @@ impl From<VMOffsetsFields> for VMOffsets {
.builtin_functions
.checked_add(
BuiltinFunctionIndex::builtin_functions_total_number()
.checked_mul(u32::from(ret.pointer_size))
.checked_mul(u32::from(ret.pointer_size()))
.unwrap(),
)
.unwrap();
@@ -266,74 +295,73 @@ impl From<VMOffsetsFields> for VMOffsets {
}
}
/// Offsets for `VMFunctionImport`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// The offset of the `body` field.
#[allow(clippy::erasing_op)]
#[inline]
pub fn vmfunction_import_body(&self) -> u8 {
0 * self.pointer_size
0 * self.pointer_size()
}
/// The offset of the `vmctx` field.
#[allow(clippy::identity_op)]
#[inline]
pub fn vmfunction_import_vmctx(&self) -> u8 {
1 * self.pointer_size
1 * self.pointer_size()
}
/// Return the size of `VMFunctionImport`.
#[inline]
pub fn size_of_vmfunction_import(&self) -> u8 {
2 * self.pointer_size
2 * self.pointer_size()
}
}
/// Offsets for `*const VMFunctionBody`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// The size of the `current_elements` field.
#[allow(clippy::identity_op)]
pub fn size_of_vmfunction_body_ptr(&self) -> u8 {
1 * self.pointer_size
1 * self.pointer_size()
}
}
/// Offsets for `VMTableImport`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// The offset of the `from` field.
#[allow(clippy::erasing_op)]
#[inline]
pub fn vmtable_import_from(&self) -> u8 {
0 * self.pointer_size
0 * self.pointer_size()
}
/// The offset of the `vmctx` field.
#[allow(clippy::identity_op)]
#[inline]
pub fn vmtable_import_vmctx(&self) -> u8 {
1 * self.pointer_size
1 * self.pointer_size()
}
/// Return the size of `VMTableImport`.
#[inline]
pub fn size_of_vmtable_import(&self) -> u8 {
2 * self.pointer_size
2 * self.pointer_size()
}
}
/// Offsets for `VMTableDefinition`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// The offset of the `base` field.
#[allow(clippy::erasing_op)]
#[inline]
pub fn vmtable_definition_base(&self) -> u8 {
0 * self.pointer_size
0 * self.pointer_size()
}
/// The offset of the `current_elements` field.
#[allow(clippy::identity_op)]
pub fn vmtable_definition_current_elements(&self) -> u8 {
1 * self.pointer_size
1 * self.pointer_size()
}
/// The size of the `current_elements` field.
@@ -345,7 +373,7 @@ impl VMOffsets {
/// Return the size of `VMTableDefinition`.
#[inline]
pub fn size_of_vmtable_definition(&self) -> u8 {
2 * self.pointer_size
2 * self.pointer_size()
}
/// The type of the `current_elements` field.
@@ -356,42 +384,42 @@ impl VMOffsets {
}
/// Offsets for `VMMemoryImport`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// The offset of the `from` field.
#[allow(clippy::erasing_op)]
#[inline]
pub fn vmmemory_import_from(&self) -> u8 {
0 * self.pointer_size
0 * self.pointer_size()
}
/// The offset of the `vmctx` field.
#[allow(clippy::identity_op)]
#[inline]
pub fn vmmemory_import_vmctx(&self) -> u8 {
1 * self.pointer_size
1 * self.pointer_size()
}
/// Return the size of `VMMemoryImport`.
#[inline]
pub fn size_of_vmmemory_import(&self) -> u8 {
2 * self.pointer_size
2 * self.pointer_size()
}
}
/// Offsets for `VMMemoryDefinition`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// The offset of the `base` field.
#[allow(clippy::erasing_op)]
#[inline]
pub fn vmmemory_definition_base(&self) -> u8 {
0 * self.pointer_size
0 * self.pointer_size()
}
/// The offset of the `current_length` field.
#[allow(clippy::identity_op)]
#[inline]
pub fn vmmemory_definition_current_length(&self) -> u8 {
1 * self.pointer_size
1 * self.pointer_size()
}
/// The size of the `current_length` field.
@@ -403,7 +431,7 @@ impl VMOffsets {
/// Return the size of `VMMemoryDefinition`.
#[inline]
pub fn size_of_vmmemory_definition(&self) -> u8 {
2 * self.pointer_size
2 * self.pointer_size()
}
/// The type of the `current_length` field.
@@ -414,24 +442,24 @@ impl VMOffsets {
}
/// Offsets for `VMGlobalImport`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// The offset of the `from` field.
#[allow(clippy::erasing_op)]
#[inline]
pub fn vmglobal_import_from(&self) -> u8 {
0 * self.pointer_size
0 * self.pointer_size()
}
/// Return the size of `VMGlobalImport`.
#[allow(clippy::identity_op)]
#[inline]
pub fn size_of_vmglobal_import(&self) -> u8 {
1 * self.pointer_size
1 * self.pointer_size()
}
}
/// Offsets for `VMGlobalDefinition`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// Return the size of `VMGlobalDefinition`; this is the size of the largest value type (i.e. a
/// V128).
#[inline]
@@ -441,7 +469,7 @@ impl VMOffsets {
}
/// Offsets for `VMSharedSignatureIndex`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// Return the size of `VMSharedSignatureIndex`.
#[inline]
pub fn size_of_vmshared_signature_index(&self) -> u8 {
@@ -450,7 +478,7 @@ impl VMOffsets {
}
/// Offsets for `VMInterrupts`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// Return the offset of the `stack_limit` field of `VMInterrupts`
#[inline]
pub fn vminterrupts_stack_limit(&self) -> u8 {
@@ -460,41 +488,41 @@ impl VMOffsets {
/// Return the offset of the `fuel_consumed` field of `VMInterrupts`
#[inline]
pub fn vminterrupts_fuel_consumed(&self) -> u8 {
self.pointer_size
self.pointer_size()
}
}
/// Offsets for `VMCallerCheckedAnyfunc`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// The offset of the `func_ptr` field.
#[allow(clippy::erasing_op)]
#[inline]
pub fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
0 * self.pointer_size
0 * self.pointer_size()
}
/// The offset of the `type_index` field.
#[allow(clippy::identity_op)]
#[inline]
pub fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
1 * self.pointer_size
1 * self.pointer_size()
}
/// The offset of the `vmctx` field.
#[inline]
pub fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
2 * self.pointer_size
2 * self.pointer_size()
}
/// Return the size of `VMCallerCheckedAnyfunc`.
#[inline]
pub fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
3 * self.pointer_size
3 * self.pointer_size()
}
}
/// Offsets for `VMContext`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// Return the offset to the `VMInterrupts` structure
#[inline]
pub fn vmctx_interrupts(&self) -> u32 {
@@ -717,21 +745,21 @@ impl VMOffsets {
/// Return the offset to builtin function in `VMBuiltinFunctionsArray` index `index`.
#[inline]
pub fn vmctx_builtin_function(&self, index: BuiltinFunctionIndex) -> u32 {
self.vmctx_builtin_functions_begin() + index.index() * u32::from(self.pointer_size)
self.vmctx_builtin_functions_begin() + index.index() * u32::from(self.pointer_size())
}
}
/// Offsets for `VMExternData`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// Return the offset for `VMExternData::ref_count`.
#[inline]
pub fn vm_extern_data_ref_count() -> u32 {
pub fn vm_extern_data_ref_count(&self) -> u32 {
0
}
}
/// Offsets for `VMExternRefActivationsTable`.
impl VMOffsets {
impl<P: PtrSize> VMOffsets<P> {
/// Return the offset for `VMExternRefActivationsTable::next`.
#[inline]
pub fn vm_extern_ref_activation_table_next(&self) -> u32 {
@@ -741,7 +769,7 @@ impl VMOffsets {
/// Return the offset for `VMExternRefActivationsTable::end`.
#[inline]
pub fn vm_extern_ref_activation_table_end(&self) -> u32 {
self.pointer_size.into()
self.pointer_size().into()
}
}

View File

@@ -175,7 +175,7 @@ struct FuncEnvironment<'module_environment> {
module: &'module_environment Module,
/// Offsets to struct fields accessed by JIT code.
offsets: VMOffsets,
offsets: VMOffsets<u8>,
}
impl<'module_environment> FuncEnvironment<'module_environment> {

View File

@@ -965,8 +965,20 @@ mod tests {
let actual_offset = (ref_count_ptr as usize) - (extern_data_ptr as usize);
let offsets = wasmtime_environ::VMOffsets::from(wasmtime_environ::VMOffsetsFields {
ptr: 8,
num_signature_ids: 0,
num_imported_functions: 0,
num_imported_tables: 0,
num_imported_memories: 0,
num_imported_globals: 0,
num_defined_functions: 0,
num_defined_tables: 0,
num_defined_memories: 0,
num_defined_globals: 0,
});
assert_eq!(
wasmtime_environ::VMOffsets::vm_extern_data_ref_count(),
offsets.vm_extern_data_ref_count(),
actual_offset.try_into().unwrap(),
);
}
@@ -981,7 +993,7 @@ mod tests {
let actual_offset = (next_ptr as usize) - (table_ptr as usize);
let offsets = wasmtime_environ::VMOffsets::from(wasmtime_environ::VMOffsetsFields {
pointer_size: 8,
ptr: 8,
num_signature_ids: 0,
num_imported_functions: 0,
num_imported_tables: 0,
@@ -1008,7 +1020,7 @@ mod tests {
let actual_offset = (end_ptr as usize) - (table_ptr as usize);
let offsets = wasmtime_environ::VMOffsets::from(wasmtime_environ::VMOffsetsFields {
pointer_size: 8,
ptr: 8,
num_signature_ids: 0,
num_imported_functions: 0,
num_imported_tables: 0,

View File

@@ -27,7 +27,7 @@ use wasmtime_environ::wasm::{
DataIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, ElemIndex, EntityIndex,
FuncIndex, GlobalIndex, MemoryIndex, TableElementType, TableIndex, WasmType,
};
use wasmtime_environ::{ir, Module, VMOffsets};
use wasmtime_environ::{ir, HostPtr, Module, VMOffsets};
mod allocator;
@@ -119,7 +119,7 @@ pub(crate) struct Instance {
module: Arc<Module>,
/// Offsets in the `vmctx` region, precomputed from the `module` above.
offsets: VMOffsets,
offsets: VMOffsets<HostPtr>,
/// WebAssembly linear memory data.
///

View File

@@ -22,8 +22,8 @@ use wasmtime_environ::wasm::{
DefinedFuncIndex, DefinedMemoryIndex, DefinedTableIndex, GlobalInit, SignatureIndex, WasmType,
};
use wasmtime_environ::{
ir, MemoryInitialization, MemoryInitializer, Module, ModuleType, TableInitializer, VMOffsets,
WASM_PAGE_SIZE,
ir, HostPtr, MemoryInitialization, MemoryInitializer, Module, ModuleType, TableInitializer,
VMOffsets, WASM_PAGE_SIZE,
};
mod pooling;
@@ -643,7 +643,7 @@ unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
let mut handle = {
let instance = Instance {
module: req.module.clone(),
offsets: VMOffsets::new(std::mem::size_of::<*const u8>() as u8, &req.module),
offsets: VMOffsets::new(HostPtr, &req.module),
memories,
tables,
dropped_elements: EntitySet::with_capacity(req.module.passive_elements.len()),

View File

@@ -21,7 +21,7 @@ use std::mem;
use std::sync::{Arc, Mutex};
use wasmtime_environ::{
entity::{EntitySet, PrimaryMap},
MemoryStyle, Module, Tunables, VMOffsets, VMOffsetsFields, WASM_PAGE_SIZE,
HostPtr, MemoryStyle, Module, Tunables, VMOffsets, VMOffsetsFields, WASM_PAGE_SIZE,
};
cfg_if::cfg_if! {
@@ -298,7 +298,7 @@ impl InstancePool {
// Calculate the maximum size of an Instance structure given the limits
let offsets = VMOffsets::from(VMOffsetsFields {
pointer_size: std::mem::size_of::<*const u8>() as u8,
ptr: HostPtr,
num_signature_ids: module_limits.types,
num_imported_functions: module_limits.imported_functions,
num_imported_tables: module_limits.imported_tables,
@@ -358,10 +358,7 @@ impl InstancePool {
instance as _,
Instance {
module: self.empty_module.clone(),
offsets: VMOffsets::new(
std::mem::size_of::<*const u8>() as u8,
&self.empty_module,
),
offsets: VMOffsets::new(HostPtr, &self.empty_module),
memories: PrimaryMap::with_capacity(limits.memories as usize),
tables: PrimaryMap::with_capacity(limits.tables as usize),
dropped_elements: EntitySet::new(),
@@ -383,10 +380,7 @@ impl InstancePool {
let instance = self.instance(index);
instance.module = req.module.clone();
instance.offsets = VMOffsets::new(
std::mem::size_of::<*const u8>() as u8,
instance.module.as_ref(),
);
instance.offsets = VMOffsets::new(HostPtr, instance.module.as_ref());
instance.host_state = std::mem::replace(&mut req.host_state, Box::new(()));
let mut limiter = req.store.and_then(|s| (*s).limiter());
@@ -497,8 +491,7 @@ impl InstancePool {
// should put everything back in a relatively pristine state for each
// fresh allocation later on.
instance.module = self.empty_module.clone();
instance.offsets =
VMOffsets::new(std::mem::size_of::<*const u8>() as u8, &self.empty_module);
instance.offsets = VMOffsets::new(HostPtr, &self.empty_module);
self.free_list.lock().unwrap().push(index);
}