Change wasm-to-host trampolines to take the values_vec size (#4192)
* Change wasm-to-host trampolines to take the values_vec size This commit changes the ABI of wasm-to-host trampolines, which are only used right now for functions created with `Func::new`, to pass along the size of the `values_vec` argument. Previously the trampoline simply received `*mut ValRaw` and assumed that it was the appropriate size. By receiving a size as well we can thread through `&mut [ValRaw]` internally instead of `*mut ValRaw`. The original motivation for this is that I'm planning to leverage these trampolines for the component model for host-defined functions. Out of an abundance of caution of making sure that everything lines up I wanted to be able to write down asserts about the size received at runtime compared to the size expected. This overall led me to the desire to thread this size parameter through on the assumption that it would not impact performance all that much. I ran two benchmarks locally from the `call.rs` benchmark and got: * `sync/no-hook/wasm-to-host - nop - unchecked` - no change * `sync/no-hook/wasm-to-host - nop-params-and-results - unchecked` - 5% slower This is what I roughly expected in that if nothing actually reads the new parameter (e.g. no arguments) then threading through the parameter is effectively otherwise free. Otherwise though accesses to the `ValRaw` storage is now bounds-checked internally in Wasmtime instead of assuming it's valid, leading to the 5% slowdown (~9.6ns to ~10.3ns). If this becomes a peformance bottleneck for a particular use case then we should be fine to remove the bounds checking here or otherwise only bounds check in debug mode, otherwise I plan on leaving this as-is. Of particular note this also changes the C API for `*_unchecked` functions where the C callback now receives the size of the array as well. * Add docs
This commit is contained in:
@@ -516,14 +516,18 @@ impl Compiler {
|
||||
let isa = &*self.isa;
|
||||
let pointer_type = isa.pointer_type();
|
||||
let wasm_signature = indirect_signature(isa, ty);
|
||||
// The host signature has an added parameter for the `values_vec` input
|
||||
// and output.
|
||||
let mut host_signature = blank_sig(isa, wasmtime_call_conv(isa));
|
||||
// The host signature has an added parameter for the `values_vec`
|
||||
// input/output buffer in addition to the size of the buffer, in units
|
||||
// of `ValRaw`.
|
||||
host_signature.params.push(ir::AbiParam::new(pointer_type));
|
||||
host_signature.params.push(ir::AbiParam::new(pointer_type));
|
||||
|
||||
// Compute the size of the values vector. The vmctx and caller vmctx are passed separately.
|
||||
let value_size = mem::size_of::<u128>();
|
||||
let values_vec_len = (value_size * cmp::max(ty.params().len(), ty.returns().len())) as u32;
|
||||
let values_vec_len = cmp::max(ty.params().len(), ty.returns().len());
|
||||
let values_vec_byte_size = u32::try_from(value_size * values_vec_len).unwrap();
|
||||
let values_vec_len = u32::try_from(values_vec_len).unwrap();
|
||||
|
||||
let CompilerContext {
|
||||
mut func_translator,
|
||||
@@ -535,7 +539,7 @@ impl Compiler {
|
||||
|
||||
let ss = context.func.create_stack_slot(ir::StackSlotData::new(
|
||||
ir::StackSlotKind::ExplicitSlot,
|
||||
values_vec_len,
|
||||
values_vec_byte_size,
|
||||
));
|
||||
|
||||
let mut builder = FunctionBuilder::new(&mut context.func, func_translator.context());
|
||||
@@ -559,7 +563,14 @@ impl Compiler {
|
||||
let vmctx_ptr_val = block_params[0];
|
||||
let caller_vmctx_ptr_val = block_params[1];
|
||||
|
||||
let callee_args = vec![vmctx_ptr_val, caller_vmctx_ptr_val, values_vec_ptr_val];
|
||||
let callee_args = vec![
|
||||
vmctx_ptr_val,
|
||||
caller_vmctx_ptr_val,
|
||||
values_vec_ptr_val,
|
||||
builder
|
||||
.ins()
|
||||
.iconst(pointer_type, i64::from(values_vec_len)),
|
||||
];
|
||||
|
||||
let new_sig = builder.import_signature(host_signature);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user