diff --git a/.azure/install-llvm.yml b/.azure/install-llvm.yml
index 0a2a674b11a..5b01ee7b9d9 100644
--- a/.azure/install-llvm.yml
+++ b/.azure/install-llvm.yml
@@ -31,20 +31,21 @@ steps:
- bash: |
set -ex
- if [ -x "`command -v llvm-config`" ]; then
- echo `command -v cmake` `llvm-config --version` installed
- else
- curl -OL https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip
- 7z x llvm-8.0.0-install.zip
- LLVM_PATH=`pwd`/llvm-8.0.0-install
- LLVM_PATH_WIN=$SYSTEM_DEFAULTWORKINGDIRECTORY\\llvm-8.0.0-install
- echo "##vso[task.prependpath]$LLVM_PATH/bin"
- echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX]$LLVM_PATH_WIN"
- # chocolatey install cmake --installargs 'ADD_CMAKE_TO_PATH=System'
- fi
+ curl -OL https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip
+ 7z x llvm-8.0.0-install.zip
+ llvm=`pwd`/llvm-8.0.0-install
+ echo "##vso[task.prependpath]$llvm/bin"
+ echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX;]$llvm"
displayName: "Install LLVM (Windows)"
condition: eq(variables['Agent.OS'], 'Windows_NT')
+ # Just to make sure the paths and vars are set properly
+ - powershell: |
+ Write-Host "##vso[task.prependpath]$pwd/llvm-8.0.0-install/bin"
+ Write-Host "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX;]$pwd/llvm-8.0.0-install/"
+ displayName: Install LLVM (Windows)
+ condition: eq(variables['Agent.OS'], 'Windows_NT')
+
- bash: |
set -ex
env
diff --git a/.azure/install-rust.yml b/.azure/install-rust.yml
index 4a7a340c01a..243cb7bf9d7 100644
--- a/.azure/install-rust.yml
+++ b/.azure/install-rust.yml
@@ -6,6 +6,15 @@
# Wasm-bindgen template: https://github.com/rustwasm/wasm-bindgen/blob/master/ci/azure-install-rust.yml
steps:
+ # - bash: |
+ # set -ex
+ # brew install openssl@1.1 curl
+ # brew link openssl@1.1 --force
+ # echo "##vso[task.prependpath]/usr/local/opt/openssl/bin"
+ # echo "##vso[task.setvariable variable=LDFLAGS;]-L/usr/local/opt/openssl/lib"
+ # echo "##vso[task.setvariable variable=CPPFLAGS;]-I/usr/local/opt/openssl/include"
+ # displayName: "Fix Cargo SSL (macOS)"
+ # condition: eq(variables['Agent.OS'], 'Darwin')
- bash: |
set -ex
if [ -x "`command -v rustup`" ]; then
@@ -15,24 +24,24 @@ steps:
echo "##vso[task.prependpath]$HOME/.cargo/bin"
fi
displayName: "Install Rust (Linux, macOS)"
- condition: not(eq(variables['Agent.OS'], 'Windows_NT'))
+ condition: ne(variables['Agent.OS'], 'Windows_NT')
- - bash: |
- set -ex
- if [ -x "`command -v rustup`" ]; then
- echo `command -v rustup` `rustup -V` installed
- else
- choco install rust -y
- # curl -sSf -o rustup-init.exe https://win.rustup.rs
- # ./rustup-init.exe -y --default-toolchain $RUST_TOOLCHAIN
- # echo "##vso[task.prependpath]$USERPROFILE/.cargo/bin"
- fi
- displayName: "Install Rust (Windows)"
- condition: eq(variables['Agent.OS'], 'Windows_NT')
+ # - bash: |
+ # set -ex
+ # if [ -x "`command -v rustup`" ]; then
+ # echo `command -v rustup` `rustup -V` installed
+ # else
+ # choco install rust -y
+ # # curl -sSf -o rustup-init.exe https://win.rustup.rs
+ # # ./rustup-init.exe -y --default-toolchain $RUST_TOOLCHAIN
+ # # echo "##vso[task.prependpath]$USERPROFILE/.cargo/bin"
+ # fi
+ # displayName: "Install Rust (Windows)"
+ # condition: eq(variables['Agent.OS'], 'Windows_NT')
- bash: |
set -ex
- rustup update $RUST_TOOLCHAIN
+ rustup update --no-self-update $RUST_TOOLCHAIN
rustup default $RUST_TOOLCHAIN
rustc -Vv
diff --git a/.azure/install-sccache.yml b/.azure/install-sccache.yml
index dffbb13d335..fa46bf6b0b6 100644
--- a/.azure/install-sccache.yml
+++ b/.azure/install-sccache.yml
@@ -28,6 +28,7 @@ steps:
- bash: |
set -ex
env
+ mkdir -p $SCCACHE_DIR
SCCACHE_ERROR_LOG=`pwd`/sccache.log RUST_LOG=debug $RUSTC_WRAPPER --start-server
$RUSTC_WRAPPER -s
cat sccache.log
@@ -35,3 +36,9 @@ steps:
env:
SCCACHE_AZURE_CONNECTION_STRING: $(SCCACHE_AZURE_CONNECTION_STRING)
SCCACHE_AZURE_BLOB_CONTAINER: $(SCCACHE_AZURE_BLOB_CONTAINER)
+ SCCACHE_DIR: $(Pipeline.Workspace)/.sccache
+ - task: CacheBeta@0
+ inputs:
+ key: sccache | $(Agent.OS) | Cargo.lock
+ path: $(Pipeline.Workspace)/.sccache
+ displayName: Cache Cargo Target
diff --git a/Cargo.lock b/Cargo.lock
index ebcfbc88217..9746f992237 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -13,7 +13,7 @@ name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -40,7 +40,7 @@ version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -173,16 +173,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cbindgen"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -491,7 +491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -719,7 +719,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -764,7 +764,7 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -773,7 +773,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -873,7 +873,7 @@ dependencies = [
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -946,7 +946,7 @@ dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1009,7 +1009,7 @@ dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1095,7 +1095,7 @@ name = "remove_dir_all"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1325,7 +1325,7 @@ dependencies = [
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1359,7 +1359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1481,7 +1481,7 @@ version = "2.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1538,7 +1538,7 @@ dependencies = [
"wasmer-runtime-core 0.6.0",
"wasmer-win-exception-handler 0.6.0",
"wasmparser 0.35.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1610,6 +1610,7 @@ dependencies = [
name = "wasmer-llvm-backend"
version = "0.6.0"
dependencies = [
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"capstone 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1624,7 +1625,7 @@ dependencies = [
"wabt 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.6.0",
"wasmparser 0.35.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1666,7 +1667,7 @@ dependencies = [
name = "wasmer-runtime-c-api"
version = "0.6.0"
dependencies = [
- "cbindgen 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime 0.6.0",
"wasmer-runtime-core 0.6.0",
@@ -1697,7 +1698,7 @@ dependencies = [
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmparser 0.35.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1742,7 +1743,7 @@ dependencies = [
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.6.0",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1768,7 +1769,7 @@ dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.6.0",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1792,7 +1793,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1814,7 +1815,7 @@ name = "winapi-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1827,7 +1828,7 @@ name = "wincolor"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1839,7 +1840,7 @@ dependencies = [
"cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
@@ -1863,7 +1864,7 @@ dependencies = [
"checksum capstone-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fae25eddcb80e24f98c35952c37a91ff7f8d0f60dbbdafb9763e8d5cc566b8d7"
"checksum cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "097f5ce64ba566a83d9d914fd005de1e5937fdd57d8c5d99a7593040955d75a9"
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
-"checksum cbindgen 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7e19db9a3892c88c74cbbdcd218196068a928f1b60e736c448b13a1e81f277"
+"checksum cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd"
"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7"
"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
@@ -2024,7 +2025,7 @@ dependencies = [
"checksum wasmparser 0.35.3 (registry+https://github.com/rust-lang/crates.io-index)" = "099aaf77635ffad3d9ab57253c29b16a46e93755c3e54cfe33fb8cf4b54f760b"
"checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
-"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
+"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
diff --git a/Cargo.toml b/Cargo.toml
index 03e224abbec..bbd596087c7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -99,6 +99,7 @@ backend-singlepass = [
"wasmer-wasi-tests/singlepass"
]
wasi = ["wasmer-wasi"]
+managed = ["backend-singlepass", "wasmer-runtime-core/managed"]
# vfs = ["wasmer-runtime-abi"]
[[example]]
diff --git a/Makefile b/Makefile
index c5a357e6f52..007e89853b0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: spectests emtests clean build install lint precommit
+.PHONY: spectests emtests clean build install lint precommit docs
# Generate files
generate-spectests:
@@ -97,9 +97,11 @@ llvm: spectests-llvm emtests-llvm wasitests-llvm
capi:
cargo build --release
cargo build -p wasmer-runtime-c-api --release
+
+test-capi: capi
cargo test -p wasmer-runtime-c-api --release
-test-rest: capi
+test-rest:
cargo test --release --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-wasi --exclude wasmer-middleware-common --exclude wasmer-middleware-common-tests --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-wasi-tests --exclude wasmer-emscripten-tests
circleci-clean:
@@ -182,3 +184,6 @@ publish-release:
# must install graphviz for `dot`
dep-graph:
cargo deps --optional-deps --filter wasmer-wasi wasmer-wasi-tests wasmer-kernel-loader wasmer-dev-utils wasmer-llvm-backend wasmer-emscripten wasmer-emscripten-tests wasmer-runtime-core wasmer-runtime wasmer-middleware-common wasmer-middleware-common-tests wasmer-singlepass-backend wasmer-clif-backend wasmer --manifest-path Cargo.toml | dot -Tpng > wasmer_depgraph.png
+
+docs:
+ cargo doc --features=backend-singlepass,backend-llvm,wasi,managed
diff --git a/README.md b/README.md
index a023b1a2cea..e4fa07e059d 100644
--- a/README.md
+++ b/README.md
@@ -35,19 +35,19 @@ curl https://get.wasmer.io -sSfL | sh
Wasmer runtime can be used as a library embedded in different languages, so you can use WebAssembly anywhere:
-| | Language | Author(s) | Maintenance | Release |
-|-|-|-|-|-|
-|  | [**Rust**](https://github.com/wasmerio/wasmer-rust-example) | Wasmer | actively developed |   |
-|  | [**C/C++**](https://github.com/wasmerio/wasmer-c-api) | Wasmer | actively developed |   |
-|  | [**Python**](https://github.com/wasmerio/python-ext-wasm) | Wasmer | actively developed |   |
-|  | [**Go**](https://github.com/wasmerio/go-ext-wasm) | Wasmer | actively developed |   |
-|  | [**PHP**](https://github.com/wasmerio/php-ext-wasm) | Wasmer | actively developed |   |
-|  | [**Ruby**](https://github.com/wasmerio/ruby-ext-wasm) | Wasmer | actively developed |   |
-|  | [**Postgres**](https://github.com/wasmerio/postgres-ext-wasm) | Wasmer | actively developed |   |
-|  | [**C#/.Net**](https://github.com/migueldeicaza/WasmerSharp) | [Miguel de Icaza](https://github.com/migueldeicaza) | actively developed |   |
-|  | [**R**](https://github.com/dirkschumacher/wasmr) | [Dirk Schumacher](https://github.com/dirkschumacher) | actively developed |  |
-|  | [**Swift**](https://github.com/markmals/swift-ext-wasm) | [Mark Malström](https://github.com/markmals/) | passively maintened |  |
-| ❓ | [your language is missing?](https://github.com/wasmerio/wasmer/issues/new?assignees=&labels=%F0%9F%8E%89+enhancement&template=---feature-request.md&title=) | | |
+| | Language | Author(s) | Maintenance | Release | Stars |
+|-|-|-|-|-|-|
+|  | [**Rust**](https://github.com/wasmerio/wasmer-rust-example) | Wasmer | actively developed |  |  |
+|  | [**C/C++**](https://github.com/wasmerio/wasmer-c-api) | Wasmer | actively developed |  |  |
+|  | [**Python**](https://github.com/wasmerio/python-ext-wasm) | Wasmer | actively developed |  |  |
+|  | [**Go**](https://github.com/wasmerio/go-ext-wasm) | Wasmer | actively developed |  |  |
+|  | [**PHP**](https://github.com/wasmerio/php-ext-wasm) | Wasmer | actively developed |  |  |
+|  | [**Ruby**](https://github.com/wasmerio/ruby-ext-wasm) | Wasmer | actively developed |  |  |
+|  | [**Postgres**](https://github.com/wasmerio/postgres-ext-wasm) | Wasmer | actively developed |  |  |
+|  | [**C#/.Net**](https://github.com/migueldeicaza/WasmerSharp) | [Miguel de Icaza](https://github.com/migueldeicaza) | actively developed |  |  |
+|  | [**R**](https://github.com/dirkschumacher/wasmr) | [Dirk Schumacher](https://github.com/dirkschumacher) | actively developed | |  |
+|  | [**Swift**](https://github.com/markmals/swift-ext-wasm) | [Mark Malström](https://github.com/markmals/) | passively maintened | |  |
+| ❓ | [your language is missing?](https://github.com/wasmerio/wasmer/issues/new?assignees=&labels=%F0%9F%8E%89+enhancement&template=---feature-request.md&title=) | | | |
### Usage
@@ -177,7 +177,7 @@ nginx and Lua do not work on Windows - you can track the progress on [this issue
## Building
-[](https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html)
+[](https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html)
Wasmer is built with [Cargo](https://crates.io/), the Rust package manager.
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 9ae585715a1..aad922544fa 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -29,10 +29,14 @@ jobs:
matrix:
linux:
imageName: "ubuntu-16.04"
- rust_toolchain: nightly-2019-06-10
+ rust_toolchain: nightly-2019-08-15
mac:
imageName: "macos-10.14"
- rust_toolchain: nightly-2019-06-10
+ rust_toolchain: nightly-2019-08-15
+ # By default schannel checks revocation of certificates unlike some other SSL
+ # backends, but we've historically had problems on CI where a revocation
+ # server goes down presumably. See #43333 for more info
+ CARGO_HTTP_CHECK_REVOKE: false
windows:
imageName: "vs2017-win2016"
rust_toolchain: stable
@@ -43,9 +47,9 @@ jobs:
- checkout: self
submodules: true
- template: .azure/install-rust.yml
+ - template: .azure/install-llvm.yml
- template: .azure/install-sccache.yml
- template: .azure/install-cmake.yml
- - template: .azure/install-llvm.yml
- bash: make test
displayName: Tests (*nix)
condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT')))
@@ -55,17 +59,17 @@ jobs:
- job: Check
pool:
- vmImage: "macos-10.14"
+ vmImage: "ubuntu-16.04"
variables:
- rust_toolchain: nightly-2019-06-10
+ rust_toolchain: nightly-2019-08-15
condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying')
steps:
- checkout: self
submodules: true
- template: .azure/install-rust.yml
+ - template: .azure/install-llvm.yml
- template: .azure/install-sccache.yml
- template: .azure/install-cmake.yml
- - template: .azure/install-llvm.yml
- bash: make check
displayName: Check with Flags
condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT')))
@@ -75,10 +79,10 @@ jobs:
matrix:
linux:
imageName: "ubuntu-16.04"
- rust_toolchain: nightly-2019-06-10
+ rust_toolchain: nightly-2019-08-15
mac:
imageName: "macos-10.14"
- rust_toolchain: nightly-2019-06-10
+ rust_toolchain: nightly-2019-08-15
MACOSX_DEPLOYMENT_TARGET: 10.10
windows:
imageName: "vs2017-win2016"
@@ -91,10 +95,10 @@ jobs:
- checkout: self
submodules: true
- template: .azure/install-rust.yml
+ - template: .azure/install-llvm.yml
- template: .azure/install-sccache.yml
- template: .azure/install-cmake.yml
- template: .azure/install-innosetup.yml
- - template: .azure/install-llvm.yml
- bash: |
mkdir -p artifacts
displayName: Create Artifacts Dir
@@ -116,6 +120,7 @@ jobs:
condition: |
and(
succeeded(),
+ eq(variables['Build.SourceBranch'], 'refs/heads/master'),
not(eq(variables['Agent.OS'], 'Windows_NT'))
)
- bash: |
@@ -137,10 +142,10 @@ jobs:
matrix:
linux:
imageName: "ubuntu-16.04"
- rust_toolchain: nightly-2019-06-10
+ rust_toolchain: nightly-2019-08-15
mac:
imageName: "macos-10.14"
- rust_toolchain: nightly-2019-06-10
+ rust_toolchain: nightly-2019-08-15
MACOSX_DEPLOYMENT_TARGET: 10.10
windows:
imageName: "vs2017-win2016"
@@ -153,26 +158,29 @@ jobs:
- checkout: self
submodules: true
- template: .azure/install-rust.yml
+ # - template: .azure/install-llvm.yml
- template: .azure/install-sccache.yml
- template: .azure/install-cmake.yml
- # - template: .azure/install-llvm.yml
- bash: |
mkdir -p artifacts
displayName: Create Artifacts Dir
- bash: |
make capi
+ make test-capi
cp target/release/libwasmer_runtime_c_api.so ./artifacts
displayName: Build c-api (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- bash: |
make capi
+ make test-capi
install_name_tool -id "@rpath/libwasmer_runtime_c_api.dylib" target/release/libwasmer_runtime_c_api.dylib
cp target/release/libwasmer_runtime_c_api.dylib ./artifacts
displayName: Build c-api (Darwin)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
- bash: |
- cargo build --release
- cargo build -p wasmer-runtime-c-api --release
+ make capi
+ # Tests are failing on Windows, comment for now
+ # make test-capi
cp target/release/wasmer_runtime_c_api.dll ./artifacts
displayName: Build c-api (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
@@ -203,6 +211,22 @@ jobs:
tag: dev
assets: $(Build.ArtifactStagingDirectory)
+ - job: Docs
+ pool:
+ vmImage: "ubuntu-16.04"
+ variables:
+ rust_toolchain: nightly-2019-08-15
+ steps:
+ - checkout: self
+ submodules: true
+ - template: .azure/install-rust.yml
+ - template: .azure/install-llvm.yml
+ - template: .azure/install-sccache.yml
+ - template: .azure/install-cmake.yml
+ - bash: |
+ make docs
+ displayName: Build documentation
+
# We only run the pipelines on PRs to Master
pr:
- master
diff --git a/docs/debugging.md b/docs/debugging.md
new file mode 100644
index 00000000000..8d49d52175b
--- /dev/null
+++ b/docs/debugging.md
@@ -0,0 +1,50 @@
+# Debugging Wasmer
+
+## When is this document useful?
+
+If you're developing wasmer or running into issues, this document will explain to useful techniques and common errors.
+
+## Tracing syscalls
+
+To trace syscalls, compile with the `debug` feature (`cargo build --features "debug"`). For even more verbose messages, use the `trace` flag.
+
+## Tracing calls
+
+TODO: did we disable tracing calls? if not talk about how to enable it
+TODO: someone with more context on the backends mention which backends this works for
+
+If you'd like to see all calls and you're using emscripten, you can use a symbol map to get better error output with the `em-symbol-map` flag.
+
+## Common things that can go wrong
+
+### Missing imports
+
+If, when attempting to run a wasm module, you get an error about missing imports there are a number of things that could be going wrong.
+
+The most likely is that we haven't implemented those imports for your ABI. If you're targeting emscripten, this is probably the issue.
+
+However if that's not the case, then there's a chance that you're using an unsupported ABI (let us know!) or that the wasm is invalid for the detected ABI. (TODO: link to wasm contracts or something)
+
+### Hitting `undefined`
+
+If this happens it's because wasmer does not have full support for whatever feature you tried to use. Running with tracing on can help clarify the issue if it's not clear from the message.
+
+To fix this, file an issue letting us know that wasmer is missing a feature that's important to you. If you'd like, you can try to implement it yourself and send us a PR.
+
+### No output
+
+If you're seeing no output from running the wasm module then it may be that:
+- this is the intended behavior of the wasm module
+- or it's very slow to compile (try compiling with a faster backend like cranelift (the default) or singlepass (requires nightly))
+
+### Segfault
+
+If you're seeing a segfault while developing wasmer, chances are that it's a cache issue. We reset the cache on every version bump, but if you're running it from source then the cache may become invalid, which can lead to segfaults.
+
+To fix this delete the cache with `wasmer cache clean` or run the command with the `disable-cache` flag (`wasmer run some.wasm --disable-cache`)
+
+If you're seeing a segfault with a released version of wasmer, please file an issue so we can ship an updated version as soon as possible.
+
+### Something else
+
+If none of this has helped with your issue, let us know and we'll do our best to help.
diff --git a/examples/iterative_hash/src/main.rs b/examples/iterative_hash/src/main.rs
index f25672047f4..043bc02a1d4 100644
--- a/examples/iterative_hash/src/main.rs
+++ b/examples/iterative_hash/src/main.rs
@@ -1,7 +1,13 @@
use blake2::{Blake2b, Digest};
+use std::time::{Duration, SystemTime};
fn main() {
let mut data: Vec = b"test".to_vec();
+ let now = SystemTime::now();
+
+ let mut last_millis: u128 = 0;
+ let mut round_count: usize = 0;
+ let mut record_count: usize = 0;
for i in 0.. {
let mut hasher = Blake2b::new();
@@ -9,8 +15,15 @@ fn main() {
let out = hasher.result();
data = out.to_vec();
- if i % 1000000 == 0 {
- println!("Round {}: {:?}", i, data);
+ if i != 0 && i % 1000 == 0 {
+ let millis = now.elapsed().unwrap().as_millis();
+ let diff = millis - last_millis;
+ if diff >= 100 {
+ record_count += 1;
+ println!("{}", (i - round_count) as f64 / diff as f64);
+ last_millis = millis;
+ round_count = i;
+ }
}
}
}
diff --git a/examples/many_params.wat b/examples/many_params.wat
new file mode 100644
index 00000000000..db5e4bb9be6
--- /dev/null
+++ b/examples/many_params.wat
@@ -0,0 +1,57 @@
+;; Test case for correctness of reading state with the presence of parameters passed on (machine) stack.
+;; Usage: Run with a backend with support for OSR. Interrupt execution randomly.
+;; Should see the stack frame for `$foo` to have locals `[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7, [7] = 8` with high probability.
+;; If the logic for reading stack parameters is broken, it's likely to see `[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = ?, [6] = ?, [7] = ?`.
+
+(module
+ (import "wasi_unstable" "proc_exit" (func $__wasi_proc_exit (param i32)))
+ (func $long_running
+ (local $count i32)
+ (loop
+ (if (i32.eq (get_local $count) (i32.const 1000000)) (then (return)))
+ (set_local $count (i32.add (i32.const 1) (get_local $count)))
+ (br 0)
+ )
+ (unreachable)
+ )
+
+ (func $foo (param i32) (param i64) (param i32) (param i32) (param i32) (param i64) (param i64) (param i64) (result i32)
+ (set_local 2 (i32.const 3))
+ (call $long_running)
+ (i32.add
+ (i32.mul (i32.const 2) (get_local 0))
+ (i32.add
+ (i32.mul (i32.const 3) (i32.wrap/i64 (get_local 1)))
+ (i32.add
+ (i32.mul (i32.const 5) (get_local 2))
+ (i32.add
+ (i32.mul (i32.const 7) (get_local 3))
+ (i32.add
+ (i32.mul (i32.const 11) (get_local 4))
+ (i32.add
+ (i32.mul (i32.const 13) (i32.wrap/i64 (get_local 5)))
+ (i32.add
+ (i32.mul (i32.const 17) (i32.wrap/i64 (get_local 6)))
+ (i32.mul (i32.const 19) (i32.wrap/i64 (get_local 7)))
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ (func $_start (export "_start")
+ (local $count i32)
+ (loop
+ (if (i32.eq (get_local $count) (i32.const 10000)) (then (return)))
+ (set_local $count (i32.add (i32.const 1) (get_local $count)))
+ (call $foo (i32.const 1) (i64.const 2) (i32.const 30) (i32.const 4) (i32.const 5) (i64.const 6) (i64.const 7) (i64.const 8))
+ (if (i32.ne (i32.const 455))
+ (then unreachable)
+ )
+ (br 0)
+ )
+ (unreachable)
+ )
+)
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 5c37cb47ed3..229a36e7f89 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -10,6 +10,8 @@ cargo-fuzz = true
[dependencies]
wasmer-runtime = { path = "../lib/runtime" }
+wasmer-runtime-core = { path = "../lib/runtime-core" }
+wasmer = { path = "../" }
libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" }
# Prevent this from interfering with workspaces
@@ -19,3 +21,7 @@ members = ["."]
[[bin]]
name = "simple_instantiate"
path = "fuzz_targets/simple_instantiate.rs"
+
+[[bin]]
+name = "validate_wasm"
+path = "fuzz_targets/validate_wasm.rs"
diff --git a/fuzz/README.md b/fuzz/README.md
index cac0a320a54..dda80ce7a6c 100644
--- a/fuzz/README.md
+++ b/fuzz/README.md
@@ -10,12 +10,16 @@ $ cargo install cargo-fuzz
`cargo-fuzz` is documented in the [Rust Fuzz Book](https://rust-fuzz.github.io/book/cargo-fuzz.html).
-## Running a fuzzer
+## Running a fuzzer (simple_instantiate, validate_wasm)
Once `cargo-fuzz` is installed, you can run the `simple_instantiate` fuzzer with
```sh
cargo fuzz run simple_instantiate
```
+or the `validate_wasm` fuzzer
+```sh
+cargo fuzz run validate_wasm
+```
You should see output that looks something like this:
diff --git a/fuzz/fuzz_targets/simple_instantiate.rs b/fuzz/fuzz_targets/simple_instantiate.rs
index 831bbb1a510..e4912546da6 100644
--- a/fuzz/fuzz_targets/simple_instantiate.rs
+++ b/fuzz/fuzz_targets/simple_instantiate.rs
@@ -1,11 +1,9 @@
#![no_main]
-#[macro_use] extern crate libfuzzer_sys;
+#[macro_use]
+extern crate libfuzzer_sys;
extern crate wasmer_runtime;
-use wasmer_runtime::{
- instantiate,
- imports,
-};
+use wasmer_runtime::{imports, instantiate};
fuzz_target!(|data: &[u8]| {
let import_object = imports! {};
diff --git a/fuzz/fuzz_targets/validate_wasm.rs b/fuzz/fuzz_targets/validate_wasm.rs
new file mode 100644
index 00000000000..f386105eccf
--- /dev/null
+++ b/fuzz/fuzz_targets/validate_wasm.rs
@@ -0,0 +1,20 @@
+#![no_main]
+#[macro_use]
+extern crate libfuzzer_sys;
+
+extern crate wasmer;
+extern crate wasmer_runtime_core;
+
+use wasmer_runtime_core::backend::Features;
+
+fuzz_target!(|data: &[u8]| {
+ let _ = wasmer::utils::is_wasm_binary(data);
+ let _ = wasmer_runtime_core::validate_and_report_errors_with_features(
+ &data,
+ Features {
+ // Modify these values to explore additional parts of wasmer.
+ simd: false,
+ threads: false,
+ },
+ );
+});
diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml
index d0bf64d7b5b..a07c86899e2 100644
--- a/lib/clif-backend/Cargo.toml
+++ b/lib/clif-backend/Cargo.toml
@@ -34,7 +34,7 @@ version = "0.11.2"
version = "0.0.7"
[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3.7", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
+winapi = { version = "0.3.8", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.6.0" }
[features]
diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs
index eed22d39ea7..60f19a877ed 100644
--- a/lib/clif-backend/src/lib.rs
+++ b/lib/clif-backend/src/lib.rs
@@ -7,6 +7,9 @@
unused_unsafe,
unreachable_patterns
)]
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
+
mod cache;
mod code;
mod libcalls;
diff --git a/lib/dev-utils/src/lib.rs b/lib/dev-utils/src/lib.rs
index 76ae6804fc7..2a470bba40d 100644
--- a/lib/dev-utils/src/lib.rs
+++ b/lib/dev-utils/src/lib.rs
@@ -1,2 +1,5 @@
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
+
pub mod file_descriptor;
pub mod stdio;
diff --git a/lib/emscripten-tests/emtests/ignores.txt b/lib/emscripten-tests/emtests/ignores.txt
index 16ff1a2a7f6..af8f21b0037 100644
--- a/lib/emscripten-tests/emtests/ignores.txt
+++ b/lib/emscripten-tests/emtests/ignores.txt
@@ -29,6 +29,7 @@ test_i16_emcc_intrinsic
test_i64
test_i64_7z
test_i64_varargs
+test_indirectbr_many
test_llvm_intrinsics
test_longjmp_exc
test_lower_intrinsics
diff --git a/lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs b/lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs
index fba25e6b20e..a96fe213816 100644
--- a/lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs
+++ b/lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs
@@ -1,4 +1,5 @@
#[test]
+#[ignore]
fn test_test_indirectbr_many() {
assert_emscripten_output!(
"../../emtests/test_indirectbr_many.wasm",
diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs
index c09f9b772c3..ba25b4be82a 100644
--- a/lib/emscripten/src/lib.rs
+++ b/lib/emscripten/src/lib.rs
@@ -7,6 +7,9 @@
unused_unsafe,
unreachable_patterns
)]
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
+
#[macro_use]
extern crate wasmer_runtime_core;
diff --git a/lib/kernel-loader/src/lib.rs b/lib/kernel-loader/src/lib.rs
index 51ca6c7da54..37f51a424ce 100644
--- a/lib/kernel-loader/src/lib.rs
+++ b/lib/kernel-loader/src/lib.rs
@@ -1,3 +1,6 @@
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
+
pub mod service;
use service::{ImportInfo, LoadProfile, RunProfile, ServiceContext, TableEntryRequest};
diff --git a/lib/kernel-net/src/lib.rs b/lib/kernel-net/src/lib.rs
index 4686867a7ce..cc6f918204b 100644
--- a/lib/kernel-net/src/lib.rs
+++ b/lib/kernel-net/src/lib.rs
@@ -1,5 +1,7 @@
#![cfg(all(target_arch = "wasm32", target_os = "wasi"))]
#![feature(wasi_ext)]
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
use std::cell::RefCell;
use std::fs::File;
diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml
index 886df698bfc..56adae97b4d 100644
--- a/lib/llvm-backend/Cargo.toml
+++ b/lib/llvm-backend/Cargo.toml
@@ -12,6 +12,7 @@ smallvec = "0.6.10"
goblin = "0.0.24"
libc = "0.2.60"
capstone = { version = "0.6.0", optional = true }
+byteorder = "1"
[dependencies.inkwell]
git = "https://github.com/wasmerio/inkwell"
@@ -23,7 +24,7 @@ features = ["llvm8-0", "target-x86"]
nix = "0.15.0"
[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3.7", features = ["memoryapi"] }
+winapi = { version = "0.3.8", features = ["memoryapi"] }
[build-dependencies]
cc = "1.0"
diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp
index bf034a30875..c4fc6d93628 100644
--- a/lib/llvm-backend/cpp/object_loader.cpp
+++ b/lib/llvm-backend/cpp/object_loader.cpp
@@ -1,161 +1,196 @@
#include "object_loader.hh"
#include
#include
+#include
extern "C" void __register_frame(uint8_t *);
extern "C" void __deregister_frame(uint8_t *);
-struct MemoryManager : llvm::RuntimeDyld::MemoryManager {
-public:
- MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
-
- virtual ~MemoryManager() override {
- deregisterEHFrames();
- // Deallocate all of the allocated memory.
- callbacks.dealloc_memory(code_section.base, code_section.size);
- callbacks.dealloc_memory(read_section.base, read_section.size);
- callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size);
+MemoryManager::~MemoryManager() {
+ deregisterEHFrames();
+ // Deallocate all of the allocated memory.
+ callbacks.dealloc_memory(code_section.base, code_section.size);
+ callbacks.dealloc_memory(read_section.base, read_section.size);
+ callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size);
+}
+void unwinding_setjmp(jmp_buf stack_out, void (*func)(void *), void *userdata) {
+ if (setjmp(stack_out)) {
+
+ } else {
+ func(userdata);
}
+}
+
+[[noreturn]] void unwinding_longjmp(jmp_buf stack_in) { longjmp(stack_in, 42); }
+
+struct UnwindPoint {
+ UnwindPoint *prev;
+ jmp_buf stack;
+ std::function *f;
+ std::unique_ptr exception;
+};
+
+static thread_local UnwindPoint *unwind_state = nullptr;
+
+static void unwind_payload(void *_point) {
+ UnwindPoint *point = (UnwindPoint *)_point;
+ (*point->f)();
+}
- virtual uint8_t *allocateCodeSection(uintptr_t size, unsigned alignment,
- unsigned section_id,
- llvm::StringRef section_name) override {
- return allocate_bump(code_section, code_bump_ptr, size, alignment);
+void catch_unwind(std::function &&f) {
+ UnwindPoint current;
+ current.prev = unwind_state;
+ current.f = &f;
+ unwind_state = ¤t;
+
+ unwinding_setjmp(current.stack, unwind_payload, (void *)¤t);
+
+ unwind_state = current.prev;
+ if (current.exception) {
+ throw std::move(current.exception);
}
+}
- virtual uint8_t *allocateDataSection(uintptr_t size, unsigned alignment,
- unsigned section_id,
- llvm::StringRef section_name,
- bool read_only) override {
- // Allocate from the read-only section or the read-write section, depending
- // on if this allocation should be read-only or not.
- if (read_only) {
- return allocate_bump(read_section, read_bump_ptr, size, alignment);
- } else {
- return allocate_bump(readwrite_section, readwrite_bump_ptr, size,
- alignment);
- }
+void unsafe_unwind(WasmException *exception) {
+ UnwindPoint *state = unwind_state;
+ if (state) {
+ state->exception.reset(exception);
+ unwinding_longjmp(state->stack);
+ } else {
+ abort();
}
+}
- virtual void reserveAllocationSpace(uintptr_t code_size, uint32_t code_align,
- uintptr_t read_data_size,
- uint32_t read_data_align,
- uintptr_t read_write_data_size,
- uint32_t read_write_data_align) override {
- auto aligner = [](uintptr_t ptr, size_t align) {
- if (ptr == 0) {
- return align;
- }
- return (ptr + align - 1) & ~(align - 1);
- };
-
- uint8_t *code_ptr_out = nullptr;
- size_t code_size_out = 0;
- auto code_result =
- callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE,
- &code_ptr_out, &code_size_out);
- assert(code_result == RESULT_OK);
- code_section = Section{code_ptr_out, code_size_out};
- code_bump_ptr = (uintptr_t)code_ptr_out;
-
- uint8_t *read_ptr_out = nullptr;
- size_t read_size_out = 0;
- auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096),
- PROTECT_READ_WRITE, &read_ptr_out,
- &read_size_out);
- assert(read_result == RESULT_OK);
- read_section = Section{read_ptr_out, read_size_out};
- read_bump_ptr = (uintptr_t)read_ptr_out;
-
- uint8_t *readwrite_ptr_out = nullptr;
- size_t readwrite_size_out = 0;
- auto readwrite_result = callbacks.alloc_memory(
- aligner(read_write_data_size, 4096), PROTECT_READ_WRITE,
- &readwrite_ptr_out, &readwrite_size_out);
- assert(readwrite_result == RESULT_OK);
- readwrite_section = Section{readwrite_ptr_out, readwrite_size_out};
- readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out;
+uint8_t *MemoryManager::allocateCodeSection(uintptr_t size, unsigned alignment,
+ unsigned section_id,
+ llvm::StringRef section_name) {
+ return allocate_bump(code_section, code_bump_ptr, size, alignment);
+}
+
+uint8_t *MemoryManager::allocateDataSection(uintptr_t size, unsigned alignment,
+ unsigned section_id,
+ llvm::StringRef section_name,
+ bool read_only) {
+ // Allocate from the read-only section or the read-write section, depending
+ // on if this allocation should be read-only or not.
+ uint8_t *ret;
+ if (read_only) {
+ ret = allocate_bump(read_section, read_bump_ptr, size, alignment);
+ } else {
+ ret = allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment);
+ }
+ if (section_name.equals(llvm::StringRef("__llvm_stackmaps")) ||
+ section_name.equals(llvm::StringRef(".llvm_stackmaps"))) {
+ stack_map_ptr = ret;
+ stack_map_size = size;
}
+ return ret;
+}
- /* Turn on the `reserveAllocationSpace` callback. */
- virtual bool needsToReserveAllocationSpace() override { return true; }
+void MemoryManager::reserveAllocationSpace(uintptr_t code_size,
+ uint32_t code_align,
+ uintptr_t read_data_size,
+ uint32_t read_data_align,
+ uintptr_t read_write_data_size,
+ uint32_t read_write_data_align) {
+ auto aligner = [](uintptr_t ptr, size_t align) {
+ if (ptr == 0) {
+ return align;
+ }
+ return (ptr + align - 1) & ~(align - 1);
+ };
+ uint8_t *code_ptr_out = nullptr;
+ size_t code_size_out = 0;
+ auto code_result =
+ callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE,
+ &code_ptr_out, &code_size_out);
+ assert(code_result == RESULT_OK);
+ code_section = Section{code_ptr_out, code_size_out};
+ code_bump_ptr = (uintptr_t)code_ptr_out;
+ code_start_ptr = (uintptr_t)code_ptr_out;
+ this->code_size = code_size;
+
+ uint8_t *read_ptr_out = nullptr;
+ size_t read_size_out = 0;
+ auto read_result =
+ callbacks.alloc_memory(aligner(read_data_size, 4096), PROTECT_READ_WRITE,
+ &read_ptr_out, &read_size_out);
+ assert(read_result == RESULT_OK);
+ read_section = Section{read_ptr_out, read_size_out};
+ read_bump_ptr = (uintptr_t)read_ptr_out;
+
+ uint8_t *readwrite_ptr_out = nullptr;
+ size_t readwrite_size_out = 0;
+ auto readwrite_result = callbacks.alloc_memory(
+ aligner(read_write_data_size, 4096), PROTECT_READ_WRITE,
+ &readwrite_ptr_out, &readwrite_size_out);
+ assert(readwrite_result == RESULT_OK);
+ readwrite_section = Section{readwrite_ptr_out, readwrite_size_out};
+ readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out;
+}
- virtual void registerEHFrames(uint8_t *addr, uint64_t LoadAddr,
- size_t size) override {
+bool MemoryManager::needsToReserveAllocationSpace() { return true; }
+
+void MemoryManager::registerEHFrames(uint8_t *addr, uint64_t LoadAddr,
+ size_t size) {
// We don't know yet how to do this on Windows, so we hide this on compilation
// so we can compile and pass spectests on unix systems
#ifndef _WIN32
- eh_frame_ptr = addr;
- eh_frame_size = size;
- eh_frames_registered = true;
- callbacks.visit_fde(addr, size, __register_frame);
+ eh_frame_ptr = addr;
+ eh_frame_size = size;
+ eh_frames_registered = true;
+ callbacks.visit_fde(addr, size, __register_frame);
#endif
- }
+}
- virtual void deregisterEHFrames() override {
+void MemoryManager::deregisterEHFrames() {
// We don't know yet how to do this on Windows, so we hide this on compilation
// so we can compile and pass spectests on unix systems
#ifndef _WIN32
- if (eh_frames_registered) {
- callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame);
- }
-#endif
+ if (eh_frames_registered) {
+ callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame);
}
+#endif
+}
- virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {
- auto code_result =
- callbacks.protect_memory(code_section.base, code_section.size,
- mem_protect_t::PROTECT_READ_EXECUTE);
- if (code_result != RESULT_OK) {
- return false;
- }
-
- auto read_result = callbacks.protect_memory(
- read_section.base, read_section.size, mem_protect_t::PROTECT_READ);
- if (read_result != RESULT_OK) {
- return false;
- }
-
- // The readwrite section is already mapped as read-write.
-
+bool MemoryManager::finalizeMemory(std::string *ErrMsg) {
+ auto code_result =
+ callbacks.protect_memory(code_section.base, code_section.size,
+ mem_protect_t::PROTECT_READ_EXECUTE);
+ if (code_result != RESULT_OK) {
return false;
}
- virtual void
- notifyObjectLoaded(llvm::RuntimeDyld &RTDyld,
- const llvm::object::ObjectFile &Obj) override {}
+ auto read_result = callbacks.protect_memory(
+ read_section.base, read_section.size, mem_protect_t::PROTECT_READ);
+ if (read_result != RESULT_OK) {
+ return false;
+ }
-private:
- struct Section {
- uint8_t *base;
- size_t size;
- };
+ // The readwrite section is already mapped as read-write.
- uint8_t *allocate_bump(Section §ion, uintptr_t &bump_ptr, size_t size,
- size_t align) {
- auto aligner = [](uintptr_t &ptr, size_t align) {
- ptr = (ptr + align - 1) & ~(align - 1);
- };
+ return false;
+}
- // Align the bump pointer to the requires alignment.
- aligner(bump_ptr, align);
+void MemoryManager::notifyObjectLoaded(llvm::RuntimeDyld &RTDyld,
+ const llvm::object::ObjectFile &Obj) {}
- auto ret_ptr = bump_ptr;
- bump_ptr += size;
+uint8_t *MemoryManager::allocate_bump(Section §ion, uintptr_t &bump_ptr,
+ size_t size, size_t align) {
+ auto aligner = [](uintptr_t &ptr, size_t align) {
+ ptr = (ptr + align - 1) & ~(align - 1);
+ };
- assert(bump_ptr <= (uintptr_t)section.base + section.size);
+ // Align the bump pointer to the requires alignment.
+ aligner(bump_ptr, align);
- return (uint8_t *)ret_ptr;
- }
+ auto ret_ptr = bump_ptr;
+ bump_ptr += size;
- Section code_section, read_section, readwrite_section;
- uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr;
- uint8_t *eh_frame_ptr;
- size_t eh_frame_size;
- bool eh_frames_registered = false;
+ assert(bump_ptr <= (uintptr_t)section.base + section.size);
- callbacks_t callbacks;
-};
+ return (uint8_t *)ret_ptr;
+}
struct SymbolLookup : llvm::JITSymbolResolver {
public:
@@ -218,3 +253,19 @@ void *WasmModule::get_func(llvm::StringRef name) const {
auto symbol = runtime_dyld->getSymbol(name);
return (void *)symbol.getAddress();
}
+
+uint8_t *WasmModule::get_stack_map_ptr() const {
+ return memory_manager->get_stack_map_ptr();
+}
+
+size_t WasmModule::get_stack_map_size() const {
+ return memory_manager->get_stack_map_size();
+}
+
+uint8_t *WasmModule::get_code_ptr() const {
+ return memory_manager->get_code_ptr();
+}
+
+size_t WasmModule::get_code_size() const {
+ return memory_manager->get_code_size();
+}
diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh
index 7a410b2dc07..bc9b9ab6717 100644
--- a/lib/llvm-backend/cpp/object_loader.hh
+++ b/lib/llvm-backend/cpp/object_loader.hh
@@ -1,7 +1,12 @@
+#pragma once
+
#include
#include
#include
+#include
#include
+#include
+#include
#include
#include
@@ -48,11 +53,92 @@ typedef struct {
size_t data, vtable;
} box_any_t;
-struct WasmException {
+enum WasmTrapType {
+ Unreachable = 0,
+ IncorrectCallIndirectSignature = 1,
+ MemoryOutOfBounds = 2,
+ CallIndirectOOB = 3,
+ IllegalArithmetic = 4,
+ Unknown,
+};
+
+extern "C" void callback_trampoline(void *, void *);
+
+struct MemoryManager : llvm::RuntimeDyld::MemoryManager {
public:
- virtual std::string description() const noexcept = 0;
+ MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
+ virtual ~MemoryManager() override;
+
+ inline uint8_t *get_stack_map_ptr() const { return stack_map_ptr; }
+ inline size_t get_stack_map_size() const { return stack_map_size; }
+ inline uint8_t *get_code_ptr() const { return (uint8_t *)code_start_ptr; }
+ inline size_t get_code_size() const { return code_size; }
+
+ virtual uint8_t *allocateCodeSection(uintptr_t size, unsigned alignment,
+ unsigned section_id,
+ llvm::StringRef section_name) override;
+ virtual uint8_t *allocateDataSection(uintptr_t size, unsigned alignment,
+ unsigned section_id,
+ llvm::StringRef section_name,
+ bool read_only) override;
+ virtual void reserveAllocationSpace(uintptr_t code_size, uint32_t code_align,
+ uintptr_t read_data_size,
+ uint32_t read_data_align,
+ uintptr_t read_write_data_size,
+ uint32_t read_write_data_align) override;
+ /* Turn on the `reserveAllocationSpace` callback. */
+ virtual bool needsToReserveAllocationSpace() override;
+ virtual void registerEHFrames(uint8_t *addr, uint64_t LoadAddr,
+ size_t size) override;
+ virtual void deregisterEHFrames() override;
+ virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override;
+ virtual void notifyObjectLoaded(llvm::RuntimeDyld &RTDyld,
+ const llvm::object::ObjectFile &Obj) override;
+
+private:
+ struct Section {
+ uint8_t *base;
+ size_t size;
+ };
+
+ uint8_t *allocate_bump(Section §ion, uintptr_t &bump_ptr, size_t size,
+ size_t align);
+
+ Section code_section, read_section, readwrite_section;
+ uintptr_t code_start_ptr;
+ size_t code_size;
+ uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr;
+ uint8_t *eh_frame_ptr;
+ size_t eh_frame_size;
+ bool eh_frames_registered = false;
+
+ callbacks_t callbacks;
+
+ uint8_t *stack_map_ptr = nullptr;
+ size_t stack_map_size = 0;
};
+struct WasmErrorSink {
+ WasmTrapType *trap_out;
+ box_any_t *user_error;
+};
+
+struct WasmException : std::exception {
+public:
+ virtual std::string description() const noexcept { return "unknown"; }
+
+ virtual const char *what() const noexcept override {
+ return "wasm exception";
+ }
+
+ virtual void write_error(WasmErrorSink &out) const noexcept {
+ *out.trap_out = WasmTrapType::Unknown;
+ }
+};
+
+void catch_unwind(std::function &&f);
+[[noreturn]] void unsafe_unwind(WasmException *exception);
+
struct UncatchableException : WasmException {
public:
virtual std::string description() const noexcept override {
@@ -70,6 +156,10 @@ public:
// The parts of a `Box`.
box_any_t error_data;
+
+ virtual void write_error(WasmErrorSink &out) const noexcept override {
+ *out.user_error = error_data;
+ }
};
struct BreakpointException : UncatchableException {
@@ -81,20 +171,35 @@ public:
}
uintptr_t callback;
+
+ virtual void write_error(WasmErrorSink &out) const noexcept override {
+ puts("CB TRAMPOLINE");
+ callback_trampoline(out.user_error, (void *)callback);
+ }
};
-struct WasmTrap : UncatchableException {
+struct WasmModule {
public:
- enum Type {
- Unreachable = 0,
- IncorrectCallIndirectSignature = 1,
- MemoryOutOfBounds = 2,
- CallIndirectOOB = 3,
- IllegalArithmetic = 4,
- Unknown,
- };
+ WasmModule(const uint8_t *object_start, size_t object_size,
+ callbacks_t callbacks);
+
+ void *get_func(llvm::StringRef name) const;
+ uint8_t *get_stack_map_ptr() const;
+ size_t get_stack_map_size() const;
+ uint8_t *get_code_ptr() const;
+ size_t get_code_size() const;
- WasmTrap(Type type) : type(type) {}
+ bool _init_failed = false;
+
+private:
+ std::unique_ptr memory_manager;
+ std::unique_ptr object_file;
+ std::unique_ptr runtime_dyld;
+};
+
+struct WasmTrap : UncatchableException {
+public:
+ WasmTrap(WasmTrapType type) : type(type) {}
virtual std::string description() const noexcept override {
std::ostringstream ss;
@@ -103,27 +208,31 @@ public:
return ss.str();
}
- Type type;
+ WasmTrapType type;
+
+ virtual void write_error(WasmErrorSink &out) const noexcept override {
+ *out.trap_out = type;
+ }
private:
- friend std::ostream &operator<<(std::ostream &out, const Type &ty) {
+ friend std::ostream &operator<<(std::ostream &out, const WasmTrapType &ty) {
switch (ty) {
- case Type::Unreachable:
+ case WasmTrapType::Unreachable:
out << "unreachable";
break;
- case Type::IncorrectCallIndirectSignature:
+ case WasmTrapType::IncorrectCallIndirectSignature:
out << "incorrect call_indirect signature";
break;
- case Type::MemoryOutOfBounds:
+ case WasmTrapType::MemoryOutOfBounds:
out << "memory access out-of-bounds";
break;
- case Type::CallIndirectOOB:
+ case WasmTrapType::CallIndirectOOB:
out << "call_indirect out-of-bounds";
break;
- case Type::IllegalArithmetic:
+ case WasmTrapType::IllegalArithmetic:
out << "illegal arithmetic operation";
break;
- case Type::Unknown:
+ case WasmTrapType::Unknown:
default:
out << "unknown";
break;
@@ -145,23 +254,7 @@ public:
uint64_t values[1];
};
-struct WasmModule {
-public:
- WasmModule(const uint8_t *object_start, size_t object_size,
- callbacks_t callbacks);
-
- void *get_func(llvm::StringRef name) const;
-
- bool _init_failed = false;
-
-private:
- std::unique_ptr memory_manager;
- std::unique_ptr object_file;
- std::unique_ptr runtime_dyld;
-};
-
extern "C" {
-void callback_trampoline(void *, void *);
result_t module_load(const uint8_t *mem_ptr, size_t mem_size,
callbacks_t callbacks, WasmModule **module_out) {
@@ -174,42 +267,40 @@ result_t module_load(const uint8_t *mem_ptr, size_t mem_size,
return RESULT_OK;
}
-[[noreturn]] void throw_trap(WasmTrap::Type ty) { throw WasmTrap(ty); }
+[[noreturn]] void throw_trap(WasmTrapType ty) {
+ unsafe_unwind(new WasmTrap(ty));
+}
void module_delete(WasmModule *module) { delete module; }
// Throw a fat pointer that's assumed to be `*mut dyn Any` on the rust
// side.
[[noreturn]] void throw_any(size_t data, size_t vtable) {
- throw UserException(data, vtable);
+ unsafe_unwind(new UserException(data, vtable));
}
// Throw a pointer that's assumed to be codegen::BreakpointHandler on the
// rust side.
[[noreturn]] void throw_breakpoint(uintptr_t callback) {
- throw BreakpointException(callback);
+ unsafe_unwind(new BreakpointException(callback));
}
bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func,
- void *params, void *results, WasmTrap::Type *trap_out,
+ void *params, void *results, WasmTrapType *trap_out,
box_any_t *user_error, void *invoke_env) noexcept {
try {
- trampoline(ctx, func, params, results);
+ catch_unwind([trampoline, ctx, func, params, results]() {
+ trampoline(ctx, func, params, results);
+ });
return true;
- } catch (const WasmTrap &e) {
- *trap_out = e.type;
- return false;
- } catch (const UserException &e) {
- *user_error = e.error_data;
- return false;
- } catch (const BreakpointException &e) {
- callback_trampoline(user_error, (void *)e.callback);
- return false;
- } catch (const WasmException &e) {
- *trap_out = WasmTrap::Type::Unknown;
+ } catch (std::unique_ptr &e) {
+ WasmErrorSink sink;
+ sink.trap_out = trap_out;
+ sink.user_error = user_error;
+ e->write_error(sink);
return false;
} catch (...) {
- *trap_out = WasmTrap::Type::Unknown;
+ *trap_out = WasmTrapType::Unknown;
return false;
}
}
@@ -217,4 +308,20 @@ bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func,
void *get_func_symbol(WasmModule *module, const char *name) {
return module->get_func(llvm::StringRef(name));
}
+
+const uint8_t *llvm_backend_get_stack_map_ptr(const WasmModule *module) {
+ return module->get_stack_map_ptr();
+}
+
+size_t llvm_backend_get_stack_map_size(const WasmModule *module) {
+ return module->get_stack_map_size();
+}
+
+const uint8_t *llvm_backend_get_code_ptr(const WasmModule *module) {
+ return module->get_code_ptr();
+}
+
+size_t llvm_backend_get_code_size(const WasmModule *module) {
+ return module->get_code_size();
+}
}
diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs
index 92f0f06a134..a0fb80c0352 100644
--- a/lib/llvm-backend/src/backend.rs
+++ b/lib/llvm-backend/src/backend.rs
@@ -1,3 +1,4 @@
+use super::stackmap::StackmapRegistry;
use crate::intrinsics::Intrinsics;
use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect};
use inkwell::{
@@ -25,6 +26,7 @@ use wasmer_runtime_core::{
},
cache::Error as CacheError,
module::ModuleInfo,
+ state::ModuleStateMap,
structures::TypedIndex,
typed_func::{Wasm, WasmTrapInfo},
types::{LocalFuncIndex, SigIndex},
@@ -40,6 +42,10 @@ extern "C" {
) -> LLVMResult;
fn module_delete(module: *mut LLVMModule);
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
+ fn llvm_backend_get_stack_map_ptr(module: *const LLVMModule) -> *const u8;
+ fn llvm_backend_get_stack_map_size(module: *const LLVMModule) -> usize;
+ fn llvm_backend_get_code_ptr(module: *const LLVMModule) -> *const u8;
+ fn llvm_backend_get_code_size(module: *const LLVMModule) -> usize;
fn throw_trap(ty: i32) -> !;
fn throw_breakpoint(ty: i64) -> !;
@@ -63,6 +69,8 @@ extern "C" {
) -> bool;
}
+static SIGNAL_HANDLER_INSTALLED: Once = Once::new();
+
fn get_callbacks() -> Callbacks {
extern "C" fn alloc_memory(
size: usize,
@@ -154,10 +162,17 @@ pub struct LLVMBackend {
module: *mut LLVMModule,
#[allow(dead_code)]
buffer: Arc,
+ msm: Option,
+ local_func_id_to_offset: Vec,
}
impl LLVMBackend {
- pub fn new(module: Module, _intrinsics: Intrinsics) -> (Self, LLVMCache) {
+ pub fn new(
+ module: Module,
+ _intrinsics: Intrinsics,
+ _stackmaps: &StackmapRegistry,
+ _module_info: &ModuleInfo,
+ ) -> (Self, LLVMCache) {
Target::initialize_x86(&InitializationConfig {
asm_parser: true,
asm_printer: true,
@@ -204,22 +219,134 @@ impl LLVMBackend {
)
};
- static SIGNAL_HANDLER_INSTALLED: Once = Once::new();
-
- SIGNAL_HANDLER_INSTALLED.call_once(|| unsafe {
- crate::platform::install_signal_handler();
- });
-
if res != LLVMResult::OK {
panic!("failed to load object")
}
let buffer = Arc::new(Buffer::LlvmMemory(memory_buffer));
+ #[cfg(all(any(target_os = "linux", target_os = "macos"), target_arch = "x86_64"))]
+ {
+ use super::stackmap::{self, StkMapRecord, StkSizeRecord};
+ use std::collections::BTreeMap;
+
+ let stackmaps = _stackmaps;
+ let module_info = _module_info;
+
+ let raw_stackmap = unsafe {
+ std::slice::from_raw_parts(
+ llvm_backend_get_stack_map_ptr(module),
+ llvm_backend_get_stack_map_size(module),
+ )
+ };
+ if raw_stackmap.len() > 0 {
+ let map = stackmap::StackMap::parse(raw_stackmap).unwrap();
+
+ let (code_ptr, code_size) = unsafe {
+ (
+ llvm_backend_get_code_ptr(module),
+ llvm_backend_get_code_size(module),
+ )
+ };
+ let mut msm = ModuleStateMap {
+ local_functions: Default::default(),
+ total_size: code_size,
+ };
+
+ let num_local_functions =
+ module_info.func_assoc.len() - module_info.imported_functions.len();
+ let mut local_func_id_to_addr: Vec = Vec::with_capacity(num_local_functions);
+
+ // All local functions.
+ for index in module_info.imported_functions.len()..module_info.func_assoc.len() {
+ let name = if cfg!(target_os = "macos") {
+ format!("_fn{}", index)
+ } else {
+ format!("fn{}", index)
+ };
+
+ let c_str = CString::new(name).unwrap();
+ let ptr = unsafe { get_func_symbol(module, c_str.as_ptr()) };
+
+ assert!(!ptr.is_null());
+ local_func_id_to_addr.push(ptr as usize);
+ }
+
+ let mut addr_to_size_record: BTreeMap = BTreeMap::new();
+
+ for record in &map.stk_size_records {
+ addr_to_size_record.insert(record.function_address as usize, record);
+ }
+
+ let mut map_records: BTreeMap = BTreeMap::new();
+
+ for record in &map.stk_map_records {
+ map_records.insert(record.patchpoint_id as usize, record);
+ }
+
+ for ((start_id, start_entry), (end_id, end_entry)) in stackmaps
+ .entries
+ .iter()
+ .enumerate()
+ .step_by(2)
+ .zip(stackmaps.entries.iter().enumerate().skip(1).step_by(2))
+ {
+ if let Some(map_record) = map_records.get(&start_id) {
+ assert_eq!(start_id, map_record.patchpoint_id as usize);
+ assert!(start_entry.is_start);
+ assert!(!end_entry.is_start);
+
+ let end_record = map_records.get(&end_id);
+
+ let addr = local_func_id_to_addr[start_entry.local_function_id];
+ let size_record = *addr_to_size_record
+ .get(&addr)
+ .expect("size_record not found");
+
+ start_entry.populate_msm(
+ module_info,
+ code_ptr as usize,
+ &map,
+ size_record,
+ map_record,
+ end_record.map(|x| (end_entry, *x)),
+ &mut msm,
+ );
+ } else {
+ // The record is optimized out.
+ }
+ }
+
+ let code_ptr = unsafe { llvm_backend_get_code_ptr(module) } as usize;
+ let code_len = unsafe { llvm_backend_get_code_size(module) } as usize;
+
+ let local_func_id_to_offset: Vec = local_func_id_to_addr
+ .iter()
+ .map(|&x| {
+ assert!(x >= code_ptr && x < code_ptr + code_len);
+ x - code_ptr
+ })
+ .collect();
+
+ return (
+ Self {
+ module,
+ buffer: Arc::clone(&buffer),
+ msm: Some(msm),
+ local_func_id_to_offset,
+ },
+ LLVMCache { buffer },
+ );
+ }
+ }
+
+ // Stackmap is not supported on this platform, or this module contains no functions so no stackmaps.
(
Self {
module,
buffer: Arc::clone(&buffer),
+ msm: None,
+ local_func_id_to_offset: vec![],
},
LLVMCache { buffer },
)
@@ -237,8 +364,6 @@ impl LLVMBackend {
return Err("failed to load object".to_string());
}
- static SIGNAL_HANDLER_INSTALLED: Once = Once::new();
-
SIGNAL_HANDLER_INSTALLED.call_once(|| {
crate::platform::install_signal_handler();
});
@@ -249,6 +374,8 @@ impl LLVMBackend {
Self {
module,
buffer: Arc::clone(&buffer),
+ msm: None,
+ local_func_id_to_offset: vec![],
},
LLVMCache { buffer },
))
@@ -300,9 +427,30 @@ impl RunnableModule for LLVMBackend {
mem::transmute(symbol)
};
+ SIGNAL_HANDLER_INSTALLED.call_once(|| unsafe {
+ crate::platform::install_signal_handler();
+ });
+
Some(unsafe { Wasm::from_raw_parts(trampoline, invoke_trampoline, None) })
}
+ fn get_code(&self) -> Option<&[u8]> {
+ Some(unsafe {
+ std::slice::from_raw_parts(
+ llvm_backend_get_code_ptr(self.module),
+ llvm_backend_get_code_size(self.module),
+ )
+ })
+ }
+
+ fn get_local_function_offsets(&self) -> Option> {
+ Some(self.local_func_id_to_offset.clone())
+ }
+
+ fn get_module_state_map(&self) -> Option {
+ self.msm.clone()
+ }
+
unsafe fn do_early_trap(&self, data: Box) -> ! {
throw_any(Box::leak(data))
}
diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs
index 1f78ccc5bf0..206e6f37a07 100644
--- a/lib/llvm-backend/src/code.rs
+++ b/lib/llvm-backend/src/code.rs
@@ -11,6 +11,8 @@ use inkwell::{
AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate,
};
use smallvec::SmallVec;
+use std::cell::RefCell;
+use std::rc::Rc;
use std::sync::{Arc, RwLock};
use wasmer_runtime_core::{
backend::{Backend, CacheGen, Token},
@@ -28,10 +30,16 @@ use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType};
use crate::backend::LLVMBackend;
use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache};
use crate::read_info::{blocktype_to_type, type_to_type};
+use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic};
use crate::state::{ControlFrame, IfElseState, State};
use crate::trampolines::generate_trampolines;
-fn func_sig_to_llvm(context: &Context, intrinsics: &Intrinsics, sig: &FuncSig) -> FunctionType {
+fn func_sig_to_llvm(
+ context: &Context,
+ intrinsics: &Intrinsics,
+ sig: &FuncSig,
+ type_to_llvm: fn(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum,
+) -> FunctionType {
let user_param_types = sig.params().iter().map(|&ty| type_to_llvm(intrinsics, ty));
let param_types: Vec<_> = std::iter::once(intrinsics.ctx_ptr_ty.as_basic_type_enum())
@@ -64,6 +72,14 @@ fn type_to_llvm(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum {
}
}
+fn type_to_llvm_int_only(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum {
+ match ty {
+ Type::I32 | Type::F32 => intrinsics.i32_ty.as_basic_type_enum(),
+ Type::I64 | Type::F64 => intrinsics.i64_ty.as_basic_type_enum(),
+ Type::V128 => intrinsics.i128_ty.as_basic_type_enum(),
+ }
+}
+
// Create a vector where each lane contains the same value.
fn splat_vector(
builder: &Builder,
@@ -491,6 +507,90 @@ fn resolve_memory_ptr(
Ok(builder.build_int_to_ptr(effective_address_int, ptr_ty, &state.var_name()))
}
+fn emit_stack_map(
+ _module_info: &ModuleInfo,
+ intrinsics: &Intrinsics,
+ builder: &Builder,
+ local_function_id: usize,
+ target: &mut StackmapRegistry,
+ kind: StackmapEntryKind,
+ locals: &[PointerValue],
+ state: &State,
+ _ctx: &mut CtxType,
+ opcode_offset: usize,
+) {
+ let stackmap_id = target.entries.len();
+
+ let mut params = Vec::with_capacity(2 + locals.len() + state.stack.len());
+
+ params.push(
+ intrinsics
+ .i64_ty
+ .const_int(stackmap_id as u64, false)
+ .as_basic_value_enum(),
+ );
+ params.push(intrinsics.i32_ty.const_int(0, false).as_basic_value_enum());
+
+ let locals: Vec<_> = locals.iter().map(|x| x.as_basic_value_enum()).collect();
+ let mut value_semantics: Vec =
+ Vec::with_capacity(locals.len() + state.stack.len());
+
+ params.extend_from_slice(&locals);
+ value_semantics.extend((0..locals.len()).map(ValueSemantic::WasmLocal));
+
+ params.extend_from_slice(&state.stack);
+ value_semantics.extend((0..state.stack.len()).map(ValueSemantic::WasmStack));
+
+ // FIXME: Information needed for Abstract -> Runtime state transform is not fully preserved
+ // to accelerate compilation and reduce memory usage. Check this again when we try to support
+ // "full" LLVM OSR.
+
+ assert_eq!(params.len(), value_semantics.len() + 2);
+
+ builder.build_call(intrinsics.experimental_stackmap, ¶ms, &state.var_name());
+
+ target.entries.push(StackmapEntry {
+ kind,
+ local_function_id,
+ local_count: locals.len(),
+ stack_count: state.stack.len(),
+ opcode_offset,
+ value_semantics,
+ is_start: true,
+ });
+}
+
+fn finalize_opcode_stack_map(
+ intrinsics: &Intrinsics,
+ builder: &Builder,
+ local_function_id: usize,
+ target: &mut StackmapRegistry,
+ kind: StackmapEntryKind,
+ opcode_offset: usize,
+) {
+ let stackmap_id = target.entries.len();
+ builder.build_call(
+ intrinsics.experimental_stackmap,
+ &[
+ intrinsics
+ .i64_ty
+ .const_int(stackmap_id as u64, false)
+ .as_basic_value_enum(),
+ intrinsics.i32_ty.const_int(0, false).as_basic_value_enum(),
+ ],
+ "opcode_stack_map_end",
+ );
+ target.entries.push(StackmapEntry {
+ kind,
+ local_function_id,
+ local_count: 0,
+ stack_count: 0,
+ opcode_offset,
+ value_semantics: vec![],
+ is_start: false,
+ });
+}
+
fn trap_if_misaligned(
builder: &Builder,
intrinsics: &Intrinsics,
@@ -575,6 +675,7 @@ pub struct LLVMModuleCodeGenerator {
func_import_count: usize,
personality_func: FunctionValue,
module: Module,
+ stackmaps: Rc>,
}
pub struct LLVMFunctionCodeGenerator {
@@ -589,6 +690,9 @@ pub struct LLVMFunctionCodeGenerator {
num_params: usize,
ctx: Option>,
unreachable_depth: usize,
+ stackmaps: Rc>,
+ index: usize,
+ opcode_offset: usize,
}
impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
@@ -658,6 +762,35 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
let ctx = CtxType::new(module_info, function, cache_builder);
self.ctx = Some(ctx);
+
+ {
+ let state = &mut self.state;
+ let builder = self.builder.as_ref().unwrap();
+ let intrinsics = self.intrinsics.as_ref().unwrap();
+
+ let mut stackmaps = self.stackmaps.borrow_mut();
+ emit_stack_map(
+ &module_info,
+ &intrinsics,
+ &builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::FunctionHeader,
+ &self.locals,
+ &state,
+ self.ctx.as_mut().unwrap(),
+ ::std::usize::MAX,
+ );
+ finalize_opcode_stack_map(
+ &intrinsics,
+ &builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::FunctionHeader,
+ ::std::usize::MAX,
+ );
+ }
+
Ok(())
}
@@ -672,9 +805,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
let signatures = &self.signatures;
let mut ctx = self.ctx.as_mut().unwrap();
+ let mut opcode_offset: Option = None;
let op = match event {
- Event::Wasm(x) => x,
- Event::WasmOwned(ref x) => x,
+ Event::Wasm(x) => {
+ opcode_offset = Some(self.opcode_offset);
+ self.opcode_offset += 1;
+ x
+ }
Event::Internal(x) => {
match x {
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {
@@ -709,6 +846,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
}
return Ok(());
}
+ Event::WasmOwned(ref x) => x,
};
if !state.reachable {
@@ -779,6 +917,35 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
};
builder.position_at_end(&loop_body);
+
+ if let Some(offset) = opcode_offset {
+ let mut stackmaps = self.stackmaps.borrow_mut();
+ emit_stack_map(
+ &info,
+ intrinsics,
+ builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::Loop,
+ &self.locals,
+ state,
+ ctx,
+ offset,
+ );
+ let signal_mem = ctx.signal_mem();
+ let iv = builder
+ .build_store(signal_mem, context.i8_type().const_int(0 as u64, false));
+ iv.set_volatile(true);
+ finalize_opcode_stack_map(
+ intrinsics,
+ builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::Loop,
+ offset,
+ );
+ }
+
state.push_loop(loop_body, loop_next, phis);
}
Operator::Br { relative_depth } => {
@@ -1040,6 +1207,33 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
// If llvm cannot prove that this is never touched,
// it will emit a `ud2` instruction on x86_64 arches.
+ // Comment out this `if` block to allow spectests to pass.
+ // TODO: fix this
+ if let Some(offset) = opcode_offset {
+ let mut stackmaps = self.stackmaps.borrow_mut();
+ emit_stack_map(
+ &info,
+ intrinsics,
+ builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::Trappable,
+ &self.locals,
+ state,
+ ctx,
+ offset,
+ );
+ builder.build_call(intrinsics.trap, &[], "trap");
+ finalize_opcode_stack_map(
+ intrinsics,
+ builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::Trappable,
+ offset,
+ );
+ }
+
builder.build_call(
intrinsics.throw_trap,
&[intrinsics.trap_unreachable],
@@ -1228,26 +1422,59 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
let llvm_sig = signatures[sigindex];
let func_sig = &info.signatures[sigindex];
- let call_site = match func_index.local_or_import(info) {
+ let (params, func_ptr) = match func_index.local_or_import(info) {
LocalOrImport::Local(local_func_index) => {
- let params: Vec<_> = [ctx.basic()]
- .iter()
- .chain(state.peekn(func_sig.params().len())?.iter())
- .map(|v| *v)
+ let params: Vec<_> = std::iter::once(ctx.basic())
+ .chain(
+ state
+ .peekn(func_sig.params().len())?
+ .iter()
+ .enumerate()
+ .map(|(i, &v)| match func_sig.params()[i] {
+ Type::F32 => builder.build_bitcast(
+ v,
+ intrinsics.i32_ty,
+ &state.var_name(),
+ ),
+ Type::F64 => builder.build_bitcast(
+ v,
+ intrinsics.i64_ty,
+ &state.var_name(),
+ ),
+ _ => v,
+ }),
+ )
.collect();
let func_ptr =
ctx.local_func(local_func_index, llvm_sig, intrinsics, builder);
- builder.build_call(func_ptr, ¶ms, &state.var_name())
+ (params, func_ptr)
}
LocalOrImport::Import(import_func_index) => {
let (func_ptr_untyped, ctx_ptr) =
ctx.imported_func(import_func_index, intrinsics);
- let params: Vec<_> = [ctx_ptr.as_basic_value_enum()]
- .iter()
- .chain(state.peekn(func_sig.params().len())?.iter())
- .map(|v| *v)
+
+ let params: Vec<_> = std::iter::once(ctx_ptr.as_basic_value_enum())
+ .chain(
+ state
+ .peekn(func_sig.params().len())?
+ .iter()
+ .enumerate()
+ .map(|(i, &v)| match func_sig.params()[i] {
+ Type::F32 => builder.build_bitcast(
+ v,
+ intrinsics.i32_ty,
+ &state.var_name(),
+ ),
+ Type::F64 => builder.build_bitcast(
+ v,
+ intrinsics.i64_ty,
+ &state.var_name(),
+ ),
+ _ => v,
+ }),
+ )
.collect();
let func_ptr_ty = llvm_sig.ptr_type(AddressSpace::Generic);
@@ -1258,15 +1485,50 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
"typed_func_ptr",
);
- builder.build_call(func_ptr, ¶ms, &state.var_name())
+ (params, func_ptr)
}
};
state.popn(func_sig.params().len())?;
+ if let Some(offset) = opcode_offset {
+ let mut stackmaps = self.stackmaps.borrow_mut();
+ emit_stack_map(
+ &info,
+ intrinsics,
+ builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::Call,
+ &self.locals,
+ state,
+ ctx,
+ offset,
+ )
+ }
+ let call_site = builder.build_call(func_ptr, ¶ms, &state.var_name());
+ if let Some(offset) = opcode_offset {
+ let mut stackmaps = self.stackmaps.borrow_mut();
+ finalize_opcode_stack_map(
+ intrinsics,
+ builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::Call,
+ offset,
+ )
+ }
if let Some(basic_value) = call_site.try_as_basic_value().left() {
match func_sig.returns().len() {
- 1 => state.push1(basic_value),
+ 1 => state.push1(match func_sig.returns()[0] {
+ Type::F32 => {
+ builder.build_bitcast(basic_value, intrinsics.f32_ty, "ret_cast")
+ }
+ Type::F64 => {
+ builder.build_bitcast(basic_value, intrinsics.f64_ty, "ret_cast")
+ }
+ _ => basic_value,
+ }),
count @ _ => {
// This is a multi-value return.
let struct_value = basic_value.into_struct_value();
@@ -1418,7 +1680,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
let pushed_args = state.popn_save(wasmer_fn_sig.params().len())?;
let args: Vec<_> = std::iter::once(ctx_ptr)
- .chain(pushed_args.into_iter())
+ .chain(pushed_args.into_iter().enumerate().map(|(i, v)| {
+ match wasmer_fn_sig.params()[i] {
+ Type::F32 => {
+ builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name())
+ }
+ Type::F64 => {
+ builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name())
+ }
+ _ => v,
+ }
+ }))
.collect();
let typed_func_ptr = builder.build_pointer_cast(
@@ -1427,13 +1699,47 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
"typed_func_ptr",
);
+ if let Some(offset) = opcode_offset {
+ let mut stackmaps = self.stackmaps.borrow_mut();
+ emit_stack_map(
+ &info,
+ intrinsics,
+ builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::Call,
+ &self.locals,
+ state,
+ ctx,
+ offset,
+ )
+ }
let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call");
+ if let Some(offset) = opcode_offset {
+ let mut stackmaps = self.stackmaps.borrow_mut();
+ finalize_opcode_stack_map(
+ intrinsics,
+ builder,
+ self.index,
+ &mut *stackmaps,
+ StackmapEntryKind::Call,
+ offset,
+ )
+ }
match wasmer_fn_sig.returns() {
[] => {}
[_] => {
let value = call_site.try_as_basic_value().left().unwrap();
- state.push1(value);
+ state.push1(match wasmer_fn_sig.returns()[0] {
+ Type::F32 => {
+ builder.build_bitcast(value, intrinsics.f32_ty, "ret_cast")
+ }
+ Type::F64 => {
+ builder.build_bitcast(value, intrinsics.f64_ty, "ret_cast")
+ }
+ _ => value,
+ });
}
_ => unimplemented!("multi-value returns"),
}
@@ -6538,7 +6844,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator {
self.builder.as_ref().unwrap().build_return(None);
}
[one_value] => {
- self.builder.as_ref().unwrap().build_return(Some(one_value));
+ let builder = self.builder.as_ref().unwrap();
+ let intrinsics = self.intrinsics.as_ref().unwrap();
+ builder.build_return(Some(&builder.build_bitcast(
+ one_value.as_basic_value_enum(),
+ type_to_llvm_int_only(intrinsics, self.func_sig.returns()[0]),
+ "return",
+ )));
}
_ => unimplemented!("multi-value returns not yet implemented"),
}
@@ -6583,6 +6895,7 @@ impl ModuleCodeGenerator
function_signatures: None,
func_import_count: 0,
personality_func,
+ stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())),
}
}
@@ -6646,15 +6959,27 @@ impl ModuleCodeGenerator
.skip(1)
.enumerate()
.map(|(index, param)| {
- let ty = param.get_type();
+ //let ty = param.get_type();
+ let real_ty = func_sig.params()[index];
+ let real_ty_llvm = type_to_llvm(&intrinsics, real_ty);
- let alloca = builder.build_alloca(ty, &format!("local{}", index));
- builder.build_store(alloca, param);
+ let alloca = builder.build_alloca(real_ty_llvm, &format!("local{}", index));
+
+ //if real_ty_llvm != ty {
+ builder.build_store(
+ alloca,
+ builder.build_bitcast(param, real_ty_llvm, &state.var_name()),
+ );
+ /*} else {
+ builder.build_store(alloca, param);
+ }*/
alloca
}),
);
let num_params = locals.len();
+ let local_func_index = self.functions.len();
+
let code = LLVMFunctionCodeGenerator {
state,
context: Some(context),
@@ -6667,6 +6992,9 @@ impl ModuleCodeGenerator
num_params,
ctx: None,
unreachable_depth: 0,
+ stackmaps: self.stackmaps.clone(),
+ index: local_func_index,
+ opcode_offset: 0,
};
self.functions.push(code);
Ok(self.functions.last_mut().unwrap())
@@ -6728,7 +7056,14 @@ impl ModuleCodeGenerator
self.module.print_to_file(path).unwrap();
}
- let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics.take().unwrap());
+ let stackmaps = self.stackmaps.borrow();
+
+ let (backend, cache_gen) = LLVMBackend::new(
+ self.module,
+ self.intrinsics.take().unwrap(),
+ &*stackmaps,
+ module_info,
+ );
Ok((backend, Box::new(cache_gen)))
}
@@ -6740,6 +7075,7 @@ impl ModuleCodeGenerator
self.context.as_ref().unwrap(),
self.intrinsics.as_ref().unwrap(),
sig,
+ type_to_llvm_int_only,
)
})
.collect();
diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs
index 22f1b3cfd5d..278e087bb41 100644
--- a/lib/llvm-backend/src/intrinsics.rs
+++ b/lib/llvm-backend/src/intrinsics.rs
@@ -151,6 +151,8 @@ pub struct Intrinsics {
pub throw_trap: FunctionValue,
pub throw_breakpoint: FunctionValue,
+ pub experimental_stackmap: FunctionValue,
+
pub ctx_ptr_ty: PointerType,
}
@@ -528,6 +530,17 @@ impl Intrinsics {
void_ty.fn_type(&[i32_ty_basic], false),
None,
),
+ experimental_stackmap: module.add_function(
+ "llvm.experimental.stackmap",
+ void_ty.fn_type(
+ &[
+ i64_ty_basic, /* id */
+ i32_ty_basic, /* numShadowBytes */
+ ],
+ true,
+ ),
+ None,
+ ),
throw_breakpoint: module.add_function(
"vm.breakpoint",
void_ty.fn_type(&[i64_ty_basic], false),
@@ -606,6 +619,8 @@ pub struct CtxType<'a> {
info: &'a ModuleInfo,
cache_builder: Builder,
+ cached_signal_mem: Option,
+
cached_memories: HashMap,
cached_tables: HashMap,
cached_sigindices: HashMap,
@@ -631,6 +646,8 @@ impl<'a> CtxType<'a> {
info,
cache_builder,
+ cached_signal_mem: None,
+
cached_memories: HashMap::new(),
cached_tables: HashMap::new(),
cached_sigindices: HashMap::new(),
@@ -645,6 +662,27 @@ impl<'a> CtxType<'a> {
self.ctx_ptr_value.as_basic_value_enum()
}
+ pub fn signal_mem(&mut self) -> PointerValue {
+ if let Some(x) = self.cached_signal_mem {
+ return x;
+ }
+
+ let (ctx_ptr_value, cache_builder) = (self.ctx_ptr_value, &self.cache_builder);
+
+ let ptr_ptr = unsafe {
+ cache_builder.build_struct_gep(
+ ctx_ptr_value,
+ offset_to_index(Ctx::offset_interrupt_signal_mem()),
+ "interrupt_signal_mem_ptr",
+ )
+ };
+ let ptr = cache_builder
+ .build_load(ptr_ptr, "interrupt_signal_mem")
+ .into_pointer_value();
+ self.cached_signal_mem = Some(ptr);
+ ptr
+ }
+
pub fn memory(&mut self, index: MemoryIndex, intrinsics: &Intrinsics) -> MemoryCache {
let (cached_memories, info, ctx_ptr_value, cache_builder) = (
&mut self.cached_memories,
@@ -718,12 +756,11 @@ impl<'a> CtxType<'a> {
})
}
- pub fn table(
+ pub fn table_prepare(
&mut self,
index: TableIndex,
intrinsics: &Intrinsics,
- builder: &Builder,
- ) -> (PointerValue, IntValue) {
+ ) -> (PointerValue, PointerValue) {
let (cached_tables, info, ctx_ptr_value, cache_builder) = (
&mut self.cached_tables,
self.info,
@@ -782,6 +819,16 @@ impl<'a> CtxType<'a> {
}
});
+ (ptr_to_base_ptr, ptr_to_bounds)
+ }
+
+ pub fn table(
+ &mut self,
+ index: TableIndex,
+ intrinsics: &Intrinsics,
+ builder: &Builder,
+ ) -> (PointerValue, IntValue) {
+ let (ptr_to_base_ptr, ptr_to_bounds) = self.table_prepare(index, intrinsics);
(
builder
.build_load(ptr_to_base_ptr, "base_ptr")
diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs
index 454fad1003d..8194f797a45 100644
--- a/lib/llvm-backend/src/lib.rs
+++ b/lib/llvm-backend/src/lib.rs
@@ -1,5 +1,4 @@
#![deny(
- dead_code,
nonstandard_style,
unused_imports,
unused_mut,
@@ -7,13 +6,17 @@
unused_unsafe,
unreachable_patterns
)]
+#![cfg_attr(not(target_os = "windows"), deny(dead_code))]
#![cfg_attr(nightly, feature(unwind_attributes))]
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
mod backend;
mod code;
mod intrinsics;
mod platform;
mod read_info;
+mod stackmap;
mod state;
mod structs;
mod trampolines;
diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs
index a07afa13042..88ceb685438 100644
--- a/lib/llvm-backend/src/platform/unix.rs
+++ b/lib/llvm-backend/src/platform/unix.rs
@@ -4,7 +4,9 @@ use libc::{
c_void, mmap, mprotect, munmap, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE,
PROT_READ, PROT_WRITE,
};
-use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGSEGV};
+use nix::sys::signal::{
+ sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGILL, SIGSEGV,
+};
use std::ptr;
/// `__register_frame` and `__deregister_frame` on macos take a single fde as an
@@ -57,6 +59,7 @@ pub unsafe fn install_signal_handler() {
);
sigaction(SIGSEGV, &sa).unwrap();
sigaction(SIGBUS, &sa).unwrap();
+ sigaction(SIGILL, &sa).unwrap();
}
#[cfg_attr(nightly, unwind(allowed))]
@@ -66,6 +69,9 @@ extern "C" fn signal_trap_handler(
_ucontext: *mut c_void,
) {
unsafe {
+ if SigSet::all().thread_unblock().is_err() {
+ std::process::abort();
+ }
// Apparently, we can unwind from arbitary instructions, as long
// as we don't need to catch the exception inside the function that
// was interrupted.
diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs
new file mode 100644
index 00000000000..a56c3c6a38d
--- /dev/null
+++ b/lib/llvm-backend/src/stackmap.rs
@@ -0,0 +1,568 @@
+// https://llvm.org/docs/StackMaps.html#stackmap-section
+
+use byteorder::{LittleEndian, ReadBytesExt};
+use std::io::{self, Cursor};
+use wasmer_runtime_core::vm::Ctx;
+use wasmer_runtime_core::{
+ module::ModuleInfo,
+ structures::TypedIndex,
+ types::{GlobalIndex, LocalOrImport, TableIndex},
+};
+
+#[derive(Default, Debug, Clone)]
+pub struct StackmapRegistry {
+ pub entries: Vec,
+}
+
+#[derive(Debug, Clone)]
+pub struct StackmapEntry {
+ pub kind: StackmapEntryKind,
+ pub local_function_id: usize,
+ pub opcode_offset: usize,
+ pub value_semantics: Vec,
+ pub local_count: usize,
+ pub stack_count: usize,
+ pub is_start: bool,
+}
+
+#[derive(Debug, Clone)]
+pub enum ValueSemantic {
+ WasmLocal(usize),
+ WasmStack(usize),
+ Ctx,
+ SignalMem,
+ PointerToMemoryBase,
+ PointerToMemoryBound, // 64-bit
+ MemoryBase,
+ MemoryBound, // 64-bit
+ PointerToGlobal(usize),
+ Global(usize),
+ PointerToTableBase,
+ PointerToTableBound,
+ ImportedFuncPointer(usize),
+ ImportedFuncCtx(usize),
+ DynamicSigindice(usize),
+}
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum StackmapEntryKind {
+ FunctionHeader,
+ Loop,
+ Call,
+ Trappable,
+}
+
+impl StackmapEntry {
+ #[cfg(all(any(target_os = "linux", target_os = "macos"), target_arch = "x86_64"))]
+ pub fn populate_msm(
+ &self,
+ module_info: &ModuleInfo,
+ code_addr: usize,
+ llvm_map: &StackMap,
+ size_record: &StkSizeRecord,
+ map_record: &StkMapRecord,
+ end: Option<(&StackmapEntry, &StkMapRecord)>,
+ msm: &mut wasmer_runtime_core::state::ModuleStateMap,
+ ) {
+ use std::collections::{BTreeMap, HashMap};
+ use wasmer_runtime_core::state::{
+ x64::{new_machine_state, X64Register, GPR},
+ FunctionStateMap, MachineStateDiff, MachineValue, OffsetInfo, RegisterIndex,
+ SuspendOffset, WasmAbstractValue,
+ };
+ use wasmer_runtime_core::vm;
+
+ let func_base_addr = (size_record.function_address as usize)
+ .checked_sub(code_addr)
+ .unwrap();
+ let target_offset = func_base_addr + map_record.instruction_offset as usize;
+ assert!(self.is_start);
+
+ if msm.local_functions.len() == self.local_function_id {
+ assert_eq!(self.kind, StackmapEntryKind::FunctionHeader);
+ msm.local_functions.insert(
+ target_offset,
+ FunctionStateMap::new(new_machine_state(), self.local_function_id, 0, vec![]),
+ );
+ } else if msm.local_functions.len() == self.local_function_id + 1 {
+ } else {
+ panic!("unordered local functions");
+ }
+
+ let (_, fsm) = msm.local_functions.iter_mut().last().unwrap();
+
+ assert_eq!(self.value_semantics.len(), map_record.locations.len());
+
+ // System V requires 16-byte alignment before each call instruction.
+ // Considering the saved rbp we need to ensure the stack size % 16 always equals to 8.
+ assert!(size_record.stack_size % 16 == 8);
+
+ // Layout begins just below saved rbp. (push rbp; mov rbp, rsp)
+ let mut machine_stack_half_layout: Vec =
+ vec![MachineValue::Undefined; (size_record.stack_size - 8) as usize / 4];
+ let mut regs: Vec<(RegisterIndex, MachineValue)> = vec![];
+ let mut stack_constants: HashMap = HashMap::new();
+
+ let mut prev_frame_diff: BTreeMap> = BTreeMap::new();
+
+ let mut wasm_locals: Vec = vec![];
+ let mut wasm_stack: Vec = vec![];
+
+ for (i, loc) in map_record.locations.iter().enumerate() {
+ let mv = match self.value_semantics[i] {
+ ValueSemantic::WasmLocal(x) => {
+ if x != wasm_locals.len() {
+ panic!("unordered local values");
+ }
+ wasm_locals.push(WasmAbstractValue::Runtime);
+ MachineValue::WasmLocal(x)
+ }
+ ValueSemantic::WasmStack(x) => {
+ if x != wasm_stack.len() {
+ panic!("unordered stack values");
+ }
+ wasm_stack.push(WasmAbstractValue::Runtime);
+ MachineValue::WasmStack(x)
+ }
+ ValueSemantic::Ctx => MachineValue::Vmctx,
+ ValueSemantic::SignalMem => {
+ MachineValue::VmctxDeref(vec![Ctx::offset_interrupt_signal_mem() as usize, 0])
+ }
+ ValueSemantic::PointerToMemoryBase => {
+ MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize])
+ }
+ ValueSemantic::PointerToMemoryBound => {
+ MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize])
+ }
+ ValueSemantic::MemoryBase => {
+ MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize, 0])
+ }
+ ValueSemantic::MemoryBound => {
+ MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize, 0])
+ }
+ ValueSemantic::PointerToGlobal(idx) => {
+ MachineValue::VmctxDeref(deref_global(module_info, idx, false))
+ }
+ ValueSemantic::Global(idx) => {
+ MachineValue::VmctxDeref(deref_global(module_info, idx, true))
+ }
+ ValueSemantic::PointerToTableBase => {
+ MachineValue::VmctxDeref(deref_table_base(module_info, 0, false))
+ }
+ ValueSemantic::PointerToTableBound => {
+ MachineValue::VmctxDeref(deref_table_bound(module_info, 0, false))
+ }
+ ValueSemantic::ImportedFuncPointer(idx) => MachineValue::VmctxDeref(vec![
+ Ctx::offset_imported_funcs() as usize,
+ vm::ImportedFunc::size() as usize * idx
+ + vm::ImportedFunc::offset_func() as usize,
+ 0,
+ ]),
+ ValueSemantic::ImportedFuncCtx(idx) => MachineValue::VmctxDeref(vec![
+ Ctx::offset_imported_funcs() as usize,
+ vm::ImportedFunc::size() as usize * idx
+ + vm::ImportedFunc::offset_vmctx() as usize,
+ 0,
+ ]),
+ ValueSemantic::DynamicSigindice(idx) => {
+ MachineValue::VmctxDeref(vec![Ctx::offset_signatures() as usize, idx * 4, 0])
+ }
+ };
+ match loc.ty {
+ LocationType::Register => {
+ let index = X64Register::from_dwarf_regnum(loc.dwarf_regnum)
+ .expect("invalid regnum")
+ .to_index();
+ regs.push((index, mv));
+ }
+ LocationType::Constant => {
+ let v = loc.offset_or_small_constant as u32 as u64;
+ match mv {
+ MachineValue::WasmStack(x) => {
+ stack_constants.insert(x, v);
+ *wasm_stack.last_mut().unwrap() = WasmAbstractValue::Const(v);
+ }
+ _ => {} // TODO
+ }
+ }
+ LocationType::ConstantIndex => {
+ let v =
+ llvm_map.constants[loc.offset_or_small_constant as usize].large_constant;
+ match mv {
+ MachineValue::WasmStack(x) => {
+ stack_constants.insert(x, v);
+ *wasm_stack.last_mut().unwrap() = WasmAbstractValue::Const(v);
+ }
+ _ => {} // TODO
+ }
+ }
+ LocationType::Direct => match mv {
+ MachineValue::WasmLocal(_) => {
+ assert_eq!(loc.location_size, 8); // the pointer itself
+ assert!(
+ X64Register::from_dwarf_regnum(loc.dwarf_regnum).unwrap()
+ == X64Register::GPR(GPR::RBP)
+ );
+ if loc.offset_or_small_constant >= 0 {
+ assert!(loc.offset_or_small_constant >= 16); // (saved_rbp, return_address)
+ assert!(loc.offset_or_small_constant % 8 == 0);
+ prev_frame_diff
+ .insert((loc.offset_or_small_constant as usize - 16) / 8, Some(mv));
+ } else {
+ let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize;
+ assert!(
+ stack_offset > 0 && stack_offset <= machine_stack_half_layout.len()
+ );
+ machine_stack_half_layout[stack_offset - 1] = mv;
+ }
+ }
+ _ => unreachable!(
+ "Direct location type is not expected for values other than local"
+ ),
+ },
+ LocationType::Indirect => {
+ assert!(loc.offset_or_small_constant < 0);
+ assert!(
+ X64Register::from_dwarf_regnum(loc.dwarf_regnum).unwrap()
+ == X64Register::GPR(GPR::RBP)
+ );
+ let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize;
+ assert!(stack_offset > 0 && stack_offset <= machine_stack_half_layout.len());
+ machine_stack_half_layout[stack_offset - 1] = mv;
+ }
+ }
+ }
+
+ assert_eq!(wasm_stack.len(), self.stack_count);
+ assert_eq!(wasm_locals.len(), self.local_count);
+
+ let mut machine_stack_layout: Vec =
+ Vec::with_capacity(machine_stack_half_layout.len() / 2);
+
+ for i in 0..machine_stack_half_layout.len() / 2 {
+ let major = &machine_stack_half_layout[i * 2 + 1]; // mod 8 == 0
+ let minor = &machine_stack_half_layout[i * 2]; // mod 8 == 4
+ let only_major = match *minor {
+ MachineValue::Undefined => true,
+ _ => false,
+ };
+ if only_major {
+ machine_stack_layout.push(major.clone());
+ } else {
+ machine_stack_layout.push(MachineValue::TwoHalves(Box::new((
+ major.clone(),
+ minor.clone(),
+ ))));
+ }
+ }
+
+ let diff = MachineStateDiff {
+ last: None,
+ stack_push: machine_stack_layout,
+ stack_pop: 0,
+ prev_frame_diff,
+ reg_diff: regs,
+ wasm_stack_push: wasm_stack,
+ wasm_stack_pop: 0,
+ wasm_stack_private_depth: 0,
+ wasm_inst_offset: self.opcode_offset,
+ };
+ let diff_id = fsm.diffs.len();
+ fsm.diffs.push(diff);
+
+ match self.kind {
+ StackmapEntryKind::FunctionHeader => {
+ fsm.locals = wasm_locals;
+ }
+ _ => {
+ assert_eq!(fsm.locals, wasm_locals);
+ }
+ }
+
+ let end_offset = {
+ if let Some(end) = end {
+ let (end_entry, end_record) = end;
+ assert_eq!(end_entry.is_start, false);
+ assert_eq!(self.opcode_offset, end_entry.opcode_offset);
+ let end_offset = func_base_addr + end_record.instruction_offset as usize;
+ assert!(end_offset >= target_offset);
+ end_offset
+ } else {
+ target_offset + 1
+ }
+ };
+
+ match self.kind {
+ StackmapEntryKind::Loop => {
+ fsm.wasm_offset_to_target_offset
+ .insert(self.opcode_offset, SuspendOffset::Loop(target_offset));
+ fsm.loop_offsets.insert(
+ target_offset,
+ OffsetInfo {
+ end_offset,
+ diff_id,
+ activate_offset: target_offset,
+ },
+ );
+ }
+ StackmapEntryKind::Call => {
+ fsm.wasm_offset_to_target_offset
+ .insert(self.opcode_offset, SuspendOffset::Call(target_offset));
+ fsm.call_offsets.insert(
+ target_offset,
+ OffsetInfo {
+ end_offset: end_offset + 1, // The return address is just after 'call' instruction. Offset by one here.
+ diff_id,
+ activate_offset: target_offset,
+ },
+ );
+ }
+ StackmapEntryKind::Trappable => {
+ fsm.wasm_offset_to_target_offset
+ .insert(self.opcode_offset, SuspendOffset::Trappable(target_offset));
+ fsm.trappable_offsets.insert(
+ target_offset,
+ OffsetInfo {
+ end_offset,
+ diff_id,
+ activate_offset: target_offset,
+ },
+ );
+ }
+ StackmapEntryKind::FunctionHeader => {
+ fsm.wasm_function_header_target_offset = Some(SuspendOffset::Loop(target_offset));
+ fsm.loop_offsets.insert(
+ target_offset,
+ OffsetInfo {
+ end_offset,
+ diff_id,
+ activate_offset: target_offset,
+ },
+ );
+ }
+ }
+ }
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct StackMap {
+ pub version: u8,
+ pub stk_size_records: Vec,
+ pub constants: Vec,
+ pub stk_map_records: Vec,
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+pub struct StkSizeRecord {
+ pub function_address: u64,
+ pub stack_size: u64,
+ pub record_count: u64,
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+pub struct Constant {
+ pub large_constant: u64,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct StkMapRecord {
+ pub patchpoint_id: u64,
+ pub instruction_offset: u32,
+ pub locations: Vec,
+ pub live_outs: Vec,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub struct Location {
+ pub ty: LocationType,
+ pub location_size: u16,
+ pub dwarf_regnum: u16,
+ pub offset_or_small_constant: i32,
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+pub struct LiveOut {
+ pub dwarf_regnum: u16,
+ pub size_in_bytes: u8,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum LocationType {
+ Register,
+ Direct,
+ Indirect,
+ Constant,
+ ConstantIndex,
+}
+
+impl StackMap {
+ pub fn parse(raw: &[u8]) -> io::Result {
+ let mut reader = Cursor::new(raw);
+ let mut map = StackMap::default();
+
+ let version = reader.read_u8()?;
+ if version != 3 {
+ return Err(io::Error::new(io::ErrorKind::Other, "version is not 3"));
+ }
+ map.version = version;
+ if reader.read_u8()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (1)",
+ ));
+ }
+ if reader.read_u16::()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (2)",
+ ));
+ }
+ let num_functions = reader.read_u32::()?;
+ let num_constants = reader.read_u32::()?;
+ let num_records = reader.read_u32::()?;
+ for _ in 0..num_functions {
+ let mut record = StkSizeRecord::default();
+ record.function_address = reader.read_u64::()?;
+ record.stack_size = reader.read_u64::()?;
+ record.record_count = reader.read_u64::()?;
+ map.stk_size_records.push(record);
+ }
+ for _ in 0..num_constants {
+ map.constants.push(Constant {
+ large_constant: reader.read_u64::()?,
+ });
+ }
+ for _ in 0..num_records {
+ let mut record = StkMapRecord::default();
+
+ record.patchpoint_id = reader.read_u64::()?;
+ record.instruction_offset = reader.read_u32::()?;
+ if reader.read_u16::()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (3)",
+ ));
+ }
+ let num_locations = reader.read_u16::()?;
+ for _ in 0..num_locations {
+ let ty = reader.read_u8()?;
+
+ let mut location = Location {
+ ty: match ty {
+ 1 => LocationType::Register,
+ 2 => LocationType::Direct,
+ 3 => LocationType::Indirect,
+ 4 => LocationType::Constant,
+ 5 => LocationType::ConstantIndex,
+ _ => {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "unknown location type",
+ ))
+ }
+ },
+ location_size: 0,
+ dwarf_regnum: 0,
+ offset_or_small_constant: 0,
+ };
+
+ if reader.read_u8()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (4)",
+ ));
+ }
+ location.location_size = reader.read_u16::()?;
+ location.dwarf_regnum = reader.read_u16::()?;
+ if reader.read_u16::()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (5)",
+ ));
+ }
+ location.offset_or_small_constant = reader.read_i32::()?;
+
+ record.locations.push(location);
+ }
+ if reader.position() % 8 != 0 {
+ if reader.read_u32::()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (6)",
+ ));
+ }
+ }
+ if reader.read_u16::()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (7)",
+ ));
+ }
+ let num_live_outs = reader.read_u16::()?;
+ for _ in 0..num_live_outs {
+ let mut liveout = LiveOut::default();
+
+ liveout.dwarf_regnum = reader.read_u16::()?;
+ if reader.read_u8()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (8)",
+ ));
+ }
+ liveout.size_in_bytes = reader.read_u8()?;
+
+ record.live_outs.push(liveout);
+ }
+ if reader.position() % 8 != 0 {
+ if reader.read_u32::()? != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "reserved field is not zero (9)",
+ ));
+ }
+ }
+
+ map.stk_map_records.push(record);
+ }
+ Ok(map)
+ }
+}
+
+fn deref_global(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec {
+ let mut x: Vec = match GlobalIndex::new(idx).local_or_import(info) {
+ LocalOrImport::Local(idx) => vec![Ctx::offset_globals() as usize, idx.index() * 8, 0],
+ LocalOrImport::Import(idx) => {
+ vec![Ctx::offset_imported_globals() as usize, idx.index() * 8, 0]
+ }
+ };
+ if deref_into_value {
+ x.push(0);
+ }
+ x
+}
+
+fn deref_table_base(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec {
+ let mut x: Vec = match TableIndex::new(idx).local_or_import(info) {
+ LocalOrImport::Local(idx) => vec![Ctx::offset_tables() as usize, idx.index() * 8, 0],
+ LocalOrImport::Import(idx) => {
+ vec![Ctx::offset_imported_tables() as usize, idx.index() * 8, 0]
+ }
+ };
+ if deref_into_value {
+ x.push(0);
+ }
+ x
+}
+
+fn deref_table_bound(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec {
+ let mut x: Vec = match TableIndex::new(idx).local_or_import(info) {
+ LocalOrImport::Local(idx) => vec![Ctx::offset_tables() as usize, idx.index() * 8, 8],
+ LocalOrImport::Import(idx) => {
+ vec![Ctx::offset_imported_tables() as usize, idx.index() * 8, 8]
+ }
+ };
+ if deref_into_value {
+ x.push(0);
+ }
+ x
+}
diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs
index 47da54a6d79..20f915ebce7 100644
--- a/lib/llvm-backend/src/state.rs
+++ b/lib/llvm-backend/src/state.rs
@@ -69,7 +69,7 @@ impl ControlFrame {
#[derive(Debug)]
pub struct State {
- stack: Vec,
+ pub stack: Vec,
control_stack: Vec,
value_counter: Cell,
diff --git a/lib/llvm-backend/src/trampolines.rs b/lib/llvm-backend/src/trampolines.rs
index 95fd676b952..cebfa9d4671 100644
--- a/lib/llvm-backend/src/trampolines.rs
+++ b/lib/llvm-backend/src/trampolines.rs
@@ -68,10 +68,8 @@ fn generate_trampoline(
};
let cast_ptr_ty = |wasmer_ty| match wasmer_ty {
- Type::I32 => intrinsics.i32_ptr_ty,
- Type::I64 => intrinsics.i64_ptr_ty,
- Type::F32 => intrinsics.f32_ptr_ty,
- Type::F64 => intrinsics.f64_ptr_ty,
+ Type::I32 | Type::F32 => intrinsics.i32_ptr_ty,
+ Type::I64 | Type::F64 => intrinsics.i64_ptr_ty,
Type::V128 => intrinsics.i128_ptr_ty,
};
diff --git a/lib/middleware-common-tests/src/lib.rs b/lib/middleware-common-tests/src/lib.rs
index 31b3e1065f9..0b6754c5f65 100644
--- a/lib/middleware-common-tests/src/lib.rs
+++ b/lib/middleware-common-tests/src/lib.rs
@@ -148,5 +148,4 @@ mod tests {
// verify it used the correct number of points
assert_eq!(get_points_used(&instance), 109); // Used points will be slightly more than `limit` because of the way we do gas checking.
}
-
}
diff --git a/lib/middleware-common/src/lib.rs b/lib/middleware-common/src/lib.rs
index 929558f252e..c7900c83a73 100644
--- a/lib/middleware-common/src/lib.rs
+++ b/lib/middleware-common/src/lib.rs
@@ -7,5 +7,8 @@
unused_unsafe,
unreachable_patterns
)]
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
+
pub mod call_trace;
pub mod metering;
diff --git a/lib/runtime-abi/src/lib.rs b/lib/runtime-abi/src/lib.rs
index 237e351b148..84923b43782 100644
--- a/lib/runtime-abi/src/lib.rs
+++ b/lib/runtime-abi/src/lib.rs
@@ -1,4 +1,8 @@
#![deny(dead_code, unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
+
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
+
#[cfg(not(target_os = "windows"))]
#[macro_use]
extern crate failure;
diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml
index c95442c625a..7744118534c 100644
--- a/lib/runtime-c-api/Cargo.toml
+++ b/lib/runtime-c-api/Cargo.toml
@@ -32,4 +32,4 @@ llvm-backend = ["wasmer-runtime/llvm", "wasmer-runtime/default-backend-llvm"]
singlepass-backend = ["wasmer-runtime/singlepass", "wasmer-runtime/default-backend-singlepass"]
[build-dependencies]
-cbindgen = "0.9.0"
+cbindgen = "0.9.1"
diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs
index 0fde6d33094..4dae18cd590 100644
--- a/lib/runtime-c-api/src/lib.rs
+++ b/lib/runtime-c-api/src/lib.rs
@@ -1,3 +1,6 @@
+#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
+#![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")]
+
//! # Wasmer Runtime C API
//!
//! Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully
diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h
index 297428ee275..816dbfeac9e 100644
--- a/lib/runtime-c-api/wasmer.h
+++ b/lib/runtime-c-api/wasmer.h
@@ -6,6 +6,9 @@
#include
#include
+/**
+ * List of export/import kinds.
+ */
enum wasmer_import_export_kind {
WASM_FUNCTION,
WASM_GLOBAL,
@@ -31,6 +34,9 @@ typedef struct {
} wasmer_module_t;
+/**
+ * Opaque pointer to `NamedExportDescriptor`.
+ */
typedef struct {
} wasmer_export_descriptor_t;
@@ -40,10 +46,16 @@ typedef struct {
uint32_t bytes_len;
} wasmer_byte_array;
+/**
+ * Opaque pointer to `NamedExportDescriptors`.
+ */
typedef struct {
} wasmer_export_descriptors_t;
+/**
+ * Opaque pointer to `wasmer_export_t`.
+ */
typedef struct {
} wasmer_export_func_t;
@@ -60,6 +72,9 @@ typedef struct {
wasmer_value value;
} wasmer_value_t;
+/**
+ * Opaque pointer to `NamedExport`.
+ */
typedef struct {
} wasmer_export_t;
@@ -68,6 +83,9 @@ typedef struct {
} wasmer_memory_t;
+/**
+ * Opaque pointer to `NamedExports`.
+ */
typedef struct {
} wasmer_exports_t;
@@ -101,6 +119,9 @@ typedef struct {
} wasmer_table_t;
+/**
+ * Union of import/export value.
+ */
typedef union {
const wasmer_import_func_t *func;
const wasmer_table_t *table;
diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh
index cf7a1c7b321..afe82536466 100644
--- a/lib/runtime-c-api/wasmer.hh
+++ b/lib/runtime-c-api/wasmer.hh
@@ -6,6 +6,7 @@
#include
#include
+/// List of export/import kinds.
enum class wasmer_import_export_kind : uint32_t {
WASM_FUNCTION,
WASM_GLOBAL,
@@ -29,6 +30,7 @@ struct wasmer_module_t {
};
+/// Opaque pointer to `NamedExportDescriptor`.
struct wasmer_export_descriptor_t {
};
@@ -38,10 +40,12 @@ struct wasmer_byte_array {
uint32_t bytes_len;
};
+/// Opaque pointer to `NamedExportDescriptors`.
struct wasmer_export_descriptors_t {
};
+/// Opaque pointer to `wasmer_export_t`.
struct wasmer_export_func_t {
};
@@ -58,6 +62,7 @@ struct wasmer_value_t {
wasmer_value value;
};
+/// Opaque pointer to `NamedExport`.
struct wasmer_export_t {
};
@@ -66,6 +71,7 @@ struct wasmer_memory_t {
};
+/// Opaque pointer to `NamedExports`.
struct wasmer_exports_t {
};
@@ -99,6 +105,7 @@ struct wasmer_table_t {
};
+/// Union of import/export value.
union wasmer_import_export_value {
const wasmer_import_func_t *func;
const wasmer_table_t *table;
diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml
index 5f13706233b..6c31cf5f5cf 100644
--- a/lib/runtime-core/Cargo.toml
+++ b/lib/runtime-core/Cargo.toml
@@ -41,7 +41,7 @@ version = "0.5.6"
version = "0.8.1"
[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3.7", features = ["memoryapi"] }
+winapi = { version = "0.3.8", features = ["memoryapi"] }
[dev-dependencies]
field-offset = "0.1.1"
@@ -58,3 +58,4 @@ trace = ["debug"]
"backend-cranelift" = []
"backend-singlepass" = []
"backend-llvm" = []
+managed = []
\ No newline at end of file
diff --git a/lib/runtime-core/build.rs b/lib/runtime-core/build.rs
index 35aafc83511..81884f0e18b 100644
--- a/lib/runtime-core/build.rs
+++ b/lib/runtime-core/build.rs
@@ -38,6 +38,5 @@ fn main() {
.file("image-loading-macos-x86-64.s")
.compile("image-loading");
} else {
-
}
}
diff --git a/lib/runtime-core/image-loading-linux-x86-64.s b/lib/runtime-core/image-loading-linux-x86-64.s
index 37ed0f98683..1d86bab0806 100644
--- a/lib/runtime-core/image-loading-linux-x86-64.s
+++ b/lib/runtime-core/image-loading-linux-x86-64.s
@@ -67,3 +67,37 @@ popq %r13
popq %r14
popq %r15
retq
+
+# For switching into a backend without information about where registers are preserved.
+.globl register_preservation_trampoline
+register_preservation_trampoline:
+subq $8, %rsp
+pushq %rax
+pushq %rcx
+pushq %rdx
+pushq %rdi
+pushq %rsi
+pushq %r8
+pushq %r9
+pushq %r10
+
+callq get_boundary_register_preservation
+
+# Keep this consistent with BoundaryRegisterPreservation
+movq %r15, 0(%rax)
+movq %r14, 8(%rax)
+movq %r13, 16(%rax)
+movq %r12, 24(%rax)
+movq %rbx, 32(%rax)
+
+popq %r10
+popq %r9
+popq %r8
+popq %rsi
+popq %rdi
+popq %rdx
+popq %rcx
+popq %rax
+addq $8, %rsp
+
+jmpq *%rax
diff --git a/lib/runtime-core/image-loading-macos-x86-64.s b/lib/runtime-core/image-loading-macos-x86-64.s
index a6a307f1fd4..ef6f9451060 100644
--- a/lib/runtime-core/image-loading-macos-x86-64.s
+++ b/lib/runtime-core/image-loading-macos-x86-64.s
@@ -67,3 +67,37 @@ popq %r13
popq %r14
popq %r15
retq
+
+# For switching into a backend without information about where registers are preserved.
+.globl _register_preservation_trampoline
+_register_preservation_trampoline:
+subq $8, %rsp
+pushq %rax
+pushq %rcx
+pushq %rdx
+pushq %rdi
+pushq %rsi
+pushq %r8
+pushq %r9
+pushq %r10
+
+callq _get_boundary_register_preservation
+
+# Keep this consistent with BoundaryRegisterPreservation
+movq %r15, 0(%rax)
+movq %r14, 8(%rax)
+movq %r13, 16(%rax)
+movq %r12, 24(%rax)
+movq %rbx, 32(%rax)
+
+popq %r10
+popq %r9
+popq %r8
+popq %rsi
+popq %rdi
+popq %rdx
+popq %rcx
+popq %rax
+addq $8, %rsp
+
+jmpq *%rax
diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs
index 2bb2303180d..0a062ba5f5c 100644
--- a/lib/runtime-core/src/backend.rs
+++ b/lib/runtime-core/src/backend.rs
@@ -159,6 +159,10 @@ pub trait RunnableModule: Send + Sync {
None
}
+ unsafe fn patch_local_function(&self, _idx: usize, _target_address: usize) -> bool {
+ false
+ }
+
/// A wasm trampoline contains the necessary data to dynamically call an exported wasm function.
/// Given a particular signature index, we are returned a trampoline that is matched with that
/// signature and an invoke function that can call the trampoline.
@@ -175,6 +179,11 @@ pub trait RunnableModule: Send + Sync {
fn get_offsets(&self) -> Option> {
None
}
+
+ /// Returns the beginning offsets of all local functions.
+ fn get_local_function_offsets(&self) -> Option> {
+ None
+ }
}
pub trait CacheGen: Send + Sync {
diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs
index b44978b1b9e..2d46d8ca25c 100644
--- a/lib/runtime-core/src/fault.rs
+++ b/lib/runtime-core/src/fault.rs
@@ -1,8 +1,9 @@
-mod raw {
+pub mod raw {
use std::ffi::c_void;
extern "C" {
pub fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: *mut u64) -> u64;
+ pub fn register_preservation_trampoline(); // NOT safe to call directly
pub fn setjmp(env: *mut c_void) -> i32;
pub fn longjmp(env: *mut c_void, val: i32) -> !;
}
@@ -10,6 +11,7 @@ mod raw {
use crate::codegen::{BreakpointInfo, BreakpointMap};
use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR, XMM};
+use crate::state::CodeVersion;
use crate::vm;
use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
use nix::sys::signal::{
@@ -17,7 +19,7 @@ use nix::sys::signal::{
SIGSEGV, SIGTRAP,
};
use std::any::Any;
-use std::cell::UnsafeCell;
+use std::cell::{Cell, RefCell, UnsafeCell};
use std::ffi::c_void;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
@@ -38,8 +40,27 @@ struct UnwindInfo {
payload: Option>, // out
}
+#[repr(packed)]
+#[derive(Default, Copy, Clone)]
+pub struct BoundaryRegisterPreservation {
+ pub r15: u64,
+ pub r14: u64,
+ pub r13: u64,
+ pub r12: u64,
+ pub rbx: u64,
+}
+
thread_local! {
static UNWIND: UnsafeCell