Merge branch 'master' into capi-wasi-overwrite-stdin-3

This commit is contained in:
Felix Schütt
2022-08-30 14:08:48 +02:00
committed by GitHub
58 changed files with 1722 additions and 1040 deletions

View File

@@ -24,7 +24,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
- name: Configure cargo data directory - name: Configure cargo data directory
# After this point, all cargo registry and crate data is stored in # After this point, all cargo registry and crate data is stored in
# $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files # $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files

View File

@@ -100,7 +100,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
target: ${{ matrix.target }} target: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v1 - uses: Swatinem/rust-cache@v1
if: matrix.use_sccache != true if: matrix.use_sccache != true
@@ -270,7 +270,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
- name: Build cross image - name: Build cross image
run: | run: |

View File

@@ -21,7 +21,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
target: ${{ matrix.target }} target: ${{ matrix.target }}
- name: Install wasm32-wasi target - name: Install wasm32-wasi target
shell: bash shell: bash

View File

@@ -21,7 +21,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
- name: Install LLVM (Linux) - name: Install LLVM (Linux)
run: | run: |
curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz -L -o llvm.tar.xz curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz -L -o llvm.tar.xz

View File

@@ -16,7 +16,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
- name: Install LLVM - name: Install LLVM
shell: bash shell: bash
run: | run: |

View File

@@ -18,7 +18,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
components: rustfmt, clippy components: rustfmt, clippy
- name: Install LLVM (Linux) - name: Install LLVM (Linux)
run: | run: |

View File

@@ -33,7 +33,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
- name: Install NodeJS - name: Install NodeJS
uses: actions/setup-node@v2 uses: actions/setup-node@v2

View File

@@ -110,7 +110,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.59 toolchain: 1.61
target: ${{ matrix.target }} target: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v1 - uses: Swatinem/rust-cache@v1
if: matrix.use_sccache != true if: matrix.use_sccache != true
@@ -199,6 +199,14 @@ jobs:
'${{ runner.tool_cache }}/cargo-sccache/bin/sccache' -s '${{ runner.tool_cache }}/cargo-sccache/bin/sccache' -s
echo 'RUSTC_WRAPPER=${{ runner.tool_cache }}/cargo-sccache/bin/sccache' >> $GITHUB_ENV echo 'RUSTC_WRAPPER=${{ runner.tool_cache }}/cargo-sccache/bin/sccache' >> $GITHUB_ENV
shell: bash shell: bash
- name: Test
if: matrix.run_test && matrix.os != 'windows-2019'
run: |
make
env:
TARGET: ${{ matrix.target }}
TARGET_DIR: target/${{ matrix.target }}/release
CARGO_TARGET: --target ${{ matrix.target }}
- name: Test - name: Test
if: matrix.run_test && matrix.os != 'windows-2019' if: matrix.run_test && matrix.os != 'windows-2019'
run: | run: |
@@ -215,6 +223,16 @@ jobs:
TARGET: ${{ matrix.target }} TARGET: ${{ matrix.target }}
TARGET_DIR: target/${{ matrix.target }}/release TARGET_DIR: target/${{ matrix.target }}/release
CARGO_TARGET: --target ${{ matrix.target }} CARGO_TARGET: --target ${{ matrix.target }}
- name: Test integration CLI
if: matrix.run_test && matrix.os != 'windows-2019'
run: |
make && make build-capi && make package-capi && make package
export WASMER_DIR=`pwd`/package
make test-integration-cli
env:
TARGET: ${{ matrix.target }}
TARGET_DIR: target/${{ matrix.target }}/release
CARGO_TARGET: --target ${{ matrix.target }}
- name: Test - name: Test
if: matrix.run_test && matrix.os == 'windows-2019' if: matrix.run_test && matrix.os == 'windows-2019'
run: | run: |

View File

@@ -13,8 +13,10 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C
- #[3096](https://github.com/wasmerio/wasmer/pull/3096) create-exe: use cached wasmer tarballs for network fetches - #[3096](https://github.com/wasmerio/wasmer/pull/3096) create-exe: use cached wasmer tarballs for network fetches
### Changed ### Changed
- #[3131](https://github.com/wasmerio/wasmer/pull/3131) Update migration docs for MemoryView changes
### Fixed ### Fixed
- #[3130](https://github.com/wasmerio/wasmer/pull/3130) Remove panics from Artifact::deserialize
## 3.0.0-beta - 2022/08/08 ## 3.0.0-beta - 2022/08/08

160
Cargo.lock generated
View File

@@ -37,6 +37,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "android_system_properties"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.12.1" version = "0.12.1"
@@ -48,9 +57,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.60" version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
@@ -81,7 +90,7 @@ checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe"
dependencies = [ dependencies = [
"bstr", "bstr",
"doc-comment", "doc-comment",
"predicates 2.1.1", "predicates",
"predicates-core", "predicates-core",
"predicates-tree", "predicates-tree",
"wait-timeout", "wait-timeout",
@@ -215,9 +224,9 @@ dependencies = [
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.10.0" version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
[[package]] [[package]]
name = "bytecheck" name = "bytecheck"
@@ -270,7 +279,7 @@ version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb"
dependencies = [ dependencies = [
"clap 3.2.16", "clap 3.2.17",
"heck", "heck",
"indexmap", "indexmap",
"log", "log",
@@ -312,10 +321,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.20" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0" checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
dependencies = [ dependencies = [
"iana-time-zone",
"js-sys", "js-sys",
"num-integer", "num-integer",
"num-traits", "num-traits",
@@ -351,9 +361,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.2.16" version = "3.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9" checksum = "29e724a68d9319343bb3328c9cc2dfde263f4b3142ee1059a9980580171c954b"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
@@ -368,9 +378,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "3.2.15" version = "3.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4" checksum = "13547f7012c01ab4a0e8f8967730ada8f9fdf419e8b6c792788f39cf4e46eefa"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error", "proc-macro-error",
@@ -474,6 +484,12 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]] [[package]]
name = "corosensei" name = "corosensei"
version = "0.1.3" version = "0.1.3"
@@ -755,12 +771,6 @@ version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "difference"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]] [[package]]
name = "difflib" name = "difflib"
version = "0.4.0" version = "0.4.0"
@@ -871,9 +881,9 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.7.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]] [[package]]
name = "enum-iterator" name = "enum-iterator"
@@ -987,9 +997,9 @@ dependencies = [
[[package]] [[package]]
name = "float-cmp" name = "float-cmp"
version = "0.8.0" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
dependencies = [ dependencies = [
"num-traits", "num-traits",
] ]
@@ -1162,6 +1172,19 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"js-sys",
"wasm-bindgen",
"winapi",
]
[[package]] [[package]]
name = "ident_case" name = "ident_case"
version = "1.0.1" version = "1.0.1"
@@ -1207,15 +1230,15 @@ dependencies = [
[[package]] [[package]]
name = "inline-c" name = "inline-c"
version = "0.1.6" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b370741c5913d9b3765d280493b9b97658818410fd64cbf6e8d333b42a1049e" checksum = "340dd3d6102fa919bd20987024a6d84954c36ec691ac1efea37742ee983c8dd5"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"cc", "cc",
"inline-c-macro", "inline-c-macro",
"lazy_static", "lazy_static",
"predicates 1.0.8", "predicates",
"regex", "regex",
"rustc_version 0.3.3", "rustc_version 0.3.3",
"target-lexicon 0.11.2", "target-lexicon 0.11.2",
@@ -1302,9 +1325,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.127" version = "0.2.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@@ -1385,9 +1408,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "memmap2" name = "memmap2"
version = "0.5.5" version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a79b39c93a7a5a27eeaf9a23b5ff43f1b9e0ad6b1cdd441140ae53c35613fc7" checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@@ -1541,9 +1564,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.13.0" version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
[[package]] [[package]]
name = "oorandom" name = "oorandom"
@@ -1568,9 +1591,9 @@ dependencies = [
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.2.0" version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
[[package]] [[package]]
name = "output_vt100" name = "output_vt100"
@@ -1620,9 +1643,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.2.1" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69486e2b8c2d2aeb9762db7b4e00b0331156393555cff467f4163ff06821eef8" checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
dependencies = [ dependencies = [
"thiserror", "thiserror",
"ucd-trie", "ucd-trie",
@@ -1642,9 +1665,9 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]] [[package]]
name = "plotters" name = "plotters"
version = "0.3.2" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9428003b84df1496fb9d6eeee9c5f8145cb41ca375eb0dad204328888832811f" checksum = "716b4eeb6c4a1d3ecc956f75b43ec2e8e8ba80026413e70a3f41fd3313d3492b"
dependencies = [ dependencies = [
"num-traits", "num-traits",
"plotters-backend", "plotters-backend",
@@ -1661,9 +1684,9 @@ checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
[[package]] [[package]]
name = "plotters-svg" name = "plotters-svg"
version = "0.3.2" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0918736323d1baff32ee0eade54984f6f201ad7e97d5cfb5d6ab4a358529615" checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
dependencies = [ dependencies = [
"plotters-backend", "plotters-backend",
] ]
@@ -1674,19 +1697,6 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "predicates"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df"
dependencies = [
"difference",
"float-cmp",
"normalize-line-endings",
"predicates-core",
"regex",
]
[[package]] [[package]]
name = "predicates" name = "predicates"
version = "2.1.1" version = "2.1.1"
@@ -1694,8 +1704,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c" checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
dependencies = [ dependencies = [
"difflib", "difflib",
"float-cmp",
"itertools", "itertools",
"normalize-line-endings",
"predicates-core", "predicates-core",
"regex",
] ]
[[package]] [[package]]
@@ -2181,9 +2194,9 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.142" version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@@ -2209,9 +2222,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.142" version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2886,9 +2899,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-encoder" name = "wasm-encoder"
version = "0.15.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8905fd25fdadeb0e7e8bf43a9f46f9f972d6291ad0c7a32573b88dd13a6cfa6b" checksum = "d443c5a7daae71697d97ec12ad70b4fe8766d3a0f4db16158ac8b781365892f7"
dependencies = [ dependencies = [
"leb128", "leb128",
] ]
@@ -2996,7 +3009,7 @@ dependencies = [
"atty", "atty",
"bytesize", "bytesize",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"clap 3.2.16", "clap 3.2.17",
"colored 2.0.0", "colored 2.0.0",
"dirs", "dirs",
"distance", "distance",
@@ -3057,7 +3070,7 @@ dependencies = [
"atty", "atty",
"bytesize", "bytesize",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"clap 3.2.16", "clap 3.2.17",
"colored 2.0.0", "colored 2.0.0",
"distance", "distance",
"fern", "fern",
@@ -3194,6 +3207,7 @@ dependencies = [
"enum-iterator", "enum-iterator",
"enumset", "enumset",
"indexmap", "indexmap",
"memoffset",
"more-asserts", "more-asserts",
"rkyv", "rkyv",
"serde", "serde",
@@ -3378,21 +3392,21 @@ checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a"
[[package]] [[package]]
name = "wasmparser" name = "wasmparser"
version = "0.88.0" version = "0.89.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb8cf7dd82407fe68161bedcd57fde15596f32ebf6e9b3bdbf3ae1da20e38e5e" checksum = "ab5d3e08b13876f96dd55608d03cd4883a0545884932d5adf11925876c96daef"
dependencies = [ dependencies = [
"indexmap", "indexmap",
] ]
[[package]] [[package]]
name = "wasmprinter" name = "wasmprinter"
version = "0.2.38" version = "0.2.39"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04f2786f19a25211ddfa331e28b7579a6d6880f5f4b18d21253cd90274aa4c21" checksum = "aa9e5ee2f56cc8a5da489558114e8c118e5a8416d96aefe63dcf1b5b05b858c6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"wasmparser 0.88.0", "wasmparser 0.89.1",
] ]
[[package]] [[package]]
@@ -3415,23 +3429,23 @@ dependencies = [
[[package]] [[package]]
name = "wast" name = "wast"
version = "45.0.0" version = "46.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186c474c4f9bb92756b566d592a16591b4526b1a4841171caa3f31d7fe330d96" checksum = "ea0ab19660e3ea6891bba69167b9be40fad00fb1fe3dd39c5eebcee15607131b"
dependencies = [ dependencies = [
"leb128", "leb128",
"memchr", "memchr",
"unicode-width", "unicode-width",
"wasm-encoder 0.15.0", "wasm-encoder 0.16.0",
] ]
[[package]] [[package]]
name = "wat" name = "wat"
version = "1.0.47" version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2d4bc4724b4f02a482c8cab053dac5ef26410f264c06ce914958f9a42813556" checksum = "8f775282def4d5bffd94d60d6ecd57bfe6faa46171cdbf8d32bd5458842b1e3e"
dependencies = [ dependencies = [
"wast 45.0.0", "wast 46.0.0",
] ]
[[package]] [[package]]
@@ -3661,9 +3675,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]] [[package]]
name = "x11-dl" name = "x11-dl"
version = "2.19.1" version = "2.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" checksum = "0c83627bc137605acc00bb399c7b908ef460b621fc37c953db2b09f88c449ea6"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",

View File

@@ -389,7 +389,7 @@ build-wasmer-headless-minimal: RUSTFLAGS += -C panic=abort
build-wasmer-headless-minimal: build-wasmer-headless-minimal:
RUSTFLAGS="${RUSTFLAGS}" xargo build --target $(HOST_TARGET) --release --manifest-path=lib/cli/Cargo.toml --no-default-features --features headless-minimal --bin wasmer-headless RUSTFLAGS="${RUSTFLAGS}" xargo build --target $(HOST_TARGET) --release --manifest-path=lib/cli/Cargo.toml --no-default-features --features headless-minimal --bin wasmer-headless
ifeq ($(IS_DARWIN), 1) ifeq ($(IS_DARWIN), 1)
strip -u target/$(HOST_TARGET)/release/wasmer-headless strip target/$(HOST_TARGET)/release/wasmer-headless
else ifeq ($(IS_WINDOWS), 1) else ifeq ($(IS_WINDOWS), 1)
strip --strip-unneeded target/$(HOST_TARGET)/release/wasmer-headless.exe strip --strip-unneeded target/$(HOST_TARGET)/release/wasmer-headless.exe
else else
@@ -455,8 +455,13 @@ build-capi-llvm-universal: capi-setup
# Headless (we include the minimal to be able to run) # Headless (we include the minimal to be able to run)
build-capi-headless: capi-setup build-capi-headless: capi-setup
RUSTFLAGS="${RUSTFLAGS} -C panic=abort" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \ ifeq ($(CARGO_TARGET),)
RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build --target $(HOST_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi --no-default-features --features compiler-headless,wasi
else
RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi
endif
build-capi-headless-ios: capi-setup build-capi-headless-ios: capi-setup
RUSTFLAGS="${RUSTFLAGS} -C panic=abort" cargo lipo --manifest-path lib/c-api/Cargo.toml --release \ RUSTFLAGS="${RUSTFLAGS} -C panic=abort" cargo lipo --manifest-path lib/c-api/Cargo.toml --release \
@@ -534,8 +539,8 @@ test-examples:
$(CARGO_BINARY) test $(CARGO_TARGET) $(compiler_features) --features wasi --examples $(CARGO_BINARY) test $(CARGO_TARGET) $(compiler_features) --features wasi --examples
$(CARGO_BINARY) test $(CARGO_TARGET) --release $(compiler_features) --features wasi --examples $(CARGO_BINARY) test $(CARGO_TARGET) --release $(compiler_features) --features wasi --examples
test-integration: test-integration-cli:
$(CARGO_BINARY) test $(CARGO_TARGET) --no-fail-fast -p wasmer-integration-tests-cli $(CARGO_BINARY) test $(CARGO_TARGET) --no-fail-fast -p wasmer-integration-tests-cli -- --nocapture
test-integration-ios: test-integration-ios:
$(CARGO_BINARY) test $(CARGO_TARGET) -p wasmer-integration-tests-ios $(CARGO_BINARY) test $(CARGO_TARGET) -p wasmer-integration-tests-ios

View File

@@ -117,6 +117,62 @@ env_mut.memory = Some(instance.exports.get_memory("memory"));
env_mut.alloc_guest_memory = Some(instance.exports.get_typed_function("__alloc")); env_mut.alloc_guest_memory = Some(instance.exports.get_typed_function("__alloc"));
``` ```
### New `MemoryView` API (preparation for shared memory)
Reading from memory has slightly changed compared to 2.x:
```rust
// 2.x
let memory = instance.exports.get_memory("mem")?;
println!("Memory size (pages) {:?}", memory.size());
println!("Memory size (bytes) {:?}", memory.data_size());
let load = instance
.exports
.get_native_function::<(), (WasmPtr<u8, Array>, i32)>("load")?;
let (ptr, length) = load.call(&mut store)?;
let str = ptr.get_utf8_string(memory, length as u32).unwrap();
println!("Memory contents: {:?}", str);
```
```rust
// 3.x
let memory = instance.exports.get_memory("mem")?;
let memory_view = memory.view(&store);
println!("Memory size (pages) {:?}", memory_view.size());
println!("Memory size (bytes) {:?}", memory_view.data_size());
let load: TypedFunction<(), (WasmPtr<u8>, i32)> =
instance.exports.get_typed_function(&mut store, "load")?;
let (ptr, length) = load.call(&mut store)?;
let memory_view = memory.view(&store);
let str = ptr.read_utf8_string(&memory_view, length as u32).unwrap();
println!("Memory contents: {:?}", str);
```
The reason for this change is that in the future this will enable
safely sharing memory across threads. The same thing goes for reading slices:
```rust
// 2.x
let new_str = b"Hello, Wasmer!";
let values = ptr.deref(memory, 0, new_str.len() as u32).unwrap();
for i in 0..new_str.len() {
values[i].set(new_str[i]);
}
```
```rust
// 3.x
let memory_view = memory.view(&store); // (can be reused)
let new_str = b"Hello, Wasmer!";
let values = ptr.slice(&memory_view, new_str.len() as u32).unwrap();
for i in 0..new_str.len() {
values.index(i as u64).write(new_str[i]).unwrap();
}
```
### Managing imports ### Managing imports

View File

@@ -75,7 +75,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("String offset: {:?}", ptr.offset()); println!("String offset: {:?}", ptr.offset());
println!("String length: {:?}", length); println!("String length: {:?}", length);
// We now know where to fin our string, let's read it. // We now know where to find our string, let's read it.
// //
// We will get bytes out of the memory so we need to // We will get bytes out of the memory so we need to
// decode them into a string. // decode them into a string.

View File

@@ -7,6 +7,7 @@ use std::fmt;
use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen::{JsCast, JsValue};
use wasmer_types::{ExternType, FunctionType, GlobalType, MemoryType, TableType}; use wasmer_types::{ExternType, FunctionType, GlobalType, MemoryType, TableType};
/// Represents linear memory that is managed by the javascript runtime
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct VMMemory { pub struct VMMemory {
pub(crate) memory: Memory, pub(crate) memory: Memory,
@@ -20,6 +21,11 @@ impl VMMemory {
pub(crate) fn new(memory: Memory, ty: MemoryType) -> Self { pub(crate) fn new(memory: Memory, ty: MemoryType) -> Self {
Self { memory, ty } Self { memory, ty }
} }
/// Attempts to clone this memory (if its clonable)
pub(crate) fn try_clone(&self) -> Option<VMMemory> {
Some(self.clone())
}
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]

View File

@@ -6,7 +6,6 @@ use crate::js::{MemoryAccessError, MemoryType};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::slice; use std::slice;
use thiserror::Error;
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
use tracing::warn; use tracing::warn;
@@ -16,22 +15,7 @@ use wasmer_types::Pages;
use super::MemoryView; use super::MemoryView;
/// Error type describing things that can go wrong when operating on Wasm Memories. pub use wasmer_types::MemoryError;
#[derive(Error, Debug, Clone, PartialEq, Hash)]
pub enum MemoryError {
/// The operation would cause the size of the memory to exceed the maximum or would cause
/// an overflow leading to unindexable memory.
#[error("The memory could not grow: current size {} pages, requested increase: {} pages", current.0, attempted_delta.0)]
CouldNotGrow {
/// The current size in pages.
current: Pages,
/// The attempted amount to grow by in pages.
attempted_delta: Pages,
},
/// A user defined error value, used for error cases not listed above.
#[error("A user-defined error occurred: {0}")]
Generic(String),
}
#[wasm_bindgen] #[wasm_bindgen]
extern "C" { extern "C" {
@@ -113,7 +97,25 @@ impl Memory {
.map_err(|_e| MemoryError::Generic("Error while creating the memory".to_owned()))?; .map_err(|_e| MemoryError::Generic("Error while creating the memory".to_owned()))?;
let vm_memory = VMMemory::new(js_memory, ty); let vm_memory = VMMemory::new(js_memory, ty);
Ok(Self::from_vm_export(store, vm_memory)) let handle = StoreHandle::new(store.objects_mut(), vm_memory);
Ok(Self::from_vm_extern(store, handle.internal_handle()))
}
/// Creates a new host `Memory` from provided JavaScript memory.
pub fn new_raw(
store: &mut impl AsStoreMut,
js_memory: js_sys::WebAssembly::Memory,
ty: MemoryType,
) -> Result<Self, MemoryError> {
let vm_memory = VMMemory::new(js_memory, ty);
let handle = StoreHandle::new(store.objects_mut(), vm_memory);
Ok(Self::from_vm_extern(store, handle.internal_handle()))
}
/// Create a memory object from an existing memory and attaches it to the store
pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self {
let handle = StoreHandle::new(new_store.objects_mut(), memory);
Self::from_vm_extern(new_store, handle.internal_handle())
} }
/// Returns the [`MemoryType`] of the `Memory`. /// Returns the [`MemoryType`] of the `Memory`.
@@ -193,12 +195,6 @@ impl Memory {
Ok(Pages(new_pages)) Ok(Pages(new_pages))
} }
pub(crate) fn from_vm_export(store: &mut impl AsStoreMut, vm_memory: VMMemory) -> Self {
Self {
handle: StoreHandle::new(store.objects_mut(), vm_memory),
}
}
pub(crate) fn from_vm_extern( pub(crate) fn from_vm_extern(
store: &mut impl AsStoreMut, store: &mut impl AsStoreMut,
internal: InternalStoreHandle<VMMemory>, internal: InternalStoreHandle<VMMemory>,
@@ -210,6 +206,12 @@ impl Memory {
} }
} }
/// Attempts to clone this memory (if its clonable)
pub fn try_clone(&self, store: &impl AsStoreRef) -> Option<VMMemory> {
let mem = self.handle.get(store.as_store_ref().objects());
mem.try_clone()
}
/// Checks whether this `Global` can be used with the given context. /// Checks whether this `Global` can be used with the given context.
pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool { pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.handle.store_id() == store.as_store_ref().objects().id() self.handle.store_id() == store.as_store_ref().objects().id()

View File

@@ -46,7 +46,7 @@ impl Extern {
} }
/// Create an `Extern` from an `wasmer_compiler::Export`. /// Create an `Extern` from an `wasmer_compiler::Export`.
pub fn from_vm_export(store: &mut impl AsStoreMut, export: Export) -> Self { pub fn from_vm_extern(store: &mut impl AsStoreMut, export: Export) -> Self {
match export { match export {
Export::Function(f) => Self::Function(Function::from_vm_extern(store, f)), Export::Function(f) => Self::Function(Function::from_vm_extern(store, f)),
Export::Memory(m) => Self::Memory(Memory::from_vm_extern(store, m)), Export::Memory(m) => Self::Memory(Memory::from_vm_extern(store, m)),

View File

@@ -36,7 +36,7 @@ impl<T> FunctionEnv<T> {
} }
/// Get the data as reference /// Get the data as reference
pub fn as_ref<'a>(&self, store: &'a impl AsStoreMut) -> &'a T pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T
where where
T: Any + Send + 'static + Sized, T: Any + Send + 'static + Sized,
{ {
@@ -112,6 +112,11 @@ impl<T: Send + 'static> FunctionEnvMut<'_, T> {
self.func_env.as_mut(&mut self.store_mut) self.func_env.as_mut(&mut self.store_mut)
} }
/// Borrows a new immmutable reference
pub fn as_ref(&self) -> FunctionEnv<T> {
self.func_env.clone()
}
/// Borrows a new mutable reference /// Borrows a new mutable reference
pub fn as_mut<'a>(&'a mut self) -> FunctionEnvMut<'a, T> { pub fn as_mut<'a>(&'a mut self) -> FunctionEnvMut<'a, T> {
FunctionEnvMut { FunctionEnvMut {

View File

@@ -174,6 +174,32 @@ impl Imports {
} }
imports imports
} }
/// Iterates through all the imports in this structure
pub fn iter<'a>(&'a self) -> ImportsIterator<'a> {
ImportsIterator::new(self)
}
}
pub struct ImportsIterator<'a> {
iter: std::collections::hash_map::Iter<'a, (String, String), Extern>,
}
impl<'a> ImportsIterator<'a> {
fn new(imports: &'a Imports) -> Self {
let iter = imports.map.iter();
Self { iter }
}
}
impl<'a> Iterator for ImportsIterator<'a> {
type Item = (&'a str, &'a str, &'a Extern);
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|(k, v)| (k.0.as_str(), k.1.as_str(), v))
}
} }
impl IntoIterator for &Imports { impl IntoIterator for &Imports {

View File

@@ -105,7 +105,7 @@ impl Instance {
})?; })?;
let export: Export = let export: Export =
Export::from_js_value(js_export, &mut store, extern_type)?.into(); Export::from_js_value(js_export, &mut store, extern_type)?.into();
let extern_ = Extern::from_vm_export(&mut store, export); let extern_ = Extern::from_vm_extern(&mut store, export);
Ok((name.to_string(), extern_)) Ok((name.to_string(), extern_))
}) })
.collect::<Result<Exports, InstantiationError>>()?; .collect::<Result<Exports, InstantiationError>>()?;

