Merge remote-tracking branch 'upstream/master' into poll
This commit is contained in:
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -71,7 +71,7 @@ jobs:
|
||||
- uses: ./.github/actions/install-rust
|
||||
with:
|
||||
toolchain: nightly
|
||||
- run: cargo install cargo-fuzz --vers "^0.6"
|
||||
- run: cargo install cargo-fuzz --vers "^0.7"
|
||||
- run: cargo fetch
|
||||
working-directory: ./fuzz
|
||||
- run: cargo fuzz build --release --debug-assertions
|
||||
@@ -165,6 +165,7 @@ jobs:
|
||||
- run: rustup target add wasm32-wasi
|
||||
|
||||
- run: cargo fetch --locked
|
||||
- run: cargo fetch --locked --manifest-path crates/test-programs/wasi-tests/Cargo.toml
|
||||
|
||||
# Build and test all features except for lightbeam
|
||||
- run: cargo test --features test_programs --all --exclude lightbeam -- --nocapture
|
||||
@@ -302,7 +303,7 @@ jobs:
|
||||
- run: $CENTOS cargo build --release --bin wasmtime --bin wasm2obj
|
||||
shell: bash
|
||||
# Build `libwasmtime.so`
|
||||
- run: $CENTOS cargo build --release --manifest-path crates/api/Cargo.toml
|
||||
- run: $CENTOS cargo build --release --manifest-path crates/c-api/Cargo.toml
|
||||
shell: bash
|
||||
# Test what we just built
|
||||
- run: $CENTOS cargo test --features test_programs --release --all --exclude lightbeam --exclude wasmtime --exclude wasmtime-fuzzing
|
||||
@@ -511,4 +512,3 @@ jobs:
|
||||
files: "dist/*"
|
||||
name: ${{ steps.tagname.outputs.val }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,8 +1,8 @@
|
||||
[submodule "spec_testsuite"]
|
||||
path = tests/spec_testsuite
|
||||
url = https://github.com/WebAssembly/testsuite
|
||||
[submodule "crates/api/c-examples/wasm-c-api"]
|
||||
path = crates/api/c-examples/wasm-c-api
|
||||
[submodule "crates/c-api/examples/wasm-c-api"]
|
||||
path = crates/c-api/examples/wasm-c-api
|
||||
url = https://github.com/WebAssembly/wasm-c-api
|
||||
[submodule "crates/wasi-common/WASI"]
|
||||
path = crates/wasi-common/wig/WASI
|
||||
|
||||
284
Cargo.lock
generated
284
Cargo.lock
generated
@@ -30,6 +30,15 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64cf76cb6e2222ed0ea86b2b0ee2f71c96ec6edd5af42e84d59160e91b836ec4"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93b22576af8f14bb2bad6a5dc09c4f80539a801f7ea340c798e222f2ce49859"
|
||||
dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.5"
|
||||
@@ -76,9 +85,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.40"
|
||||
version = "0.3.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
|
||||
checksum = "b4b1549d804b6c73f4817df2ba073709e96e426f12987127c48e6745568c350b"
|
||||
dependencies = [
|
||||
"backtrace-sys",
|
||||
"cfg-if",
|
||||
@@ -159,8 +168,8 @@ dependencies = [
|
||||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
@@ -341,24 +350,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd3225fff1be118941c5fb66f1fb1f7f3e86468fac0e7364713c4fb99b72632b"
|
||||
checksum = "40af6e6f7419110906d0f7b4b8084d3216be64d7da77aa12887885ebe0fc2776"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3e3e6679892029f76a99b9059d2b74e77ac03637d573bb014bc21579ec1b7da"
|
||||
checksum = "88583eb22e5cd0fe1ef66f0b80d0063d21d30e84e887d08b3d369def3ea7b4be"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cranelift-bforest",
|
||||
"cranelift-codegen-meta",
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-entity",
|
||||
"gimli",
|
||||
"log",
|
||||
"serde",
|
||||
"smallvec",
|
||||
@@ -368,9 +378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cabe691548e28ca82ebd218f2fe76eec4c5629b64ef3db8b58443b7d9047275"
|
||||
checksum = "353872c984943b9134d7c835eb9d12932bd90f4992dbe666593771bee920d673"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-entity",
|
||||
@@ -378,24 +388,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d173252ffade4aa6e929090977b9a4cd5ac28e15a42626f878be3844b3000ad9"
|
||||
checksum = "cd1e96479a56981cce5c8f14d26773195d662ccdbbeca39fb8eba22b5ca8ea6a"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3498ad9ba021715716a1c52e2b31d7829a149913fb0d88493e4b07d3b772b656"
|
||||
checksum = "37bc8dc3d4274ededc687d84821f491a8a03447dbb7481983936220892cf55b4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "521a30773b8de74345c807a38853f055aca8fecaa39a0fc7698bfebc5a3da515"
|
||||
checksum = "4ea33e55bda8c425f3f533355b03e3a43cf29b4e228b35b868b6a1c43b6a139e"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
@@ -405,9 +415,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624e755cbe984e437308968239736e7f9aa3193e99928fb76eec7a1946627b34"
|
||||
checksum = "2c22cfaaa5e69eddaddd6cfa7a76233de964b9b2245e81a5f47dae739931ad0d"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"raw-cpuid",
|
||||
@@ -416,9 +426,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0320733e518ab9e0e2d1a22034d40e2851fb403ed14db5220cf9b86576b9cfd4"
|
||||
checksum = "038f8fd636abc83ccd6f110e0891766521c3599b52173c0f37e61c684f19a15d"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"cranelift-entity",
|
||||
@@ -426,7 +436,7 @@ dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"wasmparser 0.45.2",
|
||||
"wasmparser 0.47.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -513,8 +523,8 @@ version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -526,6 +536,17 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_arbitrary"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b979a9f98d526ac07489ae2879e04d948ceeb195d777742997a30c3d1ab1aad6"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"syn 0.14.9",
|
||||
"synstructure 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
@@ -567,9 +588,9 @@ dependencies = [
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"owning_ref",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -667,10 +688,10 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
"synstructure 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -745,9 +766,9 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -839,9 +860,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
"unindent",
|
||||
]
|
||||
|
||||
@@ -862,9 +883,9 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a8e30575afe28eea36a9a39136b70b2fb6b0dd0a212a5bd1f30a498395c0274"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -917,10 +938,11 @@ checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-fuzz/libfuzzer-sys.git#0c4507533a79e85e1984f59765bdd35fbdaa7f1b"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94f9e4f036a9cb9f43c637990c03fe045425a33c1c44abf9bc6f555671be5969"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"arbitrary 0.3.2",
|
||||
"cc",
|
||||
]
|
||||
|
||||
@@ -1144,9 +1166,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1185,10 +1207,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53c98547ceaea14eeb26fcadf51dc70d01a2479a7839170eae133721105e4428"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"rustversion",
|
||||
"syn",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1197,10 +1219,10 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2bf5d493cf5d3e296beccfd61794e445e830dfc8070a9c248ad3ee071392c6c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"rustversion",
|
||||
"syn",
|
||||
"syn 1.0.13",
|
||||
"syn-mid",
|
||||
]
|
||||
|
||||
@@ -1210,9 +1232,18 @@ version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1221,7 +1252,7 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1251,9 +1282,9 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4882d8237fd8c7373cc25cb802fe0dab9ff70830fd56f47ef6c7f3f287fcc057"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1262,10 +1293,10 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdf321cfab555f7411298733c86d21e5136f5ded13f5872fabf9de3337beecda"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"proc-macro2 1.0.7",
|
||||
"pyo3-derive-backend",
|
||||
"quote",
|
||||
"syn",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1286,13 +1317,22 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"proc-macro2 1.0.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1517,9 +1557,9 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a0538bd897e17257b0128d2fd95c2ed6df939374073a36166051a79e2eb7986"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1549,9 +1589,9 @@ version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1584,9 +1624,9 @@ version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1669,9 +1709,20 @@ checksum = "0a97f829a34a0a9d5b353a881025a23b8c9fd09d46be6045df6b22920dbd7a93"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"unicode-xid 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1680,9 +1731,9 @@ version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1691,9 +1742,21 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fd3937748a7eccff61ba5b90af1a20dbf610858923a9192ea0ecb0cb77db1d0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"syn 0.14.9",
|
||||
"unicode-xid 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1702,10 +1765,10 @@ version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1780,9 +1843,9 @@ version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb2e25d25307eb8436894f727aba8f65d07adf02e5b35a13cebed48bd282bfef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1861,6 +1924,12 @@ version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
@@ -1921,9 +1990,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8757b0da38353d55a9687f4dee68a8f441f980dd36e16ab07d6e6c673f505f76"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1958,9 +2027,9 @@ dependencies = [
|
||||
name = "wasi-common-cbindgen"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
"trybuild",
|
||||
]
|
||||
|
||||
@@ -1988,12 +2057,6 @@ version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1527c84a5bd585215f29c06b0e2a5274e478ad4dfc970d26ffad66fdc6cb311d"
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.45.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b4eab1d9971d0803729cba3617b56eb04fcb4bd25361cb63880ed41a42f20d5"
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.47.0"
|
||||
@@ -2015,6 +2078,7 @@ name = "wasmtime"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backtrace",
|
||||
"cfg-if",
|
||||
"file-per-thread-logger",
|
||||
"libc",
|
||||
@@ -2031,6 +2095,13 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-c-api"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"wasmtime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-cli"
|
||||
version = "0.9.0"
|
||||
@@ -2113,7 +2184,7 @@ dependencies = [
|
||||
name = "wasmtime-fuzz"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"arbitrary 0.2.0",
|
||||
"env_logger 0.7.1",
|
||||
"libfuzzer-sys",
|
||||
"log",
|
||||
@@ -2127,7 +2198,7 @@ name = "wasmtime-fuzzing"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arbitrary",
|
||||
"arbitrary 0.3.2",
|
||||
"binaryen",
|
||||
"env_logger 0.7.1",
|
||||
"log",
|
||||
@@ -2205,6 +2276,7 @@ dependencies = [
|
||||
name = "wasmtime-runtime"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"indexmap",
|
||||
@@ -2233,9 +2305,9 @@ dependencies = [
|
||||
name = "wasmtime-rust-macro"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2323,8 +2395,8 @@ name = "wig"
|
||||
version = "0.9.2"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"proc-macro2 1.0.7",
|
||||
"quote 1.0.2",
|
||||
"witx",
|
||||
]
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ members = [
|
||||
"crates/fuzzing",
|
||||
"crates/misc/rust",
|
||||
"crates/misc/py",
|
||||
"crates/c-api",
|
||||
"fuzz",
|
||||
]
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ mkdir tmp/$api_pkgname/lib
|
||||
mkdir tmp/$api_pkgname/include
|
||||
cp LICENSE README.md tmp/$api_pkgname
|
||||
mv bins-$src/* tmp/$api_pkgname/lib
|
||||
cp crates/api/c-examples/wasm-c-api/include/wasm.h tmp/$api_pkgname/include
|
||||
cp crates/c-api/examples/wasm-c-api/include/wasm.h tmp/$api_pkgname/include
|
||||
mktarball $api_pkgname
|
||||
|
||||
# Move wheels to dist folder
|
||||
|
||||
@@ -8,10 +8,6 @@ repository = "https://github.com/bytecodealliance/wasmtime"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "wasmtime"
|
||||
crate-type = ["lib", "staticlib", "cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
|
||||
wasmtime-environ = { path = "../environ", version = "0.9.0" }
|
||||
@@ -22,6 +18,7 @@ anyhow = "1.0.19"
|
||||
region = "2.0.0"
|
||||
libc = "0.2"
|
||||
cfg-if = "0.1.9"
|
||||
backtrace = "0.3.42"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = "0.3.7"
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
# Implementation of wasm-c-api in Rust
|
||||
## Wasmtime Embedding API
|
||||
|
||||
https://github.com/WebAssembly/wasm-c-api
|
||||
The `wasmtime` crate is an embedding API of the `wasmtime` WebAssembly runtime.
|
||||
This is intended to be used in Rust projects and provides a high-level API of
|
||||
working with WebAssembly modules.
|
||||
|
||||
If you're interested in embedding `wasmtime` in other languages, you may wish to
|
||||
take a look a the [C embedding API](../c-api) instead!
|
||||
|
||||
@@ -141,13 +141,12 @@ impl WrappedCallable for WasmtimeFn {
|
||||
// Get the trampoline to call for this function.
|
||||
let exec_code_buf = self
|
||||
.store
|
||||
.context()
|
||||
.compiler()
|
||||
.compiler_mut()
|
||||
.get_published_trampoline(body, &signature, value_size)
|
||||
.map_err(|e| Trap::new(format!("trampoline error: {:?}", e)))?;
|
||||
|
||||
// Call the trampoline.
|
||||
if let Err(message) = unsafe {
|
||||
if let Err(error) = unsafe {
|
||||
self.instance.with_signals_on(|| {
|
||||
wasmtime_runtime::wasmtime_call_trampoline(
|
||||
vmctx,
|
||||
@@ -156,8 +155,7 @@ impl WrappedCallable for WasmtimeFn {
|
||||
)
|
||||
})
|
||||
} {
|
||||
let trap =
|
||||
take_api_trap().unwrap_or_else(|| Trap::new(format!("call error: {}", message)));
|
||||
let trap = take_api_trap().unwrap_or_else(|| Trap::from_jit(error));
|
||||
return Err(trap);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
use crate::Config;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::rc::Rc;
|
||||
use wasmtime_environ::settings;
|
||||
use wasmtime_jit::{native, Compiler, Features};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
compiler: Rc<RefCell<Compiler>>,
|
||||
features: Features,
|
||||
debug_info: bool,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(config: &Config) -> Context {
|
||||
let isa = native::builder().finish(settings::Flags::new(config.flags.clone()));
|
||||
Context::new_with_compiler(config, Compiler::new(isa, config.strategy))
|
||||
}
|
||||
|
||||
pub fn new_with_compiler(config: &Config, compiler: Compiler) -> Context {
|
||||
Context {
|
||||
compiler: Rc::new(RefCell::new(compiler)),
|
||||
features: config.features.clone(),
|
||||
debug_info: config.debug_info,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn debug_info(&self) -> bool {
|
||||
self.debug_info
|
||||
}
|
||||
|
||||
pub(crate) fn compiler(&self) -> RefMut<Compiler> {
|
||||
self.compiler.borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Context {
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
self.compiler.as_ptr().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Context {}
|
||||
|
||||
impl PartialEq for Context {
|
||||
fn eq(&self, other: &Context) -> bool {
|
||||
Rc::ptr_eq(&self.compiler, &other.compiler)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::context::Context;
|
||||
use crate::externals::Extern;
|
||||
use crate::module::Module;
|
||||
use crate::runtime::Store;
|
||||
@@ -6,9 +5,6 @@ use crate::trampoline::take_api_trap;
|
||||
use crate::trap::Trap;
|
||||
use crate::types::{ExportType, ExternType};
|
||||
use anyhow::{Error, Result};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::rc::Rc;
|
||||
use wasmtime_jit::{CompiledModule, Resolver};
|
||||
use wasmtime_runtime::{Export, InstanceHandle, InstantiationError};
|
||||
|
||||
@@ -29,19 +25,15 @@ fn instantiate_in_context(
|
||||
data: &[u8],
|
||||
imports: &[Extern],
|
||||
module_name: Option<&str>,
|
||||
context: Context,
|
||||
exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||
) -> Result<(InstanceHandle, HashSet<Context>), Error> {
|
||||
let mut contexts = HashSet::new();
|
||||
let debug_info = context.debug_info();
|
||||
) -> Result<InstanceHandle> {
|
||||
let mut resolver = SimpleResolver { imports };
|
||||
let mut compiled_module = CompiledModule::new(
|
||||
&mut context.compiler(),
|
||||
&mut store.compiler_mut(),
|
||||
data,
|
||||
module_name,
|
||||
&mut resolver,
|
||||
exports,
|
||||
debug_info,
|
||||
store.global_exports().clone(),
|
||||
store.engine().config().debug_info,
|
||||
)?;
|
||||
|
||||
// Register all module signatures
|
||||
@@ -52,40 +44,30 @@ fn instantiate_in_context(
|
||||
let instance = compiled_module.instantiate().map_err(|e| -> Error {
|
||||
if let Some(trap) = take_api_trap() {
|
||||
trap.into()
|
||||
} else if let InstantiationError::StartTrap(msg) = e {
|
||||
Trap::new(msg).into()
|
||||
} else if let InstantiationError::StartTrap(trap) = e {
|
||||
Trap::from_jit(trap).into()
|
||||
} else {
|
||||
e.into()
|
||||
}
|
||||
})?;
|
||||
contexts.insert(context);
|
||||
Ok((instance, contexts))
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Instance {
|
||||
instance_handle: InstanceHandle,
|
||||
|
||||
module: Module,
|
||||
|
||||
// We need to keep CodeMemory alive.
|
||||
contexts: HashSet<Context>,
|
||||
|
||||
exports: Box<[Extern]>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn new(module: &Module, externs: &[Extern]) -> Result<Instance, Error> {
|
||||
let store = module.store();
|
||||
let context = store.context().clone();
|
||||
let exports = store.global_exports().clone();
|
||||
let (mut instance_handle, contexts) = instantiate_in_context(
|
||||
module.store(),
|
||||
let mut instance_handle = instantiate_in_context(
|
||||
store,
|
||||
module.binary().expect("binary"),
|
||||
externs,
|
||||
module.name(),
|
||||
context,
|
||||
exports,
|
||||
)?;
|
||||
|
||||
let exports = {
|
||||
@@ -104,7 +86,6 @@ impl Instance {
|
||||
Ok(Instance {
|
||||
instance_handle,
|
||||
module: module.clone(),
|
||||
contexts,
|
||||
exports,
|
||||
})
|
||||
}
|
||||
@@ -141,8 +122,6 @@ impl Instance {
|
||||
}
|
||||
|
||||
pub fn from_handle(store: &Store, instance_handle: InstanceHandle) -> Instance {
|
||||
let contexts = HashSet::new();
|
||||
|
||||
let mut exports = Vec::new();
|
||||
let mut exports_types = Vec::new();
|
||||
let mut mutable = instance_handle.clone();
|
||||
@@ -175,7 +154,6 @@ impl Instance {
|
||||
Instance {
|
||||
instance_handle,
|
||||
module,
|
||||
contexts,
|
||||
exports: exports.into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
//! itself for consumption from other languages.
|
||||
|
||||
mod callable;
|
||||
mod context;
|
||||
mod externals;
|
||||
mod instance;
|
||||
mod module;
|
||||
@@ -18,13 +17,11 @@ mod trap;
|
||||
mod types;
|
||||
mod values;
|
||||
|
||||
pub mod wasm;
|
||||
|
||||
pub use crate::callable::Callable;
|
||||
pub use crate::externals::*;
|
||||
pub use crate::instance::Instance;
|
||||
pub use crate::module::Module;
|
||||
pub use crate::r#ref::AnyRef;
|
||||
pub use crate::r#ref::{AnyRef, HostInfo, HostRef};
|
||||
pub use crate::runtime::{Config, Engine, OptLevel, Store, Strategy};
|
||||
pub use crate::trap::{FrameInfo, Trap};
|
||||
pub use crate::types::*;
|
||||
|
||||
@@ -196,7 +196,7 @@ impl Module {
|
||||
///
|
||||
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
||||
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
|
||||
let features = store.engine().config.features.clone();
|
||||
let features = store.engine().config().features.clone();
|
||||
let config = ValidatingParserConfig {
|
||||
operator_config: OperatorValidatorConfig {
|
||||
enable_threads: features.threads,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::context::Context;
|
||||
use anyhow::Result;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
@@ -8,7 +7,7 @@ use wasmtime_environ::{
|
||||
ir,
|
||||
settings::{self, Configurable},
|
||||
};
|
||||
use wasmtime_jit::{CompilationStrategy, Features};
|
||||
use wasmtime_jit::{native, CompilationStrategy, Compiler, Features};
|
||||
|
||||
// Runtime Environment
|
||||
|
||||
@@ -297,7 +296,7 @@ pub enum OptLevel {
|
||||
/// default settings.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Engine {
|
||||
pub(crate) config: Arc<Config>,
|
||||
config: Arc<Config>,
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
@@ -308,6 +307,11 @@ impl Engine {
|
||||
config: Arc::new(config.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the configuration settings that this engine is using.
|
||||
pub fn config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
// Store
|
||||
@@ -337,7 +341,7 @@ pub struct Store {
|
||||
|
||||
struct StoreInner {
|
||||
engine: Engine,
|
||||
context: Context,
|
||||
compiler: RefCell<Compiler>,
|
||||
global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||
signature_cache: RefCell<HashMap<wasmtime_runtime::VMSharedSignatureIndex, ir::Signature>>,
|
||||
}
|
||||
@@ -345,10 +349,12 @@ struct StoreInner {
|
||||
impl Store {
|
||||
/// Creates a new store to be associated with the given [`Engine`].
|
||||
pub fn new(engine: &Engine) -> Store {
|
||||
let isa = native::builder().finish(settings::Flags::new(engine.config.flags.clone()));
|
||||
let compiler = Compiler::new(isa, engine.config.strategy);
|
||||
Store {
|
||||
inner: Rc::new(StoreInner {
|
||||
engine: engine.clone(),
|
||||
context: Context::new(&engine.config),
|
||||
compiler: RefCell::new(compiler),
|
||||
global_exports: Rc::new(RefCell::new(HashMap::new())),
|
||||
signature_cache: RefCell::new(HashMap::new()),
|
||||
}),
|
||||
@@ -360,8 +366,8 @@ impl Store {
|
||||
&self.inner.engine
|
||||
}
|
||||
|
||||
pub(crate) fn context(&self) -> &Context {
|
||||
&self.inner.context
|
||||
pub(crate) fn compiler_mut(&self) -> std::cell::RefMut<'_, Compiler> {
|
||||
self.inner.compiler.borrow_mut()
|
||||
}
|
||||
|
||||
// Specific to wasmtime: hack to pass memory around to wasi
|
||||
@@ -377,7 +383,7 @@ impl Store {
|
||||
signature: &ir::Signature,
|
||||
) -> wasmtime_runtime::VMSharedSignatureIndex {
|
||||
use std::collections::hash_map::Entry;
|
||||
let index = self.context().compiler().signatures().register(signature);
|
||||
let index = self.compiler_mut().signatures().register(signature);
|
||||
match self.inner.signature_cache.borrow_mut().entry(index) {
|
||||
Entry::Vacant(v) => {
|
||||
v.insert(signature.clone());
|
||||
@@ -398,7 +404,13 @@ impl Store {
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn ptr_eq(a: &Store, b: &Store) -> bool {
|
||||
/// Returns whether the stores `a` and `b` refer to the same underlying
|
||||
/// `Store`.
|
||||
///
|
||||
/// Because the `Store` type is reference counted multiple clones may point
|
||||
/// to the same underlying storage, and this method can be used to determine
|
||||
/// whether two stores are indeed the same.
|
||||
pub fn same(a: &Store, b: &Store) -> bool {
|
||||
Rc::ptr_eq(&a.inner, &b.inner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ use wasmtime_environ::entity::{EntityRef, PrimaryMap};
|
||||
use wasmtime_environ::ir::types;
|
||||
use wasmtime_environ::isa::TargetIsa;
|
||||
use wasmtime_environ::wasm::{DefinedFuncIndex, FuncIndex};
|
||||
use wasmtime_environ::{ir, settings, CompiledFunction, Export, Module, TrapInformation};
|
||||
use wasmtime_environ::{
|
||||
ir, settings, CompiledFunction, CompiledFunctionUnwindInfo, Export, Module, TrapInformation,
|
||||
};
|
||||
use wasmtime_jit::trampoline::ir::{
|
||||
ExternalName, Function, InstBuilder, MemFlags, StackSlotData, StackSlotKind,
|
||||
};
|
||||
@@ -136,6 +138,7 @@ fn make_trampoline(
|
||||
|
||||
let mut context = Context::new();
|
||||
context.func = Function::with_name_signature(ExternalName::user(0, 0), signature.clone());
|
||||
context.func.collect_frame_layout_info();
|
||||
|
||||
let ss = context.func.create_stack_slot(StackSlotData::new(
|
||||
StackSlotKind::ExplicitSlot,
|
||||
@@ -213,8 +216,7 @@ fn make_trampoline(
|
||||
.map_err(|error| pretty_error(&context.func, Some(isa), error))
|
||||
.expect("compile_and_emit");
|
||||
|
||||
let mut unwind_info = Vec::new();
|
||||
context.emit_unwind_info(isa, &mut unwind_info);
|
||||
let unwind_info = CompiledFunctionUnwindInfo::new(isa, &context);
|
||||
|
||||
let traps = trap_sink.traps;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::instance::Instance;
|
||||
use backtrace::Backtrace;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -11,7 +12,8 @@ pub struct Trap {
|
||||
|
||||
struct TrapInner {
|
||||
message: String,
|
||||
trace: Vec<FrameInfo>,
|
||||
wasm_trace: Vec<FrameInfo>,
|
||||
native_trace: Backtrace,
|
||||
}
|
||||
|
||||
fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
|
||||
@@ -26,10 +28,29 @@ impl Trap {
|
||||
/// assert_eq!("unexpected error", trap.message());
|
||||
/// ```
|
||||
pub fn new<I: Into<String>>(message: I) -> Self {
|
||||
Trap::new_with_trace(message.into(), Backtrace::new_unresolved())
|
||||
}
|
||||
|
||||
pub(crate) fn from_jit(jit: wasmtime_runtime::Trap) -> Self {
|
||||
Trap::new_with_trace(jit.to_string(), jit.backtrace)
|
||||
}
|
||||
|
||||
fn new_with_trace(message: String, native_trace: Backtrace) -> Self {
|
||||
let mut wasm_trace = Vec::new();
|
||||
for frame in native_trace.frames() {
|
||||
let pc = frame.ip() as usize;
|
||||
if let Some(info) = wasmtime_runtime::jit_function_registry::find(pc) {
|
||||
wasm_trace.push(FrameInfo {
|
||||
func_index: info.func_index as u32,
|
||||
module_name: info.module_id.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
Trap {
|
||||
inner: Arc::new(TrapInner {
|
||||
message: message.into(),
|
||||
trace: Vec::new(),
|
||||
message,
|
||||
wasm_trace,
|
||||
native_trace,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -40,7 +61,7 @@ impl Trap {
|
||||
}
|
||||
|
||||
pub fn trace(&self) -> &[FrameInfo] {
|
||||
&self.inner.trace
|
||||
&self.inner.wasm_trace
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +69,8 @@ impl fmt::Debug for Trap {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Trap")
|
||||
.field("message", &self.inner.message)
|
||||
.field("trace", &self.inner.trace)
|
||||
.field("wasm_trace", &self.inner.wasm_trace)
|
||||
.field("native_trace", &self.inner.native_trace)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -62,22 +84,29 @@ impl fmt::Display for Trap {
|
||||
impl std::error::Error for Trap {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FrameInfo;
|
||||
pub struct FrameInfo {
|
||||
module_name: Option<String>,
|
||||
func_index: u32,
|
||||
}
|
||||
|
||||
impl FrameInfo {
|
||||
pub fn instance(&self) -> *const Instance {
|
||||
unimplemented!("FrameInfo::instance");
|
||||
}
|
||||
|
||||
pub fn func_index() -> usize {
|
||||
unimplemented!("FrameInfo::func_index");
|
||||
pub fn func_index(&self) -> u32 {
|
||||
self.func_index
|
||||
}
|
||||
|
||||
pub fn func_offset() -> usize {
|
||||
pub fn func_offset(&self) -> usize {
|
||||
unimplemented!("FrameInfo::func_offset");
|
||||
}
|
||||
|
||||
pub fn module_offset() -> usize {
|
||||
pub fn module_offset(&self) -> usize {
|
||||
unimplemented!("FrameInfo::module_offset");
|
||||
}
|
||||
|
||||
pub fn module_name(&self) -> Option<&str> {
|
||||
self.module_name.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ fn test_invoke_func_via_table() -> Result<()> {
|
||||
"#,
|
||||
)?;
|
||||
let module = Module::new(&store, &binary).context("> Error compiling module!")?;
|
||||
let instance = Instance::new(&store, &module, &[]).context("> Error instantiating module!")?;
|
||||
let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?;
|
||||
|
||||
let f = instance
|
||||
.find_export_by_name("table")
|
||||
|
||||
@@ -41,3 +41,116 @@ fn test_trap_return() -> Result<(), String> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trap_trace() -> Result<(), String> {
|
||||
let store = Store::default();
|
||||
let binary = parse_str(
|
||||
r#"
|
||||
(module $hello_mod
|
||||
(func (export "run") (call $hello))
|
||||
(func $hello (unreachable))
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
|
||||
|
||||
let module =
|
||||
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?;
|
||||
let instance = Instance::new(&module, &[])
|
||||
.map_err(|e| format!("failed to instantiate module: {:?}", e))?;
|
||||
let run_func = instance.exports()[0]
|
||||
.func()
|
||||
.expect("expected function export");
|
||||
|
||||
let e = run_func.call(&[]).err().expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
assert_eq!(trace.len(), 2);
|
||||
assert_eq!(trace[0].module_name().unwrap(), "hello_mod");
|
||||
assert_eq!(trace[0].func_index(), 1);
|
||||
assert_eq!(trace[1].module_name().unwrap(), "hello_mod");
|
||||
assert_eq!(trace[1].func_index(), 0);
|
||||
assert!(e.message().contains("unreachable"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trap_trace_cb() -> Result<(), String> {
|
||||
struct ThrowCallback;
|
||||
|
||||
impl Callable for ThrowCallback {
|
||||
fn call(&self, _params: &[Val], _results: &mut [Val]) -> Result<(), Trap> {
|
||||
Err(Trap::new("cb throw"))
|
||||
}
|
||||
}
|
||||
|
||||
let store = Store::default();
|
||||
let binary = parse_str(
|
||||
r#"
|
||||
(module $hello_mod
|
||||
(import "" "throw" (func $throw))
|
||||
(func (export "run") (call $hello))
|
||||
(func $hello (call $throw))
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
|
||||
|
||||
let fn_type = FuncType::new(Box::new([]), Box::new([]));
|
||||
let fn_func = Func::new(&store, fn_type, Rc::new(ThrowCallback));
|
||||
|
||||
let module =
|
||||
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?;
|
||||
let instance = Instance::new(&module, &[fn_func.into()])
|
||||
.map_err(|e| format!("failed to instantiate module: {:?}", e))?;
|
||||
let run_func = instance.exports()[0]
|
||||
.func()
|
||||
.expect("expected function export");
|
||||
|
||||
let e = run_func.call(&[]).err().expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
assert_eq!(trace.len(), 2);
|
||||
assert_eq!(trace[0].module_name().unwrap(), "hello_mod");
|
||||
assert_eq!(trace[0].func_index(), 1);
|
||||
assert_eq!(trace[1].module_name().unwrap(), "hello_mod");
|
||||
assert_eq!(trace[1].func_index(), 0);
|
||||
assert_eq!(e.message(), "cb throw");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trap_stack_overflow() -> Result<(), String> {
|
||||
let store = Store::default();
|
||||
let binary = parse_str(
|
||||
r#"
|
||||
(module $rec_mod
|
||||
(func $run (export "run") (call $run))
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
|
||||
|
||||
let module =
|
||||
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?;
|
||||
let instance = Instance::new(&module, &[])
|
||||
.map_err(|e| format!("failed to instantiate module: {:?}", e))?;
|
||||
let run_func = instance.exports()[0]
|
||||
.func()
|
||||
.expect("expected function export");
|
||||
|
||||
let e = run_func.call(&[]).err().expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
assert!(trace.len() >= 32);
|
||||
for i in 0..trace.len() {
|
||||
assert_eq!(trace[i].module_name().unwrap(), "rec_mod");
|
||||
assert_eq!(trace[i].func_index(), 0);
|
||||
}
|
||||
assert!(e.message().contains("call stack exhausted"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
20
crates/c-api/Cargo.toml
Normal file
20
crates/c-api/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "wasmtime-c-api"
|
||||
version = "0.9.0"
|
||||
authors = ["The Wasmtime Project Developers"]
|
||||
description = "C API to expose the Wasmtime runtime"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/bytecodealliance/wasmtime"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "wasmtime"
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
doc = false
|
||||
test = false
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
wasmtime = { path = "../api" }
|
||||
220
crates/c-api/LICENSE
Normal file
220
crates/c-api/LICENSE
Normal file
@@ -0,0 +1,220 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
--- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
||||
3
crates/c-api/README.md
Normal file
3
crates/c-api/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Implementation of wasm-c-api in Rust
|
||||
|
||||
https://github.com/WebAssembly/wasm-c-api
|
||||
@@ -5,15 +5,14 @@
|
||||
|
||||
// TODO complete the C API
|
||||
|
||||
use super::{
|
||||
AnyRef, Callable, Engine, ExportType, Extern, ExternType, Func, FuncType, Global, GlobalType,
|
||||
ImportType, Instance, Limits, Memory, MemoryType, Module, Store, Table, TableType, Trap, Val,
|
||||
ValType,
|
||||
};
|
||||
use crate::r#ref::{HostInfo, HostRef};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::{mem, ptr, slice};
|
||||
use wasmtime::{
|
||||
AnyRef, Callable, Engine, ExportType, Extern, ExternType, Func, FuncType, Global, GlobalType,
|
||||
HostInfo, HostRef, ImportType, Instance, Limits, Memory, MemoryType, Module, Store, Table,
|
||||
TableType, Trap, Val, ValType,
|
||||
};
|
||||
|
||||
macro_rules! declare_vec {
|
||||
($name:ident, $elem_ty:path) => {
|
||||
@@ -569,14 +568,18 @@ impl wasm_val_t {
|
||||
}
|
||||
}
|
||||
|
||||
impl Callable for wasm_func_callback_t {
|
||||
struct Callback {
|
||||
callback: wasm_func_callback_t,
|
||||
}
|
||||
|
||||
impl Callable for Callback {
|
||||
fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap> {
|
||||
let params = params
|
||||
.iter()
|
||||
.map(|p| wasm_val_t::from_val(p))
|
||||
.collect::<Vec<_>>();
|
||||
let mut out_results = vec![wasm_val_t::default(); results.len()];
|
||||
let func = self.expect("wasm_func_callback_t fn");
|
||||
let func = self.callback.expect("wasm_func_callback_t fn");
|
||||
let out = unsafe { func(params.as_ptr(), out_results.as_mut_ptr()) };
|
||||
if !out.is_null() {
|
||||
let trap: Box<wasm_trap_t> = unsafe { Box::from_raw(out) };
|
||||
@@ -633,7 +636,7 @@ pub unsafe extern "C" fn wasm_func_new(
|
||||
) -> *mut wasm_func_t {
|
||||
let store = &(*store).store.borrow();
|
||||
let ty = (*ty).functype.clone();
|
||||
let callback = Rc::new(callback);
|
||||
let callback = Rc::new(Callback { callback });
|
||||
let func = Box::new(wasm_func_t {
|
||||
ext: wasm_extern_t {
|
||||
which: ExternHost::Func(HostRef::new(Func::new(store, ty, callback))),
|
||||
@@ -700,7 +703,7 @@ pub unsafe extern "C" fn wasm_instance_new(
|
||||
let module = &(*module).module.borrow();
|
||||
// FIXME(WebAssembly/wasm-c-api#126) what else can we do with the `store`
|
||||
// argument?
|
||||
if !Store::ptr_eq(&store, module.store()) {
|
||||
if !Store::same(&store, module.store()) {
|
||||
if !result.is_null() {
|
||||
let trap = Trap::new("wasm_store_t must match store in wasm_module_t");
|
||||
let trap = Box::new(wasm_trap_t {
|
||||
@@ -1254,7 +1257,7 @@ pub unsafe extern "C" fn wasm_globaltype_content(
|
||||
pub unsafe extern "C" fn wasm_globaltype_mutability(
|
||||
gt: *const wasm_globaltype_t,
|
||||
) -> wasm_mutability_t {
|
||||
use super::Mutability::*;
|
||||
use wasmtime::Mutability::*;
|
||||
match (*gt).globaltype.mutability() {
|
||||
Const => 0,
|
||||
Var => 1,
|
||||
@@ -1411,7 +1414,7 @@ pub unsafe extern "C" fn wasm_globaltype_new(
|
||||
ty: *mut wasm_valtype_t,
|
||||
mutability: wasm_mutability_t,
|
||||
) -> *mut wasm_globaltype_t {
|
||||
use super::Mutability::*;
|
||||
use wasmtime::Mutability::*;
|
||||
let ty = Box::from_raw(ty);
|
||||
let mutability = match mutability {
|
||||
0 => Const,
|
||||
@@ -13,9 +13,9 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
cranelift-codegen = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-entity = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-wasm = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-codegen = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-entity = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-wasm = { version = "0.55", features = ["enable-serde"] }
|
||||
wasmparser = "0.47.0"
|
||||
lightbeam = { path = "../lightbeam", optional = true, version = "0.9.0" }
|
||||
indexmap = "1.0.2"
|
||||
@@ -46,7 +46,7 @@ tempfile = "3"
|
||||
target-lexicon = { version = "0.10.0", default-features = false }
|
||||
pretty_env_logger = "0.3.0"
|
||||
rand = { version = "0.7.0", default-features = false, features = ["small_rng"] }
|
||||
cranelift-codegen = { version = "0.54", features = ["enable-serde", "all-arch"] }
|
||||
cranelift-codegen = { version = "0.55", features = ["enable-serde", "all-arch"] }
|
||||
filetime = "0.2.7"
|
||||
|
||||
[badges]
|
||||
|
||||
6
crates/environ/src/cache/tests.rs
vendored
6
crates/environ/src/cache/tests.rs
vendored
@@ -1,7 +1,9 @@
|
||||
use super::config::tests::test_prolog;
|
||||
use super::*;
|
||||
use crate::address_map::{FunctionAddressMap, InstructionAddressMap};
|
||||
use crate::compilation::{CompiledFunction, Relocation, RelocationTarget, TrapInformation};
|
||||
use crate::compilation::{
|
||||
CompiledFunction, CompiledFunctionUnwindInfo, Relocation, RelocationTarget, TrapInformation,
|
||||
};
|
||||
use crate::module::{MemoryPlan, MemoryStyle, Module};
|
||||
use cranelift_codegen::{binemit, ir, isa, settings, ValueLocRange};
|
||||
use cranelift_entity::EntityRef;
|
||||
@@ -259,7 +261,7 @@ fn new_module_cache_data(rng: &mut impl Rng) -> ModuleCacheData {
|
||||
CompiledFunction {
|
||||
body: (0..(i * 3 / 2)).collect(),
|
||||
jt_offsets: sm,
|
||||
unwind_info: (0..(i * 3 / 2)).collect(),
|
||||
unwind_info: CompiledFunctionUnwindInfo::Windows((0..(i * 3 / 2)).collect()),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -4,13 +4,136 @@
|
||||
use crate::cache::ModuleCacheDataTupleType;
|
||||
use crate::module;
|
||||
use crate::module_environ::FunctionBodyData;
|
||||
use cranelift_codegen::{binemit, ir, isa};
|
||||
use cranelift_codegen::{binemit, ir, isa, Context};
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, ModuleTranslationState, WasmError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::Range;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FDERelocEntry(pub i64, pub usize, pub u8);
|
||||
|
||||
/// Relocation entry for unwind info.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CompiledFunctionUnwindInfoReloc {
|
||||
/// Entry offest in the code block.
|
||||
pub offset: u32,
|
||||
/// Entry addend relative to the code block.
|
||||
pub addend: u32,
|
||||
}
|
||||
|
||||
/// Compiled function unwind information.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub enum CompiledFunctionUnwindInfo {
|
||||
/// No info.
|
||||
None,
|
||||
/// Windows UNWIND_INFO.
|
||||
Windows(Vec<u8>),
|
||||
/// Frame layout info.
|
||||
FrameLayout(Vec<u8>, usize, Vec<FDERelocEntry>),
|
||||
}
|
||||
|
||||
impl CompiledFunctionUnwindInfo {
|
||||
/// Constructs unwind info object.
|
||||
pub fn new(isa: &dyn isa::TargetIsa, context: &Context) -> Self {
|
||||
use cranelift_codegen::binemit::{
|
||||
FrameUnwindKind, FrameUnwindOffset, FrameUnwindSink, Reloc,
|
||||
};
|
||||
use cranelift_codegen::isa::CallConv;
|
||||
|
||||
struct Sink(Vec<u8>, usize, Vec<FDERelocEntry>);
|
||||
impl FrameUnwindSink for Sink {
|
||||
fn len(&self) -> FrameUnwindOffset {
|
||||
self.0.len()
|
||||
}
|
||||
fn bytes(&mut self, b: &[u8]) {
|
||||
self.0.extend_from_slice(b);
|
||||
}
|
||||
fn reserve(&mut self, len: usize) {
|
||||
self.0.reserve(len)
|
||||
}
|
||||
fn reloc(&mut self, r: Reloc, off: FrameUnwindOffset) {
|
||||
self.2.push(FDERelocEntry(
|
||||
0,
|
||||
off,
|
||||
match r {
|
||||
Reloc::Abs4 => 4,
|
||||
Reloc::Abs8 => 8,
|
||||
_ => {
|
||||
panic!("unexpected reloc type");
|
||||
}
|
||||
},
|
||||
))
|
||||
}
|
||||
fn set_entry_offset(&mut self, off: FrameUnwindOffset) {
|
||||
self.1 = off;
|
||||
}
|
||||
}
|
||||
|
||||
let kind = match context.func.signature.call_conv {
|
||||
CallConv::SystemV | CallConv::Fast | CallConv::Cold => FrameUnwindKind::Libunwind,
|
||||
CallConv::WindowsFastcall => FrameUnwindKind::Fastcall,
|
||||
_ => {
|
||||
return CompiledFunctionUnwindInfo::None;
|
||||
}
|
||||
};
|
||||
|
||||
let mut sink = Sink(Vec::new(), 0, Vec::new());
|
||||
context.emit_unwind_info(isa, kind, &mut sink);
|
||||
|
||||
let Sink(data, offset, relocs) = sink;
|
||||
if data.is_empty() {
|
||||
return CompiledFunctionUnwindInfo::None;
|
||||
}
|
||||
|
||||
match kind {
|
||||
FrameUnwindKind::Fastcall => CompiledFunctionUnwindInfo::Windows(data),
|
||||
FrameUnwindKind::Libunwind => {
|
||||
CompiledFunctionUnwindInfo::FrameLayout(data, offset, relocs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Retuns true is no unwind info data.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
CompiledFunctionUnwindInfo::None => true,
|
||||
CompiledFunctionUnwindInfo::Windows(d) => d.is_empty(),
|
||||
CompiledFunctionUnwindInfo::FrameLayout(c, _, _) => c.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns size of serilized unwind info.
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
CompiledFunctionUnwindInfo::None => 0,
|
||||
CompiledFunctionUnwindInfo::Windows(d) => d.len(),
|
||||
CompiledFunctionUnwindInfo::FrameLayout(c, _, _) => c.len(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes data into byte array.
|
||||
pub fn serialize(&self, dest: &mut [u8], relocs: &mut Vec<CompiledFunctionUnwindInfoReloc>) {
|
||||
match self {
|
||||
CompiledFunctionUnwindInfo::None => (),
|
||||
CompiledFunctionUnwindInfo::Windows(d) => {
|
||||
dest.copy_from_slice(d);
|
||||
}
|
||||
CompiledFunctionUnwindInfo::FrameLayout(code, _fde_offset, r) => {
|
||||
dest.copy_from_slice(code);
|
||||
r.iter().for_each(move |r| {
|
||||
assert_eq!(r.2, 8);
|
||||
relocs.push(CompiledFunctionUnwindInfoReloc {
|
||||
offset: r.1 as u32,
|
||||
addend: r.0 as u32,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compiled function: machine code body, jump table offsets, and unwind information.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CompiledFunction {
|
||||
@@ -21,7 +144,7 @@ pub struct CompiledFunction {
|
||||
pub jt_offsets: ir::JumpTableOffsets,
|
||||
|
||||
/// The unwind information.
|
||||
pub unwind_info: Vec<u8>,
|
||||
pub unwind_info: CompiledFunctionUnwindInfo,
|
||||
}
|
||||
|
||||
type Functions = PrimaryMap<DefinedFuncIndex, CompiledFunction>;
|
||||
@@ -50,7 +173,7 @@ impl Compilation {
|
||||
.map(|(body_range, jt_offsets, unwind_range)| CompiledFunction {
|
||||
body: buffer[body_range].to_vec(),
|
||||
jt_offsets,
|
||||
unwind_info: buffer[unwind_range].to_vec(),
|
||||
unwind_info: CompiledFunctionUnwindInfo::Windows(buffer[unwind_range].to_vec()),
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
use crate::address_map::{FunctionAddressMap, InstructionAddressMap};
|
||||
use crate::cache::{ModuleCacheData, ModuleCacheDataTupleType, ModuleCacheEntry};
|
||||
use crate::compilation::{
|
||||
Compilation, CompileError, CompiledFunction, Relocation, RelocationTarget, TrapInformation,
|
||||
Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Relocation,
|
||||
RelocationTarget, TrapInformation,
|
||||
};
|
||||
use crate::func_environ::{
|
||||
get_func_name, get_imported_memory32_grow_name, get_imported_memory32_size_name,
|
||||
@@ -204,6 +205,7 @@ impl crate::compilation::Compiler for Cranelift {
|
||||
context.func.name = get_func_name(func_index);
|
||||
context.func.signature =
|
||||
module.signatures[module.functions[func_index]].clone();
|
||||
context.func.collect_frame_layout_info();
|
||||
if generate_debug_info {
|
||||
context.func.collect_debug_info();
|
||||
}
|
||||
@@ -217,7 +219,6 @@ impl crate::compilation::Compiler for Cranelift {
|
||||
)?;
|
||||
|
||||
let mut code_buf: Vec<u8> = Vec::new();
|
||||
let mut unwind_info = Vec::new();
|
||||
let mut reloc_sink = RelocSink::new(func_index);
|
||||
let mut trap_sink = TrapSink::new();
|
||||
let mut stackmap_sink = binemit::NullStackmapSink {};
|
||||
@@ -233,7 +234,7 @@ impl crate::compilation::Compiler for Cranelift {
|
||||
CompileError::Codegen(pretty_error(&context.func, Some(isa), error))
|
||||
})?;
|
||||
|
||||
context.emit_unwind_info(isa, &mut unwind_info);
|
||||
let unwind_info = CompiledFunctionUnwindInfo::new(isa, &context);
|
||||
|
||||
let address_transform = if generate_debug_info {
|
||||
let body_len = code_buf.len();
|
||||
|
||||
@@ -362,8 +362,8 @@ impl<'module_environment> TargetEnvironment for FuncEnvironment<'module_environm
|
||||
}
|
||||
|
||||
impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> {
|
||||
fn is_wasm_parameter(&self, func: &ir::Function, index: usize) -> bool {
|
||||
func.signature.params[index].purpose == ir::ArgumentPurpose::Normal
|
||||
fn is_wasm_parameter(&self, signature: &ir::Signature, index: usize) -> bool {
|
||||
signature.params[index].purpose == ir::ArgumentPurpose::Normal
|
||||
}
|
||||
|
||||
fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> WasmResult<ir::Table> {
|
||||
|
||||
@@ -44,8 +44,9 @@ pub use crate::address_map::{
|
||||
};
|
||||
pub use crate::cache::{create_new_config as cache_create_new_config, init as cache_init};
|
||||
pub use crate::compilation::{
|
||||
Compilation, CompileError, CompiledFunction, Compiler, Relocation, RelocationTarget,
|
||||
Relocations, TrapInformation, Traps,
|
||||
Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo,
|
||||
CompiledFunctionUnwindInfoReloc, Compiler, Relocation, RelocationTarget, Relocations,
|
||||
TrapInformation, Traps,
|
||||
};
|
||||
pub use crate::cranelift::Cranelift;
|
||||
pub use crate::data_structures::*;
|
||||
|
||||
@@ -10,7 +10,7 @@ version = "0.9.0"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.22"
|
||||
arbitrary = "0.2.0"
|
||||
arbitrary = { version = "0.3.2", features = ["derive"] }
|
||||
binaryen = "0.8.2"
|
||||
env_logger = { version = "0.7.1", optional = true }
|
||||
log = "0.4.8"
|
||||
|
||||
@@ -31,13 +31,17 @@ impl fmt::Debug for WasmOptTtf {
|
||||
}
|
||||
|
||||
impl Arbitrary for WasmOptTtf {
|
||||
fn arbitrary<U>(input: &mut U) -> Result<Self, U::Error>
|
||||
where
|
||||
U: Unstructured + ?Sized,
|
||||
{
|
||||
fn arbitrary(input: &mut Unstructured) -> arbitrary::Result<Self> {
|
||||
let seed: Vec<u8> = Arbitrary::arbitrary(input)?;
|
||||
let module = binaryen::tools::translate_to_fuzz_mvp(&seed);
|
||||
let wasm = module.write();
|
||||
Ok(WasmOptTtf { wasm })
|
||||
}
|
||||
|
||||
fn arbitrary_take_rest(input: Unstructured) -> arbitrary::Result<Self> {
|
||||
let seed: Vec<u8> = Arbitrary::arbitrary_take_rest(input)?;
|
||||
let module = binaryen::tools::translate_to_fuzz_mvp(&seed);
|
||||
let wasm = module.write();
|
||||
Ok(WasmOptTtf { wasm })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
//! [swarm testing]: https://www.cs.utah.edu/~regehr/papers/swarm12.pdf
|
||||
|
||||
use arbitrary::{Arbitrary, Unstructured};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[derive(Arbitrary, Debug)]
|
||||
struct Swarm {
|
||||
config_debug_info: bool,
|
||||
module_new: bool,
|
||||
@@ -26,24 +27,8 @@ struct Swarm {
|
||||
call_exported_func: bool,
|
||||
}
|
||||
|
||||
impl Arbitrary for Swarm {
|
||||
fn arbitrary<U>(input: &mut U) -> Result<Self, U::Error>
|
||||
where
|
||||
U: Unstructured + ?Sized,
|
||||
{
|
||||
Ok(Swarm {
|
||||
config_debug_info: bool::arbitrary(input)?,
|
||||
module_new: bool::arbitrary(input)?,
|
||||
module_drop: bool::arbitrary(input)?,
|
||||
instance_new: bool::arbitrary(input)?,
|
||||
instance_drop: bool::arbitrary(input)?,
|
||||
call_exported_func: bool::arbitrary(input)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A call to one of Wasmtime's public APIs.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Arbitrary, Clone, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ApiCall {
|
||||
ConfigNew,
|
||||
@@ -61,8 +46,8 @@ use ApiCall::*;
|
||||
#[derive(Default)]
|
||||
struct Scope {
|
||||
id_counter: usize,
|
||||
modules: HashSet<usize>,
|
||||
instances: HashSet<usize>,
|
||||
modules: BTreeSet<usize>,
|
||||
instances: BTreeSet<usize>,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
@@ -81,10 +66,7 @@ pub struct ApiCalls {
|
||||
}
|
||||
|
||||
impl Arbitrary for ApiCalls {
|
||||
fn arbitrary<U>(input: &mut U) -> Result<Self, U::Error>
|
||||
where
|
||||
U: Unstructured + ?Sized,
|
||||
{
|
||||
fn arbitrary(input: &mut Unstructured) -> arbitrary::Result<Self> {
|
||||
let swarm = Swarm::arbitrary(input)?;
|
||||
let mut calls = vec![];
|
||||
|
||||
@@ -94,8 +76,8 @@ impl Arbitrary for ApiCalls {
|
||||
|
||||
let mut scope = Scope::default();
|
||||
|
||||
for _ in 0..input.container_size()? {
|
||||
let mut choices: Vec<fn(_, &mut Scope) -> Result<ApiCall, U::Error>> = vec![];
|
||||
for _ in 0..input.arbitrary_len::<ApiCall>()? {
|
||||
let mut choices: Vec<fn(_, &mut Scope) -> arbitrary::Result<ApiCall>> = vec![];
|
||||
|
||||
if swarm.module_new {
|
||||
choices.push(|input, scope| {
|
||||
@@ -108,7 +90,7 @@ impl Arbitrary for ApiCalls {
|
||||
if swarm.module_drop && !scope.modules.is_empty() {
|
||||
choices.push(|input, scope| {
|
||||
let modules: Vec<_> = scope.modules.iter().cloned().collect();
|
||||
let id = arbitrary_choice(input, &modules)?.cloned().unwrap();
|
||||
let id = *input.choose(&modules)?;
|
||||
scope.modules.remove(&id);
|
||||
Ok(ModuleDrop { id })
|
||||
});
|
||||
@@ -116,7 +98,7 @@ impl Arbitrary for ApiCalls {
|
||||
if swarm.instance_new && !scope.modules.is_empty() {
|
||||
choices.push(|input, scope| {
|
||||
let modules: Vec<_> = scope.modules.iter().cloned().collect();
|
||||
let module = arbitrary_choice(input, &modules)?.cloned().unwrap();
|
||||
let module = *input.choose(&modules)?;
|
||||
let id = scope.next_id();
|
||||
scope.instances.insert(id);
|
||||
Ok(InstanceNew { id, module })
|
||||
@@ -125,7 +107,7 @@ impl Arbitrary for ApiCalls {
|
||||
if swarm.instance_drop && !scope.instances.is_empty() {
|
||||
choices.push(|input, scope| {
|
||||
let instances: Vec<_> = scope.instances.iter().cloned().collect();
|
||||
let id = arbitrary_choice(input, &instances)?.cloned().unwrap();
|
||||
let id = *input.choose(&instances)?;
|
||||
scope.instances.remove(&id);
|
||||
Ok(InstanceDrop { id })
|
||||
});
|
||||
@@ -133,43 +115,28 @@ impl Arbitrary for ApiCalls {
|
||||
if swarm.call_exported_func && !scope.instances.is_empty() {
|
||||
choices.push(|input, scope| {
|
||||
let instances: Vec<_> = scope.instances.iter().cloned().collect();
|
||||
let instance = arbitrary_choice(input, &instances)?.cloned().unwrap();
|
||||
let instance = *input.choose(&instances)?;
|
||||
let nth = usize::arbitrary(input)?;
|
||||
Ok(CallExportedFunc { instance, nth })
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(c) = arbitrary_choice(input, &choices)? {
|
||||
calls.push(c(input, &mut scope)?);
|
||||
} else {
|
||||
if choices.is_empty() {
|
||||
break;
|
||||
}
|
||||
let c = input.choose(&choices)?;
|
||||
calls.push(c(input, &mut scope)?);
|
||||
}
|
||||
|
||||
Ok(ApiCalls { calls })
|
||||
}
|
||||
}
|
||||
|
||||
fn arbitrary_choice<'a, T, U>(input: &mut U, choices: &'a [T]) -> Result<Option<&'a T>, U::Error>
|
||||
where
|
||||
U: Unstructured + ?Sized,
|
||||
{
|
||||
if choices.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
let i = usize::arbitrary(input)? % choices.len();
|
||||
Ok(Some(&choices[i]))
|
||||
}
|
||||
}
|
||||
|
||||
fn arbitrary_config<U>(
|
||||
input: &mut U,
|
||||
fn arbitrary_config(
|
||||
input: &mut Unstructured,
|
||||
swarm: &Swarm,
|
||||
calls: &mut Vec<ApiCall>,
|
||||
) -> Result<(), U::Error>
|
||||
where
|
||||
U: Unstructured + ?Sized,
|
||||
{
|
||||
) -> arbitrary::Result<()> {
|
||||
calls.push(ConfigNew);
|
||||
|
||||
if swarm.config_debug_info && bool::arbitrary(input)? {
|
||||
|
||||
@@ -11,11 +11,11 @@ readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cranelift-codegen = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-entity = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-wasm = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-native = "0.54"
|
||||
cranelift-frontend = "0.54"
|
||||
cranelift-codegen = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-entity = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-wasm = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-native = "0.55"
|
||||
cranelift-frontend = "0.55"
|
||||
wasmtime-environ = { path = "../environ", version = "0.9.0" }
|
||||
wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
|
||||
wasmtime-debug = { path = "../debug", version = "0.9.0" }
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::cmp::max;
|
||||
use std::{fmt, mem, ptr, slice};
|
||||
use thiserror::Error;
|
||||
use wasmtime_environ::ir;
|
||||
use wasmtime_runtime::{wasmtime_call_trampoline, Export, InstanceHandle, VMInvokeArgument};
|
||||
use wasmtime_runtime::{wasmtime_call_trampoline, Export, InstanceHandle, Trap, VMInvokeArgument};
|
||||
|
||||
/// A runtime value.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
@@ -100,10 +100,7 @@ pub enum ActionOutcome {
|
||||
},
|
||||
|
||||
/// A trap occurred while the action was executing.
|
||||
Trapped {
|
||||
/// The trap message.
|
||||
message: String,
|
||||
},
|
||||
Trapped(Trap),
|
||||
}
|
||||
|
||||
/// An error detected while invoking a wasm function or reading a wasm global.
|
||||
@@ -191,7 +188,7 @@ pub fn invoke(
|
||||
compiler.publish_compiled_code();
|
||||
|
||||
// Call the trampoline.
|
||||
if let Err(message) = unsafe {
|
||||
if let Err(trap) = unsafe {
|
||||
instance.with_signals_on(|| {
|
||||
wasmtime_call_trampoline(
|
||||
callee_vmctx,
|
||||
@@ -200,7 +197,7 @@ pub fn invoke(
|
||||
)
|
||||
})
|
||||
} {
|
||||
return Ok(ActionOutcome::Trapped { message });
|
||||
return Ok(ActionOutcome::Trapped(trap));
|
||||
}
|
||||
|
||||
// Load the return values out of `values_vec`.
|
||||
|
||||
@@ -2,14 +2,45 @@
|
||||
|
||||
use crate::function_table::FunctionTable;
|
||||
use region;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::{cmp, mem};
|
||||
use wasmtime_environ::{Compilation, CompiledFunction};
|
||||
use wasmtime_runtime::{Mmap, VMFunctionBody};
|
||||
|
||||
struct CodeMemoryEntry {
|
||||
mmap: ManuallyDrop<Mmap>,
|
||||
table: ManuallyDrop<FunctionTable>,
|
||||
}
|
||||
|
||||
impl CodeMemoryEntry {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
mmap: ManuallyDrop::new(Mmap::new()),
|
||||
table: ManuallyDrop::new(FunctionTable::new()),
|
||||
}
|
||||
}
|
||||
fn with_capacity(cap: usize) -> Result<Self, String> {
|
||||
Ok(Self {
|
||||
mmap: ManuallyDrop::new(Mmap::with_at_least(cap)?),
|
||||
table: ManuallyDrop::new(FunctionTable::new()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CodeMemoryEntry {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
// Table needs to be freed before mmap.
|
||||
ManuallyDrop::drop(&mut self.table);
|
||||
ManuallyDrop::drop(&mut self.mmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory manager for executable code.
|
||||
pub struct CodeMemory {
|
||||
current: (Mmap, FunctionTable),
|
||||
mmaps: Vec<(Mmap, FunctionTable)>,
|
||||
current: CodeMemoryEntry,
|
||||
entries: Vec<CodeMemoryEntry>,
|
||||
position: usize,
|
||||
published: usize,
|
||||
}
|
||||
@@ -23,8 +54,8 @@ impl CodeMemory {
|
||||
/// Create a new `CodeMemory` instance.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
current: (Mmap::new(), FunctionTable::new()),
|
||||
mmaps: Vec::new(),
|
||||
current: CodeMemoryEntry::new(),
|
||||
entries: Vec::new(),
|
||||
position: 0,
|
||||
published: 0,
|
||||
}
|
||||
@@ -81,19 +112,20 @@ impl CodeMemory {
|
||||
self.push_current(0)
|
||||
.expect("failed to push current memory map");
|
||||
|
||||
for (m, t) in &mut self.mmaps[self.published..] {
|
||||
for CodeMemoryEntry { mmap: m, table: t } in &mut self.entries[self.published..] {
|
||||
// Remove write access to the pages due to the relocation fixups.
|
||||
t.publish(m.as_ptr() as u64)
|
||||
.expect("failed to publish function table");
|
||||
|
||||
if !m.is_empty() {
|
||||
unsafe {
|
||||
region::protect(m.as_mut_ptr(), m.len(), region::Protection::ReadExecute)
|
||||
}
|
||||
.expect("unable to make memory readonly and executable");
|
||||
}
|
||||
|
||||
t.publish(m.as_ptr() as u64)
|
||||
.expect("failed to publish function table");
|
||||
}
|
||||
|
||||
self.published = self.mmaps.len();
|
||||
self.published = self.entries.len();
|
||||
}
|
||||
|
||||
/// Allocate `size` bytes of memory which can be made executable later by
|
||||
@@ -103,7 +135,7 @@ impl CodeMemory {
|
||||
///
|
||||
/// TODO: Add an alignment flag.
|
||||
fn allocate(&mut self, size: usize) -> Result<(&mut [u8], &mut FunctionTable), String> {
|
||||
if self.current.0.len() - self.position < size {
|
||||
if self.current.mmap.len() - self.position < size {
|
||||
self.push_current(cmp::max(0x10000, size))?;
|
||||
}
|
||||
|
||||
@@ -111,8 +143,8 @@ impl CodeMemory {
|
||||
self.position += size;
|
||||
|
||||
Ok((
|
||||
&mut self.current.0.as_mut_slice()[old_position..self.position],
|
||||
&mut self.current.1,
|
||||
&mut self.current.mmap.as_mut_slice()[old_position..self.position],
|
||||
&mut self.current.table,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -153,12 +185,19 @@ impl CodeMemory {
|
||||
// Keep unwind information 32-bit aligned (round up to the nearest 4 byte boundary)
|
||||
let padding = ((func.body.len() + 3) & !3) - func.body.len();
|
||||
let (unwind, remainder) = remainder.split_at_mut(padding + func.unwind_info.len());
|
||||
unwind[padding..].copy_from_slice(&func.unwind_info);
|
||||
let mut relocs = Vec::new();
|
||||
func.unwind_info
|
||||
.serialize(&mut unwind[padding..], &mut relocs);
|
||||
|
||||
let unwind_start = func_end + (padding as u32);
|
||||
let unwind_end = unwind_start + (func.unwind_info.len() as u32);
|
||||
|
||||
table.add_function(func_start, func_end, unwind_start);
|
||||
relocs.iter_mut().for_each(move |r| {
|
||||
r.offset += unwind_start;
|
||||
r.addend += func_start;
|
||||
});
|
||||
|
||||
table.add_function(func_start, func_end, unwind_start, &relocs);
|
||||
|
||||
(unwind_end, remainder, table, vmfunc)
|
||||
}
|
||||
@@ -174,20 +213,17 @@ impl CodeMemory {
|
||||
fn push_current(&mut self, new_size: usize) -> Result<(), String> {
|
||||
let previous = mem::replace(
|
||||
&mut self.current,
|
||||
(
|
||||
if new_size == 0 {
|
||||
Mmap::new()
|
||||
CodeMemoryEntry::new()
|
||||
} else {
|
||||
Mmap::with_at_least(cmp::max(0x10000, new_size))?
|
||||
CodeMemoryEntry::with_capacity(cmp::max(0x10000, new_size))?
|
||||
},
|
||||
FunctionTable::new(),
|
||||
),
|
||||
);
|
||||
|
||||
if !previous.0.is_empty() {
|
||||
self.mmaps.push(previous);
|
||||
if !previous.mmap.is_empty() {
|
||||
self.entries.push(previous);
|
||||
} else {
|
||||
assert_eq!(previous.1.len(), 0);
|
||||
assert_eq!(previous.table.len(), 0);
|
||||
}
|
||||
|
||||
self.position = 0;
|
||||
|
||||
@@ -16,12 +16,12 @@ use wasmtime_environ::entity::{EntityRef, PrimaryMap};
|
||||
use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa};
|
||||
use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex};
|
||||
use wasmtime_environ::{
|
||||
Compilation, CompileError, CompiledFunction, Compiler as _C, FunctionBodyData, Module,
|
||||
ModuleVmctxInfo, Relocations, Traps, Tunables, VMOffsets,
|
||||
Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Compiler as _C,
|
||||
FunctionBodyData, Module, ModuleVmctxInfo, Relocations, Traps, Tunables, VMOffsets,
|
||||
};
|
||||
use wasmtime_runtime::{
|
||||
get_mut_trap_registry, InstantiationError, SignatureRegistry, TrapRegistrationGuard,
|
||||
VMFunctionBody,
|
||||
get_mut_trap_registry, jit_function_registry, InstantiationError, SignatureRegistry,
|
||||
TrapRegistrationGuard, VMFunctionBody,
|
||||
};
|
||||
|
||||
/// Select which kind of compilation to use.
|
||||
@@ -51,6 +51,7 @@ pub struct Compiler {
|
||||
|
||||
code_memory: CodeMemory,
|
||||
trap_registration_guards: Vec<TrapRegistrationGuard>,
|
||||
jit_function_ranges: Vec<(usize, usize)>,
|
||||
trampoline_park: HashMap<*const VMFunctionBody, *const VMFunctionBody>,
|
||||
signatures: SignatureRegistry,
|
||||
strategy: CompilationStrategy,
|
||||
@@ -66,6 +67,7 @@ impl Compiler {
|
||||
isa,
|
||||
code_memory: CodeMemory::new(),
|
||||
trap_registration_guards: Vec::new(),
|
||||
jit_function_ranges: Vec::new(),
|
||||
trampoline_park: HashMap::new(),
|
||||
signatures: SignatureRegistry::new(),
|
||||
fn_builder_ctx: FunctionBuilderContext::new(),
|
||||
@@ -85,6 +87,10 @@ impl Drop for Compiler {
|
||||
// Having a custom drop implementation we are independent from the field order
|
||||
// in the struct what reduces potential human error.
|
||||
self.trap_registration_guards.clear();
|
||||
|
||||
for (start, end) in self.jit_function_ranges.iter() {
|
||||
jit_function_registry::unregister(*start, *end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +161,18 @@ impl Compiler {
|
||||
&mut self.trap_registration_guards,
|
||||
);
|
||||
|
||||
for (i, allocated) in allocated_functions.iter() {
|
||||
let ptr = (*allocated) as *const VMFunctionBody;
|
||||
let body_len = compilation.get(i).body.len();
|
||||
self.jit_function_ranges
|
||||
.push((ptr as usize, ptr as usize + body_len));
|
||||
let tag = jit_function_registry::JITFunctionTag {
|
||||
module_id: module.name.clone(),
|
||||
func_index: i.index(),
|
||||
};
|
||||
jit_function_registry::register(ptr as usize, ptr as usize + body_len, tag);
|
||||
}
|
||||
|
||||
let dbg = if let Some(debug_data) = debug_data {
|
||||
let target_config = self.isa.frontend_config();
|
||||
let ofs = VMOffsets::new(target_config.pointer_bytes(), &module);
|
||||
@@ -215,6 +233,7 @@ impl Compiler {
|
||||
signature,
|
||||
value_size,
|
||||
)?;
|
||||
|
||||
entry.insert(body);
|
||||
body
|
||||
}
|
||||
@@ -266,6 +285,7 @@ fn make_trampoline(
|
||||
|
||||
let mut context = Context::new();
|
||||
context.func = ir::Function::with_name_signature(ir::ExternalName::user(0, 0), wrapper_sig);
|
||||
context.func.collect_frame_layout_info();
|
||||
|
||||
{
|
||||
let mut builder = FunctionBuilder::new(&mut context.func, fn_builder_ctx);
|
||||
@@ -326,7 +346,6 @@ fn make_trampoline(
|
||||
}
|
||||
|
||||
let mut code_buf = Vec::new();
|
||||
let mut unwind_info = Vec::new();
|
||||
let mut reloc_sink = RelocSink {};
|
||||
let mut trap_sink = binemit::NullTrapSink {};
|
||||
let mut stackmap_sink = binemit::NullStackmapSink {};
|
||||
@@ -346,7 +365,7 @@ fn make_trampoline(
|
||||
)))
|
||||
})?;
|
||||
|
||||
context.emit_unwind_info(isa, &mut unwind_info);
|
||||
let unwind_info = CompiledFunctionUnwindInfo::new(isa, &context);
|
||||
|
||||
Ok(code_memory
|
||||
.allocate_for_function(&CompiledFunction {
|
||||
|
||||
@@ -2,42 +2,7 @@
|
||||
//!
|
||||
//! This module is primarily used to track JIT functions on Windows for stack walking and unwind.
|
||||
|
||||
/// Represents a runtime function table.
|
||||
///
|
||||
/// The runtime function table is not implemented for non-Windows target platforms.
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub(crate) struct FunctionTable;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
impl FunctionTable {
|
||||
/// Creates a new function table.
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
/// Returns the number of functions in the table, also referred to as its 'length'.
|
||||
///
|
||||
/// For non-Windows platforms, the table will always be empty.
|
||||
pub fn len(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
/// Adds a function to the table based off of the start offset, end offset, and unwind offset.
|
||||
///
|
||||
/// The offsets are from the "module base", which is provided when the table is published.
|
||||
///
|
||||
/// For non-Windows platforms, this is a no-op.
|
||||
pub fn add_function(&mut self, _start: u32, _end: u32, _unwind: u32) {}
|
||||
|
||||
/// Publishes the function table using the given base address.
|
||||
///
|
||||
/// A published function table will automatically be deleted when it is dropped.
|
||||
///
|
||||
/// For non-Windows platforms, this is a no-op.
|
||||
pub fn publish(&mut self, _base_address: u64) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
type FunctionTableReloc = wasmtime_environ::CompiledFunctionUnwindInfoReloc;
|
||||
|
||||
/// Represents a runtime function table.
|
||||
///
|
||||
@@ -66,7 +31,14 @@ impl FunctionTable {
|
||||
/// Adds a function to the table based off of the start offset, end offset, and unwind offset.
|
||||
///
|
||||
/// The offsets are from the "module base", which is provided when the table is published.
|
||||
pub fn add_function(&mut self, start: u32, end: u32, unwind: u32) {
|
||||
pub fn add_function(
|
||||
&mut self,
|
||||
start: u32,
|
||||
end: u32,
|
||||
unwind: u32,
|
||||
_relocs: &[FunctionTableReloc],
|
||||
) {
|
||||
assert_eq!(_relocs.len(), 0);
|
||||
use winapi::um::winnt;
|
||||
|
||||
assert!(!self.published, "table has already been published");
|
||||
@@ -133,3 +105,106 @@ impl Drop for FunctionTable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a runtime function table.
|
||||
///
|
||||
/// This is used to register JIT code with the operating system to enable stack walking and unwinding.
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
pub(crate) struct FunctionTable {
|
||||
functions: Vec<u32>,
|
||||
relocs: Vec<FunctionTableReloc>,
|
||||
published: Option<Vec<usize>>,
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
impl FunctionTable {
|
||||
/// Creates a new function table.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
functions: Vec::new(),
|
||||
relocs: Vec::new(),
|
||||
published: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of functions in the table, also referred to as its 'length'.
|
||||
pub fn len(&self) -> usize {
|
||||
self.functions.len()
|
||||
}
|
||||
|
||||
/// Adds a function to the table based off of the start offset, end offset, and unwind offset.
|
||||
///
|
||||
/// The offsets are from the "module base", which is provided when the table is published.
|
||||
pub fn add_function(
|
||||
&mut self,
|
||||
_start: u32,
|
||||
_end: u32,
|
||||
unwind: u32,
|
||||
relocs: &[FunctionTableReloc],
|
||||
) {
|
||||
assert!(self.published.is_none(), "table has already been published");
|
||||
self.functions.push(unwind);
|
||||
self.relocs.extend_from_slice(relocs);
|
||||
}
|
||||
|
||||
/// Publishes the function table using the given base address.
|
||||
///
|
||||
/// A published function table will automatically be deleted when it is dropped.
|
||||
pub fn publish(&mut self, base_address: u64) -> Result<(), String> {
|
||||
if self.published.is_some() {
|
||||
return Err("function table was already published".into());
|
||||
}
|
||||
|
||||
if self.functions.is_empty() {
|
||||
assert_eq!(self.relocs.len(), 0);
|
||||
self.published = Some(vec![]);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// libunwind import
|
||||
fn __register_frame(fde: *const u8);
|
||||
}
|
||||
|
||||
for reloc in self.relocs.iter() {
|
||||
let addr = base_address + (reloc.offset as u64);
|
||||
let target = base_address + (reloc.addend as u64);
|
||||
unsafe {
|
||||
std::ptr::write(addr as *mut u64, target);
|
||||
}
|
||||
}
|
||||
|
||||
let mut fdes = Vec::with_capacity(self.functions.len());
|
||||
for unwind_offset in self.functions.iter() {
|
||||
let addr = base_address + (*unwind_offset as u64);
|
||||
let off = unsafe { std::ptr::read::<u32>(addr as *const u32) } as usize + 4;
|
||||
|
||||
let fde = (addr + off as u64) as usize;
|
||||
unsafe {
|
||||
__register_frame(fde as *const _);
|
||||
}
|
||||
fdes.push(fde);
|
||||
}
|
||||
|
||||
self.published = Some(fdes);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
impl Drop for FunctionTable {
|
||||
fn drop(&mut self) {
|
||||
extern "C" {
|
||||
// libunwind import
|
||||
fn __deregister_frame(fde: *const u8);
|
||||
}
|
||||
|
||||
if self.published.is_some() {
|
||||
unsafe {
|
||||
for fde in self.published.as_ref().unwrap() {
|
||||
__deregister_frame(*fde as *const _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ memoffset = "0.5.3"
|
||||
itertools = "0.8.2"
|
||||
capstone = "0.6.0"
|
||||
thiserror = "1.0.9"
|
||||
cranelift-codegen = "0.54"
|
||||
cranelift-codegen = "0.55"
|
||||
multi_mut = "0.1"
|
||||
either = "1.5"
|
||||
typemap = "0.3"
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
<PropertyGroup>
|
||||
<WasmtimeVersion>0.8.0</WasmtimeVersion>
|
||||
<WasmtimeLibraryName>wasmtime</WasmtimeLibraryName>
|
||||
<WasmtimePackageName>wasmtime-c-api</WasmtimePackageName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<LibraryExtension Condition="'$(LibraryExtension)' == ''">.so</LibraryExtension>
|
||||
<WasmtimeLibraryFilename>$(LibraryPrefix)$(WasmtimeLibraryName)$(LibraryExtension)</WasmtimeLibraryFilename>
|
||||
<WasmtimeOutputPath>$(MSBuildThisFileDirectory)../../../target/$(Configuration.ToLower())</WasmtimeOutputPath>
|
||||
<BuildWasmtimeCommand Condition="'$(Configuration)' == 'Release'">cargo build --release -p $(WasmtimeLibraryName)</BuildWasmtimeCommand>
|
||||
<BuildWasmtimeCommand Condition="'$(BuildWasmtimeCommand)' == ''">cargo build -p $(WasmtimeLibraryName)</BuildWasmtimeCommand>
|
||||
<BuildWasmtimeCommand Condition="'$(Configuration)' == 'Release'">cargo build --release -p $(WasmtimePackageName)</BuildWasmtimeCommand>
|
||||
<BuildWasmtimeCommand Condition="'$(BuildWasmtimeCommand)' == ''">cargo build -p $(WasmtimePackageName)</BuildWasmtimeCommand>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -20,6 +20,7 @@ indexmap = "1.0.2"
|
||||
thiserror = "1.0.4"
|
||||
more-asserts = "0.2.1"
|
||||
cfg-if = "0.1.9"
|
||||
backtrace = "0.3.42"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3.7", features = ["winbase", "memoryapi"] }
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::memory::LinearMemory;
|
||||
use crate::mmap::Mmap;
|
||||
use crate::signalhandlers::{wasmtime_init_eager, wasmtime_init_finish};
|
||||
use crate::table::Table;
|
||||
use crate::traphandlers::wasmtime_call;
|
||||
use crate::traphandlers::{wasmtime_call, Trap};
|
||||
use crate::vmcontext::{
|
||||
VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport,
|
||||
VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex,
|
||||
@@ -1398,6 +1398,6 @@ pub enum InstantiationError {
|
||||
Link(#[from] LinkError),
|
||||
|
||||
/// A compilation error occured.
|
||||
#[error("Trap occurred while invoking start function: {0}")]
|
||||
StartTrap(String),
|
||||
#[error("Trap occurred while invoking start function")]
|
||||
StartTrap(#[source] Trap),
|
||||
}
|
||||
|
||||
83
crates/runtime/src/jit_function_registry.rs
Normal file
83
crates/runtime/src/jit_function_registry.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
lazy_static! {
|
||||
static ref REGISTRY: RwLock<JITFunctionRegistry> = RwLock::new(JITFunctionRegistry::default());
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct JITFunctionTag {
|
||||
pub module_id: Option<String>,
|
||||
pub func_index: usize,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for JITFunctionTag {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(ref module_id) = self.module_id {
|
||||
write!(f, "{}", module_id)?;
|
||||
} else {
|
||||
write!(f, "(module)")?;
|
||||
}
|
||||
write!(f, ":{}", self.func_index)
|
||||
}
|
||||
}
|
||||
|
||||
struct JITFunctionRegistry {
|
||||
ranges: BTreeMap<usize, (usize, Arc<JITFunctionTag>)>,
|
||||
}
|
||||
|
||||
impl Default for JITFunctionRegistry {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ranges: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JITFunctionRegistry {
|
||||
fn register(&mut self, fn_start: usize, fn_end: usize, tag: JITFunctionTag) {
|
||||
self.ranges.insert(fn_end, (fn_start, Arc::new(tag)));
|
||||
}
|
||||
|
||||
fn unregister(&mut self, fn_end: usize) {
|
||||
self.ranges.remove(&fn_end);
|
||||
}
|
||||
|
||||
fn find(&self, pc: usize) -> Option<&Arc<JITFunctionTag>> {
|
||||
self.ranges
|
||||
.range(pc..)
|
||||
.next()
|
||||
.and_then(|(end, (start, s))| {
|
||||
if *start <= pc && pc < *end {
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(fn_start: usize, fn_end: usize, tag: JITFunctionTag) {
|
||||
REGISTRY
|
||||
.write()
|
||||
.expect("jit function registry lock got poisoned")
|
||||
.register(fn_start, fn_end, tag);
|
||||
}
|
||||
|
||||
pub fn unregister(_fn_start: usize, fn_end: usize) {
|
||||
REGISTRY
|
||||
.write()
|
||||
.expect("jit function registry lock got poisoned")
|
||||
.unregister(fn_end);
|
||||
}
|
||||
|
||||
pub fn find(pc: usize) -> Option<Arc<JITFunctionTag>> {
|
||||
REGISTRY
|
||||
.read()
|
||||
.expect("jit function registry lock got poisoned")
|
||||
.find(pc)
|
||||
.cloned()
|
||||
}
|
||||
@@ -34,6 +34,7 @@ mod trap_registry;
|
||||
mod traphandlers;
|
||||
mod vmcontext;
|
||||
|
||||
pub mod jit_function_registry;
|
||||
pub mod libcalls;
|
||||
|
||||
pub use crate::export::Export;
|
||||
@@ -44,7 +45,7 @@ pub use crate::mmap::Mmap;
|
||||
pub use crate::sig_registry::SignatureRegistry;
|
||||
pub use crate::signalhandlers::{wasmtime_init_eager, wasmtime_init_finish};
|
||||
pub use crate::trap_registry::{get_mut_trap_registry, get_trap_registry, TrapRegistrationGuard};
|
||||
pub use crate::traphandlers::{wasmtime_call, wasmtime_call_trampoline};
|
||||
pub use crate::traphandlers::{wasmtime_call, wasmtime_call_trampoline, Trap};
|
||||
pub use crate::vmcontext::{
|
||||
VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition,
|
||||
VMGlobalImport, VMInvokeArgument, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex,
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
use crate::trap_registry::get_trap_registry;
|
||||
use crate::trap_registry::TrapDescription;
|
||||
use crate::vmcontext::{VMContext, VMFunctionBody};
|
||||
use backtrace::Backtrace;
|
||||
use std::cell::Cell;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use wasmtime_environ::ir;
|
||||
|
||||
@@ -18,7 +20,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static RECORDED_TRAP: Cell<Option<TrapDescription>> = Cell::new(None);
|
||||
static RECORDED_TRAP: Cell<Option<Trap>> = Cell::new(None);
|
||||
static JMP_BUF: Cell<*const u8> = Cell::new(ptr::null());
|
||||
static RESET_GUARD_PAGE: Cell<bool> = Cell::new(false);
|
||||
}
|
||||
@@ -43,24 +45,26 @@ pub extern "C" fn CheckIfTrapAtAddress(_pc: *const u8) -> i8 {
|
||||
pub extern "C" fn RecordTrap(pc: *const u8, reset_guard_page: bool) {
|
||||
// TODO: please see explanation in CheckIfTrapAtAddress.
|
||||
let registry = get_trap_registry();
|
||||
let trap_desc = registry
|
||||
let trap = Trap {
|
||||
desc: registry
|
||||
.get_trap(pc as usize)
|
||||
.unwrap_or_else(|| TrapDescription {
|
||||
source_loc: ir::SourceLoc::default(),
|
||||
trap_code: ir::TrapCode::StackOverflow,
|
||||
});
|
||||
}),
|
||||
backtrace: Backtrace::new_unresolved(),
|
||||
};
|
||||
|
||||
if reset_guard_page {
|
||||
RESET_GUARD_PAGE.with(|v| v.set(true));
|
||||
}
|
||||
|
||||
RECORDED_TRAP.with(|data| {
|
||||
assert_eq!(
|
||||
data.get(),
|
||||
None,
|
||||
let prev = data.replace(Some(trap));
|
||||
assert!(
|
||||
prev.is_none(),
|
||||
"Only one trap per thread can be recorded at a moment!"
|
||||
);
|
||||
data.set(Some(trap_desc))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -108,17 +112,34 @@ fn reset_guard_page() {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn reset_guard_page() {}
|
||||
|
||||
fn trap_message() -> String {
|
||||
let trap_desc = RECORDED_TRAP
|
||||
.with(|data| data.replace(None))
|
||||
.expect("trap_message must be called after trap occurred");
|
||||
/// Stores trace message with backtrace.
|
||||
#[derive(Debug)]
|
||||
pub struct Trap {
|
||||
/// What sort of trap happened, as well as where in the original wasm module
|
||||
/// it happened.
|
||||
pub desc: TrapDescription,
|
||||
/// Native stack backtrace at the time the trap occurred
|
||||
pub backtrace: Backtrace,
|
||||
}
|
||||
|
||||
format!(
|
||||
impl fmt::Display for Trap {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"wasm trap: {}, source location: {}",
|
||||
trap_code_to_expected_string(trap_desc.trap_code),
|
||||
trap_desc.source_loc,
|
||||
trap_code_to_expected_string(self.desc.trap_code),
|
||||
self.desc.source_loc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Trap {}
|
||||
|
||||
fn last_trap() -> Trap {
|
||||
RECORDED_TRAP
|
||||
.with(|data| data.replace(None))
|
||||
.expect("trap_message must be called after trap occurred")
|
||||
}
|
||||
|
||||
fn trap_code_to_expected_string(trap_code: ir::TrapCode) -> String {
|
||||
use ir::TrapCode::*;
|
||||
@@ -146,9 +167,9 @@ pub unsafe extern "C" fn wasmtime_call_trampoline(
|
||||
vmctx: *mut VMContext,
|
||||
callee: *const VMFunctionBody,
|
||||
values_vec: *mut u8,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<(), Trap> {
|
||||
if WasmtimeCallTrampoline(vmctx as *mut u8, callee, values_vec) == 0 {
|
||||
Err(trap_message())
|
||||
Err(last_trap())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@@ -160,9 +181,9 @@ pub unsafe extern "C" fn wasmtime_call_trampoline(
|
||||
pub unsafe extern "C" fn wasmtime_call(
|
||||
vmctx: *mut VMContext,
|
||||
callee: *const VMFunctionBody,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<(), Trap> {
|
||||
if WasmtimeCall(vmctx as *mut u8, callee) == 0 {
|
||||
Err(trap_message())
|
||||
Err(last_trap())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ edition = "2018"
|
||||
wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
|
||||
wasmtime-environ = { path = "../environ", version = "0.9.0" }
|
||||
wasmtime-jit = { path = "../jit", version = "0.9.0" }
|
||||
cranelift-codegen = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-entity = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-wasm = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-codegen = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-entity = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-wasm = { version = "0.55", features = ["enable-serde"] }
|
||||
target-lexicon = "0.10.0"
|
||||
log = { version = "0.4.8", default-features = false }
|
||||
libc = "0.2.60"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::io::{Result, Write};
|
||||
use std::io::{IoSlice, Result, Write};
|
||||
|
||||
/// An adapter around a `Write` stream that guarantees that its output
|
||||
/// is valid UTF-8 and contains no control characters. It does this by
|
||||
@@ -124,6 +124,27 @@ where
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[IoSlice]) -> Result<usize> {
|
||||
// Terminal output is [not expected to be atomic], so just write all the
|
||||
// individual buffers in sequence.
|
||||
//
|
||||
// [not expected to be atomic]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html#tag_16_474_08
|
||||
let mut total_written = 0;
|
||||
|
||||
for buf in bufs {
|
||||
let written = self.write(buf)?;
|
||||
|
||||
total_written += written;
|
||||
|
||||
// Stop at the first point where the OS writes less than we asked.
|
||||
if written < buf.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(total_written)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
self.inner.flush()
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@ wasmtime-runtime = { path = "../runtime", version = "0.9.0" }
|
||||
wasmtime-environ = { path = "../environ", version = "0.9.0" }
|
||||
wasmtime-jit = { path = "../jit", version = "0.9.0" }
|
||||
wasi-common = { path = "../wasi-common", version = "0.9.0" }
|
||||
cranelift-codegen = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-entity = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-wasm = { version = "0.54", features = ["enable-serde"] }
|
||||
cranelift-codegen = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-entity = { version = "0.55", features = ["enable-serde"] }
|
||||
cranelift-wasm = { version = "0.55", features = ["enable-serde"] }
|
||||
target-lexicon = "0.10.0"
|
||||
log = { version = "0.4.8", default-features = false }
|
||||
wig = { path = "../wasi-common/wig", version = "0.9.2" }
|
||||
|
||||
@@ -15,7 +15,7 @@ log = "0.4.8"
|
||||
wasmtime-fuzzing = { path = "../crates/fuzzing", features = ["env_logger"] }
|
||||
wasmtime-jit = { path = "../crates/jit" }
|
||||
wasmtime = { path = "../crates/api" }
|
||||
libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" }
|
||||
libfuzzer-sys = "0.2.0"
|
||||
|
||||
[[bin]]
|
||||
name = "compile"
|
||||
|
||||
@@ -9,7 +9,7 @@ topdir=$(dirname "$0")/..
|
||||
cd "$topdir"
|
||||
|
||||
# All the cranelift-* crates have the same version number
|
||||
version="0.53"
|
||||
version="0.55"
|
||||
|
||||
# Update all of the Cargo.toml files.
|
||||
echo "Updating crate versions to $version"
|
||||
|
||||
@@ -17,8 +17,7 @@ use wasmtime_interface_types::ModuleData;
|
||||
use wasmtime_wasi::{
|
||||
create_wasi_instance, old::snapshot_0::create_wasi_instance as create_wasi_instance_snapshot_0,
|
||||
};
|
||||
#[cfg(feature = "wasi-c")]
|
||||
use wasmtime_wasi_c::instantiate_wasi_c;
|
||||
|
||||
#[cfg(feature = "wasi-c")]
|
||||
use wasmtime_wasi_c::instantiate_wasi_c;
|
||||
|
||||
@@ -152,7 +151,8 @@ impl RunCommand {
|
||||
#[cfg(feature = "wasi-c")]
|
||||
{
|
||||
let global_exports = store.global_exports().clone();
|
||||
let handle = instantiate_wasi_c(global_exports, &preopen_dirs, &argv, &self.vars)?;
|
||||
let handle =
|
||||
instantiate_wasi_c("", global_exports, &preopen_dirs, &argv, &self.vars)?;
|
||||
Instance::from_handle(&store, handle)
|
||||
}
|
||||
#[cfg(not(feature = "wasi-c"))]
|
||||
|
||||
@@ -128,9 +128,12 @@ mod tests {
|
||||
{
|
||||
println!("calling read_out_of_bounds...");
|
||||
let trap = invoke_export(&instance, "read_out_of_bounds").unwrap_err();
|
||||
assert!(trap
|
||||
.message()
|
||||
.starts_with("call error: wasm trap: out of bounds memory access"));
|
||||
assert!(
|
||||
trap.message()
|
||||
.starts_with("wasm trap: out of bounds memory access"),
|
||||
"bad trap message: {:?}",
|
||||
trap.message()
|
||||
);
|
||||
}
|
||||
|
||||
// these invoke wasmtime_call_trampoline from callable.rs
|
||||
@@ -151,7 +154,7 @@ mod tests {
|
||||
let trap = read_out_of_bounds_func.call(&[]).unwrap_err();
|
||||
assert!(trap
|
||||
.message()
|
||||
.starts_with("call error: wasm trap: out of bounds memory access"));
|
||||
.starts_with("wasm trap: out of bounds memory access"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user