Alter invocation of functions to use 16-byte invocation arguments
This commit is contained in:
@@ -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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user