View File

@@ -73,6 +73,12 @@ pub use crate::js::types::{
pub use crate::js::value::Value; pub use crate::js::value::Value;
pub use crate::js::value::Value as Val; pub use crate::js::value::Value as Val;
pub mod vm {
//! The `vm` module re-exports wasmer-vm types.
pub use crate::js::export::VMMemory;
}
pub use wasmer_types::is_wasm; pub use wasmer_types::is_wasm;
pub use wasmer_types::{ pub use wasmer_types::{
Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, Pages, ValueType, WASM_MAX_PAGES, Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, Pages, ValueType, WASM_MAX_PAGES,

View File

@@ -11,7 +11,6 @@ use std::marker::PhantomData;
use crate::js::externals::Function; use crate::js::externals::Function;
use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle}; use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle};
use crate::js::FunctionEnv;
use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList}; use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList};
// use std::panic::{catch_unwind, AssertUnwindSafe}; // use std::panic::{catch_unwind, AssertUnwindSafe};
use crate::js::export::VMFunction; use crate::js::export::VMFunction;

View File

@@ -263,6 +263,11 @@ mod objects {
self.id self.id
} }
/// Sets the ID of this store
pub fn set_id(&mut self, id: StoreId) {
self.id = id;
}
/// Returns a pair of mutable references from two handles. /// Returns a pair of mutable references from two handles.
/// ///
/// Panics if both handles point to the same object. /// Panics if both handles point to the same object.

View File

@@ -11,7 +11,7 @@ use std::slice;
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
use tracing::warn; use tracing::warn;
use wasmer_types::Pages; use wasmer_types::Pages;
use wasmer_vm::{InternalStoreHandle, MemoryError, StoreHandle, VMExtern, VMMemory}; use wasmer_vm::{InternalStoreHandle, LinearMemory, MemoryError, StoreHandle, VMExtern, VMMemory};
use super::MemoryView; use super::MemoryView;
@@ -60,6 +60,12 @@ impl Memory {
}) })
} }
/// Create a memory object from an existing memory and attaches it to the store
pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self {
let handle = StoreHandle::new(new_store.objects_mut(), memory);
Self::from_vm_extern(new_store, handle.internal_handle())
}
/// Returns the [`MemoryType`] of the `Memory`. /// Returns the [`MemoryType`] of the `Memory`.
/// ///
/// # Example /// # Example
@@ -142,6 +148,12 @@ impl Memory {
self.handle.store_id() == store.as_store_ref().objects().id() self.handle.store_id() == store.as_store_ref().objects().id()
} }
/// Attempts to clone this memory (if its clonable)
pub fn try_clone(&self, store: &impl AsStoreRef) -> Option<VMMemory> {
let mem = self.handle.get(store.as_store_ref().objects());
mem.try_clone().map(|mem| mem.into())
}
pub(crate) fn to_vm_extern(&self) -> VMExtern { pub(crate) fn to_vm_extern(&self) -> VMExtern {
VMExtern::Memory(self.handle.internal_handle()) VMExtern::Memory(self.handle.internal_handle())
} }

View File

@@ -5,6 +5,7 @@ use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::slice; use std::slice;
use wasmer_types::Pages; use wasmer_types::Pages;
use wasmer_vm::LinearMemory;
use super::memory::MemoryBuffer; use super::memory::MemoryBuffer;
use super::Memory; use super::Memory;

View File

@@ -174,4 +174,138 @@ mod tests {
s => panic!("Unexpected memory style: {:?}", s), s => panic!("Unexpected memory style: {:?}", s),
} }
} }
use std::cell::UnsafeCell;
use std::ptr::NonNull;
use wasmer_types::{MemoryError, MemoryStyle, MemoryType, Pages, WASM_PAGE_SIZE};
use wasmer_vm::{LinearMemory, MaybeInstanceOwned};
#[derive(Debug)]
struct VMTinyMemory {
mem: [u8; WASM_PAGE_SIZE],
}
unsafe impl Send for VMTinyMemory {}
unsafe impl Sync for VMTinyMemory {}
impl VMTinyMemory {
pub fn new() -> Result<Self, MemoryError> {
Ok(VMTinyMemory {
mem: [0; WASM_PAGE_SIZE],
})
}
}
impl LinearMemory for VMTinyMemory {
fn ty(&self) -> MemoryType {
MemoryType {
minimum: Pages::from(1u32),
maximum: Some(Pages::from(1u32)),
shared: false,
}
}
fn size(&self) -> Pages {
Pages::from(1u32)
}
fn style(&self) -> MemoryStyle {
MemoryStyle::Static {
bound: Pages::from(1u32),
offset_guard_size: 0,
}
}
fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
Err(MemoryError::CouldNotGrow {
current: Pages::from(100u32),
attempted_delta: delta,
})
}
fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition {
base: self.mem.as_ptr() as _,
current_length: WASM_PAGE_SIZE,
})))
.as_ptr()
}
fn try_clone(&self) -> Option<Box<dyn LinearMemory + 'static>> {
None
}
}
impl From<VMTinyMemory> for wasmer_vm::VMMemory {
fn from(mem: VMTinyMemory) -> Self {
Self(Box::new(mem))
}
}
struct TinyTunables;
impl Tunables for TinyTunables {
fn memory_style(&self, _memory: &MemoryType) -> MemoryStyle {
MemoryStyle::Static {
bound: Pages::from(1u32),
offset_guard_size: 0,
}
}
/// Construct a `TableStyle` for the provided `TableType`
fn table_style(&self, _table: &TableType) -> TableStyle {
TableStyle::CallerChecksSignature
}
fn create_host_memory(
&self,
_ty: &MemoryType,
_style: &MemoryStyle,
) -> Result<VMMemory, MemoryError> {
let memory = VMTinyMemory::new().unwrap();
Ok(VMMemory::from_custom(memory))
}
unsafe fn create_vm_memory(
&self,
_ty: &MemoryType,
_style: &MemoryStyle,
_vm_definition_location: NonNull<VMMemoryDefinition>,
) -> Result<VMMemory, MemoryError> {
let memory = VMTinyMemory::new().unwrap();
Ok(memory.into())
}
/// Create a table owned by the host given a [`TableType`] and a [`TableStyle`].
fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result<VMTable, String> {
VMTable::new(ty, style)
}
/// Create a table owned by the VM given a [`TableType`] and a [`TableStyle`].
///
/// # Safety
/// - `vm_definition_location` must point to a valid location in VM memory.
unsafe fn create_vm_table(
&self,
ty: &TableType,
style: &TableStyle,
vm_definition_location: NonNull<VMTableDefinition>,
) -> Result<VMTable, String> {
VMTable::from_definition(ty, style, vm_definition_location)
}
}
#[test]
fn check_linearmemory() {
let tunables = TinyTunables {};
let vmmemory = tunables.create_host_memory(
&MemoryType::new(1u32, Some(100u32), true),
&MemoryStyle::Static {
bound: Pages::from(1u32),
offset_guard_size: 0u64,
},
);
let mut vmmemory = vmmemory.unwrap();
assert!(vmmemory.grow(Pages::from(2u32)).is_err());
assert_eq!(vmmemory.size(), Pages::from(1u32));
assert_eq!(
vmmemory.grow(Pages::from(0u32)).err().unwrap(),
MemoryError::CouldNotGrow {
current: Pages::from(100u32),
attempted_delta: Pages::from(0u32)
}
);
}
} }

View File

@@ -17,7 +17,7 @@ edition = "2018"
# a conflict with the existing `wasmer` crate, see below. # a conflict with the existing `wasmer` crate, see below.
name = "wasmer" # ##lib.name## name = "wasmer" # ##lib.name##
# ^ DO NOT REMOVE, it's used the `Makefile`, see `build-docs-capi`. # ^ DO NOT REMOVE, it's used the `Makefile`, see `build-docs-capi`.
crate-type = ["cdylib", "rlib", "staticlib"] crate-type = ["staticlib", "cdylib"] #"cdylib", "rlib", "staticlib"]
[dependencies] [dependencies]
# We rename `wasmer` to `wasmer-api` to avoid the conflict with this # We rename `wasmer` to `wasmer-api` to avoid the conflict with this

View File

