45 releases
0.2.95 | Oct 10, 2024 |
---|---|
0.2.93 | Aug 12, 2024 |
0.2.92 | Mar 4, 2024 |
0.2.89 | Nov 27, 2023 |
0.2.55 | Nov 19, 2019 |
#1461 in WebAssembly
139,899 downloads per month
Used in 37 crates
(via wasm-bindgen-cli-support)
26KB
409 lines
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 stack for calling `$pair`.
(local i32)
;; Allocate space on the stack for the result.
global.get $stackPointer
i32.const 8
i32.sub
local.tee 2
global.set $stackPointer
;; Call `$pair` with our allocated stack space for its results.
local.get 2
local.get 0
local.get 1
call $pair
;; Copy the return values from the stack to the Wasm stack.
local.get 2
i32.load
local.get 2 offset=4
i32.load
;; Finally, restore the stack pointer.
local.get 2
i32.const 8
i32.add
global.set $stackPointer)
This $pairWrapper
function is what we actually end up exporting instead of
$pair
.
Dependencies
~5.5MB
~114K SLoC