diff --git a/wasmtime-environ/src/vmoffsets.rs b/wasmtime-environ/src/vmoffsets.rs index 100ce9cbe9..070a739660 100644 --- a/wasmtime-environ/src/vmoffsets.rs +++ b/wasmtime-environ/src/vmoffsets.rs @@ -22,6 +22,11 @@ fn cast_to_u32(sz: usize) -> u32 { } } +/// Align an offset used in this module to a specific byte-width by rounding up +fn align(offset: u32, width: u32) -> u32 { + (offset + (width - 1)) / width * width +} + /// This class computes offsets to fields within `VMContext` and other /// related structs that JIT code accesses directly. pub struct VMOffsets { @@ -208,9 +213,10 @@ impl VMOffsets { /// Offsets for `VMGlobalDefinition`. impl VMOffsets { - /// Return the size of `VMGlobalDefinition`. + /// Return the size of `VMGlobalDefinition`; this is the size of the largest value type (i.e. a + /// V128). pub fn size_of_vmglobal_definition(&self) -> u8 { - 8 + 16 } } @@ -324,13 +330,15 @@ impl VMOffsets { /// The offset of the `globals` array. pub fn vmctx_globals_begin(&self) -> u32 { - self.vmctx_memories_begin() + let offset = self + .vmctx_memories_begin() .checked_add( self.num_defined_memories .checked_mul(u32::from(self.size_of_vmmemory_definition())) .unwrap(), ) - .unwrap() + .unwrap(); + align(offset, 16) } /// The offset of the builtin functions array. @@ -557,3 +565,19 @@ impl TargetSharedSignatureIndex { self.0 } } + +#[cfg(test)] +mod tests { + use crate::vmoffsets::align; + + #[test] + fn alignment() { + fn is_aligned(x: u32) -> bool { + x % 16 == 0 + } + assert!(is_aligned(align(0, 16))); + assert!(is_aligned(align(32, 16))); + assert!(is_aligned(align(33, 16))); + assert!(is_aligned(align(31, 16))); + } +} diff --git a/wasmtime-jit/src/action.rs b/wasmtime-jit/src/action.rs index 0f87f168ab..301c01091a 100644 --- a/wasmtime-jit/src/action.rs +++ b/wasmtime-jit/src/action.rs @@ -7,7 +7,7 @@ use core::{fmt, mem, ptr, slice}; use cranelift_codegen::ir; use std::string::String; use std::vec::Vec; -use wasmtime_runtime::{wasmtime_call_trampoline, Export, InstanceHandle}; +use wasmtime_runtime::{wasmtime_call_trampoline, Export, InstanceHandle, VMInvokeArgument}; /// A runtime value. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -161,12 +161,12 @@ pub fn invoke( assert_eq!(value.value_type(), signature.params[index + 1].value_type); } - // TODO: Support values larger than u64. And pack the values into memory + // TODO: Support values larger than v128. And pack the values into memory // instead of just using fixed-sized slots. // Subtract one becase we don't pass the vmctx argument in `values_vec`. - let value_size = mem::size_of::(); - let mut values_vec: Vec = - vec![0; max(signature.params.len() - 1, signature.returns.len())]; + let value_size = mem::size_of::(); + let mut values_vec: Vec = + vec![VMInvokeArgument::new(); max(signature.params.len() - 1, signature.returns.len())]; // Store the argument values into `values_vec`. for (index, arg) in args.iter().enumerate() { diff --git a/wasmtime-runtime/src/lib.rs b/wasmtime-runtime/src/lib.rs index b3f394bfe6..ba11084596 100644 --- a/wasmtime-runtime/src/lib.rs +++ b/wasmtime-runtime/src/lib.rs @@ -55,8 +55,8 @@ pub use crate::trap_registry::{get_mut_trap_registry, get_trap_registry, TrapReg pub use crate::traphandlers::{wasmtime_call, wasmtime_call_trampoline}; pub use crate::vmcontext::{ VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition, - VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, - VMTableImport, + VMGlobalImport, VMInvokeArgument, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, + VMTableDefinition, VMTableImport, }; /// Version number of this crate. diff --git a/wasmtime-runtime/src/vmcontext.rs b/wasmtime-runtime/src/vmcontext.rs index 913d4c4890..df1842f0c8 100644 --- a/wasmtime-runtime/src/vmcontext.rs +++ b/wasmtime-runtime/src/vmcontext.rs @@ -250,10 +250,10 @@ mod test_vmtable_definition { /// TODO: Pack the globals more densely, rather than using the same size /// for every type. #[derive(Debug, Copy, Clone)] -#[repr(C, align(8))] +#[repr(C, align(16))] pub struct VMGlobalDefinition { - storage: [u8; 8], // TODO this may need to be 16 - // If more elements are added here, remember to add offset_of tests below! + storage: [u8; 16], + // If more elements are added here, remember to add offset_of tests below! } #[cfg(test)] @@ -268,6 +268,7 @@ mod test_vmglobal_definition { assert!(align_of::() >= align_of::()); assert!(align_of::() >= align_of::()); assert!(align_of::() >= align_of::()); + assert!(align_of::() >= align_of::<[u8; 16]>()); } #[test] @@ -279,12 +280,19 @@ mod test_vmglobal_definition { usize::from(offsets.size_of_vmglobal_definition()) ); } + + #[test] + fn check_vmglobal_begins_aligned() { + let module = Module::new(); + let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module); + assert_eq!(offsets.vmctx_globals_begin() % 16, 0); + } } impl VMGlobalDefinition { /// Construct a `VMGlobalDefinition`. pub fn new() -> Self { - Self { storage: [0; 8] } + Self { storage: [0; 16] } } /// Return a reference to the value as an i32. @@ -533,6 +541,42 @@ impl VMBuiltinFunctionsArray { } } +/// The storage for a WebAssembly invocation argument +/// +/// TODO: These could be packed more densely, rather than using the same size for every type. +#[derive(Debug, Copy, Clone)] +#[repr(C, align(16))] +pub struct VMInvokeArgument([u8; 16]); + +#[cfg(test)] +mod test_vm_invoke_argument { + use super::VMInvokeArgument; + use core::mem::{align_of, size_of}; + use wasmtime_environ::{Module, VMOffsets}; + + #[test] + fn check_vm_invoke_argument_alignment() { + assert_eq!(align_of::(), 16); + } + + #[test] + fn check_vmglobal_definition_offsets() { + let module = Module::new(); + let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module); + assert_eq!( + size_of::(), + usize::from(offsets.size_of_vmglobal_definition()) + ); + } +} + +impl VMInvokeArgument { + /// Create a new invocation argument filled with zeroes + pub fn new() -> Self { + VMInvokeArgument([0; 16]) + } +} + /// The VM "context", which is pointed to by the `vmctx` arg in Cranelift. /// This has information about globals, memories, tables, and other runtime /// state associated with the current instance.