Alter invocation of functions to use 16-byte invocation arguments

This commit is contained in:
Andrew Brown
2019-08-14 16:14:53 -07:00
committed by Dan Gohman
parent 5bd422b429
commit fb1c473342
4 changed files with 83 additions and 15 deletions

View File

@@ -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 /// This class computes offsets to fields within `VMContext` and other
/// related structs that JIT code accesses directly. /// related structs that JIT code accesses directly.
pub struct VMOffsets { pub struct VMOffsets {
@@ -208,9 +213,10 @@ impl VMOffsets {
/// Offsets for `VMGlobalDefinition`. /// Offsets for `VMGlobalDefinition`.
impl VMOffsets { 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 { pub fn size_of_vmglobal_definition(&self) -> u8 {
8 16
} }
} }
@@ -324,13 +330,15 @@ impl VMOffsets {
/// The offset of the `globals` array. /// The offset of the `globals` array.
pub fn vmctx_globals_begin(&self) -> u32 { pub fn vmctx_globals_begin(&self) -> u32 {
self.vmctx_memories_begin() let offset = self
.vmctx_memories_begin()
.checked_add( .checked_add(
self.num_defined_memories self.num_defined_memories
.checked_mul(u32::from(self.size_of_vmmemory_definition())) .checked_mul(u32::from(self.size_of_vmmemory_definition()))
.unwrap(), .unwrap(),
) )
.unwrap() .unwrap();
align(offset, 16)
} }
/// The offset of the builtin functions array. /// The offset of the builtin functions array.
@@ -557,3 +565,19 @@ impl TargetSharedSignatureIndex {
self.0 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)));
}
}

View File

@@ -7,7 +7,7 @@ use core::{fmt, mem, ptr, slice};
use cranelift_codegen::ir; use cranelift_codegen::ir;
use std::string::String; use std::string::String;
use std::vec::Vec; use std::vec::Vec;
use wasmtime_runtime::{wasmtime_call_trampoline, Export, InstanceHandle}; use wasmtime_runtime::{wasmtime_call_trampoline, Export, InstanceHandle, VMInvokeArgument};
/// A runtime value. /// A runtime value.
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -161,12 +161,12 @@ pub fn invoke(
assert_eq!(value.value_type(), signature.params[index + 1].value_type); 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. // instead of just using fixed-sized slots.
// Subtract one becase we don't pass the vmctx argument in `values_vec`. // Subtract one becase we don't pass the vmctx argument in `values_vec`.
let value_size = mem::size_of::<u64>(); let value_size = mem::size_of::<VMInvokeArgument>();
let mut values_vec: Vec<u64> = let mut values_vec: Vec<VMInvokeArgument> =
vec![0; max(signature.params.len() - 1, signature.returns.len())]; vec![VMInvokeArgument::new(); max(signature.params.len() - 1, signature.returns.len())];
// Store the argument values into `values_vec`. // Store the argument values into `values_vec`.
for (index, arg) in args.iter().enumerate() { for (index, arg) in args.iter().enumerate() {

View File

@@ -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::traphandlers::{wasmtime_call, wasmtime_call_trampoline};
pub use crate::vmcontext::{ pub use crate::vmcontext::{
VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition,
VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMGlobalImport, VMInvokeArgument, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex,
VMTableImport, VMTableDefinition, VMTableImport,
}; };
/// Version number of this crate. /// Version number of this crate.

View File

@@ -250,10 +250,10 @@ mod test_vmtable_definition {
/// TODO: Pack the globals more densely, rather than using the same size /// TODO: Pack the globals more densely, rather than using the same size
/// for every type. /// for every type.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[repr(C, align(8))] #[repr(C, align(16))]
pub struct VMGlobalDefinition { pub struct VMGlobalDefinition {
storage: [u8; 8], // TODO this may need to be 16 storage: [u8; 16],
// If more elements are added here, remember to add offset_of tests below! // If more elements are added here, remember to add offset_of tests below!
} }
#[cfg(test)] #[cfg(test)]
@@ -268,6 +268,7 @@ mod test_vmglobal_definition {
assert!(align_of::<VMGlobalDefinition>() >= align_of::<i64>()); assert!(align_of::<VMGlobalDefinition>() >= align_of::<i64>());
assert!(align_of::<VMGlobalDefinition>() >= align_of::<f32>()); assert!(align_of::<VMGlobalDefinition>() >= align_of::<f32>());
assert!(align_of::<VMGlobalDefinition>() >= align_of::<f64>()); assert!(align_of::<VMGlobalDefinition>() >= align_of::<f64>());
assert!(align_of::<VMGlobalDefinition>() >= align_of::<[u8; 16]>());
} }
#[test] #[test]
@@ -279,12 +280,19 @@ mod test_vmglobal_definition {
usize::from(offsets.size_of_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 { impl VMGlobalDefinition {
/// Construct a `VMGlobalDefinition`. /// Construct a `VMGlobalDefinition`.
pub fn new() -> Self { pub fn new() -> Self {
Self { storage: [0; 8] } Self { storage: [0; 16] }
} }
/// Return a reference to the value as an i32. /// 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::<VMInvokeArgument>(), 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::<VMInvokeArgument>(),
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. /// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
/// This has information about globals, memories, tables, and other runtime /// This has information about globals, memories, tables, and other runtime
/// state associated with the current instance. /// state associated with the current instance.