Introduce the `multi-value-xform` crate
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:
```rust
pub extern "C" fn pair(a: u32, b: u32) -> [u32; 2] {
[a, b]
}
```
LLVM will by default compile this down into the following Wasm:
```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:
```wasm
(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:
```wasm
;; 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`.
2019-09-09 14:00:04 -07:00
|
|
|
[package]
|
|
|
|
name = "wasm-bindgen-multi-value-xform"
|
2020-05-27 10:07:18 -05:00
|
|
|
version = "0.2.63"
|
Introduce the `multi-value-xform` crate
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:
```rust
pub extern "C" fn pair(a: u32, b: u32) -> [u32; 2] {
[a, b]
}
```
LLVM will by default compile this down into the following Wasm:
```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:
```wasm
(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:
```wasm
;; 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`.
2019-09-09 14:00:04 -07:00
|
|
|
authors = ["The wasm-bindgen Developers"]
|
|
|
|
license = "MIT/Apache-2.0"
|
|
|
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/multi-value-xform"
|
|
|
|
homepage = "https://rustwasm.github.io/wasm-bindgen/"
|
|
|
|
documentation = "https://docs.rs/wasm-bindgen-multi-value-xform"
|
|
|
|
description = """
|
|
|
|
Internal multi-value transformations for wasm-bindgen
|
|
|
|
"""
|
|
|
|
edition = "2018"
|
|
|
|
|
|
|
|
[dependencies]
|
2019-11-04 11:35:28 -06:00
|
|
|
anyhow = "1.0"
|
2020-05-18 09:36:30 -05:00
|
|
|
walrus = "0.17.0"
|
2019-12-03 11:16:44 -06:00
|
|
|
|
|
|
|
[dev-dependencies]
|
|
|
|
rayon = "1.0"
|
|
|
|
wasmprinter = "0.2"
|
2020-05-18 09:36:30 -05:00
|
|
|
wast = "17.0"
|
2019-12-03 11:16:44 -06:00
|
|
|
wat = "1.0"
|
|
|
|
|
|
|
|
[[test]]
|
|
|
|
name = "all"
|
|
|
|
harness = false
|