Merge branch 'master' into feature/arm-tests

This commit is contained in:
Syrus Akbary 2020-03-30 14:20:46 -07:00 committed by GitHub
commit c9113ea6ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 3563 additions and 1999 deletions

View File

@ -45,6 +45,10 @@ steps:
rustup default $RUST_TOOLCHAIN
rustup target add x86_64-unknown-linux-musl
if [ -n "$ANDROID" ]; then
rustup target add x86_64-linux-android --toolchain $RUST_TOOLCHAIN
fi
rustc -Vv
cargo -V
displayName: Install Rust

4
.gitignore vendored
View File

@ -8,3 +8,7 @@ install/
capi/
api-docs/
api-docs-repo/
# Generated by tests on Android
/avd
/core

View File

@ -2,6 +2,12 @@
## **[Unreleased]**
- [#1335](https://github.com/wasmerio/wasmer/pull/1335) Change mutability of `memory` to `const` in `wasmer_memory_data_length` in the C API
- [#1329](https://github.com/wasmerio/wasmer/pull/1329) New numbers and strings instructions for WIT
- [#1332](https://github.com/wasmerio/wasmer/pull/1332) Add option to `CompilerConfig` to force compiler IR verification off even when `debug_assertions` are enabled. This can be used to make debug builds faster, which may be important if you're creating a library that wraps Wasmer and depend on the speed of debug builds.
- [#1320](https://github.com/wasmerio/wasmer/pull/1320) Change `custom_sections` field in `ModuleInfo` to be more standards compliant by allowing multiple custom sections with the same name. To get the old behavior with the new API, you can add `.last().unwrap()` to accesses. For example, `module_info.custom_sections["custom_section_name"].last().unwrap()`.
- [#1303](https://github.com/wasmerio/wasmer/pull/1303) NaN canonicalization for singlepass backend.
- [#1292](https://github.com/wasmerio/wasmer/pull/1292) Experimental Support for Android (x86_64 and AArch64)
- [#1305](https://github.com/wasmerio/wasmer/pull/1305) Handle panics from DynamicFunc.
- [#1301](https://github.com/wasmerio/wasmer/pull/1301) Update supported stable Rust version to 1.41.1.
- [#1300](https://github.com/wasmerio/wasmer/pull/1300) Add support for multiple versions of WASI tests: wasitests now test all versions of WASI.

263
Cargo.lock generated
View File

@ -111,6 +111,12 @@ dependencies = [
"serde",
]
[[package]]
name = "bumpalo"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742"
[[package]]
name = "byteorder"
version = "1.3.4"
@ -231,7 +237,7 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a9c21f8042b9857bda93f6c1910b9f9f24100187a3d3d52f214a34e3dc5818"
dependencies = [
"cranelift-entity 0.59.0",
"cranelift-entity",
]
[[package]]
@ -244,11 +250,11 @@ dependencies = [
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"cranelift-entity 0.59.0",
"cranelift-entity",
"gimli",
"log",
"smallvec 1.2.0",
"target-lexicon 0.10.0",
"smallvec",
"target-lexicon",
"thiserror",
]
@ -259,7 +265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "084cd6d5fb0d1da28acd72c199471bfb09acc703ec8f3bf07b1699584272a3b9"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity 0.59.0",
"cranelift-entity",
]
[[package]]
@ -268,12 +274,6 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "701b599783305a58c25027a4d73f2d6b599b2d8ef3f26677275f480b4d51e05d"
[[package]]
name = "cranelift-entity"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "722957e05064d97a3157bf0976deed0f3e8ee4f8a4ce167a7c724ca63a4e8bd9"
[[package]]
name = "cranelift-entity"
version = "0.59.0"
@ -288,14 +288,14 @@ checksum = "32daf082da21c0c05d93394ff4842c2ab7c4991b1f3186a1d952f8ac660edd0b"
dependencies = [
"cranelift-codegen",
"raw-cpuid",
"target-lexicon 0.10.0",
"target-lexicon",
]
[[package]]
name = "criterion"
version = "0.2.11"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394"
checksum = "1fc755679c12bda8e5523a71e4d654b6bf2e14bd838dfc48cde6559a05caf7d1"
dependencies = [
"atty",
"cast",
@ -304,13 +304,11 @@ dependencies = [
"csv",
"itertools",
"lazy_static",
"libc",
"num-traits",
"rand_core 0.3.1",
"rand_os",
"rand_xoshiro",
"oorandom",
"plotters",
"rayon",
"rayon-core",
"regex",
"serde",
"serde_derive",
"serde_json",
@ -320,11 +318,10 @@ dependencies = [
[[package]]
name = "criterion-plot"
version = "0.3.1"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e"
checksum = "a01e15e0ea58e8234f96146b1f91fa9d0e4dd7a38da93ff7a75d42c0b9d3a545"
dependencies = [
"byteorder",
"cast",
"itertools",
]
@ -490,17 +487,17 @@ dependencies = [
[[package]]
name = "faerie"
version = "0.13.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f902f2af041f6c7177a2a04f805687cdc71e69c7cbef059a2755d8923f4cd7a8"
checksum = "74b9ed6159e4a6212c61d9c6a86bee01876b192a64accecf58d5b5ae3b667b52"
dependencies = [
"anyhow",
"goblin 0.1.3",
"goblin",
"indexmap",
"log",
"scroll 0.10.1",
"scroll",
"string-interner",
"target-lexicon 0.9.0",
"target-lexicon",
"thiserror",
]
@ -584,7 +581,7 @@ dependencies = [
"byteorder",
"fallible-iterator",
"indexmap",
"smallvec 1.2.0",
"smallvec",
"stable_deref_trait",
]
@ -600,17 +597,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "goblin"
version = "0.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0"
dependencies = [
"log",
"plain",
"scroll 0.9.2",
]
[[package]]
name = "goblin"
version = "0.1.3"
@ -619,7 +605,7 @@ checksum = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da"
dependencies = [
"log",
"plain",
"scroll 0.10.1",
"scroll",
]
[[package]]
@ -717,6 +703,15 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
[[package]]
name = "js-sys"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cb931d43e71f560c81badb0191596562bafad2be06a3f9025b845c847c60df5"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kernel-net"
version = "0.1.0"
@ -748,9 +743,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.67"
version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
[[package]]
name = "llvm-sys"
@ -927,6 +922,12 @@ version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
[[package]]
name = "oorandom"
version = "11.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebcec7c9c2a95cacc7cd0ecb89d8a8454eca13906f6deb55258ffff0adeb9405"
[[package]]
name = "orbclient"
version = "0.3.27"
@ -994,7 +995,7 @@ dependencies = [
"cloudabi",
"libc",
"redox_syscall",
"smallvec 1.2.0",
"smallvec",
"winapi",
]
@ -1010,6 +1011,18 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "plotters"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e3bb8da247d27ae212529352020f3e5ee16e83c0c258061d27b08ab92675eeb"
dependencies = [
"js-sys",
"num-traits",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plugin-for-example"
version = "0.1.0"
@ -1229,16 +1242,6 @@ dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_xoshiro"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929"
dependencies = [
"byteorder",
"rand_core 0.3.1",
]
[[package]]
name = "raw-cpuid"
version = "7.0.3"
@ -1361,34 +1364,13 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scroll"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383"
dependencies = [
"rustc_version",
"scroll_derive 0.9.5",
]
[[package]]
name = "scroll"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1"
dependencies = [
"scroll_derive 0.10.1",
]
[[package]]
name = "scroll_derive"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
"scroll_derive",
]
[[package]]
@ -1491,15 +1473,6 @@ dependencies = [
"serde",
]
[[package]]
name = "smallvec"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
dependencies = [
"maybe-uninit",
]
[[package]]
name = "smallvec"
version = "1.2.0"
@ -1596,12 +1569,6 @@ dependencies = [
"syn 1.0.16",
]
[[package]]
name = "target-lexicon"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f4c118a7a38378f305a9e111fcb2f7f838c0be324bfb31a77ea04f7f6e684b4"
[[package]]
name = "target-lexicon"
version = "0.10.0"
@ -1776,9 +1743,9 @@ dependencies = [
[[package]]
name = "wabt-sys"
version = "0.7.0"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08"
checksum = "23d7043ebb3e5d96fad7a8d3ca22ee9880748ff8c3e18092cfb2a49d3b8f9084"
dependencies = [
"cc",
"cmake",
@ -1803,19 +1770,73 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm-debug"
version = "0.1.0"
name = "wasm-bindgen"
version = "0.2.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86840eccceaf682e29be7810dcae5785b9c3b0349ce44d3eaecd9e50f893aee0"
checksum = "3557c397ab5a8e347d434782bcd31fc1483d927a6826804cec05cc792ee2519d"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0da9c9a19850d3af6df1cb9574970b566d617ecfaf36eb0b706b6f3ef9bd2f8"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2 1.0.9",
"quote 1.0.2",
"syn 1.0.16",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f6fde1d36e75a714b5fe0cffbb78978f222ea6baebb726af13c78869fdb4205"
dependencies = [
"quote 1.0.2",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25bda4168030a6412ea8a047e27238cadf56f0e53516e1e83fec0a8b7c786f6d"
dependencies = [
"proc-macro2 1.0.9",
"quote 1.0.2",
"syn 1.0.16",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc9f36ad51f25b0219a3d4d13b90eb44cd075dff8b6280cca015775d7acaddd8"
[[package]]
name = "wasm-debug"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de430168172db11a702b873514492de62c30cdfbf4e46cc8ad4a54c3b8a7506"
dependencies = [
"anyhow",
"cranelift-entity 0.52.0",
"cranelift-entity",
"faerie",
"gimli",
"more-asserts",
"target-lexicon 0.9.0",
"target-lexicon",
"thiserror",
"wasmparser 0.39.3",
"wasmparser",
]
[[package]]
@ -1855,7 +1876,7 @@ version = "0.16.2"
dependencies = [
"byteorder",
"cranelift-codegen",
"cranelift-entity 0.59.0",
"cranelift-entity",
"cranelift-native",
"libc",
"nix",
@ -1864,13 +1885,13 @@ dependencies = [
"serde-bench",
"serde_bytes",
"serde_derive",
"target-lexicon 0.10.0",
"target-lexicon",
"wasm-debug",
"wasmer-clif-fork-frontend",
"wasmer-clif-fork-wasm",
"wasmer-runtime-core",
"wasmer-win-exception-handler",
"wasmparser 0.51.4",
"wasmparser",
"winapi",
]
@ -1882,8 +1903,8 @@ checksum = "c23f2824f354a00a77e4b040eef6e1d4c595a8a3e9013bad65199cc8dade9a5a"
dependencies = [
"cranelift-codegen",
"log",
"smallvec 1.2.0",
"target-lexicon 0.10.0",
"smallvec",
"target-lexicon",
]
[[package]]
@ -1893,11 +1914,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a35e21d3aebc51cc6ebc0e830cf8458a9891c3482fb3c65ad18d408102929ae5"
dependencies = [
"cranelift-codegen",
"cranelift-entity 0.59.0",
"cranelift-entity",
"log",
"thiserror",
"wasmer-clif-fork-frontend",
"wasmparser 0.51.4",
"wasmparser",
]
[[package]]
@ -1956,7 +1977,7 @@ version = "0.16.2"
dependencies = [
"byteorder",
"cc",
"goblin 0.0.24",
"goblin",
"inkwell",
"lazy_static",
"libc",
@ -1964,10 +1985,10 @@ dependencies = [
"regex",
"rustc_version",
"semver",
"smallvec 0.6.13",
"smallvec",
"wabt",
"wasmer-runtime-core",
"wasmparser 0.51.4",
"wasmparser",
"winapi",
]
@ -2051,10 +2072,10 @@ dependencies = [
"serde-bench",
"serde_bytes",
"serde_derive",
"smallvec 0.6.13",
"target-lexicon 0.9.0",
"smallvec",
"target-lexicon",
"wasm-debug",
"wasmparser 0.51.4",
"wasmparser",
"winapi",
]
@ -2082,7 +2103,7 @@ dependencies = [
"nix",
"serde",
"serde_derive",
"smallvec 0.6.13",
"smallvec",
"wasmer-runtime-core",
]
@ -2146,18 +2167,12 @@ dependencies = [
name = "wasmer-win-exception-handler"
version = "0.16.2"
dependencies = [
"cmake",
"cc",
"libc",
"wasmer-runtime-core",
"winapi",
]
[[package]]
name = "wasmparser"
version = "0.39.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470"
[[package]]
name = "wasmparser"
version = "0.51.4"
@ -2173,6 +2188,16 @@ dependencies = [
"leb128",
]
[[package]]
name = "web-sys"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "721c6263e2c66fd44501cc5efbfa2b7dfa775d13e4ea38c46299646ed1f9c70a"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.8"

View File

@ -172,6 +172,9 @@ test-rest:
test: spectests emtests middleware wasitests test-rest examples
test-android:
ci/run-docker.sh x86_64-linux-android --manifest-path=lib/singlepass-backend/Cargo.toml
ci/run-docker.sh x86_64-linux-android --manifest-path=lib/runtime-core-tests/Cargo.toml
# Integration tests
integration-tests: release-clif examples
@ -322,7 +325,7 @@ ifeq ($(OS), Windows_NT)
else
ifeq ($(UNAME_S), Darwin)
cp target/release/libwasmer_runtime_c_api.dylib ./capi/lib/libwasmer.dylib
cp target/release/libwasmer_runtime_c_api.dylib ./capi/lib/libwasmer.a
cp target/release/libwasmer_runtime_c_api.a ./capi/lib/libwasmer.a
# Fix the rpath for the dylib
install_name_tool -id "@rpath/libwasmer.dylib" ./capi/lib/libwasmer.dylib
else

View File

@ -46,6 +46,10 @@ jobs:
linux:
imageName: "ubuntu-16.04"
rust_toolchain: nightly-2019-12-19
android:
imageName: "ubuntu-16.04"
rust_toolchain: nightly-2019-12-19
ANDROID: true
mac:
imageName: "macos-10.14"
rust_toolchain: nightly-2019-12-19
@ -81,13 +85,16 @@ jobs:
condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
- bash: make test
displayName: Tests (*nix)
condition: and(succeeded(), eq(variables['Agent.OSArchitecture'], 'X64'), not(eq(variables['Agent.OS'], 'Windows_NT')))
condition: and(succeeded(), eq(variables['Agent.OSArchitecture'], 'X64'), not(eq(variables['Agent.OS'], 'Windows_NT')), not(variables['ANDROID']))
- bash: make spectests-singlepass
displayName: Tests (Linux ARM)
condition: and(succeeded(), eq(variables['Agent.OSArchitecture'], 'ARM64'))
condition: and(succeeded(), eq(variables['Agent.OSArchitecture'], 'ARM64'), not(variables['ANDROID']))
- bash: make test-android
displayName: Tests (Android)
condition: and(succeeded(), variables['ANDROID'])
- bash: make spectests-cranelift
displayName: Tests (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), not(variables['ANDROID']))
- job: Check
pool:

3
ci/README.md Normal file
View File

@ -0,0 +1,3 @@
# About this directory
This directory is originally copied from [rust-lang/libc/ci](https://github.com/rust-lang/libc/tree/master/ci).

19
ci/android-install-ndk.sh Normal file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env sh
# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
NDK=android-ndk-r19c
curl --retry 20 -O https://dl.google.com/android/repository/${NDK}-linux-x86_64.zip
unzip -q -d ndk ${NDK}-linux-x86_64.zip
mv ./ndk/"$NDK"/* ./ndk/
rm -rf ./${NDK}-linux-x86_64.zip

73
ci/android-install-sdk.sh Normal file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env sh
# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
# Prep the SDK and emulator
#
# Note that the update process requires that we accept a bunch of licenses, and
# we can't just pipe `yes` into it for some reason, so we take the same strategy
# located in https://github.com/appunite/docker by just wrapping it in a script
# which apparently magically accepts the licenses.
SDK=4333796
mkdir sdk
curl --retry 20 https://dl.google.com/android/repository/sdk-tools-linux-${SDK}.zip -O
unzip -q -d sdk sdk-tools-linux-${SDK}.zip
case "$1" in
arm | armv7)
api=24
image="system-images;android-${api};google_apis;armeabi-v7a"
;;
aarch64)
api=24
image="system-images;android-${api};google_apis;arm64-v8a"
;;
i686)
api=28
image="system-images;android-${api};default;x86"
;;
x86_64)
api=28
image="system-images;android-${api};default;x86_64"
;;
*)
echo "invalid arch: $1"
exit 1
;;
esac;
# Try to fix warning about missing file.
# See https://askubuntu.com/a/1078784
mkdir -p /root/.android/
echo '### User Sources for Android SDK Manager' >> /root/.android/repositories.cfg
echo '#Fri Nov 03 10:11:27 CET 2017 count=0' >> /root/.android/repositories.cfg
# Print all available packages
# yes | ./sdk/tools/bin/sdkmanager --list --verbose
# --no_https avoids
# javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
#
# | grep -v = || true removes the progress bar output from the sdkmanager
# which produces an insane amount of output.
yes | ./sdk/tools/bin/sdkmanager --licenses --no_https | grep -v = || true
yes | ./sdk/tools/bin/sdkmanager --no_https \
"emulator" \
"platform-tools" \
"platforms;android-${api}" \
"${image}" | grep -v = || true
echo "no" |
./sdk/tools/bin/avdmanager create avd \
--name "${1}" \
--package "${image}" | grep -v = || true

56
ci/android-sysimage.sh Normal file
View File

@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -ex
URL=https://dl.google.com/android/repository/sys-img/android
main() {
local arch="${1}"
local name="${2}"
local dest=/system
local td
td="$(mktemp -d)"
apt-get install --no-install-recommends e2tools
pushd "${td}"
curl --retry 5 -O "${URL}/${name}"
unzip -q "${name}"
local system
system="$(find . -name system.img)"
mkdir -p ${dest}/{bin,lib,lib64}
# Extract android linker and libraries to /system
# This allows android executables to be run directly (or with qemu)
if [ "${arch}" = "x86_64" ] || [ "${arch}" = "arm64" ]; then
e2cp -p "${system}:/bin/linker64" "${dest}/bin/"
e2cp -p "${system}:/lib64/libdl.so" "${dest}/lib64/"
e2cp -p "${system}:/lib64/libc.so" "${dest}/lib64/"
e2cp -p "${system}:/lib64/libm.so" "${dest}/lib64/"
else
e2cp -p "${system}:/bin/linker" "${dest}/bin/"
e2cp -p "${system}:/lib/libdl.so" "${dest}/lib/"
e2cp -p "${system}:/lib/libc.so" "${dest}/lib/"
e2cp -p "${system}:/lib/libm.so" "${dest}/lib/"
fi
# clean up
apt-get purge --auto-remove -y e2tools
popd
rm -rf "${td}"
}
main "${@}"

View File

@ -0,0 +1,53 @@
FROM ubuntu:19.04
RUN dpkg --add-architecture i386 && \
apt-get update && \
apt-get install -y --no-install-recommends \
file \
curl \
ca-certificates \
python \
unzip \
expect \
openjdk-8-jre \
libstdc++6:i386 \
libpulse0 \
gcc \
libc6-dev \
make \
cmake # cmake is necessary to build wabt
WORKDIR /android/
COPY android* /android/
ENV ANDROID_ARCH=aarch64
ENV PATH=$PATH:/android/sdk/tools:/android/sdk/platform-tools
RUN sh /android/android-install-ndk.sh $ANDROID_ARCH
RUN sh /android/android-install-sdk.sh $ANDROID_ARCH
ENV ANDROID_NDK_HOME=/android/ndk
RUN mv /root/.android /tmp
RUN chmod 777 -R /tmp/.android
RUN chmod 755 /android/sdk/tools/* /android/sdk/emulator/qemu/linux-x86_64/*
ENV PATH=$PATH:/rust/bin:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin \
CARGO_TARGET_AARCH64_LINUX_ANDROID_AR=aarch64-linux-android-ar \
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android28-clang++ \
CC_aarch64_linux_android=aarch64-linux-android28-clang \
CXX_aarch64_linux_android=aarch64-linux-android28-clang++ \
CARGO_TARGET_AARCH64_LINUX_ANDROID_RUNNER=/tmp/runtest \
HOME=/tmp
ADD runtest-android.rs /tmp/runtest.rs
ENTRYPOINT [ \
"bash", \
"-c", \
# set SHELL so android can detect a 64bits system, see
# http://stackoverflow.com/a/41789144
"SHELL=/bin/dash /android/sdk/emulator/emulator @aarch64 -no-window & \
rustc /tmp/runtest.rs -o /tmp/runtest && \
exec \"$@\"", \
"--" \
]

View File

@ -0,0 +1,31 @@
FROM ubuntu:19.04
RUN apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
curl \
gcc \
libc-dev \
python \
unzip \
make \
cmake # cmake is necessary to build wabt
WORKDIR /android/
ENV ANDROID_ARCH=x86_64
COPY android-install-ndk.sh /android/
RUN sh /android/android-install-ndk.sh $ANDROID_ARCH
ENV ANDROID_NDK_HOME=/android/ndk/
# We do not run x86_64-linux-android tests on an android emulator.
# See ci/android-sysimage.sh for informations about how tests are run.
COPY android-sysimage.sh /android/
RUN bash /android/android-sysimage.sh x86_64 x86_64-24_r07.zip
ENV PATH=$PATH:/rust/bin:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin \
CARGO_TARGET_X86_64_LINUX_ANDROID_AR=x86_64-linux-android-ar \
CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=x86_64-linux-android28-clang++ \
CC_x86_64_linux_android=x86_64-linux-android28-clang \
CXX_x86_64_linux_android=x86_64-linux-android28-clang++ \
LD_LIBRARY_PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/ \
HOME=/tmp

35
ci/run-docker.sh Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env sh
# Small script to run tests for a target (or all targets) inside all the
# respective docker images.
set -e
echo "${HOME}"
pwd
TARGET="${1}"
shift
echo "Building docker container for target $target"
# use -f so we can use ci/ as build context
image_tag=test-"$TARGET"
docker build -t "$image_tag" -f "ci/docker/${TARGET}/Dockerfile" ci/
mkdir -p target
set -x
docker run \
--rm \
--user "$(id -u)":"$(id -g)" \
--env CARGO_HOME=/cargo \
--env CARGO_TARGET_DIR=/checkout/target \
--volume "$(dirname "$(dirname "$(command -v cargo)")")":/cargo \
--volume "$(rustc --print sysroot)":/rust:ro \
--volume "$(pwd)":/checkout:ro \
--volume "$(pwd)"/target:/checkout/target \
--init \
--workdir /checkout \
"$image_tag" \
sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec cargo test --target ${TARGET} $@"

60
ci/runtest-android.rs Normal file
View File

@ -0,0 +1,60 @@
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
let args = env::args_os()
.skip(1)
.filter(|arg| arg != "--quiet")
.collect::<Vec<_>>();
assert_eq!(args.len(), 1);
let test = PathBuf::from(&args[0]);
// required to run an executable depending on wabt-rs
let android_ndk_home = env::var("ANDROID_NDK_HOME").expect("Can't get ANDROID_NDK_HOME!");
let path = format!("{}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so", android_ndk_home);
let libcpp_shared = Path::new(&path);
let dst = Path::new("/data/local/tmp");
let dst_exec = Path::new("/data/local/tmp").join(test.file_name().unwrap());
let status = Command::new("adb")
.arg("wait-for-device")
.status()
.expect("failed to run: adb wait-for-device");
assert!(status.success());
let status = Command::new("adb")
.arg("push")
.arg(&test)
.arg(&libcpp_shared)
.arg(&dst)
.status()
.expect("failed to run: adb pushr");
assert!(status.success());
let output = Command::new("adb")
.arg("shell")
.arg("LD_LIBRARY_PATH=/data/local/tmp/")
.arg(&dst_exec)
.output()
.expect("failed to run: adb shell");
assert!(status.success());
println!(
"status: {}\nstdout ---\n{}\nstderr ---\n{}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
stdout
.lines()
.find(|l| {
(l.starts_with("PASSED ") && l.contains(" tests")) || l.starts_with("test result: ok")
})
.unwrap_or_else(|| {
panic!("failed to find successful test run");
});
}

View File

@ -23,7 +23,7 @@ byteorder = "1.3.2"
nix = "0.15.0"
libc = "0.2.60"
rayon = "1.1"
wasm-debug = { optional = true, version = "0.1" }
wasm-debug = { optional = true, version = "0.2" }
# Dependencies for caching.
[dependencies.serde]

View File

@ -19,7 +19,7 @@ use std::mem;
use std::sync::{Arc, RwLock};
use wasmer_runtime_core::error::CompileError;
use wasmer_runtime_core::{
backend::{CacheGen, Token},
backend::{CacheGen, CompilerConfig, Token},
cache::{Artifact, Error as CacheError},
codegen::*,
memory::MemoryType,
@ -36,7 +36,7 @@ use wasmparser::Type as WpType;
static BACKEND_ID: &str = "cranelift";
pub struct CraneliftModuleCodeGenerator {
isa: Box<dyn isa::TargetIsa>,
isa: Option<Box<dyn isa::TargetIsa>>,
signatures: Option<Arc<Map<SigIndex, FuncSig>>>,
pub clif_signatures: Map<SigIndex, ir::Signature>,
function_signatures: Option<Arc<Map<FuncIndex, SigIndex>>>,
@ -47,9 +47,8 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
for CraneliftModuleCodeGenerator
{
fn new() -> Self {
let isa = get_isa();
CraneliftModuleCodeGenerator {
isa,
isa: None,
clif_signatures: Map::new(),
functions: vec![],
function_signatures: None,
@ -100,7 +99,7 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
position: Position::default(),
func_env: FunctionEnvironment {
module_info: Arc::clone(&module_info),
target_config: self.isa.frontend_config().clone(),
target_config: self.isa.as_ref().unwrap().frontend_config().clone(),
clif_signatures: self.clif_signatures.clone(),
},
loc,
@ -162,9 +161,9 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
}
let (func_resolver_builder, debug_metadata, handler_data) =
FuncResolverBuilder::new(&*self.isa, func_bodies, module_info)?;
FuncResolverBuilder::new(&**self.isa.as_ref().unwrap(), func_bodies, module_info)?;
let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info));
let trampolines = Arc::new(Trampolines::new(&**self.isa.as_ref().unwrap(), module_info));
let signatures_empty = Map::new();
let signatures = if self.signatures.is_some() {
@ -191,9 +190,19 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
))
}
fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), CodegenError> {
self.isa = Some(get_isa(Some(config)));
Ok(())
}
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), CodegenError> {
self.signatures = Some(Arc::new(signatures));
let call_conv = self.isa.frontend_config().default_call_conv;
let call_conv = self
.isa
.as_ref()
.unwrap()
.frontend_config()
.default_call_conv;
for (_sig_idx, func_sig) in self.signatures.as_ref().unwrap().iter() {
self.clif_signatures
.push(convert_func_sig(func_sig, call_conv));
@ -1302,7 +1311,10 @@ fn generate_signature(
}
fn pointer_type(mcg: &CraneliftModuleCodeGenerator) -> ir::Type {
ir::Type::int(u16::from(mcg.isa.frontend_config().pointer_bits())).unwrap()
ir::Type::int(u16::from(
mcg.isa.as_ref().unwrap().frontend_config().pointer_bits(),
))
.unwrap()
}
/// Declare local variables for the signature parameters that correspond to WebAssembly locals.

View File

@ -29,6 +29,7 @@ use cranelift_codegen::{
settings::{self, Configurable},
};
use target_lexicon::Triple;
use wasmer_runtime_core::{backend::CompilerConfig, codegen::SimpleStreamingCompilerGen};
#[macro_use]
extern crate serde_derive;
@ -36,18 +37,33 @@ extern crate serde_derive;
extern crate rayon;
extern crate serde;
fn get_isa() -> Box<dyn isa::TargetIsa> {
fn get_isa(config: Option<&CompilerConfig>) -> Box<dyn isa::TargetIsa> {
let flags = {
let mut builder = settings::builder();
builder.set("opt_level", "speed_and_size").unwrap();
builder.set("enable_jump_tables", "false").unwrap();
if cfg!(test) || cfg!(debug_assertions) {
builder.set("enable_verifier", "true").unwrap();
let enable_verifier: bool;
if let Some(config) = config {
if config.nan_canonicalization {
builder.set("enable_nan_canonicalization", "true").unwrap();
}
enable_verifier = config.enable_verification;
} else {
builder.set("enable_verifier", "false").unwrap();
// Set defaults if no config found.
// NOTE: cfg(test) probably does nothing when not running `cargo test`
// on this crate
enable_verifier = cfg!(test) || cfg!(debug_assertions);
}
builder
.set(
"enable_verifier",
if enable_verifier { "true" } else { "false" },
)
.unwrap();
let flags = settings::Flags::new(builder);
debug_assert_eq!(flags.opt_level(), settings::OptLevel::SpeedAndSize);
flags
@ -58,8 +74,6 @@ fn get_isa() -> Box<dyn isa::TargetIsa> {
/// The current version of this crate
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen;
/// Streaming compiler implementation for the Cranelift backed. Compiles web assembly binary into
/// machine code.
pub type CraneliftCompiler = SimpleStreamingCompilerGen<

View File

@ -78,7 +78,7 @@ pub extern "C" fn nearbyintf64(x: f64) -> f64 {
// FIXME: Is there a replacement on AArch64?
#[cfg(all(
any(target_os = "freebsd", target_os = "linux"),
any(target_os = "freebsd", target_os = "linux", target_os = "android"),
target_arch = "aarch64"
))]
#[no_mangle]

View File

@ -229,7 +229,10 @@ unsafe fn get_faulting_addr_and_ip(
(si_addr, rip as _)
}
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
#[cfg(all(
any(target_os = "linux", target_os = "android"),
target_arch = "aarch64"
))]
unsafe fn get_faulting_addr_and_ip(
_siginfo: *const c_void,
_ucontext: *const c_void,
@ -237,7 +240,10 @@ unsafe fn get_faulting_addr_and_ip(
(::std::ptr::null(), ::std::ptr::null())
}
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[cfg(all(
any(target_os = "linux", target_os = "android"),
target_arch = "x86_64"
))]
unsafe fn get_faulting_addr_and_ip(
siginfo: *const c_void,
ucontext: *const c_void,
@ -332,5 +338,7 @@ unsafe fn get_faulting_addr_and_ip(
all(target_os = "macos", target_arch = "x86_64"),
all(target_os = "linux", target_arch = "x86_64"),
all(target_os = "linux", target_arch = "aarch64"),
all(target_os = "android", target_arch = "x86_64"),
all(target_os = "android", target_arch = "aarch64"),
)))]
compile_error!("This crate doesn't yet support compiling on operating systems other than linux and macos and architectures other than x86_64");

View File

@ -86,7 +86,7 @@ impl Trampolines {
let sig_index = module.func_assoc[*exported_func_index];
let func_sig = &module.signatures[sig_index];
let trampoline_func = generate_func(&func_sig);
let trampoline_func = generate_func(isa, &func_sig);
ctx.func = trampoline_func;
@ -150,13 +150,13 @@ impl Trampolines {
/// This function generates a trampoline for the specific signature
/// passed into it.
fn generate_func(func_sig: &FuncSig) -> ir::Function {
let trampoline_sig = generate_trampoline_signature();
fn generate_func(isa: &dyn isa::TargetIsa, func_sig: &FuncSig) -> ir::Function {
let trampoline_sig = generate_trampoline_signature(isa);
let mut func =
ir::Function::with_name_signature(ir::ExternalName::testcase("trampln"), trampoline_sig);
let export_sig_ref = func.import_signature(generate_export_signature(func_sig));
let export_sig_ref = func.import_signature(generate_export_signature(isa, func_sig));
let entry_ebb = func.dfg.make_block();
let vmctx_ptr = func.dfg.append_block_param(entry_ebb, ir::types::I64);
@ -211,8 +211,7 @@ fn wasm_ty_to_clif(ty: Type) -> ir::types::Type {
}
}
fn generate_trampoline_signature() -> ir::Signature {
let isa = super::get_isa();
fn generate_trampoline_signature(isa: &dyn isa::TargetIsa) -> ir::Signature {
let call_convention = isa.default_call_conv();
let mut sig = ir::Signature::new(call_convention);
@ -228,8 +227,7 @@ fn generate_trampoline_signature() -> ir::Signature {
sig
}
fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature {
let isa = super::get_isa();
fn generate_export_signature(isa: &dyn isa::TargetIsa, func_sig: &FuncSig) -> ir::Signature {
let call_convention = isa.default_call_conv();
let mut export_clif_sig = ir::Signature::new(call_convention);

View File

@ -41,57 +41,52 @@ binary.
## Instructions
Very basically, WebAssembly Interface Types defines a set of
instructions, used by adapters to transform the data between
WebAssembly core and the outside world ([learn
Very basically, WebAssembly Interface Types defines a [set of
instructions](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/working-notes/Instructions.md),
used by adapters to transform the data between WebAssembly core and
the outside world ([learn
mode](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md)).
Here is the instructions that are implemented:
Here is the instructions that are implemented by this crate:
| Instruction | WAT encoder | Binary encoder | WAT decoder | Binary decoder | Interpreter |
|-|-|-|-|-|-|
| `arg.get` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `call-core` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `memory-to-string` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `string-to-memory` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `call-adapter` | ❌ | ❌ | ❌ | ❌ | ❌ |
| `defer-call-core` | ❌ | ❌ | ❌ | ❌ | ❌ |
| `i32-to-s8` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i32-to-s8x` | ✅ | ✅ | ✅ | ✅ | ❌ |
| `i32-to-u8` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i32-to-s16` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i32-to-s16x` | ✅ | ✅ | ✅ | ✅ | ❌ |
| `i32-to-u16` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i32-to-s32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i32-to-u32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i32-to-s64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i32-to-u64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-s8` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-s8x` | ✅ | ✅ | ✅ | ✅ | ❌ |
| `i64-to-u8` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-s16` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-s16x` | ✅ | ✅ | ✅ | ✅ | ❌ |
| `i64-to-u16` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-s32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-s32x` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-u32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-s64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `i64-to-u64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s8-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u8-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s16-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u16-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s32-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u32-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s64-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s64-to-i32x` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u64-to-i32` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u64-to-i32x` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s8-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u8-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s16-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u16-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s32-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u32-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `s64-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `u64-to-i64` | ✅ | ✅ | ✅ | ✅ | ✅ |
| Instruction | WAT encoder/decoder | Binary encoder/decoder | Interpreter | Comment |
|-|-|-|-|-|
| `arg.get` | ✅ | ✅ | ✅ | |
| `call-core` | ✅ | ✅ | ✅ | |
| `s8.from_i32` | ✅ | ✅ | ✅ | |
| `s8.from_i64` | ✅ | ✅ | ✅ | |
| `s16.from_i32` | ✅ | ✅ | ✅ | |
| `s16.from_i64` | ✅ | ✅ | ✅ | |
| `s32.from_i32` | ✅ | ✅ | ✅ | |
| `s32.from_i64` | ✅ | ✅ | ✅ | |
| `s64.from_i32` | ✅ | ✅ | ✅ | |
| `s64.from_i64` | ✅ | ✅ | ✅ | |
| `i32.from_s8` | ✅ | ✅ | ✅ | |
| `i32.from_s16` | ✅ | ✅ | ✅ | |
| `i32.from_s32` | ✅ | ✅ | ✅ | |
| `i32.from_s64` | ✅ | ✅ | ✅ | |
| `i64.from_s8` | ✅ | ✅ | ✅ | |
| `i64.from_s16` | ✅ | ✅ | ✅ | |
| `i64.from_s32` | ✅ | ✅ | ✅ | |
| `i64.from_s64` | ✅ | ✅ | ✅ | |
| `u8.from_i32` | ✅ | ✅ | ✅ | |
| `u8.from_i64` | ✅ | ✅ | ✅ | |
| `u16.from_i32` | ✅ | ✅ | ✅ | |
| `u16.from_i64` | ✅ | ✅ | ✅ | |
| `u32.from_i32` | ✅ | ✅ | ✅ | |
| `u32.from_i64` | ✅ | ✅ | ✅ | |
| `u64.from_i32` | ✅ | ✅ | ✅ | |
| `u64.from_i64` | ✅ | ✅ | ✅ | |
| `i32.from_u8` | ✅ | ✅ | ✅ | |
| `i32.from_u16` | ✅ | ✅ | ✅ | |
| `i32.from_u32` | ✅ | ✅ | ✅ | |
| `i32.from_u64` | ✅ | ✅ | ✅ | |
| `i64.from_u8` | ✅ | ✅ | ✅ | |
| `i64.from_u16` | ✅ | ✅ | ✅ | |
| `i64.from_u32` | ✅ | ✅ | ✅ | |
| `i64.from_u64` | ✅ | ✅ | ✅ | |
| `string.lift_memory` | ✅ | ✅ | ✅ | `#memidx` is not supported; `#encoding` is not supported but UTF-8 is assumed |
| `string.lower_memory` | ✅ | ✅ | ✅ | `#memidx` is not supported; `#encoding` is not supported but UTF-8 is assumed |
| `string.size` | ✅ | ✅ | ✅ | `#encoding` is not supported but UTF-8 is assumed |
| `call-adapter` | ❌ | ❌ | ❌ | |
| `defer-call-core` | ❌ | ❌ | ❌ | |

View File

@ -169,62 +169,57 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
(
input,
Instruction::CallCore {
function_index: argument_0 as usize,
function_index: argument_0 as u32,
},
)
}
0x03 => (input, Instruction::MemoryToString),
0x02 => (input, Instruction::S8FromI32),
0x03 => (input, Instruction::S8FromI64),
0x04 => (input, Instruction::S16FromI32),
0x05 => (input, Instruction::S16FromI64),
0x06 => (input, Instruction::S32FromI32),
0x07 => (input, Instruction::S32FromI64),
0x08 => (input, Instruction::S64FromI32),
0x09 => (input, Instruction::S64FromI64),
0x0a => (input, Instruction::I32FromS8),
0x0b => (input, Instruction::I32FromS16),
0x0c => (input, Instruction::I32FromS32),
0x0d => (input, Instruction::I32FromS64),
0x0e => (input, Instruction::I64FromS8),
0x0f => (input, Instruction::I64FromS16),
0x10 => (input, Instruction::I64FromS32),
0x11 => (input, Instruction::I64FromS64),
0x12 => (input, Instruction::U8FromI32),
0x13 => (input, Instruction::U8FromI64),
0x14 => (input, Instruction::U16FromI32),
0x15 => (input, Instruction::U16FromI64),
0x16 => (input, Instruction::U32FromI32),
0x17 => (input, Instruction::U32FromI64),
0x18 => (input, Instruction::U64FromI32),
0x19 => (input, Instruction::U64FromI64),
0x1a => (input, Instruction::I32FromU8),
0x1b => (input, Instruction::I32FromU16),
0x1c => (input, Instruction::I32FromU32),
0x1d => (input, Instruction::I32FromU64),
0x1e => (input, Instruction::I64FromU8),
0x1f => (input, Instruction::I64FromU16),
0x20 => (input, Instruction::I64FromU32),
0x21 => (input, Instruction::I64FromU64),
0x04 => {
0x22 => (input, Instruction::StringLiftMemory),
0x23 => {
consume!((input, argument_0) = uleb(input)?);
(
input,
Instruction::StringToMemory {
Instruction::StringLowerMemory {
allocator_index: argument_0 as u32,
},
)
}
0x07 => (input, Instruction::I32ToS8),
0x08 => (input, Instruction::I32ToS8X),
0x09 => (input, Instruction::I32ToU8),
0x0a => (input, Instruction::I32ToS16),
0x0b => (input, Instruction::I32ToS16X),
0x0c => (input, Instruction::I32ToU16),
0x0d => (input, Instruction::I32ToS32),
0x0e => (input, Instruction::I32ToU32),
0x0f => (input, Instruction::I32ToS64),
0x10 => (input, Instruction::I32ToU64),
0x11 => (input, Instruction::I64ToS8),
0x12 => (input, Instruction::I64ToS8X),
0x13 => (input, Instruction::I64ToU8),
0x14 => (input, Instruction::I64ToS16),
0x15 => (input, Instruction::I64ToS16X),
0x16 => (input, Instruction::I64ToU16),
0x17 => (input, Instruction::I64ToS32),
0x18 => (input, Instruction::I64ToS32X),
0x19 => (input, Instruction::I64ToU32),
0x1a => (input, Instruction::I64ToS64),
0x1b => (input, Instruction::I64ToU64),
0x1c => (input, Instruction::S8ToI32),
0x1d => (input, Instruction::U8ToI32),
0x1e => (input, Instruction::S16ToI32),
0x1f => (input, Instruction::U16ToI32),
0x20 => (input, Instruction::S32ToI32),
0x21 => (input, Instruction::U32ToI32),
0x22 => (input, Instruction::S64ToI32),
0x23 => (input, Instruction::S64ToI32X),
0x24 => (input, Instruction::U64ToI32),
0x25 => (input, Instruction::U64ToI32X),
0x26 => (input, Instruction::S8ToI64),
0x27 => (input, Instruction::U8ToI64),
0x28 => (input, Instruction::S16ToI64),
0x29 => (input, Instruction::U16ToI64),
0x2a => (input, Instruction::S32ToI64),
0x2b => (input, Instruction::U32ToI64),
0x2c => (input, Instruction::S64ToI64),
0x2d => (input, Instruction::U64ToI64),
0x24 => (input, Instruction::StringSize),
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
})
@ -627,50 +622,44 @@ mod tests {
#[test]
fn test_instructions() {
let input = &[
0x2b, // list of 43 items
0x25, // list of 37 items
0x00, 0x01, // ArgumentGet { index: 1 }
0x01, 0x01, // CallCore { function_index: 1 }
0x03, // MemoryToString
0x04, 0x01, // StringToMemory { allocator_index: 1 }
0x07, // I32ToS8
0x08, // I32ToS8X
0x09, // I32ToU8
0x0a, // I32ToS16
0x0b, // I32ToS16X
0x0c, // I32ToU16
0x0d, // I32ToS32
0x0e, // I32ToU32
0x0f, // I32ToS64
0x10, // I32ToU64
0x11, // I64ToS8
0x12, // I64ToS8X
0x13, // I64ToU8
0x14, // I64ToS16
0x15, // I64ToS16X
0x16, // I64ToU16
0x17, // I64ToS32
0x18, // I64ToS32X
0x19, // I64ToU32
0x1a, // I64ToS64
0x1b, // I64ToU64
0x1c, // S8ToI32
0x1d, // U8ToI32
0x1e, // S16ToI32
0x1f, // U16ToI32
0x20, // S32ToI32
0x21, // U32ToI32
0x22, // S64ToI32
0x23, // S64ToI32X
0x24, // U64ToI32
0x25, // U64ToI32X
0x26, // S8ToI64
0x27, // U8ToI64
0x28, // S16ToI64
0x29, // U16ToI64
0x2a, // S32ToI64
0x2b, // U32ToI64
0x2c, // S64ToI64
0x2d, // U64ToI64
0x02, // S8FromI32
0x03, // S8FromI64
0x04, // S16FromI32
0x05, // S16FromI64
0x06, // S32FromI32
0x07, // S32FromI64
0x08, // S64FromI32
0x09, // S64FromI64
0x0a, // I32FromS8
0x0b, // I32FromS16
0x0c, // I32FromS32
0x0d, // I32FromS64
0x0e, // I64FromS8
0x0f, // I64FromS16
0x10, // I64FromS32
0x11, // I64FromS64
0x12, // U8FromI32
0x13, // U8FromI64
0x14, // U16FromI32
0x15, // U16FromI64
0x16, // U32FromI32
0x17, // U32FromI64
0x18, // U64FromI32
0x19, // U64FromI64
0x1a, // I32FromU8
0x1b, // I32FromU16
0x1c, // I32FromU32
0x1d, // I32FromU64
0x1e, // I64FromU8
0x1f, // I64FromU16
0x20, // I64FromU32
0x21, // I64FromU64
0x22, // StringLiftMemory
0x23, 0x01, // StringLowerMemory { allocator_index: 1 }
0x24, // StringSize
0x0a,
];
let output = Ok((
@ -678,47 +667,41 @@ mod tests {
vec![
Instruction::ArgumentGet { index: 1 },
Instruction::CallCore { function_index: 1 },
Instruction::MemoryToString,
Instruction::StringToMemory { allocator_index: 1 },
Instruction::I32ToS8,
Instruction::I32ToS8X,
Instruction::I32ToU8,
Instruction::I32ToS16,
Instruction::I32ToS16X,
Instruction::I32ToU16,
Instruction::I32ToS32,
Instruction::I32ToU32,
Instruction::I32ToS64,
Instruction::I32ToU64,
Instruction::I64ToS8,
Instruction::I64ToS8X,
Instruction::I64ToU8,
Instruction::I64ToS16,
Instruction::I64ToS16X,
Instruction::I64ToU16,
Instruction::I64ToS32,
Instruction::I64ToS32X,
Instruction::I64ToU32,
Instruction::I64ToS64,
Instruction::I64ToU64,
Instruction::S8ToI32,
Instruction::U8ToI32,
Instruction::S16ToI32,
Instruction::U16ToI32,
Instruction::S32ToI32,
Instruction::U32ToI32,
Instruction::S64ToI32,
Instruction::S64ToI32X,
Instruction::U64ToI32,
Instruction::U64ToI32X,
Instruction::S8ToI64,
Instruction::U8ToI64,
Instruction::S16ToI64,
Instruction::U16ToI64,
Instruction::S32ToI64,
Instruction::U32ToI64,
Instruction::S64ToI64,
Instruction::U64ToI64,
Instruction::S8FromI32,
Instruction::S8FromI64,
Instruction::S16FromI32,
Instruction::S16FromI64,
Instruction::S32FromI32,
Instruction::S32FromI64,
Instruction::S64FromI32,
Instruction::S64FromI64,
Instruction::I32FromS8,
Instruction::I32FromS16,
Instruction::I32FromS32,
Instruction::I32FromS64,
Instruction::I64FromS8,
Instruction::I64FromS16,
Instruction::I64FromS32,
Instruction::I64FromS64,
Instruction::U8FromI32,
Instruction::U8FromI64,
Instruction::U16FromI32,
Instruction::U16FromI64,
Instruction::U32FromI32,
Instruction::U32FromI64,
Instruction::U64FromI32,
Instruction::U64FromI64,
Instruction::I32FromU8,
Instruction::I32FromU16,
Instruction::I32FromU32,
Instruction::I32FromU64,
Instruction::I64FromU8,
Instruction::I64FromU16,
Instruction::I64FromU32,
Instruction::I64FromU64,
Instruction::StringLiftMemory,
Instruction::StringLowerMemory { allocator_index: 1 },
Instruction::StringSize,
],
));

View File

@ -28,47 +28,41 @@ mod keyword {
// Instructions.
custom_keyword!(argument_get = "arg.get");
custom_keyword!(call_core = "call-core");
custom_keyword!(memory_to_string = "memory-to-string");
custom_keyword!(string_to_memory = "string-to-memory");
custom_keyword!(i32_to_s8 = "i32-to-s8");
custom_keyword!(i32_to_s8x = "i32-to-s8x");
custom_keyword!(i32_to_u8 = "i32-to-u8");
custom_keyword!(i32_to_s16 = "i32-to-s16");
custom_keyword!(i32_to_s16x = "i32-to-s16x");
custom_keyword!(i32_to_u16 = "i32-to-u16");
custom_keyword!(i32_to_s32 = "i32-to-s32");
custom_keyword!(i32_to_u32 = "i32-to-u32");
custom_keyword!(i32_to_s64 = "i32-to-s64");
custom_keyword!(i32_to_u64 = "i32-to-u64");
custom_keyword!(i64_to_s8 = "i64-to-s8");
custom_keyword!(i64_to_s8x = "i64-to-s8x");
custom_keyword!(i64_to_u8 = "i64-to-u8");
custom_keyword!(i64_to_s16 = "i64-to-s16");
custom_keyword!(i64_to_s16x = "i64-to-s16x");
custom_keyword!(i64_to_u16 = "i64-to-u16");
custom_keyword!(i64_to_s32 = "i64-to-s32");
custom_keyword!(i64_to_s32x = "i64-to-s32x");
custom_keyword!(i64_to_u32 = "i64-to-u32");
custom_keyword!(i64_to_s64 = "i64-to-s64");
custom_keyword!(i64_to_u64 = "i64-to-u64");
custom_keyword!(s8_to_i32 = "s8-to-i32");
custom_keyword!(u8_to_i32 = "u8-to-i32");
custom_keyword!(s16_to_i32 = "s16-to-i32");
custom_keyword!(u16_to_i32 = "u16-to-i32");
custom_keyword!(s32_to_i32 = "s32-to-i32");
custom_keyword!(u32_to_i32 = "u32-to-i32");
custom_keyword!(s64_to_i32 = "s64-to-i32");
custom_keyword!(s64_to_i32x = "s64-to-i32x");
custom_keyword!(u64_to_i32 = "u64-to-i32");
custom_keyword!(u64_to_i32x = "u64-to-i32x");
custom_keyword!(s8_to_i64 = "s8-to-i64");
custom_keyword!(u8_to_i64 = "u8-to-i64");
custom_keyword!(s16_to_i64 = "s16-to-i64");
custom_keyword!(u16_to_i64 = "u16-to-i64");
custom_keyword!(s32_to_i64 = "s32-to-i64");
custom_keyword!(u32_to_i64 = "u32-to-i64");
custom_keyword!(s64_to_i64 = "s64-to-i64");
custom_keyword!(u64_to_i64 = "u64-to-i64");
custom_keyword!(s8_from_i32 = "s8.from_i32");
custom_keyword!(s8_from_i64 = "s8.from_i64");
custom_keyword!(s16_from_i32 = "s16.from_i32");
custom_keyword!(s16_from_i64 = "s16.from_i64");
custom_keyword!(s32_from_i32 = "s32.from_i32");
custom_keyword!(s32_from_i64 = "s32.from_i64");
custom_keyword!(s64_from_i32 = "s64.from_i32");
custom_keyword!(s64_from_i64 = "s64.from_i64");
custom_keyword!(i32_from_s8 = "i32.from_s8");
custom_keyword!(i32_from_s16 = "i32.from_s16");
custom_keyword!(i32_from_s32 = "i32.from_s32");
custom_keyword!(i32_from_s64 = "i32.from_s64");
custom_keyword!(i64_from_s8 = "i64.from_s8");
custom_keyword!(i64_from_s16 = "i64.from_s16");
custom_keyword!(i64_from_s32 = "i64.from_s32");
custom_keyword!(i64_from_s64 = "i64.from_s64");
custom_keyword!(u8_from_i32 = "u8.from_i32");
custom_keyword!(u8_from_i64 = "u8.from_i64");
custom_keyword!(u16_from_i32 = "u16.from_i32");
custom_keyword!(u16_from_i64 = "u16.from_i64");
custom_keyword!(u32_from_i32 = "u32.from_i32");
custom_keyword!(u32_from_i64 = "u32.from_i64");
custom_keyword!(u64_from_i32 = "u64.from_i32");
custom_keyword!(u64_from_i64 = "u64.from_i64");
custom_keyword!(i32_from_u8 = "i32.from_u8");
custom_keyword!(i32_from_u16 = "i32.from_u16");
custom_keyword!(i32_from_u32 = "i32.from_u32");
custom_keyword!(i32_from_u64 = "i32.from_u64");
custom_keyword!(i64_from_u8 = "i64.from_u8");
custom_keyword!(i64_from_u16 = "i64.from_u16");
custom_keyword!(i64_from_u32 = "i64.from_u32");
custom_keyword!(i64_from_u64 = "i64.from_u64");
custom_keyword!(string_lift_memory = "string.lift_memory");
custom_keyword!(string_lower_memory = "string.lower_memory");
custom_keyword!(string_size = "string.size");
}
impl Parse<'_> for InterfaceType {
@ -152,174 +146,150 @@ impl<'a> Parse<'a> for Instruction {
parser.parse::<keyword::call_core>()?;
Ok(Instruction::CallCore {
function_index: parser.parse::<u64>()? as usize,
function_index: parser.parse::<u32>()?,
})
} else if lookahead.peek::<keyword::memory_to_string>() {
parser.parse::<keyword::memory_to_string>()?;
} else if lookahead.peek::<keyword::s8_from_i32>() {
parser.parse::<keyword::s8_from_i32>()?;
Ok(Instruction::MemoryToString)
} else if lookahead.peek::<keyword::string_to_memory>() {
parser.parse::<keyword::string_to_memory>()?;
Ok(Instruction::S8FromI32)
} else if lookahead.peek::<keyword::s8_from_i64>() {
parser.parse::<keyword::s8_from_i64>()?;
Ok(Instruction::StringToMemory {
Ok(Instruction::S8FromI64)
} else if lookahead.peek::<keyword::s16_from_i32>() {
parser.parse::<keyword::s16_from_i32>()?;
Ok(Instruction::S16FromI32)
} else if lookahead.peek::<keyword::s16_from_i64>() {
parser.parse::<keyword::s16_from_i64>()?;
Ok(Instruction::S16FromI64)
} else if lookahead.peek::<keyword::s32_from_i32>() {
parser.parse::<keyword::s32_from_i32>()?;
Ok(Instruction::S32FromI32)
} else if lookahead.peek::<keyword::s32_from_i64>() {
parser.parse::<keyword::s32_from_i64>()?;
Ok(Instruction::S32FromI64)
} else if lookahead.peek::<keyword::s64_from_i32>() {
parser.parse::<keyword::s64_from_i32>()?;
Ok(Instruction::S64FromI32)
} else if lookahead.peek::<keyword::s64_from_i64>() {
parser.parse::<keyword::s64_from_i64>()?;
Ok(Instruction::S64FromI64)
} else if lookahead.peek::<keyword::i32_from_s8>() {
parser.parse::<keyword::i32_from_s8>()?;
Ok(Instruction::I32FromS8)
} else if lookahead.peek::<keyword::i32_from_s16>() {
parser.parse::<keyword::i32_from_s16>()?;
Ok(Instruction::I32FromS16)
} else if lookahead.peek::<keyword::i32_from_s32>() {
parser.parse::<keyword::i32_from_s32>()?;
Ok(Instruction::I32FromS32)
} else if lookahead.peek::<keyword::i32_from_s64>() {
parser.parse::<keyword::i32_from_s64>()?;
Ok(Instruction::I32FromS64)
} else if lookahead.peek::<keyword::i64_from_s8>() {
parser.parse::<keyword::i64_from_s8>()?;
Ok(Instruction::I64FromS8)
} else if lookahead.peek::<keyword::i64_from_s16>() {
parser.parse::<keyword::i64_from_s16>()?;
Ok(Instruction::I64FromS16)
} else if lookahead.peek::<keyword::i64_from_s32>() {
parser.parse::<keyword::i64_from_s32>()?;
Ok(Instruction::I64FromS32)
} else if lookahead.peek::<keyword::i64_from_s64>() {
parser.parse::<keyword::i64_from_s64>()?;
Ok(Instruction::I64FromS64)
} else if lookahead.peek::<keyword::u8_from_i32>() {
parser.parse::<keyword::u8_from_i32>()?;
Ok(Instruction::U8FromI32)
} else if lookahead.peek::<keyword::u8_from_i64>() {
parser.parse::<keyword::u8_from_i64>()?;
Ok(Instruction::U8FromI64)
} else if lookahead.peek::<keyword::u16_from_i32>() {
parser.parse::<keyword::u16_from_i32>()?;
Ok(Instruction::U16FromI32)
} else if lookahead.peek::<keyword::u16_from_i64>() {
parser.parse::<keyword::u16_from_i64>()?;
Ok(Instruction::U16FromI64)
} else if lookahead.peek::<keyword::u32_from_i32>() {
parser.parse::<keyword::u32_from_i32>()?;
Ok(Instruction::U32FromI32)
} else if lookahead.peek::<keyword::u32_from_i64>() {
parser.parse::<keyword::u32_from_i64>()?;
Ok(Instruction::U32FromI64)
} else if lookahead.peek::<keyword::u64_from_i32>() {
parser.parse::<keyword::u64_from_i32>()?;
Ok(Instruction::U64FromI32)
} else if lookahead.peek::<keyword::u64_from_i64>() {
parser.parse::<keyword::u64_from_i64>()?;
Ok(Instruction::U64FromI64)
} else if lookahead.peek::<keyword::i32_from_u8>() {
parser.parse::<keyword::i32_from_u8>()?;
Ok(Instruction::I32FromU8)
} else if lookahead.peek::<keyword::i32_from_u16>() {
parser.parse::<keyword::i32_from_u16>()?;
Ok(Instruction::I32FromU16)
} else if lookahead.peek::<keyword::i32_from_u32>() {
parser.parse::<keyword::i32_from_u32>()?;
Ok(Instruction::I32FromU32)
} else if lookahead.peek::<keyword::i32_from_u64>() {
parser.parse::<keyword::i32_from_u64>()?;
Ok(Instruction::I32FromU64)
} else if lookahead.peek::<keyword::i64_from_u8>() {
parser.parse::<keyword::i64_from_u8>()?;
Ok(Instruction::I64FromU8)
} else if lookahead.peek::<keyword::i64_from_u16>() {
parser.parse::<keyword::i64_from_u16>()?;
Ok(Instruction::I64FromU16)
} else if lookahead.peek::<keyword::i64_from_u32>() {
parser.parse::<keyword::i64_from_u32>()?;
Ok(Instruction::I64FromU32)
} else if lookahead.peek::<keyword::i64_from_u64>() {
parser.parse::<keyword::i64_from_u64>()?;
Ok(Instruction::I64FromU64)
} else if lookahead.peek::<keyword::string_lift_memory>() {
parser.parse::<keyword::string_lift_memory>()?;
Ok(Instruction::StringLiftMemory)
} else if lookahead.peek::<keyword::string_lower_memory>() {
parser.parse::<keyword::string_lower_memory>()?;
Ok(Instruction::StringLowerMemory {
allocator_index: parser.parse()?,
})
} else if lookahead.peek::<keyword::i32_to_s8>() {
parser.parse::<keyword::i32_to_s8>()?;
} else if lookahead.peek::<keyword::string_size>() {
parser.parse::<keyword::string_size>()?;
Ok(Instruction::I32ToS8)
} else if lookahead.peek::<keyword::i32_to_s8x>() {
parser.parse::<keyword::i32_to_s8x>()?;
Ok(Instruction::I32ToS8X)
} else if lookahead.peek::<keyword::i32_to_u8>() {
parser.parse::<keyword::i32_to_u8>()?;
Ok(Instruction::I32ToU8)
} else if lookahead.peek::<keyword::i32_to_s16>() {
parser.parse::<keyword::i32_to_s16>()?;
Ok(Instruction::I32ToS16)
} else if lookahead.peek::<keyword::i32_to_s16x>() {
parser.parse::<keyword::i32_to_s16x>()?;
Ok(Instruction::I32ToS16X)
} else if lookahead.peek::<keyword::i32_to_u16>() {
parser.parse::<keyword::i32_to_u16>()?;
Ok(Instruction::I32ToU16)
} else if lookahead.peek::<keyword::i32_to_s32>() {
parser.parse::<keyword::i32_to_s32>()?;
Ok(Instruction::I32ToS32)
} else if lookahead.peek::<keyword::i32_to_u32>() {
parser.parse::<keyword::i32_to_u32>()?;
Ok(Instruction::I32ToU32)
} else if lookahead.peek::<keyword::i32_to_s64>() {
parser.parse::<keyword::i32_to_s64>()?;
Ok(Instruction::I32ToS64)
} else if lookahead.peek::<keyword::i32_to_u64>() {
parser.parse::<keyword::i32_to_u64>()?;
Ok(Instruction::I32ToU64)
} else if lookahead.peek::<keyword::i64_to_s8>() {
parser.parse::<keyword::i64_to_s8>()?;
Ok(Instruction::I64ToS8)
} else if lookahead.peek::<keyword::i64_to_s8x>() {
parser.parse::<keyword::i64_to_s8x>()?;
Ok(Instruction::I64ToS8X)
} else if lookahead.peek::<keyword::i64_to_u8>() {
parser.parse::<keyword::i64_to_u8>()?;
Ok(Instruction::I64ToU8)
} else if lookahead.peek::<keyword::i64_to_s16>() {
parser.parse::<keyword::i64_to_s16>()?;
Ok(Instruction::I64ToS16)
} else if lookahead.peek::<keyword::i64_to_s16x>() {
parser.parse::<keyword::i64_to_s16x>()?;
Ok(Instruction::I64ToS16X)
} else if lookahead.peek::<keyword::i64_to_u16>() {
parser.parse::<keyword::i64_to_u16>()?;
Ok(Instruction::I64ToU16)
} else if lookahead.peek::<keyword::i64_to_s32>() {
parser.parse::<keyword::i64_to_s32>()?;
Ok(Instruction::I64ToS32)
} else if lookahead.peek::<keyword::i64_to_s32x>() {
parser.parse::<keyword::i64_to_s32x>()?;
Ok(Instruction::I64ToS32X)
} else if lookahead.peek::<keyword::i64_to_u32>() {
parser.parse::<keyword::i64_to_u32>()?;
Ok(Instruction::I64ToU32)
} else if lookahead.peek::<keyword::i64_to_s64>() {
parser.parse::<keyword::i64_to_s64>()?;
Ok(Instruction::I64ToS64)
} else if lookahead.peek::<keyword::i64_to_u64>() {
parser.parse::<keyword::i64_to_u64>()?;
Ok(Instruction::I64ToU64)
} else if lookahead.peek::<keyword::s8_to_i32>() {
parser.parse::<keyword::s8_to_i32>()?;
Ok(Instruction::S8ToI32)
} else if lookahead.peek::<keyword::u8_to_i32>() {
parser.parse::<keyword::u8_to_i32>()?;
Ok(Instruction::U8ToI32)
} else if lookahead.peek::<keyword::s16_to_i32>() {
parser.parse::<keyword::s16_to_i32>()?;
Ok(Instruction::S16ToI32)
} else if lookahead.peek::<keyword::u16_to_i32>() {
parser.parse::<keyword::u16_to_i32>()?;
Ok(Instruction::U16ToI32)
} else if lookahead.peek::<keyword::s32_to_i32>() {
parser.parse::<keyword::s32_to_i32>()?;
Ok(Instruction::S32ToI32)
} else if lookahead.peek::<keyword::u32_to_i32>() {
parser.parse::<keyword::u32_to_i32>()?;
Ok(Instruction::U32ToI32)
} else if lookahead.peek::<keyword::s64_to_i32>() {
parser.parse::<keyword::s64_to_i32>()?;
Ok(Instruction::S64ToI32)
} else if lookahead.peek::<keyword::s64_to_i32x>() {
parser.parse::<keyword::s64_to_i32x>()?;
Ok(Instruction::S64ToI32X)
} else if lookahead.peek::<keyword::u64_to_i32>() {
parser.parse::<keyword::u64_to_i32>()?;
Ok(Instruction::U64ToI32)
} else if lookahead.peek::<keyword::u64_to_i32x>() {
parser.parse::<keyword::u64_to_i32x>()?;
Ok(Instruction::U64ToI32X)
} else if lookahead.peek::<keyword::s8_to_i64>() {
parser.parse::<keyword::s8_to_i64>()?;
Ok(Instruction::S8ToI64)
} else if lookahead.peek::<keyword::u8_to_i64>() {
parser.parse::<keyword::u8_to_i64>()?;
Ok(Instruction::U8ToI64)
} else if lookahead.peek::<keyword::s16_to_i64>() {
parser.parse::<keyword::s16_to_i64>()?;
Ok(Instruction::S16ToI64)
} else if lookahead.peek::<keyword::u16_to_i64>() {
parser.parse::<keyword::u16_to_i64>()?;
Ok(Instruction::U16ToI64)
} else if lookahead.peek::<keyword::s32_to_i64>() {
parser.parse::<keyword::s32_to_i64>()?;
Ok(Instruction::S32ToI64)
} else if lookahead.peek::<keyword::u32_to_i64>() {
parser.parse::<keyword::u32_to_i64>()?;
Ok(Instruction::U32ToI64)
} else if lookahead.peek::<keyword::s64_to_i64>() {
parser.parse::<keyword::s64_to_i64>()?;
Ok(Instruction::S64ToI64)
} else if lookahead.peek::<keyword::u64_to_i64>() {
parser.parse::<keyword::u64_to_i64>()?;
Ok(Instruction::U64ToI64)
Ok(Instruction::StringSize)
} else {
Err(lookahead.error())
}
@ -667,94 +637,82 @@ mod tests {
let inputs = vec![
"arg.get 7",
"call-core 7",
"memory-to-string",
"string-to-memory 42",
"i32-to-s8",
"i32-to-s8x",
"i32-to-u8",
"i32-to-s16",
"i32-to-s16x",
"i32-to-u16",
"i32-to-s32",
"i32-to-u32",
"i32-to-s64",
"i32-to-u64",
"i64-to-s8",
"i64-to-s8x",
"i64-to-u8",
"i64-to-s16",
"i64-to-s16x",
"i64-to-u16",
"i64-to-s32",
"i64-to-s32x",
"i64-to-u32",
"i64-to-s64",
"i64-to-u64",
"s8-to-i32",
"u8-to-i32",
"s16-to-i32",
"u16-to-i32",
"s32-to-i32",
"u32-to-i32",
"s64-to-i32",
"s64-to-i32x",
"u64-to-i32",
"u64-to-i32x",
"s8-to-i64",
"u8-to-i64",
"s16-to-i64",
"u16-to-i64",
"s32-to-i64",
"u32-to-i64",
"s64-to-i64",
"u64-to-i64",
"s8.from_i32",
"s8.from_i64",
"s16.from_i32",
"s16.from_i64",
"s32.from_i32",
"s32.from_i64",
"s64.from_i32",
"s64.from_i64",
"i32.from_s8",
"i32.from_s16",
"i32.from_s32",
"i32.from_s64",
"i64.from_s8",
"i64.from_s16",
"i64.from_s32",
"i64.from_s64",
"u8.from_i32",
"u8.from_i64",
"u16.from_i32",
"u16.from_i64",
"u32.from_i32",
"u32.from_i64",
"u64.from_i32",
"u64.from_i64",
"i32.from_u8",
"i32.from_u16",
"i32.from_u32",
"i32.from_u64",
"i64.from_u8",
"i64.from_u16",
"i64.from_u32",
"i64.from_u64",
"string.lift_memory",
"string.lower_memory 42",
"string.size",
];
let outputs = vec![
Instruction::ArgumentGet { index: 7 },
Instruction::CallCore { function_index: 7 },
Instruction::MemoryToString,
Instruction::StringToMemory {
Instruction::S8FromI32,
Instruction::S8FromI64,
Instruction::S16FromI32,
Instruction::S16FromI64,
Instruction::S32FromI32,
Instruction::S32FromI64,
Instruction::S64FromI32,
Instruction::S64FromI64,
Instruction::I32FromS8,
Instruction::I32FromS16,
Instruction::I32FromS32,
Instruction::I32FromS64,
Instruction::I64FromS8,
Instruction::I64FromS16,
Instruction::I64FromS32,
Instruction::I64FromS64,
Instruction::U8FromI32,
Instruction::U8FromI64,
Instruction::U16FromI32,
Instruction::U16FromI64,
Instruction::U32FromI32,
Instruction::U32FromI64,
Instruction::U64FromI32,
Instruction::U64FromI64,
Instruction::I32FromU8,
Instruction::I32FromU16,
Instruction::I32FromU32,
Instruction::I32FromU64,
Instruction::I64FromU8,
Instruction::I64FromU16,
Instruction::I64FromU32,
Instruction::I64FromU64,
Instruction::StringLiftMemory,
Instruction::StringLowerMemory {
allocator_index: 42,
},
Instruction::I32ToS8,
Instruction::I32ToS8X,
Instruction::I32ToU8,
Instruction::I32ToS16,
Instruction::I32ToS16X,
Instruction::I32ToU16,
Instruction::I32ToS32,
Instruction::I32ToU32,
Instruction::I32ToS64,
Instruction::I32ToU64,
Instruction::I64ToS8,
Instruction::I64ToS8X,
Instruction::I64ToU8,
Instruction::I64ToS16,
Instruction::I64ToS16X,
Instruction::I64ToU16,
Instruction::I64ToS32,
Instruction::I64ToS32X,
Instruction::I64ToU32,
Instruction::I64ToS64,
Instruction::I64ToU64,
Instruction::S8ToI32,
Instruction::U8ToI32,
Instruction::S16ToI32,
Instruction::U16ToI32,
Instruction::S32ToI32,
Instruction::U32ToI32,
Instruction::S64ToI32,
Instruction::S64ToI32X,
Instruction::U64ToI32,
Instruction::U64ToI32X,
Instruction::S8ToI64,
Instruction::U8ToI64,
Instruction::S16ToI64,
Instruction::U16ToI64,
Instruction::S32ToI64,
Instruction::U32ToI64,
Instruction::S64ToI64,
Instruction::U64ToI64,
Instruction::StringSize,
];
assert_eq!(inputs.len(), outputs.len());

View File

@ -260,52 +260,47 @@ where
(*function_index as u64).to_bytes(writer)?;
}
Instruction::MemoryToString => 0x03_u8.to_bytes(writer)?,
Instruction::S8FromI32 => 0x02_u8.to_bytes(writer)?,
Instruction::S8FromI64 => 0x03_u8.to_bytes(writer)?,
Instruction::S16FromI32 => 0x04_u8.to_bytes(writer)?,
Instruction::S16FromI64 => 0x05_u8.to_bytes(writer)?,
Instruction::S32FromI32 => 0x06_u8.to_bytes(writer)?,
Instruction::S32FromI64 => 0x07_u8.to_bytes(writer)?,
Instruction::S64FromI32 => 0x08_u8.to_bytes(writer)?,
Instruction::S64FromI64 => 0x09_u8.to_bytes(writer)?,
Instruction::I32FromS8 => 0x0a_u8.to_bytes(writer)?,
Instruction::I32FromS16 => 0x0b_u8.to_bytes(writer)?,
Instruction::I32FromS32 => 0x0c_u8.to_bytes(writer)?,
Instruction::I32FromS64 => 0x0d_u8.to_bytes(writer)?,
Instruction::I64FromS8 => 0x0e_u8.to_bytes(writer)?,
Instruction::I64FromS16 => 0x0f_u8.to_bytes(writer)?,
Instruction::I64FromS32 => 0x10_u8.to_bytes(writer)?,
Instruction::I64FromS64 => 0x11_u8.to_bytes(writer)?,
Instruction::U8FromI32 => 0x12_u8.to_bytes(writer)?,
Instruction::U8FromI64 => 0x13_u8.to_bytes(writer)?,
Instruction::U16FromI32 => 0x14_u8.to_bytes(writer)?,
Instruction::U16FromI64 => 0x15_u8.to_bytes(writer)?,
Instruction::U32FromI32 => 0x16_u8.to_bytes(writer)?,
Instruction::U32FromI64 => 0x17_u8.to_bytes(writer)?,
Instruction::U64FromI32 => 0x18_u8.to_bytes(writer)?,
Instruction::U64FromI64 => 0x19_u8.to_bytes(writer)?,
Instruction::I32FromU8 => 0x1a_u8.to_bytes(writer)?,
Instruction::I32FromU16 => 0x1b_u8.to_bytes(writer)?,
Instruction::I32FromU32 => 0x1c_u8.to_bytes(writer)?,
Instruction::I32FromU64 => 0x1d_u8.to_bytes(writer)?,
Instruction::I64FromU8 => 0x1e_u8.to_bytes(writer)?,
Instruction::I64FromU16 => 0x1f_u8.to_bytes(writer)?,
Instruction::I64FromU32 => 0x20_u8.to_bytes(writer)?,
Instruction::I64FromU64 => 0x21_u8.to_bytes(writer)?,
Instruction::StringToMemory { allocator_index } => {
0x04_u8.to_bytes(writer)?;
Instruction::StringLiftMemory => 0x22_u8.to_bytes(writer)?,
Instruction::StringLowerMemory { allocator_index } => {
0x23_u8.to_bytes(writer)?;
(*allocator_index as u64).to_bytes(writer)?;
}
Instruction::I32ToS8 => 0x07_u8.to_bytes(writer)?,
Instruction::I32ToS8X => 0x08_u8.to_bytes(writer)?,
Instruction::I32ToU8 => 0x09_u8.to_bytes(writer)?,
Instruction::I32ToS16 => 0x0a_u8.to_bytes(writer)?,
Instruction::I32ToS16X => 0x0b_u8.to_bytes(writer)?,
Instruction::I32ToU16 => 0x0c_u8.to_bytes(writer)?,
Instruction::I32ToS32 => 0x0d_u8.to_bytes(writer)?,
Instruction::I32ToU32 => 0x0e_u8.to_bytes(writer)?,
Instruction::I32ToS64 => 0x0f_u8.to_bytes(writer)?,
Instruction::I32ToU64 => 0x10_u8.to_bytes(writer)?,
Instruction::I64ToS8 => 0x11_u8.to_bytes(writer)?,
Instruction::I64ToS8X => 0x12_u8.to_bytes(writer)?,
Instruction::I64ToU8 => 0x13_u8.to_bytes(writer)?,
Instruction::I64ToS16 => 0x14_u8.to_bytes(writer)?,
Instruction::I64ToS16X => 0x15_u8.to_bytes(writer)?,
Instruction::I64ToU16 => 0x16_u8.to_bytes(writer)?,
Instruction::I64ToS32 => 0x17_u8.to_bytes(writer)?,
Instruction::I64ToS32X => 0x18_u8.to_bytes(writer)?,
Instruction::I64ToU32 => 0x19_u8.to_bytes(writer)?,
Instruction::I64ToS64 => 0x1a_u8.to_bytes(writer)?,
Instruction::I64ToU64 => 0x1b_u8.to_bytes(writer)?,
Instruction::S8ToI32 => 0x1c_u8.to_bytes(writer)?,
Instruction::U8ToI32 => 0x1d_u8.to_bytes(writer)?,
Instruction::S16ToI32 => 0x1e_u8.to_bytes(writer)?,
Instruction::U16ToI32 => 0x1f_u8.to_bytes(writer)?,
Instruction::S32ToI32 => 0x20_u8.to_bytes(writer)?,
Instruction::U32ToI32 => 0x21_u8.to_bytes(writer)?,
Instruction::S64ToI32 => 0x22_u8.to_bytes(writer)?,
Instruction::S64ToI32X => 0x23_u8.to_bytes(writer)?,
Instruction::U64ToI32 => 0x24_u8.to_bytes(writer)?,
Instruction::U64ToI32X => 0x25_u8.to_bytes(writer)?,
Instruction::S8ToI64 => 0x26_u8.to_bytes(writer)?,
Instruction::U8ToI64 => 0x27_u8.to_bytes(writer)?,
Instruction::S16ToI64 => 0x28_u8.to_bytes(writer)?,
Instruction::U16ToI64 => 0x29_u8.to_bytes(writer)?,
Instruction::S32ToI64 => 0x2a_u8.to_bytes(writer)?,
Instruction::U32ToI64 => 0x2b_u8.to_bytes(writer)?,
Instruction::S64ToI64 => 0x2c_u8.to_bytes(writer)?,
Instruction::U64ToI64 => 0x2d_u8.to_bytes(writer)?,
Instruction::StringSize => 0x24_u8.to_bytes(writer)?,
}
Ok(())
@ -550,93 +545,81 @@ mod tests {
vec![
Instruction::ArgumentGet { index: 1 },
Instruction::CallCore { function_index: 1 },
Instruction::MemoryToString,
Instruction::StringToMemory { allocator_index: 1 },
Instruction::I32ToS8,
Instruction::I32ToS8X,
Instruction::I32ToU8,
Instruction::I32ToS16,
Instruction::I32ToS16X,
Instruction::I32ToU16,
Instruction::I32ToS32,
Instruction::I32ToU32,
Instruction::I32ToS64,
Instruction::I32ToU64,
Instruction::I64ToS8,
Instruction::I64ToS8X,
Instruction::I64ToU8,
Instruction::I64ToS16,
Instruction::I64ToS16X,
Instruction::I64ToU16,
Instruction::I64ToS32,
Instruction::I64ToS32X,
Instruction::I64ToU32,
Instruction::I64ToS64,
Instruction::I64ToU64,
Instruction::S8ToI32,
Instruction::U8ToI32,
Instruction::S16ToI32,
Instruction::U16ToI32,
Instruction::S32ToI32,
Instruction::U32ToI32,
Instruction::S64ToI32,
Instruction::S64ToI32X,
Instruction::U64ToI32,
Instruction::U64ToI32X,
Instruction::S8ToI64,
Instruction::U8ToI64,
Instruction::S16ToI64,
Instruction::U16ToI64,
Instruction::S32ToI64,
Instruction::U32ToI64,
Instruction::S64ToI64,
Instruction::U64ToI64,
Instruction::S8FromI32,
Instruction::S8FromI64,
Instruction::S16FromI32,
Instruction::S16FromI64,
Instruction::S32FromI32,
Instruction::S32FromI64,
Instruction::S64FromI32,
Instruction::S64FromI64,
Instruction::I32FromS8,
Instruction::I32FromS16,
Instruction::I32FromS32,
Instruction::I32FromS64,
Instruction::I64FromS8,
Instruction::I64FromS16,
Instruction::I64FromS32,
Instruction::I64FromS64,
Instruction::U8FromI32,
Instruction::U8FromI64,
Instruction::U16FromI32,
Instruction::U16FromI64,
Instruction::U32FromI32,
Instruction::U32FromI64,
Instruction::U64FromI32,
Instruction::U64FromI64,
Instruction::I32FromU8,
Instruction::I32FromU16,
Instruction::I32FromU32,
Instruction::I32FromU64,
Instruction::I64FromU8,
Instruction::I64FromU16,
Instruction::I64FromU32,
Instruction::I64FromU64,
Instruction::StringLiftMemory,
Instruction::StringLowerMemory { allocator_index: 1 },
Instruction::StringSize,
],
&[
0x2b, // list of 43 items
0x25, // list of 37 items
0x00, 0x01, // ArgumentGet { index: 1 }
0x01, 0x01, // CallCore { function_index: 1 }
0x03, // MemoryToString
0x04, 0x01, // StringToMemory { allocator_index: 1 }
0x07, // I32ToS8
0x08, // I32ToS8X
0x09, // I32ToU8
0x0a, // I32ToS16
0x0b, // I32ToS16X
0x0c, // I32ToU16
0x0d, // I32ToS32
0x0e, // I32ToU32
0x0f, // I32ToS64
0x10, // I32ToU64
0x11, // I64ToS8
0x12, // I64ToS8X
0x13, // I64ToU8
0x14, // I64ToS16
0x15, // I64ToS16X
0x16, // I64ToU16
0x17, // I64ToS32
0x18, // I64ToS32X
0x19, // I64ToU32
0x1a, // I64ToS64
0x1b, // I64ToU64
0x1c, // S8ToI32
0x1d, // U8ToI32
0x1e, // S16ToI32
0x1f, // U16ToI32
0x20, // S32ToI32
0x21, // U32ToI32
0x22, // S64ToI32
0x23, // S64ToI32X
0x24, // U64ToI32
0x25, // U64ToI32X
0x26, // S8ToI64
0x27, // U8ToI64
0x28, // S16ToI64
0x29, // U16ToI64
0x2a, // S32ToI64
0x2b, // U32ToI64
0x2c, // S64ToI64
0x2d, // U64ToI64
0x02, // S8FromI32
0x03, // S8FromI64
0x04, // S16FromI32
0x05, // S16FromI64
0x06, // S32FromI32
0x07, // S32FromI64
0x08, // S64FromI32
0x09, // S64FromI64
0x0a, // I32FromS8
0x0b, // I32FromS16
0x0c, // I32FromS32
0x0d, // I32FromS64
0x0e, // I64FromS8
0x0f, // I64FromS16
0x10, // I64FromS32
0x11, // I64FromS64
0x12, // U8FromI32
0x13, // U8FromI64
0x14, // U16FromI32
0x15, // U16FromI64
0x16, // U32FromI32
0x17, // U32FromI64
0x18, // U64FromI32
0x19, // U64FromI64
0x1a, // I32FromU8
0x1b, // I32FromU16
0x1c, // I32FromU32
0x1d, // I32FromU64
0x1e, // I64FromU8
0x1f, // I64FromU16
0x20, // I64FromU32
0x21, // I64FromU64
0x22, // StringLiftMemory
0x23, 0x01, // StringLowerMemory { allocator_index: 1 }
0x24, // StringSize
]
);
}

View File

@ -85,49 +85,43 @@ impl ToString for &Instruction {
match self {
Instruction::ArgumentGet { index } => format!("arg.get {}", index),
Instruction::CallCore { function_index } => format!("call-core {}", function_index),
Instruction::MemoryToString => "memory-to-string".into(),
Instruction::StringToMemory { allocator_index } => {
format!(r#"string-to-memory {}"#, allocator_index)
Instruction::S8FromI32 => "s8.from_i32".into(),
Instruction::S8FromI64 => "s8.from_i64".into(),
Instruction::S16FromI32 => "s16.from_i32".into(),
Instruction::S16FromI64 => "s16.from_i64".into(),
Instruction::S32FromI32 => "s32.from_i32".into(),
Instruction::S32FromI64 => "s32.from_i64".into(),
Instruction::S64FromI32 => "s64.from_i32".into(),
Instruction::S64FromI64 => "s64.from_i64".into(),
Instruction::I32FromS8 => "i32.from_s8".into(),
Instruction::I32FromS16 => "i32.from_s16".into(),
Instruction::I32FromS32 => "i32.from_s32".into(),
Instruction::I32FromS64 => "i32.from_s64".into(),
Instruction::I64FromS8 => "i64.from_s8".into(),
Instruction::I64FromS16 => "i64.from_s16".into(),
Instruction::I64FromS32 => "i64.from_s32".into(),
Instruction::I64FromS64 => "i64.from_s64".into(),
Instruction::U8FromI32 => "u8.from_i32".into(),
Instruction::U8FromI64 => "u8.from_i64".into(),
Instruction::U16FromI32 => "u16.from_i32".into(),
Instruction::U16FromI64 => "u16.from_i64".into(),
Instruction::U32FromI32 => "u32.from_i32".into(),
Instruction::U32FromI64 => "u32.from_i64".into(),
Instruction::U64FromI32 => "u64.from_i32".into(),
Instruction::U64FromI64 => "u64.from_i64".into(),
Instruction::I32FromU8 => "i32.from_u8".into(),
Instruction::I32FromU16 => "i32.from_u16".into(),
Instruction::I32FromU32 => "i32.from_u32".into(),
Instruction::I32FromU64 => "i32.from_u64".into(),
Instruction::I64FromU8 => "i64.from_u8".into(),
Instruction::I64FromU16 => "i64.from_u16".into(),
Instruction::I64FromU32 => "i64.from_u32".into(),
Instruction::I64FromU64 => "i64.from_u64".into(),
Instruction::StringLiftMemory => "string.lift_memory".into(),
Instruction::StringLowerMemory { allocator_index } => {
format!(r#"string.lower_memory {}"#, allocator_index)
}
Instruction::I32ToS8 => "i32-to-s8".into(),
Instruction::I32ToS8X => "i32-to-s8x".into(),
Instruction::I32ToU8 => "i32-to-u8".into(),
Instruction::I32ToS16 => "i32-to-s16".into(),
Instruction::I32ToS16X => "i32-to-s16x".into(),
Instruction::I32ToU16 => "i32-to-u16".into(),
Instruction::I32ToS32 => "i32-to-s32".into(),
Instruction::I32ToU32 => "i32-to-u32".into(),
Instruction::I32ToS64 => "i32-to-s64".into(),
Instruction::I32ToU64 => "i32-to-u64".into(),
Instruction::I64ToS8 => "i64-to-s8".into(),
Instruction::I64ToS8X => "i64-to-s8x".into(),
Instruction::I64ToU8 => "i64-to-u8".into(),
Instruction::I64ToS16 => "i64-to-s16".into(),
Instruction::I64ToS16X => "i64-to-s16x".into(),
Instruction::I64ToU16 => "i64-to-u16".into(),
Instruction::I64ToS32 => "i64-to-s32".into(),
Instruction::I64ToS32X => "i64-to-s32x".into(),
Instruction::I64ToU32 => "i64-to-u32".into(),
Instruction::I64ToS64 => "i64-to-s64".into(),
Instruction::I64ToU64 => "i64-to-u64".into(),
Instruction::S8ToI32 => "s8-to-i32".into(),
Instruction::U8ToI32 => "u8-to-i32".into(),
Instruction::S16ToI32 => "s16-to-i32".into(),
Instruction::U16ToI32 => "u16-to-i32".into(),
Instruction::S32ToI32 => "s32-to-i32".into(),
Instruction::U32ToI32 => "u32-to-i32".into(),
Instruction::S64ToI32 => "s64-to-i32".into(),
Instruction::S64ToI32X => "s64-to-i32x".into(),
Instruction::U64ToI32 => "u64-to-i32".into(),
Instruction::U64ToI32X => "u64-to-i32x".into(),
Instruction::S8ToI64 => "s8-to-i64".into(),
Instruction::U8ToI64 => "u8-to-i64".into(),
Instruction::S16ToI64 => "s16-to-i64".into(),
Instruction::U16ToI64 => "u16-to-i64".into(),
Instruction::S32ToI64 => "s32-to-i64".into(),
Instruction::U32ToI64 => "u32-to-i64".into(),
Instruction::S64ToI64 => "s64-to-i64".into(),
Instruction::U64ToI64 => "u64-to-i64".into(),
Instruction::StringSize => "string.size".into(),
}
}
}
@ -361,95 +355,83 @@ mod tests {
let inputs: Vec<String> = vec![
(&Instruction::ArgumentGet { index: 7 }).to_string(),
(&Instruction::CallCore { function_index: 7 }).to_string(),
(&Instruction::MemoryToString).to_string(),
(&Instruction::StringToMemory {
(&Instruction::S8FromI32).to_string(),
(&Instruction::S8FromI64).to_string(),
(&Instruction::S16FromI32).to_string(),
(&Instruction::S16FromI64).to_string(),
(&Instruction::S32FromI32).to_string(),
(&Instruction::S32FromI64).to_string(),
(&Instruction::S64FromI32).to_string(),
(&Instruction::S64FromI64).to_string(),
(&Instruction::I32FromS8).to_string(),
(&Instruction::I32FromS16).to_string(),
(&Instruction::I32FromS32).to_string(),
(&Instruction::I32FromS64).to_string(),
(&Instruction::I64FromS8).to_string(),
(&Instruction::I64FromS16).to_string(),
(&Instruction::I64FromS32).to_string(),
(&Instruction::I64FromS64).to_string(),
(&Instruction::U8FromI32).to_string(),
(&Instruction::U8FromI64).to_string(),
(&Instruction::U16FromI32).to_string(),
(&Instruction::U16FromI64).to_string(),
(&Instruction::U32FromI32).to_string(),
(&Instruction::U32FromI64).to_string(),
(&Instruction::U64FromI32).to_string(),
(&Instruction::U64FromI64).to_string(),
(&Instruction::I32FromU8).to_string(),
(&Instruction::I32FromU16).to_string(),
(&Instruction::I32FromU32).to_string(),
(&Instruction::I32FromU64).to_string(),
(&Instruction::I64FromU8).to_string(),
(&Instruction::I64FromU16).to_string(),
(&Instruction::I64FromU32).to_string(),
(&Instruction::I64FromU64).to_string(),
(&Instruction::StringLiftMemory).to_string(),
(&Instruction::StringLowerMemory {
allocator_index: 42,
})
.to_string(),
(&Instruction::I32ToS8).to_string(),
(&Instruction::I32ToS8X).to_string(),
(&Instruction::I32ToU8).to_string(),
(&Instruction::I32ToS16).to_string(),
(&Instruction::I32ToS16X).to_string(),
(&Instruction::I32ToU16).to_string(),
(&Instruction::I32ToS32).to_string(),
(&Instruction::I32ToU32).to_string(),
(&Instruction::I32ToS64).to_string(),
(&Instruction::I32ToU64).to_string(),
(&Instruction::I64ToS8).to_string(),
(&Instruction::I64ToS8X).to_string(),
(&Instruction::I64ToU8).to_string(),
(&Instruction::I64ToS16).to_string(),
(&Instruction::I64ToS16X).to_string(),
(&Instruction::I64ToU16).to_string(),
(&Instruction::I64ToS32).to_string(),
(&Instruction::I64ToS32X).to_string(),
(&Instruction::I64ToU32).to_string(),
(&Instruction::I64ToS64).to_string(),
(&Instruction::I64ToU64).to_string(),
(&Instruction::S8ToI32).to_string(),
(&Instruction::U8ToI32).to_string(),
(&Instruction::S16ToI32).to_string(),
(&Instruction::U16ToI32).to_string(),
(&Instruction::S32ToI32).to_string(),
(&Instruction::U32ToI32).to_string(),
(&Instruction::S64ToI32).to_string(),
(&Instruction::S64ToI32X).to_string(),
(&Instruction::U64ToI32).to_string(),
(&Instruction::U64ToI32X).to_string(),
(&Instruction::S8ToI64).to_string(),
(&Instruction::U8ToI64).to_string(),
(&Instruction::S16ToI64).to_string(),
(&Instruction::U16ToI64).to_string(),
(&Instruction::S32ToI64).to_string(),
(&Instruction::U32ToI64).to_string(),
(&Instruction::S64ToI64).to_string(),
(&Instruction::U64ToI64).to_string(),
(&Instruction::StringSize).to_string(),
];
let outputs = vec![
"arg.get 7",
"call-core 7",
"memory-to-string",
"string-to-memory 42",
"i32-to-s8",
"i32-to-s8x",
"i32-to-u8",
"i32-to-s16",
"i32-to-s16x",
"i32-to-u16",
"i32-to-s32",
"i32-to-u32",
"i32-to-s64",
"i32-to-u64",
"i64-to-s8",
"i64-to-s8x",
"i64-to-u8",
"i64-to-s16",
"i64-to-s16x",
"i64-to-u16",
"i64-to-s32",
"i64-to-s32x",
"i64-to-u32",
"i64-to-s64",
"i64-to-u64",
"s8-to-i32",
"u8-to-i32",
"s16-to-i32",
"u16-to-i32",
"s32-to-i32",
"u32-to-i32",
"s64-to-i32",
"s64-to-i32x",
"u64-to-i32",
"u64-to-i32x",
"s8-to-i64",
"u8-to-i64",
"s16-to-i64",
"u16-to-i64",
"s32-to-i64",
"u32-to-i64",
"s64-to-i64",
"u64-to-i64",
"s8.from_i32",
"s8.from_i64",
"s16.from_i32",
"s16.from_i64",
"s32.from_i32",
"s32.from_i64",
"s64.from_i32",
"s64.from_i64",
"i32.from_s8",
"i32.from_s16",
"i32.from_s32",
"i32.from_s64",
"i64.from_s8",
"i64.from_s16",
"i64.from_s32",
"i64.from_s64",
"u8.from_i32",
"u8.from_i64",
"u16.from_i32",
"u16.from_i64",
"u32.from_i32",
"u32.from_i64",
"u64.from_i32",
"u64.from_i64",
"i32.from_u8",
"i32.from_u16",
"i32.from_u32",
"i32.from_u64",
"i64.from_u8",
"i64.from_u16",
"i64.from_u32",
"i64.from_u64",
"string.lift_memory",
"string.lower_memory 42",
"string.size",
];
assert_eq!(inputs, outputs);

View File

@ -5,6 +5,7 @@ use crate::{ast::InterfaceType, interpreter::Instruction};
use std::{
error::Error,
fmt::{self, Display, Formatter},
num::TryFromIntError,
result::Result,
string::{self, ToString},
};
@ -149,6 +150,12 @@ pub enum InstructionErrorKind {
/// The string contains invalid UTF-8 encoding.
String(string::FromUtf8Error),
/// Out of range integral type conversion attempted.
NegativeValue {
/// The variable name that triggered the error.
subject: &'static str,
},
}
impl Error for InstructionErrorKind {}
@ -227,6 +234,18 @@ impl Display for InstructionErrorKind {
"{}",
error
),
Self::NegativeValue { subject } => write!(
formatter,
"attempted to convert `{}` but it appears to be a negative value",
subject
),
}
}
}
impl From<(TryFromIntError, &'static str)> for InstructionErrorKind {
fn from((_, subject): (TryFromIntError, &'static str)) -> Self {
InstructionErrorKind::NegativeValue { subject }
}
}

View File

@ -12,132 +12,114 @@ pub enum Instruction {
/// The `call-core` instruction.
CallCore {
/// The function index.
function_index: usize,
function_index: u32,
},
/// The `memory-to-string` instruction.
MemoryToString,
/// The `s8.from_i32` instruction.
S8FromI32,
/// The `string-to-memory` instruction.
StringToMemory {
/// The `s8.from_i64` instruction.
S8FromI64,
/// The `s16.from_i32` instruction.
S16FromI32,
/// The `s16.from_i64` instruction.
S16FromI64,
/// The `s32.from_i32` instruction.
S32FromI32,
/// The `s32.from_i64` instruction.
S32FromI64,
/// The `s64.from_i32` instruction.
S64FromI32,
/// The `s64.from_i64` instruction.
S64FromI64,
/// The `i32.from_s8` instruction.
I32FromS8,
/// The `i32.from_s16` instruction.
I32FromS16,
/// The `i32.from_s32` instruction.
I32FromS32,
/// The `i32.from_s64` instruction.
I32FromS64,
/// The `i64.from_s8` instruction.
I64FromS8,
/// The `i64.from_s16` instruction.
I64FromS16,
/// The `i64.from_s32` instruction.
I64FromS32,
/// The `i64.from_s64` instruction.
I64FromS64,
/// The `u8.from_i32` instruction.
U8FromI32,
/// The `u8.from_i64` instruction.
U8FromI64,
/// The `u16.from_i32` instruction.
U16FromI32,
/// The `u16.from_i64` instruction.
U16FromI64,
/// The `u32.from_i32` instruction.
U32FromI32,
/// The `u32.from_i64` instruction.
U32FromI64,
/// The `u64.from_i32` instruction.
U64FromI32,
/// The `u64.from_i64` instruction.
U64FromI64,
/// The `i32.from_u8` instruction.
I32FromU8,
/// The `i32.from_u16` instruction.
I32FromU16,
/// The `i32.from_u32` instruction.
I32FromU32,
/// The `i32.from_u64` instruction.
I32FromU64,
/// The `i64.from_u8` instruction.
I64FromU8,
/// The `i64.from_u16` instruction.
I64FromU16,
/// The `i64.from_u32` instruction.
I64FromU32,
/// The `i64.from_u64` instruction.
I64FromU64,
/// The `string.lift_memory` instruction.
StringLiftMemory,
/// The `string.lower_memory` instruction.
StringLowerMemory {
/// The allocator function index.
allocator_index: u32,
},
/// The `i32-to-s8,` instruction.
I32ToS8,
/// The `i32-to-s8x,` instruction.
I32ToS8X,
/// The `i32-to-u8,` instruction.
I32ToU8,
/// The `i32-to-s16,` instruction.
I32ToS16,
/// The `i32-to-s16x,` instruction.
I32ToS16X,
/// The `i32-to-u16,` instruction.
I32ToU16,
/// The `i32-to-s32,` instruction.
I32ToS32,
/// The `i32-to-u32,` instruction.
I32ToU32,
/// The `i32-to-s64,` instruction.
I32ToS64,
/// The `i32-to-u64,` instruction.
I32ToU64,
/// The `i64-to-s8,` instruction.
I64ToS8,
/// The `i64-to-s8x,` instruction.
I64ToS8X,
/// The `i64-to-u8,` instruction.
I64ToU8,
/// The `i64-to-s16,` instruction.
I64ToS16,
/// The `i64-to-s16x,` instruction.
I64ToS16X,
/// The `i64-to-u16,` instruction.
I64ToU16,
/// The `i64-to-s32,` instruction.
I64ToS32,
/// The `i64-to-s32x,` instruction.
I64ToS32X,
/// The `i64-to-u32,` instruction.
I64ToU32,
/// The `i64-to-s64,` instruction.
I64ToS64,
/// The `i64-to-u64,` instruction.
I64ToU64,
/// The `s8-to-i32,` instruction.
S8ToI32,
/// The `u8-to-i32,` instruction.
U8ToI32,
/// The `s16-to-i32,` instruction.
S16ToI32,
/// The `u16-to-i32,` instruction.
U16ToI32,
/// The `s32-to-i32,` instruction.
S32ToI32,
/// The `u32-to-i32,` instruction.
U32ToI32,
/// The `s64-to-i32,` instruction.
S64ToI32,
/// The `s64-to-i32x,` instruction.
S64ToI32X,
/// The `u64-to-i32,` instruction.
U64ToI32,
/// The `u64-to-i32x,` instruction.
U64ToI32X,
/// The `s8-to-i64,` instruction.
S8ToI64,
/// The `u8-to-i64,` instruction.
U8ToI64,
/// The `s16-to-i64,` instruction.
S16ToI64,
/// The `u16-to-i64,` instruction.
U16ToI64,
/// The `s32-to-i64,` instruction.
S32ToI64,
/// The `u32-to-i64,` instruction.
U32ToI64,
/// The `s64-to-i64,` instruction.
S64ToI64,
/// The `u64-to-i64,` instruction.
U64ToI64,
/// The `string.size` instruction.
StringSize,
}

View File

@ -8,7 +8,7 @@ executable_instruction!(
move |runtime| -> _ {
let invocation_inputs = runtime.invocation_inputs;
if index >= (invocation_inputs.len() as u32) {
if (index as usize) >= invocation_inputs.len() {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::InvocationInputIsMissing { index },

View File

@ -8,16 +8,16 @@ use crate::{
};
executable_instruction!(
call_core(function_index: usize, instruction: Instruction) -> _ {
call_core(function_index: u32, instruction: Instruction) -> _ {
move |runtime| -> _ {
let instance = &mut runtime.wasm_instance;
let index = FunctionIndex::new(function_index);
let index = FunctionIndex::new(function_index as usize);
let local_or_import = instance.local_or_import(index).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportIsMissing {
function_index: function_index as u32,
function_index: function_index,
},
)
})?;
@ -40,7 +40,7 @@ executable_instruction!(
return Err(InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportSignatureMismatch {
function_index: function_index as u32,
function_index: function_index,
expected: (local_or_import.inputs().to_vec(), vec![]),
received: (input_types, vec![]),
},
@ -51,7 +51,7 @@ executable_instruction!(
InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportCall {
function_index: function_index as u32,
function_index: function_index,
},
)
})?;
@ -70,8 +70,8 @@ mod tests {
test_executable_instruction!(
test_call_core =
instructions: [
Instruction::ArgumentGet { index: 1 },
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [
@ -113,8 +113,8 @@ mod tests {
test_executable_instruction!(
test_call_core__invalid_types_in_the_stack =
instructions: [
Instruction::ArgumentGet { index: 1 },
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [
@ -129,8 +129,8 @@ mod tests {
test_executable_instruction!(
test_call_core__failure_when_calling =
instructions: [
Instruction::ArgumentGet { index: 1 },
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [
@ -160,8 +160,8 @@ mod tests {
test_executable_instruction!(
test_call_core__void =
instructions: [
Instruction::ArgumentGet { index: 1 },
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::CallCore { function_index: 42 },
],
invocation_inputs: [

View File

@ -1,159 +0,0 @@
use super::to_native;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::{wasm::values::InterfaceValue, Instruction},
};
use std::cell::Cell;
executable_instruction!(
memory_to_string(instruction: Instruction) -> _ {
move |runtime| -> _ {
let inputs = runtime.stack.pop(2).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::StackIsTooSmall { needed: 2 },
)
})?;
let memory_index: u32 = 0;
let memory = runtime
.wasm_instance
.memory(memory_index as usize)
.ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::MemoryIsMissing { memory_index },
)
})?;
let length = to_native::<i32>(&inputs[0], instruction)? as usize;
let pointer = to_native::<i32>(&inputs[1], instruction)? as usize;
let memory_view = memory.view();
if length == 0 {
runtime.stack.push(InterfaceValue::String("".into()));
return Ok(())
}
if memory_view.len() <= pointer + length - 1 {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: pointer + length,
length: memory_view.len(),
},
));
}
let data: Vec<u8> = (&memory_view[pointer..=pointer + length - 1])
.iter()
.map(Cell::get)
.collect();
let string = String::from_utf8(data)
.map_err(|error| InstructionError::new(instruction, InstructionErrorKind::String(error)))?;
runtime.stack.push(InterfaceValue::String(string));
Ok(())
}
}
);
#[cfg(test)]
mod tests {
test_executable_instruction!(
test_memory_to_string =
instructions: [
Instruction::ArgumentGet { index: 1 },
Instruction::ArgumentGet { index: 0 },
Instruction::MemoryToString,
],
invocation_inputs: [
InterfaceValue::I32(13),
// ^^^^^^^ length
InterfaceValue::I32(0),
// ^^^^^^ pointer
],
instance: Instance {
memory: Memory::new("Hello, World!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
..Default::default()
},
stack: [InterfaceValue::String("Hello, World!".into())],
);
test_executable_instruction!(
test_memory_to_string__empty_string =
instructions: [
Instruction::ArgumentGet { index: 1 },
Instruction::ArgumentGet { index: 0 },
Instruction::MemoryToString,
],
invocation_inputs: [
InterfaceValue::I32(0),
InterfaceValue::I32(0),
],
instance: Instance {
memory: Memory::new(vec![]),
..Default::default()
},
stack: [InterfaceValue::String("".into())],
);
test_executable_instruction!(
test_memory_to_string__read_out_of_memory =
instructions: [
Instruction::ArgumentGet { index: 1 },
Instruction::ArgumentGet { index: 0 },
Instruction::MemoryToString,
],
invocation_inputs: [
InterfaceValue::I32(13),
// ^^^^^^^ length is too long
InterfaceValue::I32(0),
// ^^^^^^ pointer
],
instance: Instance {
memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
..Default::default()
},
error: r#"`memory-to-string` read out of the memory bounds (index 13 > memory length 6)"#,
);
test_executable_instruction!(
test_memory_to_string__invalid_encoding =
instructions: [
Instruction::ArgumentGet { index: 1 },
Instruction::ArgumentGet { index: 0 },
Instruction::MemoryToString,
],
invocation_inputs: [
InterfaceValue::I32(4),
// ^^^^^^ length is too long
InterfaceValue::I32(0),
// ^^^^^^ pointer
],
instance: Instance {
memory: Memory::new(vec![0, 159, 146, 150].iter().map(|b| Cell::new(*b)).collect::<Vec<Cell<u8>>>()),
..Default::default()
},
error: r#"`memory-to-string` invalid utf-8 sequence of 1 bytes from index 1"#,
);
test_executable_instruction!(
test_memory_to_string__stack_is_too_small =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::MemoryToString,
// ^^^^^^^^^^^^^^ `memory-to-string` expects 2 values on the stack, only one is present.
],
invocation_inputs: [
InterfaceValue::I32(13),
InterfaceValue::I32(0),
],
instance: Instance::new(),
error: r#"`memory-to-string` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#,
);
}

View File

@ -1,8 +1,7 @@
mod argument_get;
mod call_core;
mod lowering_lifting;
mod memory_to_string;
mod string_to_memory;
mod numbers;
mod strings;
use crate::{
errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError},
@ -13,10 +12,9 @@ use crate::{
};
pub(crate) use argument_get::argument_get;
pub(crate) use call_core::call_core;
pub(crate) use lowering_lifting::*;
pub(crate) use memory_to_string::memory_to_string;
pub(crate) use numbers::*;
use std::convert::TryFrom;
pub(crate) use string_to_memory::string_to_memory;
pub(crate) use strings::*;
/// Just a short helper to map the error of a cast from an
/// `InterfaceValue` to a native value.

View File

@ -6,7 +6,7 @@ use crate::{
use std::convert::TryInto;
macro_rules! lowering_lifting {
($instruction_function_name:ident, $instruction_name:expr, $from_variant:ident, $to_variant:ident) => {
($instruction_function_name:ident, $instruction_name:expr, $to_variant:ident, $from_variant:ident) => {
executable_instruction!(
$instruction_function_name(instruction: Instruction) -> _ {
move |runtime| -> _ {
@ -52,316 +52,316 @@ macro_rules! lowering_lifting {
};
}
lowering_lifting!(i32_to_s8, "i32-to-s8", I32, S8);
lowering_lifting!(i32_to_u8, "i32-to-u8", I32, U8);
lowering_lifting!(i32_to_s16, "i32-to-s16", I32, S16);
lowering_lifting!(i32_to_u16, "i32-to-u16", I32, U16);
lowering_lifting!(i32_to_s32, "i32-to-s32", I32, S32);
lowering_lifting!(i32_to_u32, "i32-to-u32", I32, U32);
lowering_lifting!(i32_to_s64, "i32-to-s64", I32, S64);
lowering_lifting!(i32_to_u64, "i32-to-u64", I32, U64);
lowering_lifting!(i64_to_s8, "i64-to-s8", I64, S8);
lowering_lifting!(i64_to_u8, "i64-to-u8", I64, U8);
lowering_lifting!(i64_to_s16, "i64-to-s16", I64, S16);
lowering_lifting!(i64_to_u16, "i64-to-u16", I64, U16);
lowering_lifting!(i64_to_s32, "i64-to-s32", I64, S32);
lowering_lifting!(i64_to_u32, "i64-to-u32", I64, U32);
lowering_lifting!(i64_to_s64, "i64-to-s64", I64, S64);
lowering_lifting!(i64_to_u64, "i64-to-u64", I64, U64);
lowering_lifting!(s8_to_i32, "s8-to-i32", S8, I32);
lowering_lifting!(u8_to_i32, "u8-to-i32", U8, I32);
lowering_lifting!(s16_to_i32, "s16-to-i32", S16, I32);
lowering_lifting!(u16_to_i32, "u16-to-i32", U16, I32);
lowering_lifting!(s32_to_i32, "s32-to-i32", S32, I32);
lowering_lifting!(u32_to_i32, "u32-to-i32", U32, I32);
lowering_lifting!(s64_to_i32, "s64-to-i32", S64, I32);
lowering_lifting!(u64_to_i32, "u64-to-i32", U64, I32);
lowering_lifting!(s8_to_i64, "s8-to-i64", S8, I64);
lowering_lifting!(u8_to_i64, "u8-to-i64", U8, I64);
lowering_lifting!(s16_to_i64, "s16-to-i64", S16, I64);
lowering_lifting!(u16_to_i64, "u16-to-i64", U16, I64);
lowering_lifting!(s32_to_i64, "s32-to-i64", S32, I64);
lowering_lifting!(u32_to_i64, "u32-to-i64", U32, I64);
lowering_lifting!(s64_to_i64, "s64-to-i64", S64, I64);
lowering_lifting!(u64_to_i64, "u64-to-i64", U64, I64);
lowering_lifting!(s8_from_i32, "s8.from_i32", S8, I32);
lowering_lifting!(s8_from_i64, "s8.from_i64", S8, I64);
lowering_lifting!(s16_from_i32, "s16.from_i32", S16, I32);
lowering_lifting!(s16_from_i64, "s16.from_i64", S16, I64);
lowering_lifting!(s32_from_i32, "s32.from_i32", S32, I32);
lowering_lifting!(s32_from_i64, "s32.from_i64", S32, I64);
lowering_lifting!(s64_from_i32, "s64.from_i32", S64, I32);
lowering_lifting!(s64_from_i64, "s64.from_i64", S64, I64);
lowering_lifting!(i32_from_s8, "i32.from_s8", I32, S8);
lowering_lifting!(i32_from_s16, "i32.from_s16", I32, S16);
lowering_lifting!(i32_from_s32, "i32.from_s32", I32, S32);
lowering_lifting!(i32_from_s64, "i32.from_s64", I32, S64);
lowering_lifting!(i64_from_s8, "i64.from_s8", I64, S8);
lowering_lifting!(i64_from_s16, "i64.from_s16", I64, S16);
lowering_lifting!(i64_from_s32, "i64.from_s32", I64, S32);
lowering_lifting!(i64_from_s64, "i64.from_s64", I64, S64);
lowering_lifting!(u8_from_i32, "u8.from_i32", U8, I32);
lowering_lifting!(u8_from_i64, "u8.from_i64", U8, I64);
lowering_lifting!(u16_from_i32, "u16.from_i32", U16, I32);
lowering_lifting!(u16_from_i64, "u16.from_i64", U16, I64);
lowering_lifting!(u32_from_i32, "u32.from_i32", U32, I32);
lowering_lifting!(u32_from_i64, "u32.from_i64", U32, I64);
lowering_lifting!(u64_from_i32, "u64.from_i32", U64, I32);
lowering_lifting!(u64_from_i64, "u64.from_i64", U64, I64);
lowering_lifting!(i32_from_u8, "i32.from_u8", I32, U8);
lowering_lifting!(i32_from_u16, "i32.from_u16", I32, U16);
lowering_lifting!(i32_from_u32, "i32.from_u32", I32, U32);
lowering_lifting!(i32_from_u64, "i32.from_u64", I32, U64);
lowering_lifting!(i64_from_u8, "i64.from_u8", I64, U8);
lowering_lifting!(i64_from_u16, "i64.from_u16", I64, U16);
lowering_lifting!(i64_from_u32, "i64.from_u32", I64, U32);
lowering_lifting!(i64_from_u64, "i64.from_u64", I64, U64);
#[cfg(test)]
mod tests {
test_executable_instruction!(
test_i32_to_s8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToS8],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::S8(42)],
);
test_executable_instruction!(
test_convert_fails =
instructions: [Instruction::ArgumentGet { index: 0}, Instruction::I32ToS8],
instructions: [Instruction::ArgumentGet { index: 0}, Instruction::S8FromI32],
invocation_inputs: [InterfaceValue::I32(128)],
instance: Instance::new(),
error: "`i32-to-s8` failed to cast `I32` to `S8`"
error: "`s8.from_i32` failed to cast `I32` to `S8`"
);
test_executable_instruction!(
test_type_mismatch =
instructions: [Instruction::ArgumentGet { index: 0}, Instruction::I32ToS8],
instructions: [Instruction::ArgumentGet { index: 0}, Instruction::S8FromI32],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
error: "`i32-to-s8` read a value of type `I64` from the stack, but the type `I32` was expected"
error: "`s8.from_i32` read a value of type `I64` from the stack, but the type `I32` was expected"
);
test_executable_instruction!(
test_no_value_on_the_stack =
instructions: [Instruction::I32ToS8],
instructions: [Instruction::S8FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
error: "`i32-to-s8` needed to read `1` value(s) from the stack, but it doesn't contain enough data"
error: "`s8.from_i32` needed to read `1` value(s) from the stack, but it doesn't contain enough data"
);
test_executable_instruction!(
test_i32_to_u8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToU8],
test_s8_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U8(42)],
stack: [InterfaceValue::S8(42)],
);
test_executable_instruction!(
test_i32_to_s16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToS16],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::S16(42)],
);
test_executable_instruction!(
test_i32_to_u16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToU16],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U16(42)],
);
test_executable_instruction!(
test_i32_to_s32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToS32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::S32(42)],
);
test_executable_instruction!(
test_i32_to_u32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToU32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U32(42)],
);
test_executable_instruction!(
test_i32_to_s64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToS64],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::S64(42)],
);
test_executable_instruction!(
test_i32_to_u64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32ToU64],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U64(42)],
);
test_executable_instruction!(
test_i64_to_s8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToS8],
test_s8_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::S8(42)],
);
test_executable_instruction!(
test_i64_to_u8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToU8],
invocation_inputs: [InterfaceValue::I64(42)],
test_s16_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U8(42)],
stack: [InterfaceValue::S16(42)],
);
test_executable_instruction!(
test_i64_to_s16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToS16],
test_s16_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::S16(42)],
);
test_executable_instruction!(
test_i64_to_u16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToU16],
invocation_inputs: [InterfaceValue::I64(42)],
test_s32_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U16(42)],
stack: [InterfaceValue::S32(42)],
);
test_executable_instruction!(
test_i64_to_s32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToS32],
test_s32_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::S32(42)],
);
test_executable_instruction!(
test_i64_to_u32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToU32],
invocation_inputs: [InterfaceValue::I64(42)],
test_s64_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U32(42)],
stack: [InterfaceValue::S64(42)],
);
test_executable_instruction!(
test_i64_to_s64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToS64],
test_s64_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::S64(42)],
);
test_executable_instruction!(
test_i64_to_u64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64ToU64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U64(42)],
);
test_executable_instruction!(
test_s8_to_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8ToI32],
test_i32_from_s8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS8],
invocation_inputs: [InterfaceValue::S8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_u8_to_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8ToI32],
invocation_inputs: [InterfaceValue::U8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_s16_to_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16ToI32],
test_i32_from_s16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS16],
invocation_inputs: [InterfaceValue::S16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_u16_to_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16ToI32],
invocation_inputs: [InterfaceValue::U16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_s32_to_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32ToI32],
test_i32_from_s32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS32],
invocation_inputs: [InterfaceValue::S32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_u32_to_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32ToI32],
invocation_inputs: [InterfaceValue::U32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_s64_to_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64ToI32],
test_i32_from_s64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS64],
invocation_inputs: [InterfaceValue::S64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_u64_to_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64ToI32],
test_i64_from_s8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS8],
invocation_inputs: [InterfaceValue::S8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_s16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS16],
invocation_inputs: [InterfaceValue::S16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_s32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS32],
invocation_inputs: [InterfaceValue::S32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_i64_from_s64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS64],
invocation_inputs: [InterfaceValue::S64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_u8_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U8(42)],
);
test_executable_instruction!(
test_u8_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U8(42)],
);
test_executable_instruction!(
test_u16_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U16(42)],
);
test_executable_instruction!(
test_u16_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U16(42)],
);
test_executable_instruction!(
test_u32_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U32(42)],
);
test_executable_instruction!(
test_u32_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U32(42)],
);
test_executable_instruction!(
test_u64_from_i32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64FromI32],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
stack: [InterfaceValue::U64(42)],
);
test_executable_instruction!(
test_u64_from_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64FromI64],
invocation_inputs: [InterfaceValue::I64(42)],
instance: Instance::new(),
stack: [InterfaceValue::U64(42)],
);
test_executable_instruction!(
test_i32_from_u8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU8],
invocation_inputs: [InterfaceValue::U8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_u16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU16],
invocation_inputs: [InterfaceValue::U16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_u32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU32],
invocation_inputs: [InterfaceValue::U32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_i32_from_u64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU64],
invocation_inputs: [InterfaceValue::U64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I32(42)],
);
test_executable_instruction!(
test_s8_to_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8ToI64],
invocation_inputs: [InterfaceValue::S8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_u8_to_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8ToI64],
test_i64_from_u8 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU8],
invocation_inputs: [InterfaceValue::U8(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_s16_to_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16ToI64],
invocation_inputs: [InterfaceValue::S16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_u16_to_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16ToI64],
test_i64_from_u16 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU16],
invocation_inputs: [InterfaceValue::U16(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_s32_to_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32ToI64],
invocation_inputs: [InterfaceValue::S32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_u32_to_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32ToI64],
test_i64_from_u32 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU32],
invocation_inputs: [InterfaceValue::U32(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_s64_to_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64ToI64],
invocation_inputs: [InterfaceValue::S64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],
);
test_executable_instruction!(
test_u64_to_i64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64ToI64],
test_i64_from_u64 =
instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU64],
invocation_inputs: [InterfaceValue::U64(42)],
instance: Instance::new(),
stack: [InterfaceValue::I64(42)],

View File

@ -1,175 +0,0 @@
use super::to_native;
use crate::{
ast::InterfaceType,
errors::{InstructionError, InstructionErrorKind},
interpreter::{
wasm::{
structures::{FunctionIndex, TypedIndex},
values::InterfaceValue,
},
Instruction,
},
};
executable_instruction!(
string_to_memory(allocator_index: u32, instruction: Instruction) -> _ {
move |runtime| -> _ {
let instance = &mut runtime.wasm_instance;
let index = FunctionIndex::new(allocator_index as usize);
let allocator = instance.local_or_import(index).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportIsMissing { function_index: allocator_index },
)
})?;
if allocator.inputs() != [InterfaceType::I32] || allocator.outputs() != [InterfaceType::I32] {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportSignatureMismatch {
function_index: allocator_index,
expected: (vec![InterfaceType::I32], vec![InterfaceType::I32]),
received: (allocator.inputs().to_vec(), allocator.outputs().to_vec())
}
))
}
let string = runtime.stack.pop1().ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::StackIsTooSmall { needed: 1 }
)
})?;
let string: String = to_native(&string, instruction)?;
let string_bytes = string.as_bytes();
let string_length = string_bytes.len() as i32;
let outputs = allocator.call(&[InterfaceValue::I32(string_length)]).map_err(|_| {
InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportCall { function_index: allocator_index },
)
})?;
let string_pointer: i32 = to_native(&outputs[0], instruction)?;
let memory_index: u32 = 0;
let memory_view = instance
.memory(memory_index as usize)
.ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::MemoryIsMissing { memory_index }
)
})?
.view();
for (nth, byte) in string_bytes.iter().enumerate() {
memory_view[string_pointer as usize + nth].set(*byte);
}
runtime.stack.push(InterfaceValue::I32(string_pointer));
runtime.stack.push(InterfaceValue::I32(string_length));
Ok(())
}
}
);
#[cfg(test)]
mod tests {
test_executable_instruction!(
test_string_to_memory =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringToMemory { allocator_index: 43 },
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: Instance::new(),
stack: [
InterfaceValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(13),
// ^^^^^^^ length
]
);
test_executable_instruction!(
test_string_to_memory__roundtrip_with_memory_to_string =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringToMemory { allocator_index: 43 },
Instruction::MemoryToString,
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: Instance::new(),
stack: [InterfaceValue::String("Hello, World!".into())],
);
test_executable_instruction!(
test_string_to_memory__allocator_does_not_exist =
instructions: [Instruction::StringToMemory { allocator_index: 43 }],
invocation_inputs: [],
instance: Instance { ..Default::default() },
error: r#"`string-to-memory 43` the local or import function `43` doesn't exist"#,
);
test_executable_instruction!(
test_string_to_memory__stack_is_too_small =
instructions: [
Instruction::StringToMemory { allocator_index: 43 }
// ^^ `43` expects 1 value on the stack, none is present
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: Instance::new(),
error: r#"`string-to-memory 43` needed to read `1` value(s) from the stack, but it doesn't contain enough data"#,
);
test_executable_instruction!(
test_string_to_memory__failure_when_calling_the_allocator =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringToMemory { allocator_index: 153 }
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: {
let mut instance = Instance::new();
instance.locals_or_imports.insert(
153,
LocalImport {
inputs: vec![InterfaceType::I32],
outputs: vec![InterfaceType::I32],
function: |_| Err(()),
// ^^^^^^^ function fails
},
);
instance
},
error: r#"`string-to-memory 153` failed while calling the local or import function `153`"#,
);
test_executable_instruction!(
test_string_to_memory__invalid_allocator_signature =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringToMemory { allocator_index: 153 }
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: {
let mut instance = Instance::new();
instance.locals_or_imports.insert(
153,
LocalImport {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![],
function: |_| Err(()),
},
);
instance
},
error: r#"`string-to-memory 153` the local or import function `153` has the signature `[I32] -> [I32]` but it received values of kind `[I32, I32] -> []`"#,
);
}

View File

@ -0,0 +1,437 @@
use super::to_native;
use crate::{
ast::InterfaceType,
errors::{InstructionError, InstructionErrorKind},
interpreter::{
wasm::{
structures::{FunctionIndex, TypedIndex},
values::InterfaceValue,
},
Instruction,
},
};
use std::{cell::Cell, convert::TryInto};
executable_instruction!(
string_lift_memory(instruction: Instruction) -> _ {
move |runtime| -> _ {
let inputs = runtime.stack.pop(2).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::StackIsTooSmall { needed: 2 },
)
})?;
let memory_index: u32 = 0;
let memory = runtime
.wasm_instance
.memory(memory_index as usize)
.ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::MemoryIsMissing { memory_index },
)
})?;
let pointer: usize = to_native::<i32>(&inputs[0], instruction)?
.try_into()
.map_err(|e| (e, "pointer").into())
.map_err(|k| InstructionError::new(instruction, k))?;
let length: usize = to_native::<i32>(&inputs[1], instruction)?
.try_into()
.map_err(|e| (e, "length").into())
.map_err(|k| InstructionError::new(instruction, k))?;
let memory_view = memory.view();
if length == 0 {
runtime.stack.push(InterfaceValue::String("".into()));
return Ok(())
}
if memory_view.len() <= pointer + length - 1 {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: pointer + length,
length: memory_view.len(),
},
));
}
let data: Vec<u8> = (&memory_view[pointer..=pointer + length - 1])
.iter()
.map(Cell::get)
.collect();
let string = String::from_utf8(data)
.map_err(|error| InstructionError::new(instruction, InstructionErrorKind::String(error)))?;
runtime.stack.push(InterfaceValue::String(string));
Ok(())
}
}
);
executable_instruction!(
string_lower_memory(allocator_index: u32, instruction: Instruction) -> _ {
move |runtime| -> _ {
let instance = &mut runtime.wasm_instance;
let index = FunctionIndex::new(allocator_index as usize);
let allocator = instance.local_or_import(index).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportIsMissing { function_index: allocator_index },
)
})?;
if allocator.inputs() != [InterfaceType::I32] || allocator.outputs() != [InterfaceType::I32] {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportSignatureMismatch {
function_index: allocator_index,
expected: (vec![InterfaceType::I32], vec![InterfaceType::I32]),
received: (allocator.inputs().to_vec(), allocator.outputs().to_vec())
}
))
}
let string = runtime.stack.pop1().ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::StackIsTooSmall { needed: 1 }
)
})?;
let string: String = to_native(&string, instruction)?;
let string_bytes = string.as_bytes();
let string_length: i32 = string_bytes.len().try_into().map_err(|_| {
InstructionError::new(
instruction,
InstructionErrorKind::NegativeValue { subject: "string_length" },
)
})?;
let outputs = allocator.call(&[InterfaceValue::I32(string_length)]).map_err(|_| {
InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportCall { function_index: allocator_index },
)
})?;
let string_pointer: u32 = to_native::<i32>(&outputs[0], instruction)?.try_into().map_err(|_| {
InstructionError::new(
instruction,
InstructionErrorKind::NegativeValue { subject: "string_pointer" },
)
})?;
let memory_index: u32 = 0;
let memory_view = instance
.memory(memory_index as usize)
.ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::MemoryIsMissing { memory_index }
)
})?
.view();
for (nth, byte) in string_bytes.iter().enumerate() {
memory_view[string_pointer as usize + nth].set(*byte);
}
runtime.stack.push(InterfaceValue::I32(string_pointer as i32));
runtime.stack.push(InterfaceValue::I32(string_length));
Ok(())
}
}
);
executable_instruction!(
string_size(instruction: Instruction) -> _ {
move |runtime| -> _ {
let value = runtime.stack.peek1().ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::StackIsTooSmall { needed: 1 },
)
})?;
if let InterfaceValue::String(string) = value {
let length = string.len() as i32;
runtime.stack.push(InterfaceValue::I32(length));
Ok(())
} else {
Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::String,
received_type: value.into(),
}
))
}
}
}
);
#[cfg(test)]
mod tests {
test_executable_instruction!(
test_string_lift_memory =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(13),
// ^^^^^^^ length
],
instance: Instance {
memory: Memory::new("Hello, World!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
..Default::default()
},
stack: [InterfaceValue::String("Hello, World!".into())],
);
test_executable_instruction!(
test_string_lift_memory__empty_string =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
InterfaceValue::I32(0),
],
instance: Instance {
memory: Memory::new(vec![]),
..Default::default()
},
stack: [InterfaceValue::String("".into())],
);
test_executable_instruction!(
test_string_lift_memory__negative_pointer =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(-42),
InterfaceValue::I32(13),
],
instance: Instance {
memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
..Default::default()
},
error: r#"`string.lift_memory` attempted to convert `pointer` but it appears to be a negative value"#,
);
test_executable_instruction!(
test_string_lift_memory__negative_length =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
InterfaceValue::I32(-1),
],
instance: Instance {
memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
..Default::default()
},
error: r#"`string.lift_memory` attempted to convert `length` but it appears to be a negative value"#,
);
test_executable_instruction!(
test_string_lift_memory__read_out_of_memory =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(13),
// ^^^^^^^ length is too long
],
instance: Instance {
memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()),
..Default::default()
},
error: r#"`string.lift_memory` read out of the memory bounds (index 13 > memory length 6)"#,
);
test_executable_instruction!(
test_string_lift_memory__invalid_encoding =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::ArgumentGet { index: 1 },
Instruction::StringLiftMemory,
],
invocation_inputs: [
InterfaceValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(4),
// ^^^^^^ length is too long
],
instance: Instance {
memory: Memory::new(vec![0, 159, 146, 150].iter().map(|b| Cell::new(*b)).collect::<Vec<Cell<u8>>>()),
..Default::default()
},
error: r#"`string.lift_memory` invalid utf-8 sequence of 1 bytes from index 1"#,
);
test_executable_instruction!(
test_string_lift_memory__stack_is_too_small =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringLiftMemory,
// ^^^^^^^^^^^^^^^^ `string.lift_memory` expects 2 values on the stack, only one is present.
],
invocation_inputs: [
InterfaceValue::I32(0),
InterfaceValue::I32(13),
],
instance: Instance::new(),
error: r#"`string.lift_memory` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#,
);
test_executable_instruction!(
test_string_memory =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringLowerMemory { allocator_index: 43 },
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: Instance::new(),
stack: [
InterfaceValue::I32(0),
// ^^^^^^ pointer
InterfaceValue::I32(13),
// ^^^^^^^ length
]
);
test_executable_instruction!(
test_string_memory__roundtrip_with_memory_to_string =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringLowerMemory { allocator_index: 43 },
Instruction::StringLiftMemory,
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: Instance::new(),
stack: [InterfaceValue::String("Hello, World!".into())],
);
test_executable_instruction!(
test_string_memory__allocator_does_not_exist =
instructions: [Instruction::StringLowerMemory { allocator_index: 43 }],
invocation_inputs: [],
instance: Instance { ..Default::default() },
error: r#"`string.lower_memory 43` the local or import function `43` doesn't exist"#,
);
test_executable_instruction!(
test_string_memory__stack_is_too_small =
instructions: [
Instruction::StringLowerMemory { allocator_index: 43 }
// ^^ `43` expects 1 value on the stack, none is present
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: Instance::new(),
error: r#"`string.lower_memory 43` needed to read `1` value(s) from the stack, but it doesn't contain enough data"#,
);
test_executable_instruction!(
test_string_memory__failure_when_calling_the_allocator =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringLowerMemory { allocator_index: 153 }
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: {
let mut instance = Instance::new();
instance.locals_or_imports.insert(
153,
LocalImport {
inputs: vec![InterfaceType::I32],
outputs: vec![InterfaceType::I32],
function: |_| Err(()),
// ^^^^^^^ function fails
},
);
instance
},
error: r#"`string.lower_memory 153` failed while calling the local or import function `153`"#,
);
test_executable_instruction!(
test_string_memory__invalid_allocator_signature =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringLowerMemory { allocator_index: 153 }
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: {
let mut instance = Instance::new();
instance.locals_or_imports.insert(
153,
LocalImport {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![],
function: |_| Err(()),
},
);
instance
},
error: r#"`string.lower_memory 153` the local or import function `153` has the signature `[I32] -> [I32]` but it received values of kind `[I32, I32] -> []`"#,
);
test_executable_instruction!(
test_string_size =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringSize,
],
invocation_inputs: [InterfaceValue::String("Hello, World!".into())],
instance: Instance::new(),
stack: [InterfaceValue::String("Hello, World!".into()), InterfaceValue::I32(13)],
);
test_executable_instruction!(
test_string_size__stack_is_too_small =
instructions: [
Instruction::StringSize,
],
invocation_inputs: [],
instance: Instance::new(),
error: r#"`string.size` needed to read `1` value(s) from the stack, but it doesn't contain enough data"#,
);
test_executable_instruction!(
test_string_size__invalid_value_on_the_stack =
instructions: [
Instruction::ArgumentGet { index: 0 },
Instruction::StringSize,
],
invocation_inputs: [InterfaceValue::I32(42)],
instance: Instance::new(),
error: r#"`string.size` read a value of type `I32` from the stack, but the type `String` was expected"#,
);
}

View File

@ -188,61 +188,53 @@ where
fn try_from(instructions: &Vec<Instruction>) -> Result<Self, Self::Error> {
let executable_instructions = instructions
.iter()
.map(|instruction| {
match instruction {
Instruction::ArgumentGet { index } => {
instructions::argument_get(*index, *instruction)
}
Instruction::CallCore { function_index } => {
instructions::call_core(*function_index, *instruction)
}
Instruction::MemoryToString => instructions::memory_to_string(*instruction),
Instruction::StringToMemory { allocator_index } => {
instructions::string_to_memory(*allocator_index, *instruction)
}
Instruction::I32ToS8 => instructions::i32_to_s8(*instruction),
//Instruction::I32ToS8X
Instruction::I32ToU8 => instructions::i32_to_u8(*instruction),
Instruction::I32ToS16 => instructions::i32_to_s16(*instruction),
//Instruction::I32ToS16X
Instruction::I32ToU16 => instructions::i32_to_u16(*instruction),
Instruction::I32ToS32 => instructions::i32_to_s32(*instruction),
Instruction::I32ToU32 => instructions::i32_to_u32(*instruction),
Instruction::I32ToS64 => instructions::i32_to_s64(*instruction),
Instruction::I32ToU64 => instructions::i32_to_u64(*instruction),
Instruction::I64ToS8 => instructions::i64_to_s8(*instruction),
//Instruction::I64ToS8X
Instruction::I64ToU8 => instructions::i64_to_u8(*instruction),
Instruction::I64ToS16 => instructions::i64_to_s16(*instruction),
//Instruction::I64ToS16X
Instruction::I64ToU16 => instructions::i64_to_u16(*instruction),
Instruction::I64ToS32 => instructions::i64_to_s32(*instruction),
Instruction::I64ToU32 => instructions::i64_to_u32(*instruction),
Instruction::I64ToS64 => instructions::i64_to_s64(*instruction),
Instruction::I64ToU64 => instructions::i64_to_u64(*instruction),
Instruction::S8ToI32 => instructions::s8_to_i32(*instruction),
Instruction::U8ToI32 => instructions::u8_to_i32(*instruction),
Instruction::S16ToI32 => instructions::s16_to_i32(*instruction),
Instruction::U16ToI32 => instructions::u16_to_i32(*instruction),
Instruction::S32ToI32 => instructions::s32_to_i32(*instruction),
Instruction::U32ToI32 => instructions::u32_to_i32(*instruction),
Instruction::S64ToI32 | Instruction::S64ToI32X => {
instructions::s64_to_i32(*instruction)
}
Instruction::U64ToI32 | Instruction::U64ToI32X => {
instructions::u64_to_i32(*instruction)
}
Instruction::S8ToI64 => instructions::s8_to_i64(*instruction),
Instruction::U8ToI64 => instructions::u8_to_i64(*instruction),
Instruction::S16ToI64 => instructions::s16_to_i64(*instruction),
Instruction::U16ToI64 => instructions::u16_to_i64(*instruction),
Instruction::S32ToI64 => instructions::s32_to_i64(*instruction),
Instruction::U32ToI64 => instructions::u32_to_i64(*instruction),
Instruction::S64ToI64 => instructions::s64_to_i64(*instruction),
Instruction::U64ToI64 => instructions::u64_to_i64(*instruction),
_ => unimplemented!(),
.map(|instruction| match instruction {
Instruction::ArgumentGet { index } => {
instructions::argument_get(*index, *instruction)
}
Instruction::CallCore { function_index } => {
instructions::call_core(*function_index, *instruction)
}
Instruction::S8FromI32 => instructions::s8_from_i32(*instruction),
Instruction::S8FromI64 => instructions::s8_from_i64(*instruction),
Instruction::S16FromI32 => instructions::s16_from_i32(*instruction),
Instruction::S16FromI64 => instructions::s16_from_i64(*instruction),
Instruction::S32FromI32 => instructions::s32_from_i32(*instruction),
Instruction::S32FromI64 => instructions::s32_from_i64(*instruction),
Instruction::S64FromI32 => instructions::s64_from_i32(*instruction),
Instruction::S64FromI64 => instructions::s64_from_i64(*instruction),
Instruction::I32FromS8 => instructions::i32_from_s8(*instruction),
Instruction::I32FromS16 => instructions::i32_from_s16(*instruction),
Instruction::I32FromS32 => instructions::i32_from_s32(*instruction),
Instruction::I32FromS64 => instructions::i32_from_s64(*instruction),
Instruction::I64FromS8 => instructions::i64_from_s8(*instruction),
Instruction::I64FromS16 => instructions::i64_from_s16(*instruction),
Instruction::I64FromS32 => instructions::i64_from_s32(*instruction),
Instruction::I64FromS64 => instructions::i64_from_s64(*instruction),
Instruction::U8FromI32 => instructions::u8_from_i32(*instruction),
Instruction::U8FromI64 => instructions::u8_from_i64(*instruction),
Instruction::U16FromI32 => instructions::u16_from_i32(*instruction),
Instruction::U16FromI64 => instructions::u16_from_i64(*instruction),
Instruction::U32FromI32 => instructions::u32_from_i32(*instruction),
Instruction::U32FromI64 => instructions::u32_from_i64(*instruction),
Instruction::U64FromI32 => instructions::u64_from_i32(*instruction),
Instruction::U64FromI64 => instructions::u64_from_i64(*instruction),
Instruction::I32FromU8 => instructions::i32_from_u8(*instruction),
Instruction::I32FromU16 => instructions::i32_from_u16(*instruction),
Instruction::I32FromU32 => instructions::i32_from_u32(*instruction),
Instruction::I32FromU64 => instructions::i32_from_u64(*instruction),
Instruction::I64FromU8 => instructions::i64_from_u8(*instruction),
Instruction::I64FromU16 => instructions::i64_from_u16(*instruction),
Instruction::I64FromU32 => instructions::i64_from_u32(*instruction),
Instruction::I64FromU64 => instructions::i64_from_u64(*instruction),
Instruction::StringLiftMemory => instructions::string_lift_memory(*instruction),
Instruction::StringLowerMemory { allocator_index } => {
instructions::string_lower_memory(*allocator_index, *instruction)
}
Instruction::StringSize => instructions::string_size(*instruction),
})
.collect();

View File

@ -22,9 +22,13 @@ pub trait Stackable {
/// Removes `n` elements from the end of the stack, `None` if the
/// stack doesn't contain enough elements.
/// Returned items are ordered by FIFO: the last element comes
/// first in the list.
/// Returned items are in reverse order: the last element comes
/// last in the list.
fn pop(&mut self, n: usize) -> Option<Vec<Self::Item>>;
/// Peek the last item of the stack and returns a reference to it,
/// `None` if the stack is empty.
fn peek1(&self) -> Option<&Self::Item>;
}
/// A stack implementation of the `Stackable` trait, based on a vector.
@ -78,7 +82,6 @@ where
let items = self
.inner
.drain(self.inner.len() - n..)
.rev()
.collect::<Vec<Self::Item>>();
assert!(items.len() == n);
@ -86,6 +89,14 @@ where
Some(items)
}
}
fn peek1(&self) -> Option<&Self::Item> {
if self.inner.is_empty() {
None
} else {
Some(&self.inner[self.inner.len() - 1])
}
}
}
#[cfg(test)]
@ -121,10 +132,19 @@ mod tests {
stack.push(6);
assert_eq!(stack.pop(1), Some(vec![6]));
assert_eq!(stack.pop(2), Some(vec![5, 4]));
assert_eq!(stack.pop(2), Some(vec![4, 5]));
assert_eq!(stack.pop(4), None); // not enough items
assert_eq!(stack.pop(3), Some(vec![3, 2, 1]));
assert_eq!(stack.pop(3), Some(vec![1, 2, 3]));
assert_eq!(stack.pop1(), None);
assert_eq!(stack.is_empty(), true);
}
#[test]
fn test_peek1() {
let mut stack = Stack::new();
stack.push(1);
stack.push(2);
assert_eq!(stack.peek1(), Some(&2));
}
}

View File

@ -12,8 +12,8 @@ readme = "README.md"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.16.2", features = ["generate-debug-information-no-export-symbols"] }
wasmparser = "0.51.3"
smallvec = "0.6"
goblin = "0.0.24"
smallvec = "1"
goblin = "0.1"
libc = "0.2.60"
byteorder = "1"

View File

@ -954,7 +954,6 @@ pub unsafe extern "C" fn callback_trampoline(
pub struct LLVMModuleCodeGenerator<'ctx> {
context: Option<&'ctx Context>,
builder: Option<Builder<'ctx>>,
intrinsics: Option<Intrinsics<'ctx>>,
functions: Vec<LLVMFunctionCodeGenerator<'ctx>>,
signatures: Map<SigIndex, FunctionType<'ctx>>,
@ -3701,7 +3700,7 @@ impl<'ctx> FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator<'ct
.try_as_basic_value()
.left()
.unwrap();
state.push1_extra(res, i);
state.push1_extra(res, i | ExtraInfo::pending_f32_nan());
}
Operator::F64Trunc => {
let (v, i) = state.pop1_extra()?;
@ -3714,7 +3713,7 @@ impl<'ctx> FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator<'ct
.try_as_basic_value()
.left()
.unwrap();
state.push1_extra(res, i);
state.push1_extra(res, i | ExtraInfo::pending_f64_nan());
}
Operator::F32Nearest => {
let (v, i) = state.pop1_extra()?;
@ -3727,7 +3726,7 @@ impl<'ctx> FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator<'ct
.try_as_basic_value()
.left()
.unwrap();
state.push1_extra(res, i);
state.push1_extra(res, i | ExtraInfo::pending_f32_nan());
}
Operator::F64Nearest => {
let (v, i) = state.pop1_extra()?;
@ -3740,7 +3739,7 @@ impl<'ctx> FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator<'ct
.try_as_basic_value()
.left()
.unwrap();
state.push1_extra(res, i);
state.push1_extra(res, i | ExtraInfo::pending_f64_nan());
}
Operator::F32Abs => {
let (v, i) = state.pop1_extra()?;
@ -8619,7 +8618,6 @@ impl From<LoadError> for CodegenError {
impl Drop for LLVMModuleCodeGenerator<'_> {
fn drop(&mut self) {
// Ensure that all members of the context are dropped before we drop the context.
drop(self.builder.take());
drop(self.intrinsics.take());
self.functions.clear();
self.signatures.clear();
@ -8698,8 +8696,6 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
module.set_target(&target);
module.set_data_layout(&target_machine.get_target_data().get_data_layout());
let builder = context.create_builder();
let intrinsics = Intrinsics::declare(&module, &context);
let personality_func = module.add_function(
@ -8710,7 +8706,6 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
LLVMModuleCodeGenerator {
context: Some(context),
builder: Some(builder),
intrinsics: Some(intrinsics),
module: ManuallyDrop::new(Rc::new(RefCell::new(module))),
functions: vec![],
@ -8740,15 +8735,10 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
_loc: WasmSpan,
) -> Result<&mut LLVMFunctionCodeGenerator<'ctx>, CodegenError> {
// Creates a new function and returns the function-scope code generator for it.
let (context, builder, intrinsics) = match self.functions.last_mut() {
Some(x) => (
x.context.take().unwrap(),
x.builder.take().unwrap(),
x.intrinsics.take().unwrap(),
),
let (context, intrinsics) = match self.functions.last_mut() {
Some(x) => (x.context.take().unwrap(), x.intrinsics.take().unwrap()),
None => (
self.context.take().unwrap(),
self.builder.take().unwrap(),
self.intrinsics.take().unwrap(),
),
};
@ -8766,6 +8756,7 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
alloca_builder.position_at_end(entry_block);
let return_block = context.append_basic_block(*function, "return");
let builder = context.create_builder();
builder.position_at_end(return_block);
let phis: SmallVec<[PhiValue; 1]> = func_sig
@ -8851,20 +8842,14 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
),
CodegenError,
> {
let (context, builder, intrinsics) = match self.functions.last_mut() {
Some(x) => (
x.context.take().unwrap(),
x.builder.take().unwrap(),
x.intrinsics.take().unwrap(),
),
let (context, intrinsics) = match self.functions.last_mut() {
Some(x) => (x.context.take().unwrap(), x.intrinsics.take().unwrap()),
None => (
self.context.take().unwrap(),
self.builder.take().unwrap(),
self.intrinsics.take().unwrap(),
),
};
self.context = Some(context);
self.builder = Some(builder);
self.intrinsics = Some(intrinsics);
generate_trampolines(
@ -8872,7 +8857,6 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
&self.signatures,
&self.module.borrow_mut(),
self.context.as_ref().unwrap(),
self.builder.as_ref().unwrap(),
self.intrinsics.as_ref().unwrap(),
)
.map_err(|e| CodegenError {

View File

@ -1,6 +1,5 @@
use crate::intrinsics::Intrinsics;
use inkwell::{
builder::Builder,
context::Context,
module::{Linkage, Module},
types::{BasicType, FunctionType},
@ -18,7 +17,6 @@ pub fn generate_trampolines<'ctx>(
signatures: &SliceMap<SigIndex, FunctionType<'ctx>>,
module: &Module<'ctx>,
context: &'ctx Context,
builder: &Builder<'ctx>,
intrinsics: &Intrinsics<'ctx>,
) -> Result<(), String> {
for (sig_index, sig) in info.signatures.iter() {
@ -42,7 +40,7 @@ pub fn generate_trampolines<'ctx>(
Some(Linkage::External),
);
generate_trampoline(trampoline_func, sig, context, builder, intrinsics)?;
generate_trampoline(trampoline_func, sig, context, intrinsics)?;
}
Ok(())
}
@ -51,10 +49,10 @@ fn generate_trampoline<'ctx>(
trampoline_func: FunctionValue,
func_sig: &FuncSig,
context: &'ctx Context,
builder: &Builder<'ctx>,
intrinsics: &Intrinsics<'ctx>,
) -> Result<(), String> {
let entry_block = context.append_basic_block(trampoline_func, "entry");
let builder = context.create_builder();
builder.position_at_end(entry_block);
let (vmctx_ptr, func_ptr, args_ptr, returns_ptr) = match trampoline_func.get_params().as_slice()

View File

@ -21,7 +21,7 @@ singlepass = ["wasmer-singlepass-backend"]
[dev-dependencies]
wabt = "0.9.1"
criterion = "0.2"
criterion = "0.3"
[[bench]]
name = "metering_benchmark"

View File

@ -198,7 +198,7 @@ pub extern "C" fn wasmer_memory_data(memory: *const wasmer_memory_t) -> *mut u8
/// ```
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub extern "C" fn wasmer_memory_data_length(memory: *mut wasmer_memory_t) -> u32 {
pub extern "C" fn wasmer_memory_data_length(memory: *const wasmer_memory_t) -> u32 {
if memory.is_null() {
return 0;
}

View File

@ -1171,7 +1171,7 @@ uint8_t *wasmer_memory_data(const wasmer_memory_t *memory);
* uint32_t memory_data_length = wasmer_memory_data_length(memory);
* ```
*/
uint32_t wasmer_memory_data_length(wasmer_memory_t *memory);
uint32_t wasmer_memory_data_length(const wasmer_memory_t *memory);
/**
* Frees memory for the given `wasmer_memory_t`.

View File

@ -964,7 +964,7 @@ uint8_t *wasmer_memory_data(const wasmer_memory_t *memory);
/// ```c
/// uint32_t memory_data_length = wasmer_memory_data_length(memory);
/// ```
uint32_t wasmer_memory_data_length(wasmer_memory_t *memory);
uint32_t wasmer_memory_data_length(const wasmer_memory_t *memory);
/// Frees memory for the given `wasmer_memory_t`.
///

View File

@ -16,12 +16,12 @@ wasmparser = "0.51.3"
parking_lot = "0.10.0"
lazy_static = "1.4"
errno = "0.2"
libc = "0.2.60"
libc = "0.2.68"
hex = "0.4"
smallvec = "0.6"
smallvec = "1"
bincode = "1.1"
wasm-debug = { optional = true, version = "0.1.0" }
target-lexicon = "0.9"
wasm-debug = { optional = true, version = "0.2.0" }
target-lexicon = "0.10"
[dependencies.indexmap]
version = "1.2"

View File

@ -37,7 +37,7 @@ fn main() {
.file("image-loading-freebsd-x86-64.s")
.compile("image-loading");
}
("linux", "x86_64") => {
("linux", "x86_64") | ("android", "x86_64") => {
cc::Build::new()
.file("image-loading-linux-x86-64.s")
.compile("image-loading");

View File

@ -106,7 +106,7 @@ impl BackendCompilerConfig {
}
/// Configuration data for the compiler
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct CompilerConfig {
/// Symbol information generated from emscripten; used for more detailed debug messages
pub symbol_map: Option<HashMap<u32, String>>,
@ -132,6 +132,17 @@ pub struct CompilerConfig {
/// When enabled there can be a small amount of runtime performance overhead.
pub full_preemption: bool,
/// Always choose a unique bit representation for NaN.
/// Enabling this makes execution deterministic but increases runtime overhead.
pub nan_canonicalization: bool,
/// Turns on verification that is done by default when `debug_assertions` are enabled
/// (for example in 'debug' builds). Disabling this flag will make compilation faster
/// in debug mode at the cost of not detecting bugs in the compiler.
///
/// These verifications are disabled by default in 'release' builds.
pub enable_verification: bool,
pub features: Features,
// Target info. Presently only supported by LLVM.
@ -144,6 +155,30 @@ pub struct CompilerConfig {
pub generate_debug_info: bool,
}
impl Default for CompilerConfig {
fn default() -> Self {
Self {
symbol_map: Default::default(),
memory_bound_check_mode: Default::default(),
enforce_stack_check: Default::default(),
track_state: Default::default(),
full_preemption: Default::default(),
nan_canonicalization: Default::default(),
features: Default::default(),
triple: Default::default(),
cpu_name: Default::default(),
cpu_features: Default::default(),
backend_specific_config: Default::default(),
generate_debug_info: Default::default(),
// Default verification to 'on' when testing or running in debug mode.
// NOTE: cfg(test) probably does nothing when not running `cargo test`
// on this crate
enable_verification: cfg!(test) || cfg!(debug_assertions),
}
}
}
impl CompilerConfig {
/// Use this to check if we should be generating debug information.
/// This function takes into account the features that runtime-core was

View File

@ -410,7 +410,7 @@ impl MiddlewareChain {
};
sink.push(ev);
for m in &mut self.chain {
let prev: SmallVec<[Event; 2]> = sink.buffer.drain().collect();
let prev: SmallVec<[Event; 2]> = sink.buffer.drain(..).collect();
for ev in prev {
m.feed_event(ev, module_info, &mut sink, source_loc)?;
}

View File

@ -743,7 +743,10 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> F
}
}
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
#[cfg(all(
any(target_os = "linux", target_os = "android"),
target_arch = "aarch64"
))]
/// Get fault info from siginfo and ucontext.
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
#[allow(dead_code)]
@ -810,7 +813,10 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> F
}
}
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[cfg(all(
any(target_os = "linux", target_os = "android"),
target_arch = "x86_64"
))]
/// Get fault info from siginfo and ucontext.
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo {
use libc::{

View File

@ -78,7 +78,7 @@ pub struct ModuleInfo {
pub em_symbol_map: Option<HashMap<u32, String>>,
/// Custom sections.
pub custom_sections: HashMap<String, Vec<u8>>,
pub custom_sections: HashMap<String, Vec<Vec<u8>>>,
/// Flag controlling whether or not debug information for use in a debugger
/// will be generated.
@ -102,7 +102,8 @@ impl ModuleInfo {
let bytes = reader.read_bytes(len)?;
let data = bytes.to_vec();
let name = name.to_string();
self.custom_sections.insert(name, data);
let entry: &mut Vec<Vec<u8>> = self.custom_sections.entry(name).or_default();
entry.push(data);
}
}
Ok(())

View File

@ -34,7 +34,7 @@ version = "1.0"
[dev-dependencies]
tempfile = "3.1"
criterion = "0.2"
criterion = "0.3"
wabt = "0.9.1"
[dependencies.wasmer-llvm-backend]

View File

@ -17,8 +17,8 @@ dynasmrt = "0.5"
lazy_static = "1.4"
byteorder = "1.3"
nix = "0.15"
libc = "0.2.60"
smallvec = "0.6"
libc = "0.2.68"
smallvec = "1"
serde = "1.0"
serde_derive = "1.0"
bincode = "1.2"

File diff suppressed because it is too large Load Diff

View File

@ -17,8 +17,17 @@
all(target_os = "macos", target_arch = "x86_64"),
all(target_os = "linux", target_arch = "x86_64"),
all(target_os = "linux", target_arch = "aarch64"),
all(target_os = "android", target_arch = "x86_64"),
all(target_os = "android", target_arch = "aarch64"),
)))]
compile_error!("This crate doesn't yet support compiling on operating systems other than FreeBSD, linux and macos and architectures other than x86_64");
compile_error!("This crate doesn't yet support compiling on operating systems and architectures other than these:
- FreeBSD and x86_64
- FreeBSD and AArch64
- macOS and x86_64
- Linux and x86_64
- Linux and AArch64
- Android and x86_64
- Android and AArch64");
extern crate dynasmrt;

View File

@ -3,15 +3,21 @@
(module
;; Auxiliary definitions
(type $out-i32 (func (result i32)))
(type $f32-id (func (param f32) (result f32)))
(type $f64-id (func (param f64) (result f64)))
(func $const-i32 (type $out-i32) (i32.const 0x132))
(table funcref
(elem
$const-i32
$nan-canonicalization-f32-func-call-target
$nan-canonicalization-f64-func-call-target
)
)
(memory 1)
;; https://github.com/wasmerio/wasmer/pull/1191
(func (export "call-indirect-from-spilled-stack") (result i32)
(i64.add (i64.const 0) (i64.const 0))
@ -28,6 +34,182 @@
(call_indirect (type $out-i32))
(return)
)
;; NaN canonicalization tests.
;; Things that are covered by spectests canonicalization (`fabs`, `fneg`, `fcopysign`, `reinterpret`, `const`) won't be duplicated here.
(func (export "nan-canonicalization-f32-add") (param i32) (result i32)
(i32.reinterpret_f32 (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
)
(func (export "nan-canonicalization-f32-sub") (param i32) (result i32)
(i32.reinterpret_f32 (f32.sub (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
)
(func (export "nan-canonicalization-f32-mul") (param i32) (result i32)
(i32.reinterpret_f32 (f32.mul (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
)
(func (export "nan-canonicalization-f32-div") (param i32) (result i32)
(i32.reinterpret_f32 (f32.div (f32.reinterpret_i32 (get_local 0)) (f32.const 1)))
)
(func (export "nan-canonicalization-f32-max") (param i32) (result i32)
(i32.reinterpret_f32 (f32.max (f32.reinterpret_i32 (get_local 0)) (f32.const 1)))
)
(func (export "nan-canonicalization-f32-min") (param i32) (result i32)
(i32.reinterpret_f32 (f32.min (f32.reinterpret_i32 (get_local 0)) (f32.const 1)))
)
(func (export "nan-canonicalization-f32-nearest") (param i32) (result i32)
(i32.reinterpret_f32 (f32.nearest (f32.reinterpret_i32 (get_local 0))))
)
(func (export "nan-canonicalization-f32-floor") (param i32) (result i32)
(i32.reinterpret_f32 (f32.floor (f32.reinterpret_i32 (get_local 0))))
)
(func (export "nan-canonicalization-f32-ceil") (param i32) (result i32)
(i32.reinterpret_f32 (f32.ceil (f32.reinterpret_i32 (get_local 0))))
)
(func (export "nan-canonicalization-f32-trunc") (param i32) (result i32)
(i32.reinterpret_f32 (f32.trunc (f32.reinterpret_i32 (get_local 0))))
)
(func (export "nan-canonicalization-f32-sqrt") (param i32) (result i32)
(i32.reinterpret_f32 (f32.sqrt (f32.reinterpret_i32 (get_local 0))))
)
(func (export "nan-canonicalization-f32-mem") (param i32) (result i32)
(f32.store (i32.const 0) (f32.reinterpret_i32 (get_local 0)))
(i32.reinterpret_f32 (f32.load (i32.const 0)))
)
(func (export "nan-canonicalization-f32-mem-cncl") (param i32) (result i32)
(f32.store (i32.const 0) (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
(i32.reinterpret_f32 (f32.load (i32.const 0)))
)
(func (export "nan-canonicalization-f32-local") (param i32) (result i32)
(local f32)
(set_local 1 (f32.reinterpret_i32 (get_local 0)))
(i32.reinterpret_f32 (get_local 1))
)
(func (export "nan-canonicalization-f32-local-cncl") (param i32) (result i32)
(local f32)
(set_local 1 (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
(i32.reinterpret_f32 (get_local 1))
)
(func $nan-canonicalization-f32-func-call-target (param f32) (result f32)
(get_local 0)
)
(func (export "nan-canonicalization-f32-func-call") (param i32) (result i32)
(i32.reinterpret_f32 (call $nan-canonicalization-f32-func-call-target (f32.reinterpret_i32 (get_local 0))))
)
(func (export "nan-canonicalization-f32-func-call-cncl") (param i32) (result i32)
(i32.reinterpret_f32 (call $nan-canonicalization-f32-func-call-target (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0))))
)
(func (export "nan-canonicalization-f32-func-call-indirect") (param i32) (result i32)
(i32.reinterpret_f32 (call_indirect (type $f32-id) (f32.reinterpret_i32 (get_local 0)) (i32.const 1)))
)
(func (export "nan-canonicalization-f32-func-call-indirect-cncl") (param i32) (result i32)
(i32.reinterpret_f32 (call_indirect (type $f32-id) (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0)) (i32.const 1)))
)
(func (export "nan-canonicalization-f64-add") (param i64) (result i64)
(i64.reinterpret_f64 (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
)
(func (export "nan-canonicalization-f64-sub") (param i64) (result i64)
(i64.reinterpret_f64 (f64.sub (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
)
(func (export "nan-canonicalization-f64-mul") (param i64) (result i64)
(i64.reinterpret_f64 (f64.mul (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
)
(func (export "nan-canonicalization-f64-div") (param i64) (result i64)
(i64.reinterpret_f64 (f64.div (f64.reinterpret_i64 (get_local 0)) (f64.const 1)))
)
(func (export "nan-canonicalization-f64-max") (param i64) (result i64)
(i64.reinterpret_f64 (f64.max (f64.reinterpret_i64 (get_local 0)) (f64.const 1)))
)
(func (export "nan-canonicalization-f64-min") (param i64) (result i64)
(i64.reinterpret_f64 (f64.min (f64.reinterpret_i64 (get_local 0)) (f64.const 1)))
)
(func (export "nan-canonicalization-f64-nearest") (param i64) (result i64)
(i64.reinterpret_f64 (f64.nearest (f64.reinterpret_i64 (get_local 0))))
)
(func (export "nan-canonicalization-f64-floor") (param i64) (result i64)
(i64.reinterpret_f64 (f64.floor (f64.reinterpret_i64 (get_local 0))))
)
(func (export "nan-canonicalization-f64-ceil") (param i64) (result i64)
(i64.reinterpret_f64 (f64.ceil (f64.reinterpret_i64 (get_local 0))))
)
(func (export "nan-canonicalization-f64-trunc") (param i64) (result i64)
(i64.reinterpret_f64 (f64.trunc (f64.reinterpret_i64 (get_local 0))))
)
(func (export "nan-canonicalization-f64-sqrt") (param i64) (result i64)
(i64.reinterpret_f64 (f64.sqrt (f64.reinterpret_i64 (get_local 0))))
)
(func (export "nan-canonicalization-f64-mem") (param i64) (result i64)
(f64.store (i32.const 0) (f64.reinterpret_i64 (get_local 0)))
(i64.reinterpret_f64 (f64.load (i32.const 0)))
)
(func (export "nan-canonicalization-f64-mem-cncl") (param i64) (result i64)
(f64.store (i32.const 0) (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
(i64.reinterpret_f64 (f64.load (i32.const 0)))
)
(func (export "nan-canonicalization-f64-local") (param i64) (result i64)
(local f64)
(set_local 1 (f64.reinterpret_i64 (get_local 0)))
(i64.reinterpret_f64 (get_local 1))
)
(func (export "nan-canonicalization-f64-local-cncl") (param i64) (result i64)
(local f64)
(set_local 1 (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
(i64.reinterpret_f64 (get_local 1))
)
(func $nan-canonicalization-f64-func-call-target (param f64) (result f64)
(get_local 0)
)
(func (export "nan-canonicalization-f64-func-call") (param i64) (result i64)
(i64.reinterpret_f64 (call $nan-canonicalization-f64-func-call-target (f64.reinterpret_i64 (get_local 0))))
)
(func (export "nan-canonicalization-f64-func-call-cncl") (param i64) (result i64)
(i64.reinterpret_f64 (call $nan-canonicalization-f64-func-call-target (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0))))
)
(func (export "nan-canonicalization-f64-func-call-indirect") (param i64) (result i64)
(i64.reinterpret_f64 (call_indirect (type $f64-id) (f64.reinterpret_i64 (get_local 0)) (i32.const 2)))
)
(func (export "nan-canonicalization-f64-func-call-indirect-cncl") (param i64) (result i64)
(i64.reinterpret_f64 (call_indirect (type $f64-id) (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0)) (i32.const 2)))
)
)
(assert_return (invoke "call-indirect-from-spilled-stack") (i32.const 0x132))
(assert_return (invoke "call-indirect-from-spilled-stack") (i32.const 0x132))
(assert_return (invoke "nan-canonicalization-f32-add" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-sub" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-mul" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-div" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-max" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-min" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-nearest" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-floor" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-ceil" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-trunc" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-sqrt" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-mem" (i32.const 0x7fc00001)) (i32.const 0x7fc00001))
(assert_return (invoke "nan-canonicalization-f32-mem-cncl" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-local" (i32.const 0x7fc00001)) (i32.const 0x7fc00001))
(assert_return (invoke "nan-canonicalization-f32-local-cncl" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-func-call" (i32.const 0x7fc00001)) (i32.const 0x7fc00001))
(assert_return (invoke "nan-canonicalization-f32-func-call-cncl" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-func-call-indirect" (i32.const 0x7fc00001)) (i32.const 0x7fc00001))
(assert_return (invoke "nan-canonicalization-f32-func-call-indirect-cncl" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f64-add" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-sub" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-mul" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-div" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-max" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-min" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-nearest" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-floor" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-ceil" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-trunc" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-sqrt" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-mem" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-mem-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-local" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-local-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-func-call" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-func-call-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-func-call-indirect" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-func-call-indirect-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))

View File

@ -244,10 +244,6 @@ clif:fail:exports.wast:167:windows # Module - caught panic Any
clif:fail:exports.wast:168:windows # Module - caught panic Any
clif:fail:exports.wast:169:windows # Module - caught panic Any
clif:fail:exports.wast:170:windows # Module - caught panic Any
clif:fail:f32.wast:2496:windows # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN)
clif:fail:f32.wast:2498:windows # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN)
clif:fail:f64.wast:2496:windows # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN)
clif:fail:f64.wast:2498:windows # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN)
clif:fail:func.wast:289:windows # Module - caught panic Any
clif:fail:memory.wast:3:windows # Module - caught panic Any
clif:fail:memory.wast:4:windows # Module - caught panic Any
@ -523,4 +519,36 @@ singlepass:fail:traps.wast:53:*:aarch64 # AssertTrap - expected trap, got []
singlepass:fail:traps.wast:54:*:aarch64 # AssertTrap - expected trap, got []
singlepass:fail:traps.wast:55:*:aarch64 # AssertTrap - expected trap, got []
singlepass:fail:traps.wast:56:*:aarch64 # AssertTrap - expected trap, got []
singlepass:fail:traps.wast:57:*:aarch64 # AssertTrap - expected trap, got []
singlepass:fail:traps.wast:57:*:aarch64 # AssertTrap - expected trap, got []
# NaN canonicalization is not yet implemented for aarch64.
singlepass:fail:wasmer.wast:177:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:178:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:179:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:180:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:181:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:182:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:183:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:184:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:185:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:186:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:187:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:189:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:191:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:193:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:195:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000")
singlepass:fail:wasmer.wast:197:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:198:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:199:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:200:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:201:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:202:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:203:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:204:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:205:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:206:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:207:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:209:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:211:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:213:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")
singlepass:fail:wasmer.wast:215:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000")

View File

@ -336,6 +336,8 @@ mod tests {
simd: true,
threads: true,
},
nan_canonicalization: true,
enable_verification: true,
..Default::default()
};
let module = compile_with_config(&module.into_vec(), config)
@ -774,6 +776,8 @@ mod tests {
simd: true,
threads: true,
},
nan_canonicalization: true,
enable_verification: true,
..Default::default()
};
compile_with_config(&module.into_vec(), config)
@ -826,6 +830,8 @@ mod tests {
simd: true,
threads: true,
},
nan_canonicalization: true,
enable_verification: true,
..Default::default()
};
compile_with_config(&module.into_vec(), config)
@ -877,6 +883,8 @@ mod tests {
simd: true,
threads: true,
},
nan_canonicalization: true,
enable_verification: true,
..Default::default()
};
let module = compile_with_config(&module.into_vec(), config)
@ -972,6 +980,8 @@ mod tests {
simd: true,
threads: true,
},
nan_canonicalization: true,
enable_verification: true,
..Default::default()
};
let module = compile_with_config(&module.into_vec(), config)

View File

@ -1,6 +1,11 @@
#![allow(unused, clippy::too_many_arguments)]
pub mod types;
#[cfg(any(target_os = "freebsd", target_os = "linux", target_os = "macos"))]
#[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "android",
target_os = "macos"
))]
pub mod unix;
#[cfg(any(target_os = "windows"))]
pub mod windows;
@ -23,7 +28,12 @@ use std::convert::{Infallible, TryInto};
use std::io::{self, Read, Seek, Write};
use wasmer_runtime_core::{memory::Memory, vm::Ctx};
#[cfg(any(target_os = "freebsd", target_os = "linux", target_os = "macos"))]
#[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "android",
target_os = "macos"
))]
pub use unix::*;
#[cfg(any(target_os = "windows"))]

View File

@ -13,4 +13,4 @@ winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwinde
libc = "0.2.60"
[build-dependencies]
cmake = "0.1"
cc = "1.0"

View File

@ -1,10 +1,10 @@
fn main() {
#[cfg(target_os = "windows")]
{
use cmake::Config;
let project_name = "exception_handling";
let dst = Config::new(project_name).build();
println!("cargo:rustc-link-search=native={}", dst.display());
println!("cargo:rustc-link-lib=static={}", project_name);
if std::env::var("CARGO_CFG_TARGET_OS").expect("TARGET_OS not specified") != "windows" {
return;
}
cc::Build::new()
.include("exception_handling")
.file("exception_handling/exception_handling.c")
.compile("exception_handling");
}

View File

@ -1 +0,0 @@
cmake-build-*

View File

@ -1,6 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project(exception_handling C)
add_library(exception_handling STATIC exception_handling.c)
install(TARGETS exception_handling DESTINATION .)

View File

@ -1,5 +1,6 @@
#include <windows.h>
#include <setjmp.h>
#include <intrin.h>
#include "exception_handling.h"
#define CALL_FIRST 1