Crate wasm_bindgen_multi_value_xform[−][src]
Expand description
The wasm-bindgen
multi-value transformation.
This crate provides a transformation to turn exported functions that use a return pointer into exported functions that use multi-value.
Consider the following function:
#[no_mangle] pub extern "C" fn pair(a: u32, b: u32) -> [u32; 2] { [a, b] }
LLVM will by default compile this down into the following Wasm:
(func $pair (param i32 i32 i32) local.get 0 local.get 2 i32.store offset=4 local.get 0 local.get 1 i32.store)
What’s happening here is that the function is not directly returning the
pair at all, but instead the first i32
parameter is a pointer to some
scratch space, and the return value is written into the scratch space. LLVM
does this because it doesn’t yet have support for multi-value Wasm, and so
it only knows how to return a single value at a time.
Ideally, with multi-value, what we would like instead is this:
(func $pair (param i32 i32) (result i32 i32) local.get 0 local.get 1)
However, that’s not what this transformation does at the moment. This transformation is a little simpler than mutating existing functions to produce a multi-value result, instead it introduces new functions that wrap the original function and translate the return pointer to multi-value results in this wrapper function.
With our running example, we end up with this:
;; The original function. (func $pair (param i32 i32 i32) local.get 0 local.get 2 i32.store offset=4 local.get 0 local.get 1 i32.store) (func $pairWrapper (param i32 i32) (result i32 i32) ;; Our return pointer that points to the scratch space we are allocating ;; on the shadow stack for calling `$pair`. (local i32) ;; Allocate space on the shadow stack for the result. global.get $shadowStackPointer i32.const 8 i32.sub local.tee 2 global.set $shadowStackPointer ;; Call `$pair` with our allocated shadow stack space for its results. local.get 2 local.get 0 local.get 1 call $pair ;; Copy the return values from the shadow stack to the wasm stack. local.get 2 i32.load local.get 2 offset=4 i32.load ;; Finally, restore the shadow stack pointer. local.get 2 i32.const 8 i32.add global.set $shadowStackPointer)
This $pairWrapper
function is what we actually end up exporting instead of
$pair
.
Functions
Run the transformation.