@@ -125,7 +125,7 @@ impl CType {
#[allow(clippy::borrowed_box)] #[allow(clippy::borrowed_box)]
let ret: CType = return_value let ret: CType = return_value
.as_ref() .as_ref()
.map(|i: &Box<CType>| (&**i).clone()) .map(|i: &Box<CType>| (**i).clone())
.unwrap_or_default(); .unwrap_or_default();
ret.generate_c(w); ret.generate_c(w);
w.push(' '); w.push(' ');
@@ -183,7 +183,7 @@ impl CType {
#[allow(clippy::borrowed_box)] #[allow(clippy::borrowed_box)]
let ret: CType = return_value let ret: CType = return_value
.as_ref() .as_ref()
.map(|i: &Box<CType>| (&**i).clone()) .map(|i: &Box<CType>| (**i).clone())
.unwrap_or_default(); .unwrap_or_default();
ret.generate_c(w); ret.generate_c(w);
w.push(' '); w.push(' ');

View File

@@ -58,8 +58,8 @@ wasm_byte_vec_t generate_serialized_data() {
return module_byte_vec; return module_byte_vec;
} }
wasm_module_t* wasmer_static_module_new(wasm_store_t* store, const char* wasm_name) { wasm_module_t* wasmer_object_module_new(wasm_store_t* store, const char* module_name) {
// wasm_name intentionally unused for now: will be used in the future. // module_name intentionally unused for now: will be used in the future.
wasm_byte_vec_t module_byte_vec = generate_serialized_data(); wasm_byte_vec_t module_byte_vec = generate_serialized_data();
wasm_module_t* module = wasm_module_deserialize(store, &module_byte_vec); wasm_module_t* module = wasm_module_deserialize(store, &module_byte_vec);
free(module_byte_vec.data); free(module_byte_vec.data);

View File

@@ -21,8 +21,7 @@ use wasmer_object::{emit_serialized, get_object_for_target};
pub type PrefixerFn = Box<dyn Fn(&[u8]) -> String + Send>; pub type PrefixerFn = Box<dyn Fn(&[u8]) -> String + Send>;
const WASMER_MAIN_C_SOURCE: &[u8] = include_bytes!("wasmer_create_exe_main.c"); const WASMER_MAIN_C_SOURCE: &[u8] = include_bytes!("wasmer_create_exe_main.c");
#[cfg(feature = "static-artifact-create")] const WASMER_DESERIALIZE_HEADER: &str = include_str!("wasmer_deserialize_module.h");
const WASMER_STATIC_MAIN_C_SOURCE: &[u8] = include_bytes!("wasmer_static_create_exe_main.c");
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct CrossCompile { struct CrossCompile {
@@ -40,6 +39,7 @@ struct CrossCompileSetup {
target: Triple, target: Triple,
zig_binary_path: PathBuf, zig_binary_path: PathBuf,
library: PathBuf, library: PathBuf,
working_dir: PathBuf,
} }
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@@ -111,6 +111,11 @@ pub struct CreateExe {
impl CreateExe { impl CreateExe {
/// Runs logic for the `compile` subcommand /// Runs logic for the `compile` subcommand
pub fn execute(&self) -> Result<()> { pub fn execute(&self) -> Result<()> {
let object_format = self.object_format.unwrap_or(ObjectFormat::Symbols);
let working_dir = tempfile::tempdir()?;
let starting_cd = env::current_dir()?;
let output_path = starting_cd.join(&self.output);
/* Making library_path, tarball zig_binary_path flags require that target_triple flag /* Making library_path, tarball zig_binary_path flags require that target_triple flag
* is set cannot be encoded with structopt, so we have to perform cli flag validation * is set cannot be encoded with structopt, so we have to perform cli flag validation
* manually here */ * manually here */
@@ -150,10 +155,6 @@ impl CreateExe {
}) })
.unwrap_or_default(); .unwrap_or_default();
let object_format = self.object_format.unwrap_or(ObjectFormat::Symbols);
let working_dir = tempfile::tempdir()?;
let starting_cd = env::current_dir()?;
let output_path = starting_cd.join(&self.output);
env::set_current_dir(&working_dir)?; env::set_current_dir(&working_dir)?;
let cross_compilation: Option<CrossCompileSetup> = if let Some(mut cross_subc) = let cross_compilation: Option<CrossCompileSetup> = if let Some(mut cross_subc) =
@@ -256,6 +257,7 @@ impl CreateExe {
target, target,
zig_binary_path, zig_binary_path,
library, library,
working_dir: working_dir.path().to_path_buf(),
}) })
} else { } else {
None None
@@ -268,30 +270,37 @@ impl CreateExe {
println!("Format: {:?}", object_format); println!("Format: {:?}", object_format);
#[cfg(not(windows))] #[cfg(not(windows))]
let wasm_object_path = PathBuf::from("wasm.o"); let wasm_object_path = working_dir.path().join("wasm.o");
#[cfg(windows)] #[cfg(windows)]
let wasm_object_path = PathBuf::from("wasm.obj"); let wasm_object_path = working_dir.path().join("wasm.obj");
let wasm_module_path = starting_cd.join(&self.path); let wasm_module_path = starting_cd.join(&self.path);
let static_defs_header_path: PathBuf = working_dir.path().join("static_defs.h");
if let Some(header_path) = self.header.as_ref() { if let Some(header_path) = self.header.as_ref() {
/* In this case, since a header file is given, the input file is expected to be an /* In this case, since a header file is given, the input file is expected to be an
* object created with `create-obj` subcommand */ * object created with `create-obj` subcommand */
let header_path = starting_cd.join(&header_path); let header_path = starting_cd.join(&header_path);
std::fs::copy(&header_path, Path::new("static_defs.h")) std::fs::copy(&header_path, &static_defs_header_path)
.context("Could not access given header file")?; .context("Could not access given header file")?;
let object_file_path = wasm_module_path;
if let Some(setup) = cross_compilation.as_ref() { if let Some(setup) = cross_compilation.as_ref() {
self.compile_zig( self.compile_zig(
output_path, output_path,
wasm_module_path, object_file_path,
std::path::Path::new("static_defs.h").into(), static_defs_header_path,
setup, setup,
)?; )?;
} else { } else {
self.link( self.link(
static_defs_header_path,
LinkCode {
object_paths: vec![object_file_path, "main_obj.obj".into()],
output_path, output_path,
wasm_module_path, working_dir: working_dir.path().to_path_buf(),
std::path::Path::new("static_defs.h").into(), ..Default::default()
},
)?; )?;
} }
} else { } else {
@@ -307,9 +316,44 @@ impl CreateExe {
.map_err(|err| anyhow::anyhow!(err.to_string()))?; .map_err(|err| anyhow::anyhow!(err.to_string()))?;
writer.flush()?; writer.flush()?;
drop(writer); drop(writer);
// Write down header file that includes deserialize function
{
let mut writer = BufWriter::new(File::create(&static_defs_header_path)?);
writer.write_all(WASMER_DESERIALIZE_HEADER.as_bytes())?;
writer.flush()?;
}
let cli_given_triple = self.target_triple.clone(); // write C src to disk
self.compile_c(wasm_object_path, cli_given_triple, output_path)?; let c_src_path: PathBuf = working_dir.path().join("wasmer_main.c");
#[cfg(not(windows))]
let c_src_obj: PathBuf = working_dir.path().join("wasmer_main.o");
#[cfg(windows)]
let c_src_obj: PathBuf = working_dir.path().join("wasmer_main.obj");
{
let mut c_src_file = fs::OpenOptions::new()
.create_new(true)
.write(true)
.open(&c_src_path)
.context("Failed to open C source code file")?;
c_src_file.write_all(WASMER_MAIN_C_SOURCE)?;
}
run_c_compile(
&c_src_path,
&c_src_obj,
static_defs_header_path,
self.target_triple.clone(),
)
.context("Failed to compile C source code")?;
LinkCode {
object_paths: vec![c_src_obj, wasm_object_path],
output_path,
additional_libraries: self.libraries.clone(),
target: self.target_triple.clone(),
..Default::default()
}
.run()
.context("Failed to link objects together")?;
} }
#[cfg(not(feature = "static-artifact-create"))] #[cfg(not(feature = "static-artifact-create"))]
ObjectFormat::Symbols => { ObjectFormat::Symbols => {
@@ -336,27 +380,31 @@ impl CreateExe {
); );
// Write object file with functions // Write object file with functions
let object_file_path: std::path::PathBuf = let object_file_path: std::path::PathBuf =
std::path::Path::new("functions.o").into(); working_dir.path().join("functions.o");
let mut writer = BufWriter::new(File::create(&object_file_path)?); let mut writer = BufWriter::new(File::create(&object_file_path)?);
obj.write_stream(&mut writer) obj.write_stream(&mut writer)
.map_err(|err| anyhow::anyhow!(err.to_string()))?; .map_err(|err| anyhow::anyhow!(err.to_string()))?;
writer.flush()?; writer.flush()?;
// Write down header file that includes pointer arrays and the deserialize function // Write down header file that includes pointer arrays and the deserialize function
let mut writer = BufWriter::new(File::create("static_defs.h")?); let mut writer = BufWriter::new(File::create(&static_defs_header_path)?);
writer.write_all(header_file_src.as_bytes())?; writer.write_all(header_file_src.as_bytes())?;
writer.flush()?; writer.flush()?;
if let Some(setup) = cross_compilation.as_ref() { if let Some(setup) = cross_compilation.as_ref() {
self.compile_zig( self.compile_zig(
output_path, output_path,
object_file_path, object_file_path,
std::path::Path::new("static_defs.h").into(), static_defs_header_path,
setup, setup,
)?; )?;
} else { } else {
self.link( self.link(
static_defs_header_path,
LinkCode {
object_paths: vec![object_file_path, "main_obj.obj".into()],
output_path, output_path,
object_file_path, working_dir: working_dir.path().to_path_buf(),
std::path::Path::new("static_defs.h").into(), ..Default::default()
},
)?; )?;
} }
} }
@@ -379,55 +427,25 @@ impl CreateExe {
Ok(()) Ok(())
} }
fn compile_c(
&self,
wasm_object_path: PathBuf,
target_triple: Option<wasmer::Triple>,
output_path: PathBuf,
) -> anyhow::Result<()> {
// write C src to disk
let c_src_path = Path::new("wasmer_main.c");
#[cfg(not(windows))]
let c_src_obj = PathBuf::from("wasmer_main.o");
#[cfg(windows)]
let c_src_obj = PathBuf::from("wasmer_main.obj");
{
let mut c_src_file = fs::OpenOptions::new()
.create_new(true)
.write(true)
.open(&c_src_path)
.context("Failed to open C source code file")?;
c_src_file.write_all(WASMER_MAIN_C_SOURCE)?;
}
run_c_compile(c_src_path, &c_src_obj, target_triple.clone())
.context("Failed to compile C source code")?;
LinkCode {
object_paths: vec![c_src_obj, wasm_object_path],
output_path,
additional_libraries: self.libraries.clone(),
target: target_triple,
..Default::default()
}
.run()
.context("Failed to link objects together")?;
Ok(())
}
fn compile_zig( fn compile_zig(
&self, &self,
output_path: PathBuf, output_path: PathBuf,
object_path: PathBuf, object_path: PathBuf,
mut header_code_path: PathBuf, mut header_path: PathBuf,
setup: &CrossCompileSetup, setup: &CrossCompileSetup,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let c_src_path = Path::new("wasmer_main.c"); debug_assert!(
header_path.is_absolute(),
"compile_zig() called with relative header file path {}",
header_path.display()
);
let CrossCompileSetup { let CrossCompileSetup {
ref target, ref target,
ref zig_binary_path, ref zig_binary_path,
ref library, ref library,
ref working_dir,
} = setup; } = setup;
let c_src_path = working_dir.join("wasmer_main.c");
let mut libwasmer_path = library.to_path_buf(); let mut libwasmer_path = library.to_path_buf();
println!("Library Path: {}", libwasmer_path.display()); println!("Library Path: {}", libwasmer_path.display());
@@ -449,15 +467,11 @@ impl CreateExe {
.write(true) .write(true)
.open(&c_src_path) .open(&c_src_path)
.context("Failed to open C source code file")?; .context("Failed to open C source code file")?;
c_src_file.write_all(WASMER_STATIC_MAIN_C_SOURCE)?; c_src_file.write_all(WASMER_MAIN_C_SOURCE)?;
} }
if !header_code_path.is_dir() { if !header_path.is_dir() {
header_code_path.pop(); header_path.pop();
}
if header_code_path.display().to_string().is_empty() {
header_code_path = std::env::current_dir()?;
} }
/* Compile main function */ /* Compile main function */
@@ -478,7 +492,7 @@ impl CreateExe {
.arg(&format!("-L{}", libwasmer_path.display())) .arg(&format!("-L{}", libwasmer_path.display()))
.arg(&format!("-l:{}", lib_filename)) .arg(&format!("-l:{}", lib_filename))
.arg(&format!("-I{}", include_dir.display())) .arg(&format!("-I{}", include_dir.display()))
.arg(&format!("-I{}", header_code_path.display())); .arg(&format!("-I{}", header_path.display()));
if !zig_triple.contains("windows") { if !zig_triple.contains("windows") {
cmd_mut = cmd_mut.arg("-lunwind"); cmd_mut = cmd_mut.arg("-lunwind");
} }
@@ -500,18 +514,13 @@ impl CreateExe {
} }
#[cfg(feature = "static-artifact-create")] #[cfg(feature = "static-artifact-create")]
fn link( fn link(&self, mut header_path: PathBuf, linkcode: LinkCode) -> anyhow::Result<()> {
&self, debug_assert!(
output_path: PathBuf, header_path.is_absolute(),
object_path: PathBuf, "link() called with relative header file path {}",
mut header_code_path: PathBuf, header_path.display()
) -> anyhow::Result<()> { );
let linkcode = LinkCode { let c_src_path: PathBuf = linkcode.working_dir.join("wasmer_main.c");
object_paths: vec![object_path, "main_obj.obj".into()],
output_path,
..Default::default()
};
let c_src_path = Path::new("wasmer_main.c");
let mut libwasmer_path = get_libwasmer_path()? let mut libwasmer_path = get_libwasmer_path()?
.canonicalize() .canonicalize()
.context("Failed to find libwasmer")?; .context("Failed to find libwasmer")?;
@@ -531,15 +540,11 @@ impl CreateExe {
.write(true) .write(true)
.open(&c_src_path) .open(&c_src_path)
.context("Failed to open C source code file")?; .context("Failed to open C source code file")?;
c_src_file.write_all(WASMER_STATIC_MAIN_C_SOURCE)?; c_src_file.write_all(WASMER_MAIN_C_SOURCE)?;
} }
if !header_code_path.is_dir() { if !header_path.is_dir() {
header_code_path.pop(); header_path.pop();
}
if header_code_path.display().to_string().is_empty() {
header_code_path = std::env::current_dir()?;
} }
/* Compile main function */ /* Compile main function */
@@ -568,7 +573,7 @@ impl CreateExe {
.arg("-ldl") .arg("-ldl")
.arg("-lm") .arg("-lm")
.arg("-pthread") .arg("-pthread")
.arg(&format!("-I{}", header_code_path.display())) .arg(&format!("-I{}", header_path.display()))
.arg("-v") .arg("-v")
.arg("-o") .arg("-o")
.arg("main_obj.obj") .arg("main_obj.obj")
@@ -652,8 +657,15 @@ fn get_libwasmer_cache_path() -> anyhow::Result<PathBuf> {
fn run_c_compile( fn run_c_compile(
path_to_c_src: &Path, path_to_c_src: &Path,
output_name: &Path, output_name: &Path,
mut header_path: PathBuf,
target: Option<Triple>, target: Option<Triple>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
debug_assert!(
header_path.is_absolute(),
"run_c_compile() called with relative header file path {}",
header_path.display()
);
#[cfg(not(windows))] #[cfg(not(windows))]
let c_compiler = "cc"; let c_compiler = "cc";
// We must use a C++ compiler on Windows because wasm.h uses `static_assert` // We must use a C++ compiler on Windows because wasm.h uses `static_assert`
@@ -661,13 +673,17 @@ fn run_c_compile(
#[cfg(windows)] #[cfg(windows)]
let c_compiler = "clang++"; let c_compiler = "clang++";
if !header_path.is_dir() {
header_path.pop();
}
let mut command = Command::new(c_compiler); let mut command = Command::new(c_compiler);
let command = command let command = command
.arg("-O2") .arg("-O2")
.arg("-c") .arg("-c")
.arg(path_to_c_src) .arg(path_to_c_src)
.arg("-I") .arg(&format!("-I{}", header_path.display()))
.arg(get_wasmer_include_directory()?); .arg(&format!("-I{}", get_wasmer_include_directory()?.display()));
let command = if let Some(target) = target { let command = if let Some(target) = target {
command.arg("-target").arg(format!("{}", target)) command.arg("-target").arg(format!("{}", target))
@@ -706,6 +722,8 @@ struct LinkCode {
libwasmer_path: PathBuf, libwasmer_path: PathBuf,
/// The target to link the executable for. /// The target to link the executable for.
target: Option<Triple>, target: Option<Triple>,
/// Working directory
working_dir: PathBuf,
} }
impl Default for LinkCode { impl Default for LinkCode {
@@ -722,6 +740,7 @@ impl Default for LinkCode {
output_path: PathBuf::from("a.out"), output_path: PathBuf::from("a.out"),
libwasmer_path: get_libwasmer_path().unwrap(), libwasmer_path: get_libwasmer_path().unwrap(),
target: None, target: None,
working_dir: env::current_dir().expect("could not get current dir from environment"),
} }
} }
} }
@@ -965,6 +984,7 @@ mod http_fetch {
.expect("Could not join downloading thread"); .expect("Could not join downloading thread");
match super::get_libwasmer_cache_path() { match super::get_libwasmer_cache_path() {
Ok(mut cache_path) => { Ok(mut cache_path) => {
let _ = std::fs::create_dir_all(&cache_path);
cache_path.push(&filename); cache_path.push(&filename);
if !cache_path.exists() { if !cache_path.exists() {
if let Err(err) = std::fs::copy(&filename, &cache_path) { if let Err(err) = std::fs::copy(&filename, &cache_path) {

View File

@@ -1,5 +1,4 @@
#![allow(dead_code)] //! Create a compiled standalone object file for a given Wasm file.
//! Create a standalone native executable for a given Wasm file.
use super::ObjectFormat; use super::ObjectFormat;
use crate::{commands::PrefixerFn, store::CompilerOptions}; use crate::{commands::PrefixerFn, store::CompilerOptions};
@@ -11,11 +10,10 @@ use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::BufWriter; use std::io::BufWriter;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command;
use wasmer::*; use wasmer::*;
use wasmer_object::{emit_serialized, get_object_for_target}; use wasmer_object::{emit_serialized, get_object_for_target};
const WASMER_SERIALIZED_HEADER: &[u8] = include_bytes!("wasmer_create_exe.h"); const WASMER_SERIALIZED_HEADER: &[u8] = include_bytes!("wasmer_deserialize_module.h");
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
/// The options for the `wasmer create-exe` subcommand /// The options for the `wasmer create-exe` subcommand
@@ -152,66 +150,17 @@ impl CreateObj {
self.output.display(), self.output.display(),
header_output.display(), header_output.display(),
); );
eprintln!("\n---\n");
eprintln!(
r#"To use, link the object file to your executable and call the `wasmer_object_module_new` function defined in the header file. For example, in the C language:
#include "{}"
wasm_module_t *module = wasmer_object_module_new(store, "my_module_name");
"#,
header_output.display(),
);
Ok(()) Ok(())
} }
} }
fn link(
output_path: PathBuf,
object_path: PathBuf,
header_code_path: PathBuf,
) -> anyhow::Result<()> {
let libwasmer_path = get_libwasmer_path()?
.canonicalize()
.context("Failed to find libwasmer")?;
println!(
"link output {:?}",
Command::new("cc")
.arg(&header_code_path)
.arg(&format!("-L{}", libwasmer_path.display()))
//.arg(&format!("-I{}", header_code_path.display()))
.arg("-pie")
.arg("-o")
.arg("header_obj.o")
.output()?
);
//ld -relocatable a.o b.o -o c.o
println!(
"link output {:?}",
Command::new("ld")
.arg("-relocatable")
.arg(&object_path)
.arg("header_obj.o")
.arg("-o")
.arg(&output_path)
.output()?
);
Ok(())
}
/// path to the static libwasmer
fn get_libwasmer_path() -> anyhow::Result<PathBuf> {
let mut path = get_wasmer_dir()?;
path.push("lib");
// TODO: prefer headless Wasmer if/when it's a separate library.
#[cfg(not(windows))]
path.push("libwasmer.a");
#[cfg(windows)]
path.push("wasmer.lib");
Ok(path)
}
fn get_wasmer_dir() -> anyhow::Result<PathBuf> {
Ok(PathBuf::from(
env::var("WASMER_DIR")
.or_else(|e| {
option_env!("WASMER_INSTALL_PREFIX")
.map(str::to_string)
.ok_or(e)
})
.context("Trying to read env var `WASMER_DIR`")?,
))
}

View File

@@ -1,7 +1,5 @@
#include "wasmer.h" #include "wasmer.h"
//#include "my_wasm.h" #include "static_defs.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -11,8 +9,8 @@
// TODO: make this define templated so that the Rust code can toggle it on/off // TODO: make this define templated so that the Rust code can toggle it on/off
#define WASI #define WASI
extern size_t WASMER_MODULE_LENGTH asm("WASMER_MODULE_LENGTH"); extern wasm_module_t* wasmer_object_module_new(wasm_store_t* store, const char* module_name) asm("wasmer_object_module_new");
extern char WASMER_MODULE_DATA asm("WASMER_MODULE_DATA");
static void print_wasmer_error() { static void print_wasmer_error() {
int error_len = wasmer_last_error_length(); int error_len = wasmer_last_error_length();
@@ -95,11 +93,7 @@ int main(int argc, char *argv[]) {
wasm_engine_t *engine = wasm_engine_new_with_config(config); wasm_engine_t *engine = wasm_engine_new_with_config(config);
wasm_store_t *store = wasm_store_new(engine); wasm_store_t *store = wasm_store_new(engine);
wasm_byte_vec_t module_byte_vec = { wasm_module_t *module = wasmer_object_module_new(store, "module");
.size = WASMER_MODULE_LENGTH,
.data = (const char*)&WASMER_MODULE_DATA,
};
wasm_module_t *module = wasm_module_deserialize(store, &module_byte_vec);
if (!module) { if (!module) {
fprintf(stderr, "Failed to create module\n"); fprintf(stderr, "Failed to create module\n");

View File

@@ -10,7 +10,7 @@ extern "C" {
extern size_t WASMER_MODULE_LENGTH asm("WASMER_MODULE_LENGTH"); extern size_t WASMER_MODULE_LENGTH asm("WASMER_MODULE_LENGTH");
extern char WASMER_MODULE_DATA asm("WASMER_MODULE_DATA"); extern char WASMER_MODULE_DATA asm("WASMER_MODULE_DATA");
wasm_module_t* wasmer_module_new(wasm_store_t* store, const char* wasm_name) { wasm_module_t* wasmer_object_module_new(wasm_store_t* store, const char* module_name) {
wasm_byte_vec_t module_byte_vec = { wasm_byte_vec_t module_byte_vec = {
.size = WASMER_MODULE_LENGTH, .size = WASMER_MODULE_LENGTH,
.data = (const char*)&WASMER_MODULE_DATA, .data = (const char*)&WASMER_MODULE_DATA,

View File

@@ -1,192 +0,0 @@
#include "wasmer.h"
#include "static_defs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define own
// TODO: make this define templated so that the Rust code can toggle it on/off
#define WASI
extern wasm_module_t* wasmer_module_new(wasm_store_t* store) asm("wasmer_module_new");
extern wasm_module_t* wasmer_static_module_new(wasm_store_t* store,const char* wasm_name) asm("wasmer_static_module_new");
static void print_wasmer_error() {
int error_len = wasmer_last_error_length();
printf("Error len: `%d`\n", error_len);
char *error_str = (char *)malloc(error_len);
wasmer_last_error_message(error_str, error_len);
printf("%s\n", error_str);
free(error_str);
}
#ifdef WASI
static void pass_mapdir_arg(wasi_config_t *wasi_config, char *mapdir) {
int colon_location = strchr(mapdir, ':') - mapdir;
if (colon_location == 0) {
// error malformed argument
fprintf(stderr, "Expected mapdir argument of the form alias:directory\n");
exit(-1);
}
char *alias = (char *)malloc(colon_location + 1);
memcpy(alias, mapdir, colon_location);
alias[colon_location] = '\0';
int dir_len = strlen(mapdir) - colon_location;
char *dir = (char *)malloc(dir_len + 1);
memcpy(dir, &mapdir[colon_location + 1], dir_len);
dir[dir_len] = '\0';
wasi_config_mapdir(wasi_config, alias, dir);
free(alias);
free(dir);
}
// We try to parse out `--dir` and `--mapdir` ahead of time and process those
// specially. All other arguments are passed to the guest program.
static void handle_arguments(wasi_config_t *wasi_config, int argc,
char *argv[]) {
for (int i = 1; i < argc; ++i) {
// We probably want special args like `--dir` and `--mapdir` to not be
// passed directly
if (strcmp(argv[i], "--dir") == 0) {
// next arg is a preopen directory
if ((i + 1) < argc) {
i++;
wasi_config_preopen_dir(wasi_config, argv[i]);
} else {
fprintf(stderr, "--dir expects a following argument specifying which "
"directory to preopen\n");
exit(-1);
}
} else if (strcmp(argv[i], "--mapdir") == 0) {
// next arg is a mapdir
if ((i + 1) < argc) {
i++;
pass_mapdir_arg(wasi_config, argv[i]);
} else {
fprintf(stderr,
"--mapdir expects a following argument specifying which "
"directory to preopen in the form alias:directory\n");
exit(-1);
}
} else if (strncmp(argv[i], "--dir=", strlen("--dir=")) == 0) {
// this arg is a preopen dir
char *dir = argv[i] + strlen("--dir=");
wasi_config_preopen_dir(wasi_config, dir);
} else if (strncmp(argv[i], "--mapdir=", strlen("--mapdir=")) == 0) {
// this arg is a mapdir
char *mapdir = argv[i] + strlen("--mapdir=");
pass_mapdir_arg(wasi_config, mapdir);
} else {
// guest argument
wasi_config_arg(wasi_config, argv[i]);
}
}
}
#endif
int main(int argc, char *argv[]) {
wasm_config_t *config = wasm_config_new();
wasm_engine_t *engine = wasm_engine_new_with_config(config);
wasm_store_t *store = wasm_store_new(engine);
wasm_module_t *module = wasmer_static_module_new(store, "module");
if (!module) {
fprintf(stderr, "Failed to create module\n");
print_wasmer_error();
return -1;
}
// We have now finished the memory buffer book keeping and we have a valid
// Module.
#ifdef WASI
wasi_config_t *wasi_config = wasi_config_new(argv[0]);
handle_arguments(wasi_config, argc, argv);
wasi_env_t *wasi_env = wasi_env_new(store, wasi_config);
if (!wasi_env) {
fprintf(stderr, "Error building WASI env!\n");
print_wasmer_error();
return 1;
}
#endif
wasm_importtype_vec_t import_types;
wasm_module_imports(module, &import_types);
wasm_extern_vec_t imports;
wasm_extern_vec_new_uninitialized(&imports, import_types.size);
wasm_importtype_vec_delete(&import_types);
#ifdef WASI
bool get_imports_result = wasi_get_imports(store, wasi_env, module, &imports);
if (!get_imports_result) {
fprintf(stderr, "Error getting WASI imports!\n");
print_wasmer_error();
return 1;
}
#endif
wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
fprintf(stderr, "Failed to create instance\n");
print_wasmer_error();
return -1;
}
#ifdef WASI
// Read the exports.
wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
wasm_memory_t* mem = NULL;
for (size_t i = 0; i < exports.size; i++) {
mem = wasm_extern_as_memory(exports.data[i]);
if (mem) {
break;
}
}
if (!mem) {
fprintf(stderr, "Failed to create instance: Could not find memory in exports\n");
print_wasmer_error();
return -1;
}
wasi_env_set_memory(wasi_env, mem);
own wasm_func_t *start_function = wasi_get_start_function(instance);
if (!start_function) {
fprintf(stderr, "`_start` function not found\n");
print_wasmer_error();
return -1;
}
wasm_val_vec_t args = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
own wasm_trap_t *trap = wasm_func_call(start_function, &args, &results);
if (trap) {
fprintf(stderr, "Trap is not NULL: TODO:\n");
return -1;
}
#endif
// TODO: handle non-WASI start (maybe with invoke?)
#ifdef WASI
wasi_env_delete(wasi_env);
wasm_extern_vec_delete(&exports);
#endif
wasm_instance_delete(instance);
wasm_module_delete(module);
wasm_store_delete(store);
wasm_engine_delete(engine);
return 0;
}

View File

@@ -201,7 +201,7 @@ impl ArtifactCreate for ArtifactBuild {
} }
fn data_initializers(&self) -> &[OwnedDataInitializer] { fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.serializable.data_initializers &self.serializable.data_initializers
} }
fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> { fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {

View File

@@ -116,9 +116,13 @@ impl Artifact {
"The provided bytes are not wasmer-universal".to_string(), "The provided bytes are not wasmer-universal".to_string(),
)); ));
} }
let bytes = &bytes[ArtifactBuild::MAGIC_HEADER.len()..];
let bytes = Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
let metadata_len = MetadataHeader::parse(bytes)?; let metadata_len = MetadataHeader::parse(bytes)?;
let metadata_slice: &[u8] = &bytes[MetadataHeader::LEN..][..metadata_len]; let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
let serializable = SerializableModule::deserialize(metadata_slice)?; let serializable = SerializableModule::deserialize(metadata_slice)?;
let artifact = ArtifactBuild::from_serializable(serializable); let artifact = ArtifactBuild::from_serializable(serializable);
let mut inner_engine = engine.inner_mut(); let mut inner_engine = engine.inner_mut();
@@ -343,7 +347,7 @@ impl Artifact {
// Get pointers to where metadata about local tables should live in VM memory. // Get pointers to where metadata about local tables should live in VM memory.
let (allocator, memory_definition_locations, table_definition_locations) = let (allocator, memory_definition_locations, table_definition_locations) =
InstanceAllocator::new(&*module); InstanceAllocator::new(&module);
let finished_memories = tunables let finished_memories = tunables
.create_memories( .create_memories(
context, context,
@@ -400,7 +404,7 @@ impl Artifact {
.iter() .iter()
.map(|init| DataInitializer { .map(|init| DataInitializer {
location: init.location.clone(), location: init.location.clone(),
data: &*init.data, data: &init.data,
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
handle handle
@@ -573,6 +577,19 @@ impl Artifact {
)) ))
} }
fn get_byte_slice(input: &[u8], start: usize, end: usize) -> Result<&[u8], DeserializeError> {
if (start == end && input.len() > start)
|| (start < end && input.len() > start && input.len() >= end)
{
Ok(&input[start..end])
} else {
Err(DeserializeError::InvalidByteLength {
expected: end - start,
got: input.len(),
})
}
}
/// Deserialize a ArtifactBuild from an object file /// Deserialize a ArtifactBuild from an object file
/// ///
/// # Safety /// # Safety
@@ -583,15 +600,17 @@ impl Artifact {
bytes: &[u8], bytes: &[u8],
) -> Result<Self, DeserializeError> { ) -> Result<Self, DeserializeError> {
let metadata_len = MetadataHeader::parse(bytes)?; let metadata_len = MetadataHeader::parse(bytes)?;
let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
let metadata_slice = &bytes[MetadataHeader::LEN..][..metadata_len]; let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
let metadata: ModuleMetadata = ModuleMetadata::deserialize(metadata_slice)?; let metadata: ModuleMetadata = ModuleMetadata::deserialize(metadata_slice)?;
const WORD_SIZE: usize = mem::size_of::<usize>(); const WORD_SIZE: usize = mem::size_of::<usize>();
let mut byte_buffer = [0u8; WORD_SIZE]; let mut byte_buffer = [0u8; WORD_SIZE];
let mut cur_offset = MetadataHeader::LEN + metadata_len; let mut cur_offset = MetadataHeader::LEN + metadata_len;
byte_buffer[0..WORD_SIZE].clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]);
let byte_buffer_slice = Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
cur_offset += WORD_SIZE; cur_offset += WORD_SIZE;
let num_finished_functions = usize::from_ne_bytes(byte_buffer); let num_finished_functions = usize::from_ne_bytes(byte_buffer);
@@ -603,8 +622,9 @@ impl Artifact {
// read finished functions in order now... // read finished functions in order now...
for _i in 0..num_finished_functions { for _i in 0..num_finished_functions {
byte_buffer[0..WORD_SIZE] let byte_buffer_slice =
.clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]); Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _); let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
cur_offset += WORD_SIZE; cur_offset += WORD_SIZE;
@@ -625,12 +645,15 @@ impl Artifact {
// read trampolines in order // read trampolines in order
let mut finished_function_call_trampolines = PrimaryMap::new(); let mut finished_function_call_trampolines = PrimaryMap::new();
byte_buffer[0..WORD_SIZE].clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]);
let byte_buffer_slice = Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
cur_offset += WORD_SIZE; cur_offset += WORD_SIZE;
let num_function_trampolines = usize::from_ne_bytes(byte_buffer); let num_function_trampolines = usize::from_ne_bytes(byte_buffer);
for _ in 0..num_function_trampolines { for _ in 0..num_function_trampolines {
byte_buffer[0..WORD_SIZE] let byte_buffer_slice =
.clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]); Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
cur_offset += WORD_SIZE; cur_offset += WORD_SIZE;
let trampoline_ptr_bytes = usize::from_ne_bytes(byte_buffer); let trampoline_ptr_bytes = usize::from_ne_bytes(byte_buffer);
let trampoline = mem::transmute::<usize, VMTrampoline>(trampoline_ptr_bytes); let trampoline = mem::transmute::<usize, VMTrampoline>(trampoline_ptr_bytes);
@@ -640,12 +663,14 @@ impl Artifact {
// read dynamic function trampolines in order now... // read dynamic function trampolines in order now...
let mut finished_dynamic_function_trampolines = PrimaryMap::new(); let mut finished_dynamic_function_trampolines = PrimaryMap::new();
byte_buffer[0..WORD_SIZE].clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]); let byte_buffer_slice = Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
cur_offset += WORD_SIZE; cur_offset += WORD_SIZE;
let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer); let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer);
for _i in 0..num_dynamic_trampoline_functions { for _i in 0..num_dynamic_trampoline_functions {
byte_buffer[0..WORD_SIZE] let byte_buffer_slice =
.clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]); Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _); let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
cur_offset += WORD_SIZE; cur_offset += WORD_SIZE;

View File

@@ -8,8 +8,9 @@ use wasmer_types::{
}; };
use wasmer_vm::{ use wasmer_vm::{
FunctionBodyPtr, Imports, MemoryStyle, StoreObjects, TableStyle, VMExtern, VMFunctionBody, FunctionBodyPtr, Imports, LinearMemory, MemoryStyle, StoreObjects, TableStyle, VMExtern,
VMFunctionImport, VMFunctionKind, VMGlobalImport, VMMemoryImport, VMTableImport, VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalImport, VMMemoryImport,
VMTableImport,
}; };
/// Get an `ExternType` given a import index. /// Get an `ExternType` given a import index.
@@ -149,7 +150,7 @@ pub fn resolve_imports(
bound: import_bound, bound: import_bound,
.. ..
}, },
) = (export_memory_style.clone(), &import_memory_style) ) = (export_memory_style, &import_memory_style)
{ {
assert_ge!(bound, *import_bound); assert_ge!(bound, *import_bound);
} }

View File

@@ -105,7 +105,7 @@ impl EmEnv {
/// Get a reference to the memory /// Get a reference to the memory
pub fn memory(&self, _mem_idx: u32) -> Memory { pub fn memory(&self, _mem_idx: u32) -> Memory {
(&*self.memory.read().unwrap()).as_ref().cloned().unwrap() (*self.memory.read().unwrap()).as_ref().cloned().unwrap()
} }
pub fn set_functions(&mut self, funcs: EmscriptenFunctions) { pub fn set_functions(&mut self, funcs: EmscriptenFunctions) {

View File

@@ -21,6 +21,9 @@ enum-iterator = "0.7.0"
target-lexicon = { version = "0.12.2", default-features = false } target-lexicon = { version = "0.12.2", default-features = false }
enumset = "1.0" enumset = "1.0"
[dev-dependencies]
memoffset = "0.6"
[features] [features]
default = ["std"] default = ["std"]
std = [] std = []

View File

@@ -1,5 +1,5 @@
//! The WebAssembly possible errors //! The WebAssembly possible errors
use crate::ExternType; use crate::{ExternType, Pages};
use std::io; use std::io;
use thiserror::Error; use thiserror::Error;
@@ -35,6 +35,56 @@ pub enum DeserializeError {
/// trying to allocate the required resources. /// trying to allocate the required resources.
#[error(transparent)] #[error(transparent)]
Compiler(#[from] CompileError), Compiler(#[from] CompileError),
/// Input artifact bytes have an invalid length
#[error("invalid input bytes: expected {expected} bytes, got {got}")]
InvalidByteLength {
/// How many bytes were expected
expected: usize,
/// How many bytes the artifact contained
got: usize,
},
}
/// Error type describing things that can go wrong when operating on Wasm Memories.
#[derive(Error, Debug, Clone, PartialEq, Eq, Hash)]
pub enum MemoryError {
/// Low level error with mmap.
#[error("Error when allocating memory: {0}")]
Region(String),
/// The operation would cause the size of the memory to exceed the maximum or would cause
/// an overflow leading to unindexable memory.
#[error("The memory could not grow: current size {} pages, requested increase: {} pages", current.0, attempted_delta.0)]
CouldNotGrow {
/// The current size in pages.
current: Pages,
/// The attempted amount to grow by in pages.
attempted_delta: Pages,
},
/// The operation would cause the size of the memory size exceed the maximum.
#[error("The memory is invalid because {}", reason)]
InvalidMemory {
/// The reason why the provided memory is invalid.
reason: String,
},
/// Caller asked for more minimum memory than we can give them.
#[error("The minimum requested ({} pages) memory is greater than the maximum allowed memory ({} pages)", min_requested.0, max_allowed.0)]
MinimumMemoryTooLarge {
/// The number of pages requested as the minimum amount of memory.
min_requested: Pages,
/// The maximum amount of memory we can allocate.
max_allowed: Pages,
},
/// Caller asked for a maximum memory greater than we can give them.
#[error("The maximum requested memory ({} pages) is greater than the maximum allowed memory ({} pages)", max_requested.0, max_allowed.0)]
MaximumMemoryTooLarge {
/// The number of pages requested as the maximum amount of memory.
max_requested: Pages,
/// The number of pages requested as the maximum amount of memory.
max_allowed: Pages,
},
/// A user defined error value, used for error cases not listed above.
#[error("A user-defined error occurred: {0}")]
Generic(String),
} }
/// An ImportError. /// An ImportError.
@@ -52,6 +102,10 @@ pub enum ImportError {
/// This error occurs when an import was expected but not provided. /// This error occurs when an import was expected but not provided.
#[error("unknown import. Expected {0:?}")] #[error("unknown import. Expected {0:?}")]
UnknownImport(ExternType), UnknownImport(ExternType),
/// Memory Error
#[error("memory error. {0}")]
MemoryError(String),
} }
/// An error while preinstantiating a module. /// An error while preinstantiating a module.

View File

@@ -76,8 +76,8 @@ pub use crate::compilation::target::{
}; };
pub use crate::serialize::{MetadataHeader, SerializableCompilation, SerializableModule}; pub use crate::serialize::{MetadataHeader, SerializableCompilation, SerializableModule};
pub use error::{ pub use error::{
CompileError, DeserializeError, ImportError, MiddlewareError, ParseCpuFeatureError, CompileError, DeserializeError, ImportError, MemoryError, MiddlewareError,
PreInstantiationError, SerializeError, WasmError, WasmResult, ParseCpuFeatureError, PreInstantiationError, SerializeError, WasmError, WasmResult,
}; };
/// The entity module, with common helpers for Rust structures /// The entity module, with common helpers for Rust structures

View File

@@ -7,7 +7,7 @@ use std::iter::Sum;
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
/// Implementation styles for WebAssembly linear memory. /// Implementation styles for WebAssembly linear memory.
#[derive(Debug, Clone, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[archive(as = "Self")] #[archive(as = "Self")]
pub enum MemoryStyle { pub enum MemoryStyle {
@@ -84,6 +84,9 @@ pub unsafe trait MemorySize: Copy {
/// Zero value used for `WasmPtr::is_null`. /// Zero value used for `WasmPtr::is_null`.
const ZERO: Self::Offset; const ZERO: Self::Offset;
/// One value used for counting.
const ONE: Self::Offset;
/// Convert an `Offset` to a `Native`. /// Convert an `Offset` to a `Native`.
fn offset_to_native(offset: Self::Offset) -> Self::Native; fn offset_to_native(offset: Self::Offset) -> Self::Native;
@@ -98,6 +101,7 @@ unsafe impl MemorySize for Memory32 {
type Offset = u32; type Offset = u32;
type Native = i32; type Native = i32;
const ZERO: Self::Offset = 0; const ZERO: Self::Offset = 0;
const ONE: Self::Offset = 1;
fn offset_to_native(offset: Self::Offset) -> Self::Native { fn offset_to_native(offset: Self::Offset) -> Self::Native {
offset as Self::Native offset as Self::Native
} }
@@ -113,6 +117,7 @@ unsafe impl MemorySize for Memory64 {
type Offset = u64; type Offset = u64;
type Native = i64; type Native = i64;
const ZERO: Self::Offset = 0; const ZERO: Self::Offset = 0;
const ONE: Self::Offset = 1;
fn offset_to_native(offset: Self::Offset) -> Self::Native { fn offset_to_native(offset: Self::Offset) -> Self::Native {
offset as Self::Native offset as Self::Native
} }

View File

@@ -144,7 +144,7 @@ impl SerializableModule {
/// Returns data initializers to pass to `InstanceHandle::initialize` /// Returns data initializers to pass to `InstanceHandle::initialize`
pub fn data_initializers(&self) -> &[OwnedDataInitializer] { pub fn data_initializers(&self) -> &[OwnedDataInitializer] {
&*self.data_initializers &self.data_initializers
} }
/// Returns the memory styles associated with this `Artifact`. /// Returns the memory styles associated with this `Artifact`.

View File

@@ -10,16 +10,16 @@ mod allocator;
use crate::export::VMExtern; use crate::export::VMExtern;
use crate::imports::Imports; use crate::imports::Imports;
use crate::memory::MemoryError;
use crate::store::{InternalStoreHandle, StoreObjects}; use crate::store::{InternalStoreHandle, StoreObjects};
use crate::table::TableElement; use crate::table::TableElement;
use crate::trap::{catch_traps, Trap, TrapCode}; use crate::trap::{catch_traps, Trap, TrapCode};
use crate::vmcontext::{ use crate::vmcontext::{
VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionContext, memory_copy, memory_fill, VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext,
VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, VMFunctionContext, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport,
VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline,
}; };
use crate::{FunctionBodyPtr, MaybeInstanceOwned, TrapHandlerFn, VMFunctionBody}; use crate::{FunctionBodyPtr, MaybeInstanceOwned, TrapHandlerFn, VMFunctionBody};
use crate::{LinearMemory, VMMemoryDefinition};
use crate::{VMFuncRef, VMFunction, VMGlobal, VMMemory, VMTable}; use crate::{VMFuncRef, VMFunction, VMGlobal, VMMemory, VMTable};
pub use allocator::InstanceAllocator; pub use allocator::InstanceAllocator;
use memoffset::offset_of; use memoffset::offset_of;
@@ -36,8 +36,8 @@ use std::sync::Arc;
use wasmer_types::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap}; use wasmer_types::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap};
use wasmer_types::{ use wasmer_types::{
DataIndex, DataInitializer, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, GlobalInit, DataIndex, DataInitializer, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, GlobalInit,
LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryError,
ModuleInfo, Pages, SignatureIndex, TableIndex, TableInitializer, VMOffsets, MemoryIndex, ModuleInfo, Pages, SignatureIndex, TableIndex, TableInitializer, VMOffsets,
}; };
/// A WebAssembly instance. /// A WebAssembly instance.
@@ -116,7 +116,7 @@ impl Instance {
} }
pub(crate) fn module_ref(&self) -> &ModuleInfo { pub(crate) fn module_ref(&self) -> &ModuleInfo {
&*self.module &self.module
} }
fn context(&self) -> &StoreObjects { fn context(&self) -> &StoreObjects {
@@ -632,7 +632,7 @@ impl Instance {
let memory = self.memory(memory_index); let memory = self.memory(memory_index);
// The following memory copy is not synchronized and is not atomic: // The following memory copy is not synchronized and is not atomic:
unsafe { memory.memory_copy(dst, src, len) } unsafe { memory_copy(&memory, dst, src, len) }
} }
/// Perform a `memory.copy` on an imported memory. /// Perform a `memory.copy` on an imported memory.
@@ -646,7 +646,7 @@ impl Instance {
let import = self.imported_memory(memory_index); let import = self.imported_memory(memory_index);
let memory = unsafe { import.definition.as_ref() }; let memory = unsafe { import.definition.as_ref() };
// The following memory copy is not synchronized and is not atomic: // The following memory copy is not synchronized and is not atomic:
unsafe { memory.memory_copy(dst, src, len) } unsafe { memory_copy(memory, dst, src, len) }
} }
/// Perform the `memory.fill` operation on a locally defined memory. /// Perform the `memory.fill` operation on a locally defined memory.
@@ -663,7 +663,7 @@ impl Instance {
) -> Result<(), Trap> { ) -> Result<(), Trap> {
let memory = self.memory(memory_index); let memory = self.memory(memory_index);
// The following memory fill is not synchronized and is not atomic: // The following memory fill is not synchronized and is not atomic:
unsafe { memory.memory_fill(dst, val, len) } unsafe { memory_fill(&memory, dst, val, len) }
} }
/// Perform the `memory.fill` operation on an imported memory. /// Perform the `memory.fill` operation on an imported memory.
@@ -681,7 +681,7 @@ impl Instance {
let import = self.imported_memory(memory_index); let import = self.imported_memory(memory_index);
let memory = unsafe { import.definition.as_ref() }; let memory = unsafe { import.definition.as_ref() };
// The following memory fill is not synchronized and is not atomic: // The following memory fill is not synchronized and is not atomic:
unsafe { memory.memory_fill(dst, val, len) } unsafe { memory_fill(memory, dst, val, len) }
} }
/// Performs the `memory.init` operation. /// Performs the `memory.init` operation.
@@ -868,7 +868,7 @@ impl InstanceHandle {
let instance = instance_handle.instance_mut(); let instance = instance_handle.instance_mut();
let vmctx_ptr = instance.vmctx_ptr(); let vmctx_ptr = instance.vmctx_ptr();
(instance.funcrefs, instance.imported_funcrefs) = build_funcrefs( (instance.funcrefs, instance.imported_funcrefs) = build_funcrefs(
&*instance.module, &instance.module,
context, context,
&imports, &imports,
&instance.functions, &instance.functions,

View File

@@ -45,7 +45,7 @@ pub use crate::function_env::VMFunctionEnvironment;
pub use crate::global::*; pub use crate::global::*;
pub use crate::imports::Imports; pub use crate::imports::Imports;
pub use crate::instance::{InstanceAllocator, InstanceHandle}; pub use crate::instance::{InstanceAllocator, InstanceHandle};
pub use crate::memory::{MemoryError, VMMemory}; pub use crate::memory::{LinearMemory, VMMemory};
pub use crate::mmap::Mmap; pub use crate::mmap::Mmap;
pub use crate::probestack::PROBESTACK; pub use crate::probestack::PROBESTACK;
pub use crate::sig_registry::SignatureRegistry; pub use crate::sig_registry::SignatureRegistry;
@@ -60,6 +60,7 @@ pub use crate::vmcontext::{
VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline,
}; };
pub use wasmer_types::LibCall; pub use wasmer_types::LibCall;
pub use wasmer_types::MemoryError;
pub use wasmer_types::MemoryStyle; pub use wasmer_types::MemoryStyle;
use wasmer_types::RawValue; use wasmer_types::RawValue;
pub use wasmer_types::TableStyle; pub use wasmer_types::TableStyle;

View File

@@ -189,7 +189,7 @@ pub unsafe extern "C" fn wasmer_vm_imported_memory32_grow(
/// `vmctx` must be dereferenceable. /// `vmctx` must be dereferenceable.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 { pub unsafe extern "C" fn wasmer_vm_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 {
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
let memory_index = LocalMemoryIndex::from_u32(memory_index); let memory_index = LocalMemoryIndex::from_u32(memory_index);
instance.memory_size(memory_index).0 instance.memory_size(memory_index).0
@@ -205,7 +205,7 @@ pub unsafe extern "C" fn wasmer_vm_imported_memory32_size(
vmctx: *mut VMContext, vmctx: *mut VMContext,
memory_index: u32, memory_index: u32,
) -> u32 { ) -> u32 {
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
let memory_index = MemoryIndex::from_u32(memory_index); let memory_index = MemoryIndex::from_u32(memory_index);
instance.imported_memory_size(memory_index).0 instance.imported_memory_size(memory_index).0
@@ -303,7 +303,7 @@ pub unsafe extern "C" fn wasmer_vm_table_fill(
/// `vmctx` must be dereferenceable. /// `vmctx` must be dereferenceable.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasmer_vm_table_size(vmctx: *mut VMContext, table_index: u32) -> u32 { pub unsafe extern "C" fn wasmer_vm_table_size(vmctx: *mut VMContext, table_index: u32) -> u32 {
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
let table_index = LocalTableIndex::from_u32(table_index); let table_index = LocalTableIndex::from_u32(table_index);
instance.table_size(table_index) instance.table_size(table_index)
@@ -319,7 +319,7 @@ pub unsafe extern "C" fn wasmer_vm_imported_table_size(
vmctx: *mut VMContext, vmctx: *mut VMContext,
table_index: u32, table_index: u32,
) -> u32 { ) -> u32 {
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
let table_index = TableIndex::from_u32(table_index); let table_index = TableIndex::from_u32(table_index);
instance.imported_table_size(table_index) instance.imported_table_size(table_index)
@@ -336,7 +336,7 @@ pub unsafe extern "C" fn wasmer_vm_table_get(
table_index: u32, table_index: u32,
elem_index: u32, elem_index: u32,
) -> RawTableElement { ) -> RawTableElement {
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
let table_index = LocalTableIndex::from_u32(table_index); let table_index = LocalTableIndex::from_u32(table_index);
// TODO: type checking, maybe have specialized accessors // TODO: type checking, maybe have specialized accessors
@@ -495,7 +495,7 @@ pub unsafe extern "C" fn wasmer_vm_func_ref(
vmctx: *mut VMContext, vmctx: *mut VMContext,
function_index: u32, function_index: u32,
) -> VMFuncRef { ) -> VMFuncRef {
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
let function_index = FunctionIndex::from_u32(function_index); let function_index = FunctionIndex::from_u32(function_index);
instance.func_ref(function_index).unwrap() instance.func_ref(function_index).unwrap()
@@ -510,7 +510,7 @@ pub unsafe extern "C" fn wasmer_vm_func_ref(
pub unsafe extern "C" fn wasmer_vm_elem_drop(vmctx: *mut VMContext, elem_index: u32) { pub unsafe extern "C" fn wasmer_vm_elem_drop(vmctx: *mut VMContext, elem_index: u32) {
on_host_stack(|| { on_host_stack(|| {
let elem_index = ElemIndex::from_u32(elem_index); let elem_index = ElemIndex::from_u32(elem_index);
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
instance.elem_drop(elem_index); instance.elem_drop(elem_index);
}) })
} }
@@ -530,7 +530,7 @@ pub unsafe extern "C" fn wasmer_vm_memory32_copy(
) { ) {
let result = { let result = {
let memory_index = LocalMemoryIndex::from_u32(memory_index); let memory_index = LocalMemoryIndex::from_u32(memory_index);
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
instance.local_memory_copy(memory_index, dst, src, len) instance.local_memory_copy(memory_index, dst, src, len)
}; };
if let Err(trap) = result { if let Err(trap) = result {
@@ -553,7 +553,7 @@ pub unsafe extern "C" fn wasmer_vm_imported_memory32_copy(
) { ) {
let result = { let result = {
let memory_index = MemoryIndex::from_u32(memory_index); let memory_index = MemoryIndex::from_u32(memory_index);
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
instance.imported_memory_copy(memory_index, dst, src, len) instance.imported_memory_copy(memory_index, dst, src, len)
}; };
if let Err(trap) = result { if let Err(trap) = result {
@@ -576,7 +576,7 @@ pub unsafe extern "C" fn wasmer_vm_memory32_fill(
) { ) {
let result = { let result = {
let memory_index = LocalMemoryIndex::from_u32(memory_index); let memory_index = LocalMemoryIndex::from_u32(memory_index);
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
instance.local_memory_fill(memory_index, dst, val, len) instance.local_memory_fill(memory_index, dst, val, len)
}; };
if let Err(trap) = result { if let Err(trap) = result {
@@ -599,7 +599,7 @@ pub unsafe extern "C" fn wasmer_vm_imported_memory32_fill(
) { ) {
let result = { let result = {
let memory_index = MemoryIndex::from_u32(memory_index); let memory_index = MemoryIndex::from_u32(memory_index);
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
instance.imported_memory_fill(memory_index, dst, val, len) instance.imported_memory_fill(memory_index, dst, val, len)
}; };
if let Err(trap) = result { if let Err(trap) = result {
@@ -624,7 +624,7 @@ pub unsafe extern "C" fn wasmer_vm_memory32_init(
let result = { let result = {
let memory_index = MemoryIndex::from_u32(memory_index); let memory_index = MemoryIndex::from_u32(memory_index);
let data_index = DataIndex::from_u32(data_index); let data_index = DataIndex::from_u32(data_index);
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
instance.memory_init(memory_index, data_index, dst, src, len) instance.memory_init(memory_index, data_index, dst, src, len)
}; };
if let Err(trap) = result { if let Err(trap) = result {
@@ -641,7 +641,7 @@ pub unsafe extern "C" fn wasmer_vm_memory32_init(
pub unsafe extern "C" fn wasmer_vm_data_drop(vmctx: *mut VMContext, data_index: u32) { pub unsafe extern "C" fn wasmer_vm_data_drop(vmctx: *mut VMContext, data_index: u32) {
on_host_stack(|| { on_host_stack(|| {
let data_index = DataIndex::from_u32(data_index); let data_index = DataIndex::from_u32(data_index);
let instance = (&*vmctx).instance(); let instance = (*vmctx).instance();
instance.data_drop(data_index) instance.data_drop(data_index)
}) })
} }

View File

@@ -5,88 +5,156 @@
//! //!
//! `Memory` is to WebAssembly linear memories what `Table` is to WebAssembly tables. //! `Memory` is to WebAssembly linear memories what `Table` is to WebAssembly tables.
use crate::vmcontext::VMMemoryDefinition; use crate::{mmap::Mmap, store::MaybeInstanceOwned, vmcontext::VMMemoryDefinition};
use crate::{mmap::Mmap, store::MaybeInstanceOwned};
use more_asserts::assert_ge; use more_asserts::assert_ge;
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::convert::TryInto; use std::convert::TryInto;
use std::ptr::NonNull; use std::ptr::NonNull;
use thiserror::Error; use wasmer_types::{Bytes, MemoryError, MemoryStyle, MemoryType, Pages};
use wasmer_types::{Bytes, MemoryStyle, MemoryType, Pages};
/// Error type describing things that can go wrong when operating on Wasm Memories.
#[derive(Error, Debug, Clone, Eq, PartialEq, Hash)]
pub enum MemoryError {
/// Low level error with mmap.
#[error("Error when allocating memory: {0}")]
Region(String),
/// The operation would cause the size of the memory to exceed the maximum or would cause
/// an overflow leading to unindexable memory.
#[error("The memory could not grow: current size {} pages, requested increase: {} pages", current.0, attempted_delta.0)]
CouldNotGrow {
/// The current size in pages.
current: Pages,
/// The attempted amount to grow by in pages.
attempted_delta: Pages,
},
/// The operation would cause the size of the memory size exceed the maximum.
#[error("The memory is invalid because {}", reason)]
InvalidMemory {
/// The reason why the provided memory is invalid.
reason: String,
},
/// Caller asked for more minimum memory than we can give them.
#[error("The minimum requested ({} pages) memory is greater than the maximum allowed memory ({} pages)", min_requested.0, max_allowed.0)]
MinimumMemoryTooLarge {
/// The number of pages requested as the minimum amount of memory.
min_requested: Pages,
/// The maximum amount of memory we can allocate.
max_allowed: Pages,
},
/// Caller asked for a maximum memory greater than we can give them.
#[error("The maximum requested memory ({} pages) is greater than the maximum allowed memory ({} pages)", max_requested.0, max_allowed.0)]
MaximumMemoryTooLarge {
/// The number of pages requested as the maximum amount of memory.
max_requested: Pages,
/// The number of pages requested as the maximum amount of memory.
max_allowed: Pages,
},
/// A user defined error value, used for error cases not listed above.
#[error("A user-defined error occurred: {0}")]
Generic(String),
}
/// A linear memory instance.
pub struct VMMemory {
// The underlying allocation.
mmap: WasmMmap,
// The optional maximum size in wasm pages of this linear memory.
maximum: Option<Pages>,
/// The WebAssembly linear memory description.
memory: MemoryType,
/// Our chosen implementation style.
style: MemoryStyle,
// Size in bytes of extra guard pages after the end to optimize loads and stores with
// constant offsets.
offset_guard_size: usize,
/// The owned memory definition used by the generated code
vm_memory_definition: MaybeInstanceOwned<VMMemoryDefinition>,
}
// The memory mapped area
#[derive(Debug)] #[derive(Debug)]
struct WasmMmap { struct WasmMmap {
// Our OS allocation of mmap'd memory. // Our OS allocation of mmap'd memory.
alloc: Mmap, alloc: Mmap,
// The current logical size in wasm pages of this linear memory. // The current logical size in wasm pages of this linear memory.
size: Pages, size: Pages,
/// The owned memory definition used by the generated code
vm_memory_definition: MaybeInstanceOwned<VMMemoryDefinition>,
} }
impl VMMemory { impl WasmMmap {
fn get_vm_memory_definition(&self) -> NonNull<VMMemoryDefinition> {
self.vm_memory_definition.as_ptr()
}
fn size(&self) -> Pages {
unsafe {
let md_ptr = self.get_vm_memory_definition();
let md = md_ptr.as_ref();
Bytes::from(md.current_length).try_into().unwrap()
}
}
fn grow(&mut self, delta: Pages, conf: VMMemoryConfig) -> Result<Pages, MemoryError> {
// Optimization of memory.grow 0 calls.
if delta.0 == 0 {
return Ok(self.size);
}
let new_pages = self
.size
.checked_add(delta)
.ok_or(MemoryError::CouldNotGrow {
current: self.size,
attempted_delta: delta,
})?;
let prev_pages = self.size;
if let Some(maximum) = conf.maximum {
if new_pages > maximum {
return Err(MemoryError::CouldNotGrow {
current: self.size,
attempted_delta: delta,
});
}
}
// Wasm linear memories are never allowed to grow beyond what is
// indexable. If the memory has no maximum, enforce the greatest
// limit here.
if new_pages >= Pages::max_value() {
// Linear memory size would exceed the index range.
return Err(MemoryError::CouldNotGrow {
current: self.size,
attempted_delta: delta,
});
}
let delta_bytes = delta.bytes().0;
let prev_bytes = prev_pages.bytes().0;
let new_bytes = new_pages.bytes().0;
if new_bytes > self.alloc.len() - conf.offset_guard_size {
// If the new size is within the declared maximum, but needs more memory than we
// have on hand, it's a dynamic heap and it can move.
let guard_bytes = conf.offset_guard_size;
let request_bytes =
new_bytes
.checked_add(guard_bytes)
.ok_or_else(|| MemoryError::CouldNotGrow {
current: new_pages,
attempted_delta: Bytes(guard_bytes).try_into().unwrap(),
})?;
let mut new_mmap =
Mmap::accessible_reserved(new_bytes, request_bytes).map_err(MemoryError::Region)?;
let copy_len = self.alloc.len() - conf.offset_guard_size;
new_mmap.as_mut_slice()[..copy_len].copy_from_slice(&self.alloc.as_slice()[..copy_len]);
self.alloc = new_mmap;
} else if delta_bytes > 0 {
// Make the newly allocated pages accessible.
self.alloc
.make_accessible(prev_bytes, delta_bytes)
.map_err(MemoryError::Region)?;
}
self.size = new_pages;
// update memory definition
unsafe {
let mut md_ptr = self.vm_memory_definition.as_ptr();
let md = md_ptr.as_mut();
md.current_length = new_pages.bytes().0;
md.base = self.alloc.as_mut_ptr() as _;
}
Ok(prev_pages)
}
}
/// A linear memory instance.
#[derive(Debug, Clone)]
struct VMMemoryConfig {
// The optional maximum size in wasm pages of this linear memory.
maximum: Option<Pages>,
/// The WebAssembly linear memory description.
memory: MemoryType,
/// Our chosen implementation style.
style: MemoryStyle,
// Size in bytes of extra guard pages after the end to optimize loads and stores with
// constant offsets.
offset_guard_size: usize,
}
impl VMMemoryConfig {
fn ty(&self, minimum: Pages) -> MemoryType {
let mut out = self.memory;
out.minimum = minimum;
out
}
fn style(&self) -> MemoryStyle {
self.style
}
}
/// A linear memory instance.
#[derive(Debug)]
pub struct VMOwnedMemory {
// The underlying allocation.
mmap: WasmMmap,
// Configuration of this memory
config: VMMemoryConfig,
}
unsafe impl Send for VMOwnedMemory {}
unsafe impl Sync for VMOwnedMemory {}
impl VMOwnedMemory {
/// Create a new linear memory instance with specified minimum and maximum number of wasm pages. /// Create a new linear memory instance with specified minimum and maximum number of wasm pages.
/// ///
/// This creates a `Memory` with owned metadata: this can be used to create a memory /// This creates a `Memory` with owned metadata: this can be used to create a memory
@@ -154,18 +222,11 @@ impl VMMemory {
let mapped_pages = memory.minimum; let mapped_pages = memory.minimum;
let mapped_bytes = mapped_pages.bytes(); let mapped_bytes = mapped_pages.bytes();
let mut mmap = WasmMmap { let mut alloc = Mmap::accessible_reserved(mapped_bytes.0, request_bytes)
alloc: Mmap::accessible_reserved(mapped_bytes.0, request_bytes) .map_err(MemoryError::Region)?;
.map_err(MemoryError::Region)?, let base_ptr = alloc.as_mut_ptr();
size: memory.minimum,
};
let base_ptr = mmap.alloc.as_mut_ptr();
let mem_length = memory.minimum.bytes().0; let mem_length = memory.minimum.bytes().0;
Ok(Self { let mmap = WasmMmap {
mmap,
maximum: memory.maximum,
offset_guard_size: offset_guard_bytes,
vm_memory_definition: if let Some(mem_loc) = vm_memory_location { vm_memory_definition: if let Some(mem_loc) = vm_memory_location {
{ {
let mut ptr = mem_loc; let mut ptr = mem_loc;
@@ -180,127 +241,173 @@ impl VMMemory {
current_length: mem_length, current_length: mem_length,
}))) })))
}, },
alloc,
size: memory.minimum,
};
Ok(Self {
mmap,
config: VMMemoryConfig {
maximum: memory.maximum,
offset_guard_size: offset_guard_bytes,
memory: *memory, memory: *memory,
style: style.clone(), style: *style,
},
}) })
} }
}
/// Get the `VMMemoryDefinition`. impl LinearMemory for VMOwnedMemory {
fn get_vm_memory_definition(&self) -> NonNull<VMMemoryDefinition> { /// Returns the type for this memory.
self.vm_memory_definition.as_ptr() fn ty(&self) -> MemoryType {
let minimum = self.mmap.size();
self.config.ty(minimum)
} }
/// Returns the type for this memory. /// Returns the size of hte memory in pages
pub fn ty(&self) -> MemoryType { fn size(&self) -> Pages {
let minimum = self.size(); self.mmap.size()
let mut out = self.memory;
out.minimum = minimum;
out
} }
/// Returns the memory style for this memory. /// Returns the memory style for this memory.
pub fn style(&self) -> &MemoryStyle { fn style(&self) -> MemoryStyle {
&self.style self.config.style()
}
/// Returns the number of allocated wasm pages.
pub fn size(&self) -> Pages {
// TODO: investigate this function for race conditions
unsafe {
let md_ptr = self.get_vm_memory_definition();
let md = md_ptr.as_ref();
Bytes::from(md.current_length).try_into().unwrap()
}
} }
/// Grow memory by the specified amount of wasm pages. /// Grow memory by the specified amount of wasm pages.
/// ///
/// Returns `None` if memory can't be grown by the specified amount /// Returns `None` if memory can't be grown by the specified amount
/// of wasm pages. /// of wasm pages.
pub fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> { fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
// Optimization of memory.grow 0 calls. self.mmap.grow(delta, self.config.clone())
if delta.0 == 0 {
return Ok(self.mmap.size);
}
let new_pages = self
.mmap
.size
.checked_add(delta)
.ok_or(MemoryError::CouldNotGrow {
current: self.mmap.size,
attempted_delta: delta,
})?;
let prev_pages = self.mmap.size;
if let Some(maximum) = self.maximum {
if new_pages > maximum {
return Err(MemoryError::CouldNotGrow {
current: self.mmap.size,
attempted_delta: delta,
});
}
}
// Wasm linear memories are never allowed to grow beyond what is
// indexable. If the memory has no maximum, enforce the greatest
// limit here.
if new_pages >= Pages::max_value() {
// Linear memory size would exceed the index range.
return Err(MemoryError::CouldNotGrow {
current: self.mmap.size,
attempted_delta: delta,
});
}
let delta_bytes = delta.bytes().0;
let prev_bytes = prev_pages.bytes().0;
let new_bytes = new_pages.bytes().0;
if new_bytes > self.mmap.alloc.len() - self.offset_guard_size {
// If the new size is within the declared maximum, but needs more memory than we
// have on hand, it's a dynamic heap and it can move.
let guard_bytes = self.offset_guard_size;
let request_bytes =
new_bytes
.checked_add(guard_bytes)
.ok_or_else(|| MemoryError::CouldNotGrow {
current: new_pages,
attempted_delta: Bytes(guard_bytes).try_into().unwrap(),
})?;
let mut new_mmap =
Mmap::accessible_reserved(new_bytes, request_bytes).map_err(MemoryError::Region)?;
let copy_len = self.mmap.alloc.len() - self.offset_guard_size;
new_mmap.as_mut_slice()[..copy_len]
.copy_from_slice(&self.mmap.alloc.as_slice()[..copy_len]);
self.mmap.alloc = new_mmap;
} else if delta_bytes > 0 {
// Make the newly allocated pages accessible.
self.mmap
.alloc
.make_accessible(prev_bytes, delta_bytes)
.map_err(MemoryError::Region)?;
}
self.mmap.size = new_pages;
// update memory definition
unsafe {
let mut md_ptr = self.get_vm_memory_definition();
let md = md_ptr.as_mut();
md.current_length = new_pages.bytes().0;
md.base = self.mmap.alloc.as_mut_ptr() as _;
}
Ok(prev_pages)
} }
/// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code. /// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code.
pub fn vmmemory(&self) -> NonNull<VMMemoryDefinition> { fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
self.get_vm_memory_definition() self.mmap.vm_memory_definition.as_ptr()
}
/// Owned memory can not be cloned (this will always return None)
fn try_clone(&self) -> Option<Box<dyn LinearMemory + 'static>> {
None
} }
} }
impl From<VMOwnedMemory> for VMMemory {
fn from(mem: VMOwnedMemory) -> Self {
Self(Box::new(mem))
}
}
/// Represents linear memory that can be either owned or shared
#[derive(Debug)]
pub struct VMMemory(pub Box<dyn LinearMemory + 'static>);
impl From<Box<dyn LinearMemory + 'static>> for VMMemory {
fn from(mem: Box<dyn LinearMemory + 'static>) -> Self {
Self(mem)
}
}
impl LinearMemory for VMMemory {
/// Returns the type for this memory.
fn ty(&self) -> MemoryType {
self.0.ty()
}
/// Returns the size of hte memory in pages
fn size(&self) -> Pages {
self.0.size()
}
/// Grow memory by the specified amount of wasm pages.
///
/// Returns `None` if memory can't be grown by the specified amount
/// of wasm pages.
fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
self.0.grow(delta)
}
/// Returns the memory style for this memory.
fn style(&self) -> MemoryStyle {
self.0.style()
}
/// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code.
fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
self.0.vmmemory()
}
/// Attempts to clone this memory (if its clonable)
fn try_clone(&self) -> Option<Box<dyn LinearMemory + 'static>> {
self.0.try_clone()
}
}
impl VMMemory {
/// Creates a new linear memory instance of the correct type with specified
/// minimum and maximum number of wasm pages.
///
/// This creates a `Memory` with owned metadata: this can be used to create a memory
/// that will be imported into Wasm modules.
pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<VMMemory, MemoryError> {
Ok(Self(Box::new(VMOwnedMemory::new(memory, style)?)))
}
/// Create a new linear memory instance with specified minimum and maximum number of wasm pages.
///
/// This creates a `Memory` with metadata owned by a VM, pointed to by
/// `vm_memory_location`: this can be used to create a local memory.
///
/// # Safety
/// - `vm_memory_location` must point to a valid location in VM memory.
pub unsafe fn from_definition(
memory: &MemoryType,
style: &MemoryStyle,
vm_memory_location: NonNull<VMMemoryDefinition>,
) -> Result<VMMemory, MemoryError> {
Ok(Self(Box::new(VMOwnedMemory::from_definition(
memory,
style,
vm_memory_location,
)?)))
}
/// Creates VMMemory from a custom implementation - the following into implementations
/// are natively supported
/// - VMOwnedMemory -> VMMemory
/// - Box<dyn LinearMemory + 'static> -> VMMemory
pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> VMMemory
where
IntoVMMemory: Into<VMMemory>,
{
memory.into()
}
}
/// Represents memory that is used by the WebAsssembly module
pub trait LinearMemory
where
Self: std::fmt::Debug + Send,
{
/// Returns the type for this memory.
fn ty(&self) -> MemoryType;
/// Returns the size of hte memory in pages
fn size(&self) -> Pages;
/// Returns the memory style for this memory.
fn style(&self) -> MemoryStyle;
/// Grow memory by the specified amount of wasm pages.
///
/// Returns `None` if memory can't be grown by the specified amount
/// of wasm pages.
fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError>;
/// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code.
fn vmmemory(&self) -> NonNull<VMMemoryDefinition>;
/// Attempts to clone this memory (if its clonable)
fn try_clone(&self) -> Option<Box<dyn LinearMemory + 'static>>;
}

View File

@@ -266,3 +266,23 @@ impl<T> MaybeInstanceOwned<T> {
} }
} }
} }
impl<T> std::fmt::Debug for MaybeInstanceOwned<T>
where
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MaybeInstanceOwned::Host(p) => {
write!(f, "host(")?;
p.as_ref().fmt(f)?;
write!(f, ")")
}
MaybeInstanceOwned::Instance(p) => {
write!(f, "instance(")?;
unsafe { p.as_ref().fmt(f)? };
write!(f, ")")
}
}
}
}

View File

@@ -303,49 +303,29 @@ mod test_vmglobal_import {
} }
} }
/// The fields compiled code needs to access to utilize a WebAssembly linear /// Do an unsynchronized, non-atomic `memory.copy` for the memory.
/// memory defined within the instance, namely the start address and the ///
/// size in bytes. /// # Errors
#[derive(Debug, Copy, Clone)] ///
#[repr(C)] /// Returns a `Trap` error when the source or destination ranges are out of
pub struct VMMemoryDefinition { /// bounds.
/// The start address which is always valid, even if the memory grows. ///
pub base: *mut u8,
/// The current logical size of this linear memory in bytes.
pub current_length: usize,
}
/// # Safety /// # Safety
/// This data is safe to share between threads because it's plain data that /// The memory is not copied atomically and is not synchronized: it's the
/// is the user's responsibility to synchronize. /// caller's responsibility to synchronize.
unsafe impl Send for VMMemoryDefinition {} pub(crate) unsafe fn memory_copy(
/// # Safety mem: &VMMemoryDefinition,
/// This data is safe to share between threads because it's plain data that dst: u32,
/// is the user's responsibility to synchronize. And it's `Copy` so there's src: u32,
/// really no difference between passing it by reference or by value as far as len: u32,
/// correctness in a multi-threaded context is concerned. ) -> Result<(), Trap> {
unsafe impl Sync for VMMemoryDefinition {}
impl VMMemoryDefinition {
/// Do an unsynchronized, non-atomic `memory.copy` for the memory.
///
/// # Errors
///
/// Returns a `Trap` error when the source or destination ranges are out of
/// bounds.
///
/// # Safety
/// The memory is not copied atomically and is not synchronized: it's the
/// caller's responsibility to synchronize.
pub(crate) unsafe fn memory_copy(&self, dst: u32, src: u32, len: u32) -> Result<(), Trap> {
// https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy
if src if src
.checked_add(len) .checked_add(len)
.map_or(true, |n| usize::try_from(n).unwrap() > self.current_length) .map_or(true, |n| usize::try_from(n).unwrap() > mem.current_length)
|| dst || dst
.checked_add(len) .checked_add(len)
.map_or(true, |m| usize::try_from(m).unwrap() > self.current_length) .map_or(true, |m| usize::try_from(m).unwrap() > mem.current_length)
{ {
return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
} }
@@ -355,27 +335,32 @@ impl VMMemoryDefinition {
// Bounds and casts are checked above, by this point we know that // Bounds and casts are checked above, by this point we know that
// everything is safe. // everything is safe.
let dst = self.base.add(dst); let dst = mem.base.add(dst);
let src = self.base.add(src); let src = mem.base.add(src);
ptr::copy(src, dst, len as usize); ptr::copy(src, dst, len as usize);
Ok(()) Ok(())
} }
/// Perform the `memory.fill` operation for the memory in an unsynchronized, /// Perform the `memory.fill` operation for the memory in an unsynchronized,
/// non-atomic way. /// non-atomic way.
/// ///
/// # Errors /// # Errors
/// ///
/// Returns a `Trap` error if the memory range is out of bounds. /// Returns a `Trap` error if the memory range is out of bounds.
/// ///
/// # Safety /// # Safety
/// The memory is not filled atomically and is not synchronized: it's the /// The memory is not filled atomically and is not synchronized: it's the
/// caller's responsibility to synchronize. /// caller's responsibility to synchronize.
pub(crate) unsafe fn memory_fill(&self, dst: u32, val: u32, len: u32) -> Result<(), Trap> { pub(crate) unsafe fn memory_fill(
mem: &VMMemoryDefinition,
dst: u32,
val: u32,
len: u32,
) -> Result<(), Trap> {
if dst if dst
.checked_add(len) .checked_add(len)
.map_or(true, |m| usize::try_from(m).unwrap() > self.current_length) .map_or(true, |m| usize::try_from(m).unwrap() > mem.current_length)
{ {
return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds)); return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
} }
@@ -385,38 +370,10 @@ impl VMMemoryDefinition {
// Bounds and casts are checked above, by this point we know that // Bounds and casts are checked above, by this point we know that
// everything is safe. // everything is safe.
let dst = self.base.offset(dst); let dst = mem.base.offset(dst);
ptr::write_bytes(dst, val, len as usize); ptr::write_bytes(dst, val, len as usize);
Ok(()) Ok(())
}
}
#[cfg(test)]
mod test_vmmemory_definition {
use super::VMMemoryDefinition;
use crate::VMOffsets;
use memoffset::offset_of;
use std::mem::size_of;
use wasmer_types::ModuleInfo;
#[test]
fn check_vmmemory_definition_offsets() {
let module = ModuleInfo::new();
let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
assert_eq!(
size_of::<VMMemoryDefinition>(),
usize::from(offsets.size_of_vmmemory_definition())
);
assert_eq!(
offset_of!(VMMemoryDefinition, base),
usize::from(offsets.vmmemory_definition_base())
);
assert_eq!(
offset_of!(VMMemoryDefinition, current_length),
usize::from(offsets.vmmemory_definition_current_length())
);
}
} }
/// The fields compiled code needs to access to utilize a WebAssembly table /// The fields compiled code needs to access to utilize a WebAssembly table
@@ -720,3 +677,54 @@ pub type VMTrampoline = unsafe extern "C" fn(
*const VMFunctionBody, // function we're actually calling *const VMFunctionBody, // function we're actually calling
*mut RawValue, // space for arguments and return values *mut RawValue, // space for arguments and return values
); );
/// The fields compiled code needs to access to utilize a WebAssembly linear
/// memory defined within the instance, namely the start address and the
/// size in bytes.
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct VMMemoryDefinition {
/// The start address which is always valid, even if the memory grows.
pub base: *mut u8,
/// The current logical size of this linear memory in bytes.
pub current_length: usize,
}
/// # Safety
/// This data is safe to share between threads because it's plain data that
/// is the user's responsibility to synchronize.
unsafe impl Send for VMMemoryDefinition {}
/// # Safety
/// This data is safe to share between threads because it's plain data that
/// is the user's responsibility to synchronize. And it's `Copy` so there's
/// really no difference between passing it by reference or by value as far as
/// correctness in a multi-threaded context is concerned.
unsafe impl Sync for VMMemoryDefinition {}
#[cfg(test)]
mod test_vmmemory_definition {
use super::VMMemoryDefinition;
use crate::ModuleInfo;
use crate::VMOffsets;
use memoffset::offset_of;
use std::mem::size_of;
#[test]
fn check_vmmemory_definition_offsets() {
let module = ModuleInfo::new();
let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module);
assert_eq!(
size_of::<VMMemoryDefinition>(),
usize::from(offsets.size_of_vmmemory_definition())
);
assert_eq!(
offset_of!(VMMemoryDefinition, base),
usize::from(offsets.vmmemory_definition_base())
);
assert_eq!(
offset_of!(VMMemoryDefinition, current_length),
usize::from(offsets.vmmemory_definition_current_length())
);
}
}

View File

@@ -10,9 +10,6 @@ license = "MIT"
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
cfg-if = "1.0" cfg-if = "1.0"
thiserror = "1" thiserror = "1"

View File

@@ -307,7 +307,7 @@ pub fn args_get<M: MemorySize>(
let env = ctx.data(); let env = ctx.data();
let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
let result = write_buffer_array(&memory, &*state.args, argv, argv_buf); let result = write_buffer_array(&memory, &state.args, argv, argv_buf);
debug!( debug!(
"=> args:\n{}", "=> args:\n{}",
@@ -433,7 +433,7 @@ pub fn environ_get<M: MemorySize>(
let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0); let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
trace!(" -> State envs: {:?}", state.envs); trace!(" -> State envs: {:?}", state.envs);
write_buffer_array(&memory, &*state.envs, environ, environ_buf) write_buffer_array(&memory, &state.envs, environ, environ_buf)
} }
/// ### `environ_sizes_get()` /// ### `environ_sizes_get()`
@@ -5555,7 +5555,7 @@ pub unsafe fn sock_send_file<M: MemorySize>(
sock, sock,
__WASI_RIGHT_SOCK_SEND, __WASI_RIGHT_SOCK_SEND,
|socket| { |socket| {
let buf = (&buf[..]).to_vec(); let buf = (buf[..]).to_vec();
socket.send_bytes::<M>(Bytes::from(buf)) socket.send_bytes::<M>(Bytes::from(buf))
} }
)); ));

View File

@@ -1 +1 @@
1.59 1.61

View File

@@ -1,199 +1,366 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
# This is a script for publishing the wasmer crates to crates.io. """This is a script for publishing the wasmer crates to crates.io.
# It should be run in the root of wasmer like `python3 scripts/publish.py --no-dry-run`. It should be run in the root of wasmer like `python3 scripts/publish.py --help`.
# By default the script executes a test run and does not publish the crates to crates.io.
# install dependencies: Please lint with pylint and format with black.
# pip3 install toposort
$ pylint scripts/publish.py
--------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)
$ black scripts/publish.py
"""
import argparse import argparse
import itertools
import os import os
import re import re
import subprocess import subprocess
import time import time
import sys
from typing import Optional import typing
from pprint import pprint
try: try:
from toposort import toposort_flatten # try import tomllib from standard Python library: New in version 3.11.
import tomllib
except ModuleNotFoundError:
try:
# if tomllib is missing, this is an older python3 version. Try
# importing the equivalent third-party library tomli:
import tomli as tomllib
except ModuleNotFoundError:
print("Please install tomli, `pip3 install tomli`")
sys.exit(1)
try:
from graphlib import TopologicalSorter
except ImportError: except ImportError:
print("Please install toposort, `pip3 install toposort`") print("Incompatible python3 version: lacks graphlib standard library module.")
sys.exit(1)
SETTINGS = {
# TODO: find this automatically # extra features to put when publishing, for example wasmer-cli needs a
target_version = "3.0.0-beta" # compiler by default otherwise it won't work standalone
"publish_features": {
# TODO: generate this by parsing toml files "wasmer-cli": "default,cranelift",
dep_graph = { },
"wasmer-types": set([]), # workspace members we want to publish but whose path doesn't start by
"wasmer-derive": set([]), # "./lib/"
"wasmer-vm": set(["wasmer-types"]), "non-lib-workspace-members": set(["tests/lib/wast"]),
"wasmer-compiler": set(["wasmer-types"]),
"wasmer-compiler-singlepass": set(["wasmer-types", "wasmer-compiler"]),
"wasmer-compiler-cranelift": set(["wasmer-types", "wasmer-compiler"]),
"wasmer-compiler-cli": set(
[
"wasmer-compiler",
"wasmer-types",
"wasmer-compiler-singlepass",
"wasmer-compiler-cranelift",
]
),
"wasmer-object": set(["wasmer-types", "wasmer-compiler"]),
"wasmer-compiler-llvm": set(["wasmer-compiler", "wasmer-vm", "wasmer-types"]),
"wasmer": set(
[
"wasmer-vm",
"wasmer-compiler",
"wasmer-derive",
"wasmer-types",
"wasmer-compiler-singlepass",
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
]
),
"wasmer-vfs": set([]),
"wasmer-vbus": set([]),
"wasmer-vnet": set([]),
"wasmer-wasi-local-networking": set([]),
"wasmer-cache": set(["wasmer"]),
"wasmer-wasi": set(["wasmer", "wasmer-wasi-types", "wasmer-vfs", "wasmer-vbus", "wasmer-vnet"]),
"wasmer-wasi-types": set(["wasmer-types"]),
"wasmer-wasi-experimental-io-devices": set(["wasmer-wasi"]),
"wasmer-emscripten": set(["wasmer"]),
"wasmer-c-api": set(
[
"wasmer",
"wasmer-compiler",
"wasmer-compiler-cranelift",
"wasmer-compiler-singlepass",
"wasmer-compiler-llvm",
"wasmer-emscripten",
"wasmer-middlewares",
"wasmer-wasi",
"wasmer-types",
]
),
"wasmer-middlewares": set(["wasmer", "wasmer-types", "wasmer-vm"]),
"wasmer-wast": set(["wasmer", "wasmer-wasi", "wasmer-vfs"]),
"wasmer-cli": set(
[
"wasmer",
"wasmer-compiler",
"wasmer-compiler-cranelift",
"wasmer-compiler-singlepass",
"wasmer-compiler-llvm",
"wasmer-emscripten",
"wasmer-vm",
"wasmer-wasi",
"wasmer-wasi-experimental-io-devices",
"wasmer-wast",
"wasmer-cache",
"wasmer-types",
"wasmer-vfs",
]
),
} }
# where each crate is located in the `lib` directory
# TODO: this could also be generated from the toml files
location = {
"wasmer-compiler-cli": "cli-compiler",
"wasmer-types": "types",
"wasmer-derive": "derive",
"wasmer-vm": "vm",
"wasmer-compiler": "compiler",
"wasmer-object": "object",
"wasmer-compiler-singlepass": "compiler-singlepass",
"wasmer-compiler-cranelift": "compiler-cranelift",
"wasmer-compiler-llvm": "compiler-llvm",
"wasmer-cache": "cache",
"wasmer": "api",
"wasmer-wasi": "wasi",
"wasmer-wasi-types": "wasi-types",
"wasmer-emscripten": "emscripten",
"wasmer-wasi-experimental-io-devices": "wasi-experimental-io-devices",
"wasmer-c-api": "c-api",
"wasmer-middlewares": "middlewares",
"wasmer-vfs": "vfs",
"wasmer-vbus": "vbus",
"wasmer-vnet": "vnet",
"wasmer-cli": "cli",
"wasmer-wasi-local-networking": "wasi-local-networking",
"wasmer-wast": "../tests/lib/wast",
}
no_dry_run = False def get_latest_version_for_crate(crate_name: str) -> typing.Optional[str]:
"""Fetches the latest version of a given crate name in local cargo registry."""
output = subprocess.run(
def get_latest_version_for_crate(crate_name: str) -> Optional[str]: ["cargo", "search", crate_name], capture_output=True, check=True
output = subprocess.run(["cargo", "search", crate_name], capture_output=True) )
rexp_src = '^{} = "([^"]+)"'.format(crate_name) rexp_src = f'^{crate_name} = "([^"]+)"'
prog = re.compile(rexp_src) prog = re.compile(rexp_src)
haystack = output.stdout.decode("utf-8") haystack = output.stdout.decode("utf-8")
for line in haystack.splitlines(): for line in haystack.splitlines():
result = prog.match(line) result = prog.match(line)
if result: if result:
return result.group(1) return result.group(1)
return None
def is_crate_already_published(crate_name: str) -> bool: class Crate:
found_string = get_latest_version_for_crate(crate_name) """Represents a workspace crate that is to be published to crates.io."""
def __init__(
self,
dependencies: typing.List[str],
cargo_manifest: dict,
cargo_file_path="Cargo.toml",
):
self.name = cargo_manifest["package"]["name"]
self.dependencies = dependencies
self.cargo_manifest = cargo_manifest
if not os.path.isabs(cargo_file_path):
cargo_file_path = os.path.join(os.getcwd(), cargo_file_path)
self.cargo_file_path = cargo_file_path
def __str__(self):
return f"{self.name}: {self.dependencies} {self.cargo_file_path} {self.path()}"
@property
def path(self) -> str:
"""Return the absolute filesystem path containing this crate."""
return os.path.dirname(self.cargo_file_path)
@property
def version(self) -> str:
"""Return the crate's version according to its manifest."""
return self.cargo_manifest["package"]["version"]
class Publisher:
"""A class responsible for figuring out dependencies,
creating a topological sorting in order to publish them
to crates.io in a valid order."""
def __init__(self, version=None, dry_run=True, verbose=True):
self.dry_run: bool = dry_run
self.verbose: bool = verbose
# open workspace Cargo.toml
with open("Cargo.toml", "rb") as file:
data = tomllib.load(file)
if version is None:
version = data["package"]["version"]
self.version: str = version
if self.verbose and not self.dry_run:
print(f"Publishing version {self.version}")
elif self.verbose and self.dry_run:
print(f"Publishing version {self.version} dry run!")
# define helper function
check_local_dep_fn = lambda t: isinstance(t[1], dict) and "path" in t[1]
members = set(
map(
lambda p: p + "/Cargo.toml",
filter(
lambda path: (
path.startswith("lib/") and os.path.exists(path + "/Cargo.toml")
)
or path in SETTINGS["non-lib-workspace-members"],
itertools.chain(
data["workspace"]["members"],
map(
lambda p: p[1]["path"],
filter(check_local_dep_fn, data["dependencies"].items()),
),
),
),
)
)
crates = []
for member in members:
with open(member, "rb") as file:
member_data = tomllib.load(file)
def return_dependencies(toml) -> typing.List[str]:
acc = set()
stack = [toml]
while len(stack) > 0:
toml = stack.pop()
if "dependencies" in toml:
acc.update(
list(
map(
lambda dep: dep[1]["package"]
if "package" in dep[1]
else dep[0],
filter(
check_local_dep_fn, toml["dependencies"].items()
),
)
)
)
if "target" in toml:
stack.append(toml["target"])
for key, value in toml.items():
if key.startswith("cfg"):
stack.append(value)
return list(acc)
dependencies = return_dependencies(member_data)
crates.append(Crate(dependencies, member_data, cargo_file_path=member))
invalids: typing.List[str] = []
for crate in crates:
if crate.version != self.version:
print(
f"Crate {crate.name} is version {crate.version} but"
f" we're publishing for version {self.version}"
)
invalids.append(crate.name)
if len(invalids) > 0:
raise Exception(
f"Some crates have a different version than the"
f" one we're publishing ({self.version}): {invalids}"
)
self.crates = crates
self.crate_index: typing.Dict[str, Crate] = {c.name: c for c in crates}
self.create_publish_order()
self.starting_dir = os.getcwd()
def create_publish_order(self):
"""Creates a valid publish order by topologically
sorting crates using the dependency graph."""
topological_sorter = TopologicalSorter()
for crate in self.crates:
topological_sorter.add(crate.name, *crate.dependencies)
self.publish_order: typing.List[str] = [*topological_sorter.static_order()]
def is_crate_already_published(self, crate_name: str) -> bool:
"""Checks if a given crate name is already published
with the version string we intend to publish with."""
found_string: str = get_latest_version_for_crate(crate_name)
if found_string is None: if found_string is None:
return False return False
return target_version == found_string return self.version == found_string
def publish_crate(self, crate_name: str):
def publish_crate(crate: str): # pylint: disable=broad-except
starting_dir = os.getcwd() """Publish a given crate by name."""
os.chdir("lib/{}".format(location[crate])) status = None
try:
global no_dry_run crate = self.crate_index[crate_name]
if no_dry_run: os.chdir(crate.path)
output = subprocess.run(["cargo", "publish"]) extra_args = []
if crate_name in SETTINGS["publish_features"]:
extra_args = ["--features", SETTINGS["publish_features"][crate_name]]
if self.dry_run:
print(f"In dry-run: not publishing crate `{crate_name}`")
command = ["cargo", "publish", "--dry-run"] + extra_args
if self.verbose:
print(*command)
output = subprocess.run(command, check=True)
if self.verbose:
print(output)
else: else:
print("In dry-run: not publishing crate `{}`".format(crate)) command = ["cargo", "publish"] + extra_args
output = subprocess.run(["cargo", "publish", "--dry-run"]) if self.verbose:
print(*command)
output = subprocess.run(command, check=True)
if self.verbose:
print(output)
if self.verbose:
print("Success.")
except Exception as exc:
if self.verbose:
print(f"Failed to publish {crate_name}.")
print(exc)
status = exc
finally:
os.chdir(self.starting_dir)
return status
os.chdir(starting_dir) def publish(self):
# pylint: disable=too-many-branches
"""Publish all packages in workspace."""
if self.verbose and self.dry_run:
print("(Dry run, not actually publishing anything)")
if self.verbose:
print("Publishing order:")
pprint(self.publish_order)
status = {}
failures = 0
for crate_name in self.publish_order:
print(f"Publishing `{crate_name}`...")
if not self.is_crate_already_published(crate_name):
status[crate_name] = self.publish_crate(crate_name)
if status[crate_name]:
failures = +1
else:
print(f"`{crate_name}` was already published!")
continue
# sleep for 16 seconds between crates to ensure the crates.io
# index has time to update
if not self.dry_run:
print(
"Sleeping for 16 seconds to allow the `crates.io` index to update..."
)
time.sleep(16)
else:
print("In dry-run: not sleeping for crates.io to update.")
if failures > 0 and self.verbose:
print(f"encountered {failures} failures.")
for key, value in status.items():
if value is None:
result = "ok"
else:
result = str(value)
print(f"{key}\t{result}")
if self.verbose:
print(f"Published {len(status) - failures} crates.")
return failures
def main(): def main():
"""Main executable function."""
os.environ["WASMER_PUBLISH_SCRIPT_IS_RUNNING"] = "1" os.environ["WASMER_PUBLISH_SCRIPT_IS_RUNNING"] = "1"
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Publish the Wasmer crates to crates.io" description="Publish the Wasmer crates to crates.io"
) )
parser.add_argument( subparsers = parser.add_subparsers(dest="subcommand")
"--no-dry-run", health_cmd = subparsers.add_parser(
"health-check",
help="""Check the dependency graph is a tree, meaning a non-cyclic
planar graph. Combine with verbosity to print a topological sorting
of the graph.""",
)
health_cmd.add_argument(
"-v",
"--verbose",
default=False, default=False,
action="store_true", action="store_true",
help="Run the script without actually publishing anything to crates.io", help="Be verbose.",
)
health_cmd.add_argument(
"--print-dependencies",
default=False,
action="store_true",
help="For each crate, print its dependencies.",
)
publish_cmd = subparsers.add_parser(
"publish", help="Publish Wasmer crates to crates.io."
)
publish_cmd.add_argument(
"--version",
default=None,
type=str,
help="""Define the semver target triple (Default is automatically
read from workspace Cargo.toml.""",
)
publish_cmd.add_argument(
"--dry-run",
default=False,
action="store_true",
help="""Run the script without actually publishing anything to
crates.io""",
)
publish_cmd.add_argument(
"-v",
"--verbose",
default=False,
action="store_true",
help="Be verbose.",
) )
args = vars(parser.parse_args())
global no_dry_run args = parser.parse_args()
no_dry_run = args["no_dry_run"] if args.subcommand == "health-check":
verbose = args.verbose
publisher = Publisher(verbose=verbose)
if verbose:
print(f"Version is {publisher.version}")
pprint(publisher.publish_order)
if args.print_dependencies:
for crate in publisher.crates:
print(f"{crate.name}: {crate.dependencies}")
return 0
# get the order to publish the crates in if args.subcommand == "publish":
order = list(toposort_flatten(dep_graph, sort=True)) verbose = args.verbose
publisher = Publisher(dry_run=args.dry_run, verbose=verbose)
for crate in order: return publisher.publish()
print("Publishing `{}`...".format(crate)) return 0
if not is_crate_already_published(crate):
publish_crate(crate)
else:
print("`{}` was already published!".format(crate))
continue
# sleep for 16 seconds between crates to ensure the crates.io index has time to update
# this can be optimized with knowledge of our dep graph via toposort; we can even publish
# crates in parallel; however this is out of scope for the first version of this script
if no_dry_run:
print("Sleeping for 16 seconds to allow the `crates.io` index to update...")
time.sleep(16)
else:
print("In dry-run: not sleeping for crates.io to update.")
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -1,6 +1,13 @@
use anyhow::Result; use anyhow::Result;
use wasmer::*; use wasmer::*;
#[test]
fn sanity_test_artifact_deserialize() {
let engine = Engine::headless();
let result = unsafe { Artifact::deserialize(&engine, &[]) };
assert!(result.is_err());
}
#[compiler_test(serialize)] #[compiler_test(serialize)]
fn test_serialize(config: crate::Config) -> Result<()> { fn test_serialize(config: crate::Config) -> Result<()> {
let mut store = config.store(); let mut store = config.store();

View File

@@ -1,6 +1,6 @@
fn main() { fn main() {
println!( println!(
"cargo:rustc-env=TARGET={}", "cargo:rustc-env=CARGO_BUILD_TARGET={}",
std::env::var("TARGET").unwrap() std::env::var("TARGET").unwrap()
); );
} }

View File

@@ -3,74 +3,49 @@ use std::path::PathBuf;
pub const C_ASSET_PATH: &str = concat!( pub const C_ASSET_PATH: &str = concat!(
env!("CARGO_MANIFEST_DIR"), env!("CARGO_MANIFEST_DIR"),
"/../../../lib/c-api/examples/assets" "/../../../lib/c-api/examples/assets/"
); );
pub const ASSET_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../tests/examples"); pub const ASSET_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../tests/examples/");
pub const WASMER_INCLUDE_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../lib/c-api"); pub const WASMER_INCLUDE_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../lib/c-api/");
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
pub const WASMER_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../target/debug/wasmer"); pub const WASMER_TARGET_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../target/debug/");
#[cfg(not(feature = "debug"))]
pub const WASMER_PATH: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../../target/release/wasmer"
);
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
pub const WASMER_TARGET_PATH: &str = concat!( pub const WASMER_TARGET_PATH_2: &str = concat!(
env!("CARGO_MANIFEST_DIR"), env!("CARGO_MANIFEST_DIR"),
"/../../../", "/../../../target/",
env!("CARGO_CFG_TARGET"), env!("CARGO_BUILD_TARGET"),
"/debug/wasmer" "/debug/"
); );
/* env var TARGET is set by tests/integration/cli/build.rs on compile-time */ /* env var TARGET is set by tests/integration/cli/build.rs on compile-time */
#[cfg(not(feature = "debug"))] #[cfg(not(feature = "debug"))]
pub const WASMER_TARGET_PATH: &str = concat!( pub const WASMER_TARGET_PATH: &str =
concat!(env!("CARGO_MANIFEST_DIR"), "/../../../target/release/");
#[cfg(not(feature = "debug"))]
pub const WASMER_TARGET_PATH2: &str = concat!(
env!("CARGO_MANIFEST_DIR"), env!("CARGO_MANIFEST_DIR"),
"/../../../target/", "/../../../target/",
env!("TARGET"), env!("CARGO_BUILD_TARGET"),
"/release/wasmer" "/release/"
); );
#[cfg(not(windows))] #[cfg(not(windows))]
pub const LIBWASMER_PATH: &str = concat!( pub const LIBWASMER_FILENAME: &str = "libwasmer.a";
env!("CARGO_MANIFEST_DIR"),
"/../../../target/release/libwasmer.a"
);
#[cfg(windows)] #[cfg(windows)]
pub const LIBWASMER_PATH: &str = concat!( pub const LIBWASMER_PATH: &str = "wasmer.lib";
env!("CARGO_MANIFEST_DIR"),
"/../../../target/release/wasmer.lib"
);
#[cfg(not(windows))]
pub const LIBWASMER_TARGET_PATH: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../../target",
env!("TARGET"),
"/release/libwasmer.a"
);
#[cfg(windows)]
pub const LIBWASMER_TARGET_PATH: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../../",
env!("TARGET"),
"/release/wasmer.lib"
);
/// Get the path to the `libwasmer.a` static library. /// Get the path to the `libwasmer.a` static library.
pub fn get_libwasmer_path() -> PathBuf { pub fn get_libwasmer_path() -> PathBuf {
let mut ret = PathBuf::from( let mut ret = PathBuf::from(
env::var("WASMER_TEST_LIBWASMER_PATH").unwrap_or_else(|_| LIBWASMER_PATH.to_string()), env::var("WASMER_TEST_LIBWASMER_PATH")
.unwrap_or_else(|_| format!("{}{}", WASMER_TARGET_PATH, LIBWASMER_FILENAME)),
); );
if !ret.exists() { if !ret.exists() {
ret = PathBuf::from(LIBWASMER_TARGET_PATH.to_string()); ret = PathBuf::from(format!("{}{}", WASMER_TARGET_PATH2, LIBWASMER_FILENAME));
} }
if !ret.exists() { if !ret.exists() {
panic!("Could not find libwasmer path! {:?}", ret); panic!("Could not find libwasmer path! {:?}", ret);
@@ -81,10 +56,11 @@ pub fn get_libwasmer_path() -> PathBuf {
/// Get the path to the `wasmer` executable to be used in this test. /// Get the path to the `wasmer` executable to be used in this test.
pub fn get_wasmer_path() -> PathBuf { pub fn get_wasmer_path() -> PathBuf {
let mut ret = PathBuf::from( let mut ret = PathBuf::from(
env::var("WASMER_TEST_WASMER_PATH").unwrap_or_else(|_| WASMER_PATH.to_string()), env::var("WASMER_TEST_WASMER_PATH")
.unwrap_or_else(|_| format!("{}wasmer", WASMER_TARGET_PATH)),
); );
if !ret.exists() { if !ret.exists() {
ret = PathBuf::from(WASMER_TARGET_PATH.to_string()); ret = PathBuf::from(format!("{}wasmer", WASMER_TARGET_PATH2));
} }
if !ret.exists() { if !ret.exists() {
panic!("Could not find wasmer executable path! {:?}", ret); panic!("Could not find wasmer executable path! {:?}", ret);

View File

@@ -26,6 +26,8 @@ struct WasmerCreateExe {
native_executable_path: PathBuf, native_executable_path: PathBuf,
/// Compiler with which to compile the Wasm. /// Compiler with which to compile the Wasm.
compiler: Compiler, compiler: Compiler,
/// Extra CLI flags
extra_cli_flags: Vec<&'static str>,
} }
impl Default for WasmerCreateExe { impl Default for WasmerCreateExe {
@@ -40,17 +42,19 @@ impl Default for WasmerCreateExe {
wasm_path: PathBuf::from(create_exe_test_wasm_path()), wasm_path: PathBuf::from(create_exe_test_wasm_path()),
native_executable_path, native_executable_path,
compiler: Compiler::Cranelift, compiler: Compiler::Cranelift,
extra_cli_flags: vec![],
} }
} }
} }
impl WasmerCreateExe { impl WasmerCreateExe {
fn run(&self) -> anyhow::Result<()> { fn run(&self) -> anyhow::Result<Vec<u8>> {
let output = Command::new(&self.wasmer_path) let output = Command::new(&self.wasmer_path)
.current_dir(&self.current_dir) .current_dir(&self.current_dir)
.arg("create-exe") .arg("create-exe")
.arg(&self.wasm_path.canonicalize()?) .arg(&self.wasm_path.canonicalize()?)
.arg(&self.compiler.to_flag()) .arg(&self.compiler.to_flag())
.args(self.extra_cli_flags.iter())
.arg("-o") .arg("-o")
.arg(&self.native_executable_path) .arg(&self.native_executable_path)
.output()?; .output()?;
@@ -64,7 +68,66 @@ impl WasmerCreateExe {
.expect("stderr is not utf8! need to handle arbitrary bytes") .expect("stderr is not utf8! need to handle arbitrary bytes")
); );
} }
Ok(()) Ok(output.stdout)
}
}
/// Data used to run the `wasmer compile` command.
#[derive(Debug)]
struct WasmerCreateObj {
/// The directory to operate in.
current_dir: PathBuf,
/// Path to wasmer executable used to run the command.
wasmer_path: PathBuf,
/// Path to the Wasm file to compile.
wasm_path: PathBuf,
/// Path to the object file produced by compiling the Wasm.
output_object_path: PathBuf,
/// Compiler with which to compile the Wasm.
compiler: Compiler,
/// Extra CLI flags
extra_cli_flags: Vec<&'static str>,
}
impl Default for WasmerCreateObj {
fn default() -> Self {
#[cfg(not(windows))]
let output_object_path = PathBuf::from("wasm.o");
#[cfg(windows)]
let output_object_path = PathBuf::from("wasm.obj");
Self {
current_dir: std::env::current_dir().unwrap(),
wasmer_path: get_wasmer_path(),
wasm_path: PathBuf::from(create_exe_test_wasm_path()),
output_object_path,
compiler: Compiler::Cranelift,
extra_cli_flags: vec![],
}
}
}
impl WasmerCreateObj {
fn run(&self) -> anyhow::Result<Vec<u8>> {
let output = Command::new(&self.wasmer_path)
.current_dir(&self.current_dir)
.arg("create-obj")
.arg(&self.wasm_path.canonicalize()?)
.arg(&self.compiler.to_flag())
.args(self.extra_cli_flags.iter())
.arg("-o")
.arg(&self.output_object_path)
.output()?;
if !output.status.success() {
bail!(
"wasmer create-obj failed with: stdout: {}\n\nstderr: {}",
std::str::from_utf8(&output.stdout)
.expect("stdout is not utf8! need to handle arbitrary bytes"),
std::str::from_utf8(&output.stderr)
.expect("stderr is not utf8! need to handle arbitrary bytes")
);
}
Ok(output.stdout)
} }
} }
@@ -160,3 +223,187 @@ fn create_exe_works_with_file() -> anyhow::Result<()> {
Ok(()) Ok(())
} }
#[test]
fn create_exe_serialized_works() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_test_wasm_path());
#[cfg(not(windows))]
let executable_path = operating_dir.join("wasm.out");
#[cfg(windows)]
let executable_path = operating_dir.join("wasm.exe");
let output: Vec<u8> = WasmerCreateExe {
current_dir: operating_dir.clone(),
wasm_path,
native_executable_path: executable_path.clone(),
compiler: Compiler::Cranelift,
extra_cli_flags: vec!["--object-format", "serialized"],
..Default::default()
}
.run()
.context("Failed to create-exe wasm with Wasmer")?;
let result = run_code(
&operating_dir,
&executable_path,
&["--eval".to_string(), "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));".to_string()],
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
assert_eq!(result_lines, vec!["\"Hello, World\""],);
let output_str = String::from_utf8_lossy(&output);
assert!(
output_str.contains("Serialized"),
"create-exe output doesn't mention `serialized` format keyword:\n{}",
output_str
);
Ok(())
}
fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_test_wasm_path());
#[cfg(not(windows))]
let object_path = operating_dir.join("wasm.o");
#[cfg(windows)]
let object_path = operating_dir.join("wasm.obj");
let output: Vec<u8> = WasmerCreateObj {
current_dir: operating_dir.clone(),
wasm_path,
output_object_path: object_path.clone(),
compiler: Compiler::Cranelift,
extra_cli_flags: args,
..Default::default()
}
.run()
.context("Failed to create-obj wasm with Wasmer")?;
assert!(
object_path.exists(),
"create-obj successfully completed but object output file `{}` missing",
object_path.display()
);
let mut object_header_path = object_path.clone();
object_header_path.set_extension("h");
assert!(
object_header_path.exists(),
"create-obj successfully completed but object output header file `{}` missing",
object_header_path.display()
);
let output_str = String::from_utf8_lossy(&output);
assert!(
output_str.contains(keyword_needle),
"create-obj output doesn't mention `{}` format keyword:\n{}",
keyword,
output_str
);
Ok(())
}
#[test]
fn create_obj_default() -> anyhow::Result<()> {
create_obj(vec![], "Symbols", "symbols")
}
#[test]
fn create_obj_symbols() -> anyhow::Result<()> {
create_obj(vec!["--object-format", "symbols"], "Symbols", "symbols")
}
#[test]
fn create_obj_serialized() -> anyhow::Result<()> {
create_obj(
vec!["--object-format", "serialized"],
"Serialized",
"serialized",
)
}
fn create_exe_with_object_input(args: Vec<&'static str>) -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_test_wasm_path());
#[cfg(not(windows))]
let object_path = operating_dir.join("wasm.o");
#[cfg(windows)]
let object_path = operating_dir.join("wasm.obj");
WasmerCreateObj {
current_dir: operating_dir.clone(),
wasm_path,
output_object_path: object_path.clone(),
compiler: Compiler::Cranelift,
extra_cli_flags: args,
..Default::default()
}
.run()
.context("Failed to create-obj wasm with Wasmer")?;
assert!(
object_path.exists(),
"create-obj successfully completed but object output file `{}` missing",
object_path.display()
);
let mut object_header_path = object_path.clone();
object_header_path.set_extension("h");
assert!(
object_header_path.exists(),
"create-obj successfully completed but object output header file `{}` missing",
object_header_path.display()
);
#[cfg(not(windows))]
let executable_path = operating_dir.join("wasm.out");
#[cfg(windows)]
let executable_path = operating_dir.join("wasm.exe");
WasmerCreateExe {
current_dir: operating_dir.clone(),
wasm_path: object_path,
native_executable_path: executable_path.clone(),
compiler: Compiler::Cranelift,
extra_cli_flags: vec!["--header", "wasm.h"],
..Default::default()
}
.run()
.context("Failed to create-exe wasm with Wasmer")?;
let result = run_code(
&operating_dir,
&executable_path,
&["--eval".to_string(), "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));".to_string()],
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
assert_eq!(result_lines, vec!["\"Hello, World\""],);
Ok(())
}
#[test]
fn create_exe_with_object_input_default() -> anyhow::Result<()> {
create_exe_with_object_input(vec![])
}
#[test]
fn create_exe_with_object_input_symbols() -> anyhow::Result<()> {
create_exe_with_object_input(vec!["--object-format", "symbols"])
}
#[test]
fn create_exe_with_object_input_serialized() -> anyhow::Result<()> {
create_exe_with_object_input(vec!["--object-format", "serialized"])
}

View File

@@ -2,7 +2,7 @@
use anyhow::bail; use anyhow::bail;
use std::process::Command; use std::process::Command;
use wasmer_integration_tests_cli::{ASSET_PATH, C_ASSET_PATH, WASMER_PATH}; use wasmer_integration_tests_cli::{get_wasmer_path, ASSET_PATH, C_ASSET_PATH};
fn wasi_test_wasm_path() -> String { fn wasi_test_wasm_path() -> String {
format!("{}/{}", C_ASSET_PATH, "qjs.wasm") format!("{}/{}", C_ASSET_PATH, "qjs.wasm")
@@ -18,7 +18,7 @@ fn test_no_start_wat_path() -> String {
#[test] #[test]
fn run_wasi_works() -> anyhow::Result<()> { fn run_wasi_works() -> anyhow::Result<()> {
let output = Command::new(WASMER_PATH) let output = Command::new(get_wasmer_path())
.arg("run") .arg("run")
.arg(wasi_test_wasm_path()) .arg(wasi_test_wasm_path())
.arg("--") .arg("--")
@@ -44,7 +44,7 @@ fn run_wasi_works() -> anyhow::Result<()> {
#[test] #[test]
fn run_no_imports_wasm_works() -> anyhow::Result<()> { fn run_no_imports_wasm_works() -> anyhow::Result<()> {
let output = Command::new(WASMER_PATH) let output = Command::new(get_wasmer_path())
.arg("run") .arg("run")
.arg(test_no_imports_wat_path()) .arg(test_no_imports_wat_path())
.output()?; .output()?;
@@ -82,7 +82,7 @@ fn run_invoke_works_with_nomain_wasi() -> anyhow::Result<()> {
let random = rand::random::<u64>(); let random = rand::random::<u64>();
let module_file = std::env::temp_dir().join(&format!("{random}.wat")); let module_file = std::env::temp_dir().join(&format!("{random}.wat"));
std::fs::write(&module_file, wasi_wat.as_bytes()).unwrap(); std::fs::write(&module_file, wasi_wat.as_bytes()).unwrap();
let output = Command::new(WASMER_PATH) let output = Command::new(get_wasmer_path())
.arg("run") .arg("run")
.arg(&module_file) .arg(&module_file)
.output()?; .output()?;
@@ -94,7 +94,7 @@ fn run_invoke_works_with_nomain_wasi() -> anyhow::Result<()> {
panic!(); panic!();
} }
let output = Command::new(WASMER_PATH) let output = Command::new(get_wasmer_path())
.arg("run") .arg("run")
.arg("--invoke") .arg("--invoke")
.arg("_start") .arg("_start")
@@ -114,7 +114,7 @@ fn run_invoke_works_with_nomain_wasi() -> anyhow::Result<()> {
#[test] #[test]
fn run_no_start_wasm_report_error() -> anyhow::Result<()> { fn run_no_start_wasm_report_error() -> anyhow::Result<()> {
let output = Command::new(WASMER_PATH) let output = Command::new(get_wasmer_path())
.arg("run") .arg("run")
.arg(test_no_start_wat_path()) .arg(test_no_start_wat_path())
.output()?; .output()?;

View File

@@ -1,16 +1,17 @@
use anyhow::bail; use anyhow::bail;
use std::process::Command; use std::process::Command;
use wasmer_integration_tests_cli::WASMER_PATH; use wasmer_integration_tests_cli::get_wasmer_path;
const WASMER_VERSION: &str = env!("CARGO_PKG_VERSION"); const WASMER_VERSION: &str = env!("CARGO_PKG_VERSION");
#[test] #[test]
fn version_string_is_correct() -> anyhow::Result<()> { fn version_string_is_correct() -> anyhow::Result<()> {
let expected_version_output = format!("wasmer {}\n", WASMER_VERSION); let expected_version_output = format!("wasmer {}\n", WASMER_VERSION);
let wasmer_path = get_wasmer_path();
let outputs = [ let outputs = [
Command::new(WASMER_PATH).arg("--version").output()?, Command::new(&wasmer_path).arg("--version").output()?,
Command::new(WASMER_PATH).arg("-V").output()?, Command::new(&wasmer_path).arg("-V").output()?,
]; ];
for output in &outputs { for output in &outputs {
@@ -34,10 +35,11 @@ fn version_string_is_correct() -> anyhow::Result<()> {
#[test] #[test]
fn help_text_contains_version() -> anyhow::Result<()> { fn help_text_contains_version() -> anyhow::Result<()> {
let expected_version_output = format!("wasmer {}", WASMER_VERSION); let expected_version_output = format!("wasmer {}", WASMER_VERSION);
let wasmer_path = get_wasmer_path();
let outputs = [ let outputs = [
Command::new(WASMER_PATH).arg("--help").output()?, Command::new(&wasmer_path).arg("--help").output()?,
Command::new(WASMER_PATH).arg("-h").output()?, Command::new(&wasmer_path).arg("-h").output()?,
]; ];
for output in &outputs { for output in &outputs {