Merge branch 'master' into test-c-api

This commit is contained in:
Ivan Enderlin
2020-12-01 11:37:41 +01:00
78 changed files with 2226 additions and 774 deletions

View File

@@ -43,15 +43,14 @@ jobs:
- build: linux
os: ubuntu-18.04
rust: 1.47.0
llvm_url: 'https://github.com/wasmerio/llvm-build/releases/download/10.x/Ubuntu1604_Release.tar.xz'
# llvm_url: 'https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz'
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/10.x/linux-amd64.tar.gz'
artifact_name: 'wasmer-linux-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_linux'
run_integration_tests: true
- build: macos
os: macos-latest
rust: 1.47.0
llvm_url: 'https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-apple-darwin.tar.xz'
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/10.x/darwin-amd64.tar.gz'
artifact_name: 'wasmer-darwin-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_mac'
run_integration_tests: true
@@ -63,13 +62,14 @@ jobs:
- build: windows
os: windows-latest
rust: 1.47.0
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/10.x/windows-amd64.tar.gz'
artifact_name: 'wasmer-windows-amd64'
cross_compilation_artifact_name: 'cross_compiled_from_win'
run_integration_tests: true
- build: linux-aarch64
os: [self-hosted, linux, ARM64]
rust: 1.47.0
llvm_url: 'https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-aarch64-linux-gnu.tar.xz'
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/10.x/linux-aarch64.tar.gz'
artifact_name: 'wasmer-linux-aarch64'
run_integration_tests: false
env:
@@ -103,18 +103,13 @@ jobs:
shell: cmd
run: |
choco install llvm
# run: |
# curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe -L -o llvm-installer.exe
# 7z x llvm-installer.exe -oC:/llvm-10
# echo C:/llvm-10/bin >> $GITHUB_PATH
# echo "LLVM_SYS_100_PREFIX=C:/llvm-10" >> $GITHUB_ENV
# echo "LIBCLANG_PATH=C:/llvm-10/bin/libclang.dll" >> $GITHUB_ENV
- name: Install LLVM (Unix)
if: matrix.os != 'windows-latest' && matrix.target != 'aarch64-apple-darwin'
- name: Install LLVM
if: matrix.os != 'windows-latest' && matrix.os != 'macos-11.0'
shell: bash
run: |
curl --proto '=https' --tlsv1.2 -sSf ${{ matrix.llvm_url }} -L -o llvm.tar.xz
mkdir -p ${{ env.LLVM_DIR }}
tar xf llvm.tar.xz --strip-components=1 -C ${{ env.LLVM_DIR }}
curl --proto '=https' --tlsv1.2 -sSf ${{ matrix.llvm_url }} -L -o llvm.tar.gz
mkdir ${{ env.LLVM_DIR }}
tar xf llvm.tar.gz --strip-components=1 -C ${{ env.LLVM_DIR }}
echo "${{ env.LLVM_DIR }}/bin" >> $GITHUB_PATH
echo "LLVM_SYS_100_PREFIX=${{ env.LLVM_DIR }}" >> $GITHUB_ENV
env:

View File

@@ -14,6 +14,7 @@
### Changed
- [#1739](https://github.com/wasmerio/wasmer/pull/1739) Environments passed to host function- must now implement the `WasmerEnv` trait. You can implement it on your existing type with `#[derive(WasmerEnv)]`.
- [#1838](https://github.com/wasmerio/wasmer/pull/1838) Deprecate `WasiEnv::state_mut`: prefer `WasiEnv::state` instead.
- [#1663](https://github.com/wasmerio/wasmer/pull/1663) Function environments passed to host functions now must be passed by `&` instead of `&mut`. This is a breaking change. This change fixes a race condition when a host function is called from multiple threads. If you need mutability in your environment, consider using `std::sync::Mutex` or other synchronization primitives.
- [#1830](https://github.com/wasmerio/wasmer/pull/1830) Minimum supported Rust version bumped to 1.47.0
@@ -21,6 +22,7 @@
### Fixed
- [#1841](https://github.com/wasmerio/wasmer/pull/1841) We will now panic when attempting to use a native function with a captured env as a host function. Previously this would silently do the wrong thing. See [#1840](https://github.com/wasmerio/wasmer/pull/1840) for info about Wasmer's support of closures as host functions.
- [#1764](https://github.com/wasmerio/wasmer/pull/1764) Fix bug in WASI `path_rename` allowing renamed files to be 1 directory below a preopened directory.
## 1.0.0-alpha5 - 2020-11-06

297
Cargo.lock generated
View File

@@ -71,9 +71,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "assert_cmd"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da"
checksum = "3dc1679af9a1ab4bea16f228b05d18f8363f8327b1fa8db00d2760cfafc6b61e"
dependencies = [
"doc-comment",
"predicates",
@@ -107,18 +107,24 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "backtrace"
version = "0.3.54"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2baad346b2d4e94a24347adeee9c7a93f412ee94b9cc26e5b59dea23848e9f28"
checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598"
dependencies = [
"addr2line",
"cfg-if 1.0.0",
"libc",
"miniz_oxide",
"object 0.22.0",
"object",
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
[[package]]
name = "bincode"
version = "1.3.1"
@@ -135,6 +141,17 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2b_simd"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "blake3"
version = "0.3.7"
@@ -219,9 +236,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.62"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
[[package]]
name = "cfg-if"
@@ -290,6 +307,27 @@ dependencies = [
"winapi",
]
[[package]]
name = "compiletest_rs"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29"
dependencies = [
"diff",
"filetime",
"getopts",
"libc",
"log",
"miow",
"regex",
"rustfix",
"serde",
"serde_derive",
"serde_json",
"tester",
"winapi",
]
[[package]]
name = "const_fn"
version = "0.4.3"
@@ -473,7 +511,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
"crossbeam-utils 0.8.1",
]
[[package]]
@@ -484,32 +522,42 @@ checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch",
"crossbeam-utils",
"crossbeam-utils 0.8.1",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f"
checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
dependencies = [
"cfg-if 1.0.0",
"const_fn",
"crossbeam-utils",
"crossbeam-utils 0.8.1",
"lazy_static",
"memoffset",
"memoffset 0.6.1",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.0"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg 1.0.1",
"cfg-if 0.1.10",
"lazy_static",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
dependencies = [
"autocfg 1.0.1",
"cfg-if 1.0.0",
"const_fn",
"lazy_static",
]
@@ -590,6 +638,12 @@ dependencies = [
"syn",
]
[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]]
name = "difference"
version = "2.0.0"
@@ -605,6 +659,27 @@ dependencies = [
"generic-array",
]
[[package]]
name = "dirs"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
dependencies = [
"cfg-if 0.1.10",
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "distance"
version = "0.4.0"
@@ -702,6 +777,18 @@ dependencies = [
"log",
]
[[package]]
name = "filetime"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e"
dependencies = [
"cfg-if 0.1.10",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "float-cmp"
version = "0.8.0"
@@ -743,6 +830,15 @@ dependencies = [
"version_check",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "getrandom"
version = "0.1.15"
@@ -913,9 +1009,9 @@ dependencies = [
[[package]]
name = "inline-c"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6acf1564e52050c9f7102e87951265c4c8012873181998be24640cb6b5e3f77c"
checksum = "f3f35c2ef14070ed26ac0c6ff16e22d12b35bf1a6a97dcbd1a693b56aa87a61c"
dependencies = [
"assert_cmd",
"cc",
@@ -939,9 +1035,9 @@ dependencies = [
[[package]]
name = "instant"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
dependencies = [
"cfg-if 1.0.0",
]
@@ -1056,9 +1152,9 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
dependencies = [
"scopeguard",
]
@@ -1118,6 +1214,15 @@ dependencies = [
"autocfg 1.0.1",
]
[[package]]
name = "memoffset"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
dependencies = [
"autocfg 1.0.1",
]
[[package]]
name = "minifb"
version = "0.19.1"
@@ -1147,6 +1252,16 @@ dependencies = [
"autocfg 1.0.1",
]
[[package]]
name = "miow"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
dependencies = [
"socket2",
"winapi",
]
[[package]]
name = "more-asserts"
version = "0.2.1"
@@ -1168,9 +1283,9 @@ dependencies = [
[[package]]
name = "nom"
version = "5.1.2"
version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
checksum = "88034cfd6b4a0d54dd14f4a507eceee36c0b70e5a02236c4e4df571102be17f0"
dependencies = [
"memchr",
"version_check",
@@ -1235,20 +1350,14 @@ dependencies = [
[[package]]
name = "object"
version = "0.21.1"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693"
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
dependencies = [
"crc32fast",
"indexmap",
]
[[package]]
name = "object"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
[[package]]
name = "once_cell"
version = "1.5.2"
@@ -1257,9 +1366,9 @@ checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "oorandom"
version = "11.1.2"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "orbclient"
@@ -1273,9 +1382,9 @@ dependencies = [
[[package]]
name = "parking_lot"
version = "0.11.0"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
dependencies = [
"instant",
"lock_api",
@@ -1327,9 +1436,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.1.11"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"
checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c"
[[package]]
name = "pkg-config"
@@ -1625,7 +1734,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"crossbeam-utils 0.8.1",
"lazy_static",
"num_cpus",
]
@@ -1645,6 +1754,17 @@ version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_users"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
dependencies = [
"getrandom 0.1.15",
"redox_syscall",
"rust-argon2",
]
[[package]]
name = "ref_thread_local"
version = "0.0.0"
@@ -1721,6 +1841,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "rust-argon2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils 0.7.2",
]
[[package]]
name = "rustc-demangle"
version = "0.1.18"
@@ -1751,6 +1883,18 @@ dependencies = [
"semver 0.11.0",
]
[[package]]
name = "rustfix"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e"
dependencies = [
"anyhow",
"log",
"serde",
"serde_json",
]
[[package]]
name = "ryu"
version = "1.0.5"
@@ -1901,9 +2045,21 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.4.2"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85"
[[package]]
name = "socket2"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44"
dependencies = [
"cfg-if 0.1.10",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "stable_deref_trait"
@@ -1955,9 +2111,9 @@ checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd"
[[package]]
name = "syn"
version = "1.0.48"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
checksum = "3b4f34193997d92804d359ed09953e25d5138df6bcc055a71bf68ee89fdf9223"
dependencies = [
"proc-macro2",
"quote",
@@ -1984,6 +2140,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "term"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5"
dependencies = [
"dirs",
"winapi",
]
[[package]]
name = "test-generator"
version = "0.1.0"
@@ -1992,6 +2158,17 @@ dependencies = [
"target-lexicon",
]
[[package]]
name = "tester"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c"
dependencies = [
"getopts",
"libc",
"term",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@@ -2062,11 +2239,11 @@ dependencies = [
[[package]]
name = "tracing"
version = "0.1.21"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27"
checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"log",
"pin-project-lite",
"tracing-attributes",
@@ -2137,9 +2314,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unicode-segmentation"
version = "1.7.0"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8716a166f290ff49dabc18b44aa407cb7c6dbe1aa0971b44b8a24b0ca35aae"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]]
name = "unicode-width"
@@ -2273,6 +2450,7 @@ dependencies = [
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
"wasmer-compiler-singlepass",
"wasmer-derive",
"wasmer-engine",
"wasmer-engine-jit",
"wasmer-engine-native",
@@ -2405,7 +2583,7 @@ dependencies = [
"rayon",
"regex",
"rustc_version 0.2.3",
"semver 0.9.0",
"semver 0.11.0",
"smallvec",
"target-lexicon",
"wasmer-compiler",
@@ -2431,6 +2609,18 @@ dependencies = [
"wasmer-vm",
]
[[package]]
name = "wasmer-derive"
version = "1.0.0-alpha5"
dependencies = [
"compiletest_rs",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
"wasmer",
]
[[package]]
name = "wasmer-emscripten"
version = "1.0.0-alpha5"
@@ -2540,7 +2730,7 @@ dependencies = [
name = "wasmer-object"
version = "1.0.0-alpha5"
dependencies = [
"object 0.21.1",
"object",
"thiserror",
"wasmer-compiler",
"wasmer-types",
@@ -2563,7 +2753,7 @@ dependencies = [
"cfg-if 0.1.10",
"indexmap",
"libc",
"memoffset",
"memoffset 0.5.6",
"more-asserts",
"region",
"serde",
@@ -2636,6 +2826,7 @@ dependencies = [
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
"wasmer-compiler-singlepass",
"wasmer-emscripten",
"wasmer-engine",
"wasmer-engine-dummy",
"wasmer-engine-jit",
@@ -2814,9 +3005,9 @@ dependencies = [
[[package]]
name = "xcursor"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3a481cfdefd35e1c50073ae33a8000d695c98039544659f5dc5dd71311b0d01"
checksum = "3a9a231574ae78801646617cefd13bfe94be907c0e4fa979cfd8b770aa3c5d08"
dependencies = [
"nom",
]

View File

@@ -15,6 +15,7 @@ wasmer-compiler = { version = "1.0.0-alpha5", path = "lib/compiler" }
wasmer-compiler-cranelift = { version = "1.0.0-alpha5", path = "lib/compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "1.0.0-alpha5", path = "lib/compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "1.0.0-alpha5", path = "lib/compiler-llvm", optional = true }
wasmer-emscripten = { version = "1.0.0-alpha5", path = "lib/emscripten", optional = true }
wasmer-engine = { version = "1.0.0-alpha5", path = "lib/engine" }
wasmer-engine-jit = { version = "1.0.0-alpha5", path = "lib/engine-jit", optional = true }
wasmer-engine-native = { version = "1.0.0-alpha5", path = "lib/engine-native", optional = true }
@@ -35,6 +36,7 @@ members = [
"lib/compiler-cranelift",
"lib/compiler-singlepass",
"lib/compiler-llvm",
"lib/derive",
"lib/emscripten",
"lib/engine",
"lib/engine-jit",
@@ -78,7 +80,7 @@ default = [
"object-file",
"cache",
"wasi",
# "emscripten",
"emscripten",
]
engine = []
jit = [
@@ -96,7 +98,7 @@ object-file = [
cache = ["wasmer-cache"]
wast = ["wasmer-wast"]
wasi = ["wasmer-wasi"]
# emscripten = ["wasmer-emscripten"]
emscripten = ["wasmer-emscripten"]
wat = ["wasmer/wat"]
compiler = [
"wasmer/compiler",

View File

@@ -16,14 +16,14 @@ compilers := cranelift
test_compilers_engines :=
# Autodetect LLVM from llvm-config
ifneq (, $(shell which llvm-config))
ifneq (, $(shell which llvm-config 2>/dev/null))
LLVM_VERSION := $(shell llvm-config --version)
# If findstring is not empty, then it have found the value
ifneq (, $(findstring 10,$(LLVM_VERSION)))
compilers += llvm
endif
else
ifneq (, $(shell which llvm-config-10))
ifneq (, $(shell which llvm-config-10 2>/dev/null))
compilers += llvm
endif
endif

View File

@@ -21,7 +21,7 @@
use std::cell::RefCell;
use std::sync::Arc;
use wasmer::{imports, wat2wasm, Function, Instance, Module, Store};
use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, WasmerEnv};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;
@@ -68,7 +68,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
//
// This struct may have been anything. The only constraint is it must be
// possible to know the size of the `Env` at compile time (i.e it has to
// implement the `Sized` trait).
// implement the `Sized` trait) and that it implement the `WasmerEnv` trait.
// We derive a default implementation of `WasmerEnv` here.
#[derive(WasmerEnv)]
struct Env {
counter: Arc<RefCell<i32>>,
}

View File

@@ -51,9 +51,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let import_object = wasi_env.import_object(&module)?;
let instance = Instance::new(&module, &import_object)?;
// WASI requires to explicitly set the memory for the `WasiEnv`
wasi_env.set_memory(instance.exports.get_memory("memory")?.clone());
println!("Call WASI `_start` function...");
// And we just call the `_start` function!
let start = instance.exports.get_function("_start")?;

View File

@@ -16,6 +16,7 @@ wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "1.0.0
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "1.0.0-alpha5", optional = true }
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "1.0.0-alpha5", optional = true }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5" }
wasmer-derive = { path = "../derive", version = "1.0.0-alpha5" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha5" }
wasmer-engine-jit = { path = "../engine-jit", version = "1.0.0-alpha5", optional = true }
wasmer-engine-native = { path = "../engine-native", version = "1.0.0-alpha5", optional = true }

208
lib/api/src/env.rs Normal file
View File

@@ -0,0 +1,208 @@
use crate::{ExportError, Instance};
use thiserror::Error;
/// An error while initializing the user supplied host env with the `WasmerEnv` trait.
#[derive(Error, Debug)]
#[error("Host env initialization error: {0}")]
pub enum HostEnvInitError {
/// An error occurred when accessing an export
Export(ExportError),
}
impl From<ExportError> for HostEnvInitError {
fn from(other: ExportError) -> Self {
Self::Export(other)
}
}
/// Trait for initializing the environments passed to host functions after
/// instantiation but before execution.
///
/// This is useful for filling an environment with data that can only be accesed
/// after instantiation. For example, exported items such as memories and
/// functions which don't exist prior to instantiation can be accessed here so
/// that host functions can use them.
///
/// # Examples
///
/// This trait can be derived like so:
///
/// ```
/// use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc};
///
/// #[derive(WasmerEnv)]
/// pub struct MyEnvWithNoInstanceData {
/// non_instance_data: u8,
/// }
///
/// #[derive(WasmerEnv)]
/// pub struct MyEnvWithInstanceData {
/// non_instance_data: u8,
/// #[wasmer(export)]
/// memory: LazyInit<Memory>,
/// #[wasmer(export(name = "real_name"))]
/// func: LazyInit<NativeFunc<(i32, i32), i32>>,
/// }
///
/// ```
///
/// When deriving `WasmerEnv`, you must wrap your types to be initialized in
/// [`LazyInit`]. The derive macro will also generate helper methods of the form
/// `<field_name>_ref` and `<field_name>_ref_unchecked` for easy access to the
/// data.
///
/// This trait can also be implemented manually:
/// ```
/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
/// pub struct MyEnv {
/// memory: LazyInit<Memory>,
/// }
///
/// impl WasmerEnv for MyEnv {
/// fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
/// let memory = instance.exports.get_memory("memory").unwrap();
/// self.memory.initialize(memory.clone());
/// Ok(())
/// }
/// }
/// ```
pub trait WasmerEnv {
/// The function that Wasmer will call on your type to let it finish
/// setting up the environment with data from the `Instance`.
///
/// This function is called after `Instance` is created but before it is
/// returned to the user via `Instance::new`.
fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> {
Ok(())
}
}
impl WasmerEnv for u8 {}
impl WasmerEnv for i8 {}
impl WasmerEnv for u16 {}
impl WasmerEnv for i16 {}
impl WasmerEnv for u32 {}
impl WasmerEnv for i32 {}
impl WasmerEnv for u64 {}
impl WasmerEnv for i64 {}
impl WasmerEnv for u128 {}
impl WasmerEnv for i128 {}
impl WasmerEnv for f32 {}
impl WasmerEnv for f64 {}
impl WasmerEnv for usize {}
impl WasmerEnv for isize {}
impl WasmerEnv for char {}
impl WasmerEnv for bool {}
impl WasmerEnv for String {}
impl WasmerEnv for ::std::sync::atomic::AtomicBool {}
impl WasmerEnv for ::std::sync::atomic::AtomicI8 {}
impl WasmerEnv for ::std::sync::atomic::AtomicU8 {}
impl WasmerEnv for ::std::sync::atomic::AtomicI16 {}
impl WasmerEnv for ::std::sync::atomic::AtomicU16 {}
impl WasmerEnv for ::std::sync::atomic::AtomicI32 {}
impl WasmerEnv for ::std::sync::atomic::AtomicU32 {}
impl WasmerEnv for ::std::sync::atomic::AtomicI64 {}
impl WasmerEnv for ::std::sync::atomic::AtomicUsize {}
impl WasmerEnv for ::std::sync::atomic::AtomicIsize {}
impl WasmerEnv for dyn ::std::any::Any {}
impl<T: WasmerEnv> WasmerEnv for Box<T> {
fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
(&mut **self).init_with_instance(instance)
}
}
impl<T: WasmerEnv> WasmerEnv for &'static mut T {
fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
(*self).init_with_instance(instance)
}
}
/// Lazily init an item
pub struct LazyInit<T: Sized> {
/// The data to be initialized
data: std::mem::MaybeUninit<T>,
/// Whether or not the data has been initialized
initialized: bool,
}
impl<T> LazyInit<T> {
/// Creates an unitialized value.
pub fn new() -> Self {
Self {
data: std::mem::MaybeUninit::uninit(),
initialized: false,
}
}
/// # Safety
/// - The data must be initialized first
pub unsafe fn get_unchecked(&self) -> &T {
&*self.data.as_ptr()
}
/// Get the inner data.
pub fn get_ref(&self) -> Option<&T> {
if !self.initialized {
None
} else {
Some(unsafe { self.get_unchecked() })
}
}
/// Sets a value and marks the data as initialized.
pub fn initialize(&mut self, value: T) -> bool {
if self.initialized {
return false;
}
unsafe {
self.data.as_mut_ptr().write(value);
}
self.initialized = true;
true
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for LazyInit<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("LazyInit")
.field("data", &self.get_ref())
.finish()
}
}
impl<T: Clone> Clone for LazyInit<T> {
fn clone(&self) -> Self {
if let Some(inner) = self.get_ref() {
Self {
data: std::mem::MaybeUninit::new(inner.clone()),
initialized: true,
}
} else {
Self {
data: std::mem::MaybeUninit::uninit(),
initialized: false,
}
}
}
}
impl<T> Drop for LazyInit<T> {
fn drop(&mut self) {
if self.initialized {
unsafe {
let ptr = self.data.as_mut_ptr();
std::ptr::drop_in_place(ptr);
};
}
}
}
impl<T> Default for LazyInit<T> {
fn default() -> Self {
Self::new()
}
}
unsafe impl<T: Send> Send for LazyInit<T> {}
// I thought we could opt out of sync..., look into this
// unsafe impl<T> !Sync for InitWithInstance<T> {}

View File

@@ -7,7 +7,7 @@ use std::fmt;
use std::iter::{ExactSizeIterator, FromIterator};
use std::sync::Arc;
use thiserror::Error;
use wasmer_vm::Export;
use wasmer_engine::Export;
/// The `ExportError` can happen when trying to get a specific
/// export [`Extern`] from the [`Instance`] exports.
@@ -150,6 +150,19 @@ impl Exports {
.map_err(|_| ExportError::IncompatibleType)
}
/// Hack to get this working with nativefunc too
pub fn get_with_generics<'a, T, Args, Rets>(&'a self, name: &str) -> Result<T, ExportError>
where
Args: WasmTypeList,
Rets: WasmTypeList,
T: ExportableWithGenerics<'a, Args, Rets>,
{
match self.map.get(name) {
None => Err(ExportError::Missing(name.to_string())),
Some(extern_) => T::get_self_from_extern_with_generics(extern_),
}
}
/// Get an export as an `Extern`.
pub fn get_extern(&self, name: &str) -> Option<&Extern> {
self.map.get(name)
@@ -279,3 +292,19 @@ pub trait Exportable<'a>: Sized {
/// [`Instance`]: crate::Instance
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>;
}
/// A trait for accessing exports (like [`Exportable`]) but it takes generic
/// `Args` and `Rets` parameters so that `NativeFunc` can be accessed directly
/// as well.
pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized {
/// Get an export with the given generics.
fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result<Self, ExportError>;
}
/// We implement it for all concrete [`Exportable`] types (that are `Clone`)
/// with empty `Args` and `Rets`.
impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T {
fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result<Self, ExportError> {
T::get_self_from_extern(_extern).map(|i| i.clone())
}
}

View File

@@ -5,15 +5,17 @@ use crate::types::Val;
use crate::FunctionType;
use crate::NativeFunc;
use crate::RuntimeError;
use crate::WasmerEnv;
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
#[cfg(feature = "deprecated")]
pub use inner::{UnsafeMutableEnv, WithUnsafeMutableEnv};
use std::cmp::max;
use std::fmt;
use wasmer_engine::{Export, ExportFunction};
use wasmer_vm::{
raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction,
VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment,
raise_user_trap, resume_panic, wasmer_call_trampoline, VMCallerCheckedAnyfunc,
VMDynamicFunctionContext, VMExportFunction, VMFunctionBody, VMFunctionEnvironment,
VMFunctionKind, VMTrampoline,
};
@@ -51,6 +53,12 @@ pub enum FunctionDefinition {
/// during execution of the function.
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#function-instances
///
/// # Panics
/// - Closures (functions with captured environments) are not currently supported
/// with native functions. Attempting to create a native `Function` with one will
/// result in a panic.
/// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
#[derive(Clone, PartialEq)]
pub struct Function {
pub(crate) store: Store,
@@ -95,11 +103,14 @@ impl Function {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Dynamic,
vmctx,
signature: ty.clone(),
call_trampoline: None,
import_init_function_ptr: None,
vm_function: VMExportFunction {
address,
kind: VMFunctionKind::Dynamic,
vmctx,
signature: ty.clone(),
call_trampoline: None,
},
},
}
}
@@ -109,9 +120,10 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # use wasmer::{Function, FunctionType, Type, Store, Value, WasmerEnv};
/// # let store = Store::default();
/// #
/// #[derive(WasmerEnv)]
/// struct Env {
/// multiplier: i32,
/// };
@@ -128,7 +140,7 @@ impl Function {
pub fn new_with_env<F, Env>(store: &Store, ty: &FunctionType, env: Env, func: F) -> Self
where
F: Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static,
Env: Sized + 'static,
Env: Sized + WasmerEnv + 'static,
{
let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithEnv {
env: Box::new(env),
@@ -142,16 +154,25 @@ impl Function {
let vmctx = VMFunctionEnvironment {
host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _,
};
// TODO: look into removing transmute by changing API type signatures
let import_init_function_ptr = Some(unsafe {
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(
Env::init_with_instance,
)
});
Self {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Dynamic,
vmctx,
signature: ty.clone(),
call_trampoline: None,
import_init_function_ptr,
vm_function: VMExportFunction {
address,
kind: VMFunctionKind::Dynamic,
vmctx,
signature: ty.clone(),
call_trampoline: None,
},
},
}
}
@@ -180,6 +201,9 @@ impl Function {
Rets: WasmTypeList,
Env: Sized + 'static,
{
if std::mem::size_of::<F>() != 0 {
Self::closures_unsupported_panic();
}
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address() as *const VMFunctionBody;
let vmctx = VMFunctionEnvironment {
@@ -190,12 +214,18 @@ impl Function {
Self {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }),
exported: ExportFunction {
address,
vmctx,
signature,
kind: VMFunctionKind::Static,
call_trampoline: None,
// TODO: figure out what's going on in this function: it takes an `Env`
// param but also marks itself as not having an env
import_init_function_ptr: None,
vm_function: VMExportFunction {
address,
vmctx,
signature,
kind: VMFunctionKind::Static,
call_trampoline: None,
},
},
}
}
@@ -208,9 +238,10 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{Store, Function};
/// # use wasmer::{Store, Function, WasmerEnv};
/// # let store = Store::default();
/// #
/// #[derive(WasmerEnv)]
/// struct Env {
/// multiplier: i32,
/// };
@@ -227,8 +258,11 @@ impl Function {
F: HostFunction<Args, Rets, WithEnv, Env>,
Args: WasmTypeList,
Rets: WasmTypeList,
Env: Sized + 'static,
Env: Sized + WasmerEnv + 'static,
{
if std::mem::size_of::<F>() != 0 {
Self::closures_unsupported_panic();
}
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address();
@@ -241,17 +275,26 @@ impl Function {
let vmctx = VMFunctionEnvironment {
host_env: Box::into_raw(box_env) as *mut _,
};
// TODO: look into removing transmute by changing API type signatures
let import_init_function_ptr = Some(unsafe {
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(
Env::init_with_instance,
)
});
let signature = function.ty();
Self {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Static,
vmctx,
signature,
call_trampoline: None,
import_init_function_ptr,
vm_function: VMExportFunction {
address,
kind: VMFunctionKind::Static,
vmctx,
signature,
call_trampoline: None,
},
},
}
}
@@ -273,8 +316,11 @@ impl Function {
F: HostFunction<Args, Rets, WithUnsafeMutableEnv, Env>,
Args: WasmTypeList,
Rets: WasmTypeList,
Env: UnsafeMutableEnv + 'static,
Env: UnsafeMutableEnv + WasmerEnv + 'static,
{
if std::mem::size_of::<F>() != 0 {
Self::closures_unsupported_panic();
}
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address();
@@ -283,16 +329,24 @@ impl Function {
host_env: Box::into_raw(box_env) as *mut _,
};
let signature = function.ty();
// TODO: look into removing transmute by changing API type signatures
let import_init_function_ptr = Some(std::mem::transmute::<
fn(_, _) -> Result<(), _>,
fn(_, _) -> Result<(), _>,
>(Env::init_with_instance));
Self {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Static,
vmctx,
signature,
call_trampoline: None,
import_init_function_ptr,
vm_function: VMExportFunction {
address,
kind: VMFunctionKind::Static,
vmctx,
signature,
call_trampoline: None,
},
},
}
}
@@ -315,7 +369,7 @@ impl Function {
/// assert_eq!(f.ty().results(), vec![Type::I32]);
/// ```
pub fn ty(&self) -> &FunctionType {
&self.exported.signature
&self.exported.vm_function.signature
}
/// Returns the [`Store`] where the `Function` belongs.
@@ -372,9 +426,9 @@ impl Function {
// Call the trampoline.
if let Err(error) = unsafe {
wasmer_call_trampoline(
self.exported.vmctx,
self.exported.vm_function.vmctx,
func.trampoline,
self.exported.address,
self.exported.vm_function.address,
values_vec.as_mut_ptr() as *mut u8,
)
} {
@@ -475,7 +529,7 @@ impl Function {
}
pub(crate) fn from_export(store: &Store, wasmer_export: ExportFunction) -> Self {
if let Some(trampoline) = wasmer_export.call_trampoline {
if let Some(trampoline) = wasmer_export.vm_function.call_trampoline {
Self {
store: store.clone(),
definition: FunctionDefinition::Wasm(WasmFunctionDefinition { trampoline }),
@@ -485,7 +539,7 @@ impl Function {
Self {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition {
has_env: !wasmer_export.vmctx.is_null(),
has_env: !wasmer_export.vm_function.vmctx.is_null(),
}),
exported: wasmer_export,
}
@@ -496,11 +550,11 @@ impl Function {
let vmsignature = self
.store
.engine()
.register_signature(&self.exported.signature);
.register_signature(&self.exported.vm_function.signature);
VMCallerCheckedAnyfunc {
func_ptr: self.exported.address,
func_ptr: self.exported.vm_function.address,
type_index: vmsignature,
vmctx: self.exported.vmctx,
vmctx: self.exported.vm_function.vmctx,
}
}
@@ -586,7 +640,7 @@ impl Function {
{
// type check
{
let expected = self.exported.signature.params();
let expected = self.exported.vm_function.signature.params();
let given = Args::wasm_types();
if expected != given {
@@ -599,7 +653,7 @@ impl Function {
}
{
let expected = self.exported.signature.results();
let expected = self.exported.vm_function.signature.results();
let given = Rets::wasm_types();
if expected != given {
@@ -614,12 +668,16 @@ impl Function {
Ok(NativeFunc::new(
self.store.clone(),
self.exported.address,
self.exported.vmctx,
self.exported.kind,
self.exported.vm_function.address,
self.exported.vm_function.vmctx,
self.exported.vm_function.kind,
self.definition.clone(),
))
}
fn closures_unsupported_panic() -> ! {
unimplemented!("Closures (functions with captured environments) are currently unsupported with native functions. See: https://github.com/wasmerio/wasmer/issues/1840")
}
}
impl<'a> Exportable<'a> for Function {

View File

@@ -7,7 +7,8 @@ use crate::Mutability;
use crate::RuntimeError;
use std::fmt;
use std::sync::Arc;
use wasmer_vm::{Export, ExportGlobal, Global as RuntimeGlobal};
use wasmer_engine::{Export, ExportGlobal};
use wasmer_vm::{Global as RuntimeGlobal, VMExportGlobal};
/// A WebAssembly `global` instance.
///
@@ -183,7 +184,7 @@ impl Global {
pub(crate) fn from_export(store: &Store, wasmer_export: ExportGlobal) -> Self {
Self {
store: store.clone(),
global: wasmer_export.from,
global: wasmer_export.vm_global.from,
}
}
@@ -217,7 +218,9 @@ impl fmt::Debug for Global {
impl<'a> Exportable<'a> for Global {
fn to_export(&self) -> Export {
ExportGlobal {
from: self.global.clone(),
vm_global: VMExportGlobal {
from: self.global.clone(),
},
}
.into()
}

View File

@@ -5,8 +5,9 @@ use crate::{MemoryType, MemoryView};
use std::convert::TryInto;
use std::slice;
use std::sync::Arc;
use wasmer_engine::{Export, ExportMemory};
use wasmer_types::{Pages, ValueType};
use wasmer_vm::{Export, ExportMemory, Memory as RuntimeMemory, MemoryError};
use wasmer_vm::{Memory as RuntimeMemory, MemoryError, VMExportMemory};
/// A WebAssembly `memory` instance.
///
@@ -223,7 +224,7 @@ impl Memory {
pub(crate) fn from_export(store: &Store, wasmer_export: ExportMemory) -> Self {
Self {
store: store.clone(),
memory: wasmer_export.from,
memory: wasmer_export.vm_memory.from,
}
}
@@ -247,7 +248,9 @@ impl Memory {
impl<'a> Exportable<'a> for Memory {
fn to_export(&self) -> Export {
ExportMemory {
from: self.memory.clone(),
vm_memory: VMExportMemory {
from: self.memory.clone(),
},
}
.into()
}

View File

@@ -17,7 +17,7 @@ use crate::exports::{ExportError, Exportable};
use crate::store::{Store, StoreObject};
use crate::ExternType;
use std::fmt;
use wasmer_vm::Export;
use wasmer_engine::Export;
/// An `Extern` is the runtime representation of an entity that
/// can be imported or exported.

View File

@@ -5,7 +5,8 @@ use crate::types::{Val, ValFuncRef};
use crate::RuntimeError;
use crate::TableType;
use std::sync::Arc;
use wasmer_vm::{Export, ExportTable, Table as RuntimeTable, VMCallerCheckedAnyfunc};
use wasmer_engine::{Export, ExportTable};
use wasmer_vm::{Table as RuntimeTable, VMCallerCheckedAnyfunc, VMExportTable};
/// A WebAssembly `table` instance.
///
@@ -142,7 +143,7 @@ impl Table {
pub(crate) fn from_export(store: &Store, wasmer_export: ExportTable) -> Self {
Self {
store: store.clone(),
table: wasmer_export.from,
table: wasmer_export.vm_table.from,
}
}
@@ -155,7 +156,9 @@ impl Table {
impl<'a> Exportable<'a> for Table {
fn to_export(&self) -> Export {
ExportTable {
from: self.table.clone(),
vm_table: VMExportTable {
from: self.table.clone(),
},
}
.into()
}

View File

@@ -6,8 +6,7 @@ use std::collections::VecDeque;
use std::collections::{hash_map::Entry, HashMap};
use std::fmt;
use std::sync::{Arc, Mutex};
use wasmer_engine::NamedResolver;
use wasmer_vm::Export;
use wasmer_engine::{Export, NamedResolver};
/// The `LikeNamespace` trait represents objects that act as a namespace for imports.
/// For example, an `Instance` or `Namespace` could be
@@ -265,7 +264,6 @@ mod test {
use crate::{Global, Store, Val};
use wasmer_engine::ChainableNamedResolver;
use wasmer_types::Type;
use wasmer_vm::Export;
#[test]
fn chaining_works() {
@@ -320,7 +318,7 @@ mod test {
let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap();
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
happy_dog_global.from.ty().ty == Type::I64
happy_dog_global.vm_global.from.ty().ty == Type::I64
} else {
false
});
@@ -346,7 +344,7 @@ mod test {
let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap();
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
happy_dog_global.from.ty().ty == Type::I32
happy_dog_global.vm_global.from.ty().ty == Type::I32
} else {
false
});
@@ -366,7 +364,7 @@ mod test {
let happy_dog_entry = imports1.resolve_by_name("dog", "happy").unwrap();
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
happy_dog_global.from.ty().ty == Type::I32
happy_dog_global.vm_global.from.ty().ty == Type::I32
} else {
false
});

View File

@@ -2,9 +2,10 @@ use crate::exports::Exports;
use crate::externals::Extern;
use crate::module::Module;
use crate::store::Store;
use crate::InstantiationError;
use crate::{HostEnvInitError, LinkError, RuntimeError};
use std::fmt;
use std::sync::{Arc, Mutex};
use thiserror::Error;
use wasmer_engine::Resolver;
use wasmer_vm::{InstanceHandle, VMContext};
@@ -38,6 +39,44 @@ mod send_test {
}
}
/// An error while instantiating a module.
///
/// This is not a common WebAssembly error, however
/// we need to differentiate from a `LinkError` (an error
/// that happens while linking, on instantiation), a
/// Trap that occurs when calling the WebAssembly module
/// start function, and an error when initializing the user's
/// host environments.
#[derive(Error, Debug)]
pub enum InstantiationError {
/// A linking ocurred during instantiation.
#[error(transparent)]
Link(LinkError),
/// A runtime error occured while invoking the start function
#[error(transparent)]
Start(RuntimeError),
/// Error occurred when initializing the host environment.
#[error(transparent)]
HostEnvInitialization(HostEnvInitError),
}
impl From<wasmer_engine::InstantiationError> for InstantiationError {
fn from(other: wasmer_engine::InstantiationError) -> Self {
match other {
wasmer_engine::InstantiationError::Link(e) => Self::Link(e),
wasmer_engine::InstantiationError::Start(e) => Self::Start(e),
}
}
}
impl From<HostEnvInitError> for InstantiationError {
fn from(other: HostEnvInitError) -> Self {
Self::HostEnvInitialization(other)
}
}
impl Instance {
/// Creates a new `Instance` from a WebAssembly [`Module`] and a
/// set of imports resolved by the [`Resolver`].
@@ -80,16 +119,34 @@ impl Instance {
.map(|export| {
let name = export.name().to_string();
let export = handle.lookup(&name).expect("export");
let extern_ = Extern::from_export(store, export);
let extern_ = Extern::from_export(store, export.into());
(name, extern_)
})
.collect::<Exports>();
Ok(Self {
let instance = Self {
handle: Arc::new(Mutex::new(handle)),
module: module.clone(),
exports,
})
};
// # Safety
// `initialize_host_envs` should be called after instantiation but before
// returning an `Instance` to the user. We set up the host environments
// via `WasmerEnv::init_with_instance`.
//
// This usage is correct because we pass a valid pointer to `instance` and the
// correct error type returned by `WasmerEnv::init_with_instance` as a generic
// parameter.
unsafe {
instance
.handle
.lock()
.unwrap()
.initialize_host_envs::<HostEnvInitError>(&instance as *const _ as *const _)?;
}
Ok(instance)
}
/// Gets the [`Module`] associated with this instance.

View File

@@ -28,6 +28,7 @@
)
)]
mod env;
mod exports;
mod externals;
mod import_object;
@@ -40,6 +41,8 @@ mod tunables;
mod types;
mod utils;
pub use wasmer_derive::WasmerEnv;
pub mod internals {
//! We use the internals module for exporting types that are only
//! intended to use in internal crates such as the compatibility crate
@@ -51,12 +54,13 @@ pub mod internals {
pub use crate::externals::{WithEnv, WithoutEnv};
}
pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv};
pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator};
pub use crate::externals::{
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList,
};
pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
pub use crate::instance::Instance;
pub use crate::instance::{Instance, InstantiationError};
pub use crate::module::Module;
pub use crate::native::NativeFunc;
pub use crate::ptr::{Array, Item, WasmPtr};
@@ -76,8 +80,8 @@ pub use wasmer_compiler::{
};
pub use wasmer_compiler::{CpuFeature, Features, Target};
pub use wasmer_engine::{
ChainableNamedResolver, DeserializeError, Engine, FrameInfo, InstantiationError, LinkError,
NamedResolver, NamedResolverChain, Resolver, RuntimeError, SerializeError,
ChainableNamedResolver, DeserializeError, Engine, Export, FrameInfo, LinkError, NamedResolver,
NamedResolverChain, Resolver, RuntimeError, SerializeError,
};
pub use wasmer_types::{
Atomically, Bytes, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
@@ -85,7 +89,7 @@ pub use wasmer_types::{
};
// TODO: should those be moved into wasmer::vm as well?
pub use wasmer_vm::{raise_user_trap, Export, MemoryError};
pub use wasmer_vm::{raise_user_trap, MemoryError, VMExport};
pub mod vm {
//! We use the vm module for re-exporting wasmer-vm types

View File

@@ -15,9 +15,11 @@ use crate::externals::function::{
};
use crate::{FromToNativeWasmType, Function, FunctionType, RuntimeError, Store, WasmTypeList};
use std::panic::{catch_unwind, AssertUnwindSafe};
use wasmer_engine::ExportFunction;
use wasmer_types::NativeWasmType;
use wasmer_vm::{
ExportFunction, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind,
VMDynamicFunctionContext, VMExportFunction, VMFunctionBody, VMFunctionEnvironment,
VMFunctionKind,
};
/// A WebAssembly function that can be called natively
@@ -57,7 +59,8 @@ where
}
}
impl<Args, Rets> From<&NativeFunc<Args, Rets>> for ExportFunction
/*
impl<Args, Rets> From<&NativeFunc<Args, Rets>> for VMExportFunction
where
Args: WasmTypeList,
Rets: WasmTypeList,
@@ -72,6 +75,27 @@ where
call_trampoline: None,
}
}
}*/
impl<Args, Rets> From<&NativeFunc<Args, Rets>> for ExportFunction
where
Args: WasmTypeList,
Rets: WasmTypeList,
{
fn from(other: &NativeFunc<Args, Rets>) -> Self {
let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
Self {
// TODO:
import_init_function_ptr: None,
vm_function: VMExportFunction {
address: other.address,
vmctx: other.vmctx,
signature,
kind: other.arg_kind,
call_trampoline: None,
},
}
}
}
impl<Args, Rets> From<NativeFunc<Args, Rets>> for Function
@@ -85,11 +109,15 @@ where
store: other.store,
definition: other.definition,
exported: ExportFunction {
address: other.address,
vmctx: other.vmctx,
signature,
kind: other.arg_kind,
call_trampoline: None,
// TODO:
import_init_function_ptr: None,
vm_function: VMExportFunction {
address: other.address,
vmctx: other.vmctx,
signature,
kind: other.arg_kind,
call_trampoline: None,
},
},
}
}
@@ -201,6 +229,18 @@ macro_rules! impl_native_traits {
}
}
#[allow(unused_parens)]
impl<'a, $( $x, )* Rets> crate::exports::ExportableWithGenerics<'a, ($( $x ),*), Rets> for NativeFunc<( $( $x ),* ), Rets>
where
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
{
fn get_self_from_extern_with_generics(_extern: &crate::externals::Extern) -> Result<Self, crate::exports::ExportError> {
use crate::exports::Exportable;
crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::exports::ExportError::IncompatibleType)
}
}
};
}

View File

@@ -73,14 +73,19 @@ impl ValFuncRef for Val {
.engine()
.lookup_signature(item.type_index)
.expect("Signature not found in store");
let export = wasmer_vm::ExportFunction {
address: item.func_ptr,
signature,
// All functions in tables are already Static (as dynamic functions
// are converted to use the trampolines with static signatures).
kind: wasmer_vm::VMFunctionKind::Static,
vmctx: item.vmctx,
call_trampoline: None,
let export = wasmer_engine::ExportFunction {
// TODO:
// figure out if we ever need a value here: need testing with complicated import patterns
import_init_function_ptr: None,
vm_function: wasmer_vm::VMExportFunction {
address: item.func_ptr,
signature,
// All functions in tables are already Static (as dynamic functions
// are converted to use the trampolines with static signatures).
kind: wasmer_vm::VMFunctionKind::Static,
vmctx: item.vmctx,
call_trampoline: None,
},
};
let f = Function::from_export(store, export);
Self::FuncRef(f)

View File

@@ -208,8 +208,9 @@ fn function_new() -> Result<()> {
#[test]
fn function_new_env() -> Result<()> {
let store = Store::default();
#[derive(Clone)]
#[derive(Clone, WasmerEnv)]
struct MyEnv {};
let my_env = MyEnv {};
let function = Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| {});
assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
@@ -270,7 +271,7 @@ fn function_new_dynamic() -> Result<()> {
#[test]
fn function_new_dynamic_env() -> Result<()> {
let store = Store::default();
#[derive(Clone)]
#[derive(Clone, WasmerEnv)]
struct MyEnv {};
let my_env = MyEnv {};
@@ -376,3 +377,33 @@ fn function_outlives_instance() -> Result<()> {
Ok(())
}
#[test]
fn manually_generate_wasmer_env() -> Result<()> {
let store = Store::default();
#[derive(WasmerEnv)]
struct MyEnv {
val: u32,
memory: LazyInit<Memory>,
}
fn host_function(env: &mut MyEnv, arg1: u32, arg2: u32) -> u32 {
env.val + arg1 + arg2
}
let mut env = MyEnv {
val: 5,
memory: LazyInit::new(),
};
let result = host_function(&mut env, 7, 9);
assert_eq!(result, 21);
let memory = Memory::new(&store, MemoryType::new(0, None, false))?;
env.memory.initialize(memory);
let result = host_function(&mut env, 1, 2);
assert_eq!(result, 8);
Ok(())
}

View File

@@ -21,7 +21,7 @@ use std::collections::HashMap;
use wasmer::{
ChainableNamedResolver, Exports, Extern, Function, FunctionType, Global, ImportObject,
ImportObjectIterator, ImportType, Memory, Module, NamedResolver, RuntimeError, Table, Val,
ValType,
ValType, WasmerEnv,
};
#[repr(C)]
@@ -45,10 +45,10 @@ pub(crate) struct CAPIImportObject {
/// but the new/current API does not. So we store them here to pass them to the Instance
/// to allow functions to access this data for backwards compatibilty.
pub(crate) imported_memories: Vec<*mut Memory>,
/// List of pointers to `UnsafeMutableEnv`s used to patch imported functions to be able to
/// List of pointers to `LegacyEnv`s used to patch imported functions to be able to
/// pass a the "vmctx" as the first argument.
/// Needed here because of extending import objects.
pub(crate) instance_pointers_to_update: Vec<NonNull<UnsafeMutableEnv>>,
pub(crate) instance_pointers_to_update: Vec<NonNull<LegacyEnv>>,
}
#[repr(C)]
@@ -399,7 +399,7 @@ pub unsafe extern "C" fn wasmer_import_object_imports_destroy(
let function_wrapper: Box<FunctionWrapper> =
Box::from_raw(import.value.func as *mut _);
let _: Box<Function> = Box::from_raw(function_wrapper.func.as_ptr());
let _: Box<UnsafeMutableEnv> = Box::from_raw(function_wrapper.legacy_env.as_ptr());
let _: Box<LegacyEnv> = Box::from_raw(function_wrapper.legacy_env.as_ptr());
}
wasmer_import_export_kind::WASM_GLOBAL => {
let _: Box<Global> = Box::from_raw(import.value.global as *mut _);
@@ -634,12 +634,13 @@ pub unsafe extern "C" fn wasmer_import_func_params_arity(
}
/// struct used to pass in context to functions (which must be back-patched)
#[derive(Debug, Default)]
pub(crate) struct UnsafeMutableEnv {
#[derive(Debug, Default, WasmerEnv)]
pub(crate) struct LegacyEnv {
pub(crate) instance_ptr: Option<NonNull<CAPIInstance>>,
}
impl UnsafeMutableEnv {
impl LegacyEnv {
pub(crate) fn ctx_ptr(&self) -> *mut CAPIInstance {
self.instance_ptr
.map(|p| p.as_ptr())
@@ -647,13 +648,13 @@ impl UnsafeMutableEnv {
}
}
/// struct used to hold on to `UnsafeMutableEnv` pointer as well as the function.
/// we need to do this to initialize the context ptr inside of `UnsafeMutableEnv` when
/// struct used to hold on to `LegacyEnv` pointer as well as the function.
/// we need to do this to initialize the context ptr inside of `LegacyEnv` when
/// instantiating the module.
#[derive(Debug)]
pub(crate) struct FunctionWrapper {
pub(crate) func: NonNull<Function>,
pub(crate) legacy_env: NonNull<UnsafeMutableEnv>,
pub(crate) legacy_env: NonNull<LegacyEnv>,
}
/// Creates new host function, aka imported function. `func` is a
@@ -690,7 +691,7 @@ pub unsafe extern "C" fn wasmer_import_func_new(
let store = get_global_store();
let env_ptr = Box::into_raw(Box::new(UnsafeMutableEnv::default()));
let env_ptr = Box::into_raw(Box::new(LegacyEnv::default()));
let func = Function::new_with_env(store, &func_type, &mut *env_ptr, move |env, args| {
use libffi::high::call::{call, Arg};

View File

@@ -4,7 +4,7 @@ use libc::c_uchar;
use std::path::PathBuf;
use std::ptr;
use std::str;
use wasmer::{Memory, MemoryType, NamedResolver};
use wasmer::NamedResolver;
use wasmer_wasi as wasi;
#[derive(Debug, PartialEq)]
@@ -213,11 +213,6 @@ pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object() -> *mut wa
let mut wasi_state_builder = wasi::WasiState::new("wasmer-wasi-default-program-name");
let wasi_state = wasi_state_builder.build().unwrap();
let mut wasi_env = wasi::WasiEnv::new(wasi_state);
// this API will now leak a `Memory`
let memory_type = MemoryType::new(0, None, false);
let memory = Memory::new(store, memory_type).expect("create memory");
wasi_env.set_memory(memory);
// TODO(mark): review lifetime of `Memory` here
let import_object_inner: Box<dyn NamedResolver> = Box::new(
wasi::generate_import_object_from_env(store, wasi_env, wasi::WasiVersion::Latest),
);

View File

@@ -1,5 +1,5 @@
//! Ordered Resolvers are a custom kind of [`Resolver`] that retrieves
//! `Export`s based on the index of the import, and not the module or name.
//! `EngineExport`s based on the index of the import, and not the module or name.
//!
//! This resolver is used in the Wasm-C-API as the imports are provided
//! by index and not by module and name.

View File

@@ -29,7 +29,7 @@ pub type wasm_func_callback_with_env_t = unsafe extern "C" fn(
) -> *mut wasm_trap_t;
#[allow(non_camel_case_types)]
pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void);
pub type wasm_env_finalizer_t = unsafe extern "C" fn(*mut c_void);
#[no_mangle]
pub unsafe extern "C" fn wasm_func_new(
@@ -92,7 +92,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
function_type: Option<&wasm_functype_t>,
callback: Option<wasm_func_callback_with_env_t>,
env: *mut c_void,
finalizer: wasm_env_finalizer_t,
finalizer: Option<wasm_env_finalizer_t>,
) -> Option<Box<wasm_func_t>> {
let store = store?;
let function_type = function_type?;
@@ -100,7 +100,23 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
let func_sig = &function_type.inner().function_type;
let num_rets = func_sig.results().len();
let inner_callback = move |env: &*mut c_void, args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
#[derive(wasmer::WasmerEnv)]
#[repr(C)]
struct WrapperEnv {
env: *mut c_void,
finalizer: Option<wasm_env_finalizer_t>,
};
impl Drop for WrapperEnv {
fn drop(&mut self) {
if let Some(finalizer) = self.finalizer {
unsafe { (finalizer)(self.env as _) }
}
}
}
let inner_callback = move |env: &WrapperEnv, args: &[Val]| -> Result<Vec<Val>, RuntimeError> {
let processed_args: wasm_val_vec_t = args
.into_iter()
.map(TryInto::try_into)
@@ -117,7 +133,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
]
.into();
let trap = callback(*env, &processed_args, &mut results);
let trap = callback(env.env, &processed_args, &mut results);
if !trap.is_null() {
let trap: Box<wasm_trap_t> = Box::from_raw(trap);
@@ -136,7 +152,12 @@ pub unsafe extern "C" fn wasm_func_new_with_env(
Ok(processed_results)
};
let function = Function::new_with_env(&store.inner, &func_sig, env, inner_callback);
let function = Function::new_with_env(
&store.inner,
&func_sig,
WrapperEnv { env, finalizer },
inner_callback,
);
Some(Box::new(wasm_func_t {
instance: None,

View File

@@ -66,6 +66,12 @@ pub unsafe extern "C" fn wasm_instance_new(
return None;
}
Err(InstantiationError::HostEnvInitialization(error)) => {
crate::error::update_last_error(error);
return None;
}
};
Some(Box::new(wasm_instance_t { inner: instance }))

View File

@@ -174,21 +174,31 @@ pub extern "C" fn wasi_env_new(mut config: Box<wasi_config_t>) -> Option<Box<was
#[no_mangle]
pub extern "C" fn wasi_env_delete(_state: Option<Box<wasi_env_t>>) {}
/// This function is deprecated. You may safely remove all calls to it and everything
/// will continue to work.
// Dead code: deprecate or remove
#[allow(unused_variables)]
#[no_mangle]
pub extern "C" fn wasi_env_set_instance(env: &mut wasi_env_t, instance: &wasm_instance_t) -> bool {
/*
let memory = if let Ok(memory) = instance.inner.exports.get_memory("memory") {
memory
} else {
return false;
};
env.inner.set_memory(memory.clone());
*/
true
}
/// This function is deprecated. You may safely remove all calls to it and everything
/// will continue to work.
// Dead code: deprecate or remove
#[allow(unused_variables)]
#[no_mangle]
pub extern "C" fn wasi_env_set_memory(env: &mut wasi_env_t, memory: &wasm_memory_t) {
env.inner.set_memory(memory.inner.clone());
//env.inner.set_memory(memory.inner.clone());
}
#[no_mangle]

View File

@@ -103,7 +103,6 @@ int main(int argc, const char* argv[]) {
}
fprintf(stderr, "found %zu exports\n", exports.size);
wasi_env_set_instance(wasi_env, instance);
wasm_func_t* run_func = wasi_get_start_function(instance);
if (run_func == NULL) {
printf("> Error accessing export!\n");

View File

@@ -29,9 +29,6 @@
# define DEPRECATED(message) __declspec(deprecated(message))
#endif
// The `jit` feature has been enabled for this build.
#define WASMER_JIT_ENABLED
// The `compiler` feature has been enabled for this build.
#define WASMER_COMPILER_ENABLED
@@ -145,10 +142,18 @@ intptr_t wasi_env_read_stdout(wasi_env_t *env, char *buffer, uintptr_t buffer_le
#endif
#if defined(WASMER_WASI_ENABLED)
/**
* This function is deprecated. You may safely remove all calls to it and everything
* will continue to work.
*/
bool wasi_env_set_instance(wasi_env_t *env, const wasm_instance_t *instance);
#endif
#if defined(WASMER_WASI_ENABLED)
/**
* This function is deprecated. You may safely remove all calls to it and everything
* will continue to work.
*/
void wasi_env_set_memory(wasi_env_t *env, const wasm_memory_t *memory);
#endif

View File

@@ -116,7 +116,7 @@ impl Run {
if is_emscripten_module(&module) {
let mut emscripten_globals = EmscriptenGlobals::new(module.store(), &module)
.map_err(|e| anyhow!("{}", e))?;
let mut em_env = EmEnv::new();
let mut em_env = EmEnv::new(&emscripten_globals.data, Default::default());
let import_object =
generate_emscripten_env(module.store(), &mut emscripten_globals, &mut em_env);
let mut instance = Instance::new(&module, &import_object)
@@ -132,8 +132,7 @@ impl Run {
self.path.to_str().unwrap()
},
self.args.iter().map(|arg| arg.as_str()).collect(),
None, //run.em_entrypoint.clone(),
vec![], //mapped_dirs,
None, //run.em_entrypoint.clone(),
)?;
return Ok(());
}

View File

@@ -58,8 +58,6 @@ impl Wasi {
let import_object = wasi_env.import_object(&module)?;
let instance = Instance::new(&module, &import_object)?;
wasi_env.set_memory(instance.exports.get_memory("memory")?.clone());
let start = instance.exports.get_function("_start")?;
let result = start.call(&[]);

View File

@@ -160,10 +160,6 @@ int main(int argc, char* argv[]) {
return -1;
}
#ifdef WASI
wasi_env_set_instance(wasi_env, instance);
#endif
#ifdef WASI
own wasm_func_t* start_function = wasi_get_start_function(instance);
if (!start_function) {

View File

@@ -23,7 +23,7 @@ rayon = "1.5"
serde = { version = "1.0", features = ["derive"] }
more-asserts = "0.2"
gimli = { version = "0.22", optional = true }
smallvec = "1.0.0"
smallvec = "1.5"
[dev-dependencies]
target-lexicon = { version = "0.11", default-features = false }

View File

@@ -16,7 +16,7 @@ wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", features = [
wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" }
target-lexicon = { version = "0.11", default-features = false }
smallvec = "1"
smallvec = "1.5"
goblin = "0.2"
libc = { version = "^0.2", default-features = false }
byteorder = "1"
@@ -32,7 +32,7 @@ features = ["llvm10-0", "target-x86", "target-aarch64"]
cc = "1.0"
lazy_static = "1.4"
regex = "1.3"
semver = "0.9"
semver = "0.11"
rustc_version = "0.2"
[features]

View File

@@ -23,7 +23,7 @@ dynasm = "1.0"
dynasmrt = "1.0"
lazy_static = "1.4"
byteorder = "1.3"
smallvec = "1"
smallvec = "1.5"
[badges]
maintenance = { status = "actively-developed" }

View File

@@ -5129,11 +5129,8 @@ impl<'a> FuncGen<'a> {
&& self.config.enable_nan_canonicalization
&& fp.canonicalization.is_some()
{
self.canonicalize_nan(
fp.canonicalization.unwrap().to_size(),
params[index],
params[index],
);
let size = fp.canonicalization.unwrap().to_size();
self.canonicalize_nan(size, params[index], params[index]);
}
self.fp_stack.pop().unwrap();
} else {
@@ -5230,11 +5227,8 @@ impl<'a> FuncGen<'a> {
&& self.config.enable_nan_canonicalization
&& fp.canonicalization.is_some()
{
self.canonicalize_nan(
fp.canonicalization.unwrap().to_size(),
params[index],
params[index],
);
let size = fp.canonicalization.unwrap().to_size();
self.canonicalize_nan(size, params[index], params[index]);
}
self.fp_stack.pop().unwrap();
} else {

View File

@@ -20,7 +20,7 @@ hashbrown = { version = "0.9", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
thiserror = "1.0"
serde_bytes = { version = "0.11", optional = true }
smallvec = "1.4"
smallvec = "1.5"
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
raw-cpuid = "7.0"

View File

@@ -1118,6 +1118,7 @@ dependencies = [
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
"wasmer-compiler-singlepass",
"wasmer-derive",
"wasmer-engine",
"wasmer-engine-jit",
"wasmer-engine-native",
@@ -1210,6 +1211,16 @@ dependencies = [
"wasmer-vm",
]
[[package]]
name = "wasmer-derive"
version = "1.0.0-alpha5"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "wasmer-engine"
version = "1.0.0-alpha5"

View File

@@ -1,3 +1,3 @@
pub use crate::new::wasmer::{ExportError, MemoryError};
pub use crate::new::wasmer::{ExportError, InstantiationError, MemoryError};
pub use crate::new::wasmer_compiler::CompileError;
pub use crate::new::wasmer_engine::{InstantiationError, LinkError, RuntimeError};
pub use crate::new::wasmer_engine::{LinkError, RuntimeError};

View File

@@ -1,4 +1,4 @@
pub use crate::new::{
wasmer::Export as RuntimeExport,
wasmer::{Exportable, Extern as Export},
wasmer_vm::Export as RuntimeExport,
};

View File

@@ -78,9 +78,7 @@ pub fn validate(bytes: &[u8]) -> bool {
///
/// # Usage
///
/// Function pointers or closures are supported. Closures can capture
/// their environment (with `move`). The first parameter is of kind
/// `vm::Ctx`.
/// Function pointers are supported. The first parameter is of kind `vm::Ctx`.
///
/// ```
/// # use wasmer_runtime_core::{imports, func, vm};
@@ -90,15 +88,12 @@ pub fn validate(bytes: &[u8]) -> bool {
/// n
/// }
///
/// let i = 7;
///
/// let import_object = imports! {
/// "env" => {
/// "foo" => func!(func),
/// // A closure with a captured environment.
/// "bar" => func!(move |_: &mut vm::Ctx, n: i32| -> i32 {
/// n + i
/// }),
/// "bar" => func!(|_: &mut vm::Ctx, n: i32| -> i32 {
/// n + 7
/// }),
/// },
/// };
/// ```

View File

@@ -87,7 +87,7 @@ impl From<&new::wasmer::Global> for Global {
}
impl<'a> new::wasmer::Exportable<'a> for Global {
fn to_export(&self) -> new::wasmer_vm::Export {
fn to_export(&self) -> new::wasmer::Export {
self.new_global.to_export()
}

View File

@@ -30,11 +30,11 @@ impl Namespace {
}
impl LikeNamespace for Namespace {
fn get_namespace_export(&self, name: &str) -> Option<new::wasmer_vm::Export> {
fn get_namespace_export(&self, name: &str) -> Option<new::wasmer::Export> {
self.exports.new_exports.get_namespace_export(name)
}
fn get_namespace_exports(&self) -> Vec<(String, new::wasmer_vm::Export)> {
fn get_namespace_exports(&self) -> Vec<(String, new::wasmer::Export)> {
self.exports.new_exports.get_namespace_exports()
}
}

View File

@@ -222,11 +222,11 @@ impl Instance {
}
impl LikeNamespace for Instance {
fn get_namespace_export(&self, name: &str) -> Option<new::wasmer_vm::Export> {
fn get_namespace_export(&self, name: &str) -> Option<new::wasmer::Export> {
self.exports.new_exports.get_namespace_export(name)
}
fn get_namespace_exports(&self) -> Vec<(String, new::wasmer_vm::Export)> {
fn get_namespace_exports(&self) -> Vec<(String, new::wasmer::Export)> {
self.exports.new_exports.get_namespace_exports()
}
}
@@ -256,11 +256,11 @@ impl Exports {
}
impl LikeNamespace for Exports {
fn get_namespace_export(&self, name: &str) -> Option<new::wasmer_vm::Export> {
fn get_namespace_export(&self, name: &str) -> Option<new::wasmer::Export> {
self.new_exports.get_namespace_export(name)
}
fn get_namespace_exports(&self) -> Vec<(String, new::wasmer_vm::Export)> {
fn get_namespace_exports(&self) -> Vec<(String, new::wasmer::Export)> {
self.new_exports.get_namespace_exports()
}
}

View File

@@ -9,8 +9,8 @@ pub mod ptr {
pub use crate::new::wasmer::{Array, Item, WasmPtr};
}
pub use new::wasmer_types::MemoryType as MemoryDescriptor;
pub use new::wasmer::{Atomically, MemoryView};
pub use new::wasmer_types::MemoryType as MemoryDescriptor;
pub use new::wasmer_vm::MemoryStyle as MemoryType;
/// A Wasm linear memory.
@@ -108,7 +108,7 @@ impl From<&new::wasmer::Memory> for Memory {
}
impl<'a> new::wasmer::Exportable<'a> for Memory {
fn to_export(&self) -> new::wasmer_vm::Export {
fn to_export(&self) -> new::wasmer::Export {
self.new_memory.to_export()
}

View File

@@ -8,7 +8,7 @@ use crate::{
types::{FuncSig, Value},
vm,
};
use new::wasmer_vm::Export;
use new::wasmer::Export;
use std::{
cell::RefCell,
collections::HashMap,
@@ -98,18 +98,20 @@ impl Module {
// `function` is a static host function
// constructed with
// `new::wasmer::Function::new_env`.
if !function.address.is_null() {
if !function.vm_function.address.is_null() {
// Properly drop the empty `vm::Ctx`
// created by the host function.
unsafe {
ptr::drop_in_place::<vm::Ctx>(function.vmctx.host_env as _);
ptr::drop_in_place::<vm::Ctx>(
function.vm_function.vmctx.host_env as _,
);
}
// Update the pointer to `VMContext`,
// which is actually a `vm::Ctx`
// pointer, to fallback on the
// environment hack.
function.vmctx.host_env = pre_instance.vmctx_ptr() as _;
function.vm_function.vmctx.host_env = pre_instance.vmctx_ptr() as _;
}
// `function` is a dynamic host function
// constructed with
@@ -147,13 +149,15 @@ impl Module {
new::wasmer_vm::VMDynamicFunctionContext<
VMDynamicFunctionWithEnv<DynamicCtx>,
>,
> = unsafe { Box::from_raw(function.vmctx.host_env as *mut _) };
> = unsafe {
Box::from_raw(function.vm_function.vmctx.host_env as *mut _)
};
// Replace the environment by ours.
vmctx.ctx.env.borrow_mut().vmctx = pre_instance.vmctx();
// … without anyone noticing…
function.vmctx.host_env = Box::into_raw(vmctx) as _;
function.vm_function.vmctx.host_env = Box::into_raw(vmctx) as _;
}
}

View File

@@ -70,7 +70,7 @@ impl From<&new::wasmer::Table> for Table {
}
impl<'a> new::wasmer::Exportable<'a> for Table {
fn to_export(&self) -> new::wasmer_vm::Export {
fn to_export(&self) -> new::wasmer::Export {
self.new_table.to_export()
}

View File

@@ -7,7 +7,7 @@ use crate::{
use std::marker::PhantomData;
pub use new::wasmer::internals::UnsafeMutableEnv;
pub use new::wasmer::{HostFunction, WasmTypeList};
pub use new::wasmer::{HostFunction, WasmTypeList, WasmerEnv};
/// Represents a function that can be used by WebAssembly.
#[derive(Clone)]
@@ -201,7 +201,7 @@ where
Args: WasmTypeList,
Rets: WasmTypeList,
{
fn to_export(&self) -> new::wasmer_vm::Export {
fn to_export(&self) -> new::wasmer::Export {
self.new_function.to_export()
}
@@ -235,6 +235,7 @@ use std::{
/// Initially, it holds an empty `vm::Ctx`, but it is replaced by the
/// `vm::Ctx` from `instance::PreInstance` in
/// `module::Module::instantiate`.
#[derive(WasmerEnv)]
pub(crate) struct DynamicCtx {
pub(crate) vmctx: Rc<RefCell<vm::Ctx>>,
inner_func:
@@ -311,7 +312,7 @@ impl From<&new::wasmer::Function> for DynamicFunc {
}
impl<'a> new::wasmer::Exportable<'a> for DynamicFunc {
fn to_export(&self) -> new::wasmer_vm::Export {
fn to_export(&self) -> new::wasmer::Export {
self.new_function.to_export()
}

View File

@@ -1,4 +1,5 @@
use crate::{module::ModuleInfo, new};
use new::wasmer::WasmerEnv;
use std::{ffi::c_void, ptr};
use new::wasmer::internals::UnsafeMutableEnv;
@@ -15,7 +16,7 @@ use new::wasmer::internals::UnsafeMutableEnv;
/// it may someday be pinned to a register (especially
/// on arm, which has a ton of registers) to reduce
/// register shuffling.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, WasmerEnv)]
#[repr(C)]
pub struct Ctx {
/// A pointer to the `ModuleInfo` of this instance.

View File

@@ -1118,6 +1118,7 @@ dependencies = [
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
"wasmer-compiler-singlepass",
"wasmer-derive",
"wasmer-engine",
"wasmer-engine-jit",
"wasmer-engine-native",
@@ -1210,6 +1211,16 @@ dependencies = [
"wasmer-vm",
]
[[package]]
name = "wasmer-derive"
version = "1.0.0-alpha5"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "wasmer-engine"
version = "1.0.0-alpha5"

21
lib/derive/Cargo.toml Normal file
View File

@@ -0,0 +1,21 @@
[package]
name = "wasmer-derive"
version = "1.0.0-alpha5"
description = "Wasmer derive macros"
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
repository = "https://github.com/wasmerio/wasmer"
license = "MIT"
edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = { version = "1", features = ["full"] }
quote = "1"
proc-macro2 = "1"
proc-macro-error = "1.0.0"
[dev-dependencies]
wasmer = { path = "../api", version = "1.0.0-alpha4" }
compiletest_rs = "0.5"

214
lib/derive/src/lib.rs Normal file
View File

@@ -0,0 +1,214 @@
extern crate proc_macro;
use proc_macro2::TokenStream;
use proc_macro_error::{abort, proc_macro_error, set_dummy};
use quote::{quote, quote_spanned, ToTokens};
use syn::{spanned::Spanned, *};
mod parse;
use crate::parse::WasmerAttr;
#[proc_macro_error]
#[proc_macro_derive(WasmerEnv, attributes(wasmer))]
pub fn derive_wasmer_env(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input: DeriveInput = syn::parse(input).unwrap();
let gen = impl_wasmer_env(&input);
gen.into()
}
fn impl_wasmer_env_for_struct(
name: &Ident,
data: &DataStruct,
generics: &Generics,
_attrs: &[Attribute],
) -> TokenStream {
let (trait_methods, helper_methods) = derive_struct_fields(data);
let lifetimes_and_generics = generics.params.clone();
let where_clause = generics.where_clause.clone();
quote! {
impl < #lifetimes_and_generics > ::wasmer::WasmerEnv for #name < #lifetimes_and_generics > #where_clause{
#trait_methods
}
impl < #lifetimes_and_generics > #name < #lifetimes_and_generics > #where_clause {
#helper_methods
}
}
}
fn impl_wasmer_env(input: &DeriveInput) -> TokenStream {
let struct_name = &input.ident;
set_dummy(quote! {
impl ::wasmer::WasmerEnv for #struct_name {
fn init_with_instance(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> {
Ok(())
}
}
});
match &input.data {
Data::Struct(ds) => {
impl_wasmer_env_for_struct(struct_name, ds, &input.generics, &input.attrs)
}
_ => todo!(),
}
/*match input.data {
Struct(ds /*DataStruct {
fields: syn::Fields::Named(ref fields),
..
}*/) => ,
Enum(ref e) => impl_wasmer_env_for_enum(struct_name, &e.variants, &input.attrs),
_ => abort_call_site!("structopt only supports non-tuple structs and enums"),
}*/
}
fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) {
let mut finish = vec![];
let mut helpers = vec![];
//let mut assign_tokens = vec![];
let mut touched_fields = vec![];
let fields: Vec<Field> = match &data.fields {
Fields::Named(ref fields) => fields.named.iter().cloned().collect(),
Fields::Unit => vec![],
Fields::Unnamed(fields) => fields.unnamed.iter().cloned().collect(),
};
for (field_num, f) in fields.into_iter().enumerate() {
let name = f.ident.clone();
let top_level_ty: &Type = &f.ty;
touched_fields.push(name.clone());
let mut wasmer_attr = None;
for attr in &f.attrs {
// if / filter
if attr.path.is_ident(&Ident::new("wasmer", attr.span())) {
let tokens = attr.tokens.clone();
match syn::parse2(tokens) {
Ok(attr) => {
wasmer_attr = Some(attr);
break;
}
Err(e) => {
abort!(attr, "Failed to parse `wasmer` attribute: {}", e);
}
}
}
}
if let Some(wasmer_attr) = wasmer_attr {
let inner_type = get_identifier(top_level_ty);
if let Some(name) = &name {
let name_ref_str = format!("{}_ref", name);
let name_ref = syn::Ident::new(&name_ref_str, name.span());
let name_ref_unchecked_str = format!("{}_ref_unchecked", name);
let name_ref_unchecked = syn::Ident::new(&name_ref_unchecked_str, name.span());
let helper_tokens = quote_spanned! {f.span()=>
/// Get access to the underlying data.
///
/// If `WasmerEnv::finish` has been called, this function will never
/// return `None` unless the underlying data has been mutated manually.
pub fn #name_ref(&self) -> Option<&#inner_type> {
self.#name.get_ref()
}
/// Gets the item without checking if it's been initialized.
///
/// # Safety
/// `WasmerEnv::finish` must have been called on this function or
/// this type manually initialized.
pub unsafe fn #name_ref_unchecked(&self) -> &#inner_type {
self.#name.get_unchecked()
}
};
helpers.push(helper_tokens);
}
match wasmer_attr {
WasmerAttr::Export { identifier, span } => {
let finish_tokens = if let Some(name) = name {
let name_str = name.to_string();
let item_name =
identifier.unwrap_or_else(|| LitStr::new(&name_str, name.span()));
quote_spanned! {f.span()=>
let #name: #inner_type = instance.exports.get_with_generics(#item_name)?;
self.#name.initialize(#name);
}
} else {
if let Some(identifier) = identifier {
let local_var =
Ident::new(&format!("field_{}", field_num), identifier.span());
quote_spanned! {f.span()=>
let #local_var: #inner_type = instance.exports.get_with_generics(#identifier)?;
self.#field_num.initialize(#local_var);
}
} else {
abort!(
span,
"Expected `name` field on export attribute because field does not have a name. For example: `#[wasmer(export(name = \"wasm_ident\"))]`.",
);
}
};
finish.push(finish_tokens);
}
}
}
}
let trait_methods = quote! {
fn init_with_instance(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> {
#(#finish)*
Ok(())
}
};
let helper_methods = quote! {
#(#helpers)*
};
(trait_methods, helper_methods)
}
// TODO: name this something that makes sense
fn get_identifier(ty: &Type) -> TokenStream {
match ty {
Type::Path(TypePath {
path: Path { segments, .. },
..
}) => {
if let Some(PathSegment { ident, arguments }) = segments.last() {
if ident != "LazyInit" {
abort!(
ident,
"WasmerEnv derive expects all `export`s to be wrapped in `LazyInit`"
);
}
if let PathArguments::AngleBracketed(AngleBracketedGenericArguments {
args, ..
}) = arguments
{
// TODO: proper error handling
assert_eq!(args.len(), 1);
if let GenericArgument::Type(Type::Path(TypePath {
path: Path { segments, .. },
..
})) = &args[0]
{
segments
.last()
.expect("there must be at least one segment; TODO: error handling")
.to_token_stream()
} else {
abort!(
&args[0],
"unrecognized type in first generic position on `LazyInit`"
);
}
} else {
abort!(arguments, "Expected a generic parameter on `LazyInit`");
}
} else {
abort!(segments, "Unknown type found");
}
}
_ => abort!(ty, "Unrecognized/unsupported type"),
}
}

103
lib/derive/src/parse.rs Normal file
View File

@@ -0,0 +1,103 @@
use proc_macro2::Span;
use proc_macro_error::abort;
use syn::{
parenthesized,
parse::{Parse, ParseStream},
token, Ident, LitStr, Token,
};
pub enum WasmerAttr {
Export {
/// The identifier is an override, otherwise we use the field name as the name
/// to lookup in `instance.exports`.
identifier: Option<LitStr>,
span: Span,
},
}
struct ExportExpr {
name: Option<LitStr>,
}
struct ExportOptions {
name: Option<LitStr>,
}
impl Parse for ExportOptions {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let ident = input.parse::<Ident>()?;
let _ = input.parse::<Token![=]>()?;
let ident_str = ident.to_string();
let name;
match ident_str.as_str() {
"name" => {
name = Some(input.parse::<LitStr>()?);
}
otherwise => {
abort!(
ident,
"Unrecognized argument in export options: expected `name` found `{}`",
otherwise
);
}
}
Ok(ExportOptions { name })
}
}
impl Parse for ExportExpr {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let name;
if input.peek(Ident) {
let options = input.parse::<ExportOptions>()?;
name = options.name;
} else {
name = None;
}
Ok(Self { name })
}
}
// allows us to handle parens more cleanly
struct WasmerAttrInner(WasmerAttr);
impl Parse for WasmerAttrInner {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let ident: Ident = input.parse()?;
let ident_str = ident.to_string();
let span = ident.span();
let out = match ident_str.as_str() {
"export" => {
let export_expr;
let name = if input.peek(token::Paren) {
let _: token::Paren = parenthesized!(export_expr in input);
let expr = export_expr.parse::<ExportExpr>()?;
expr.name
} else {
None
};
WasmerAttr::Export {
identifier: name,
span,
}
}
otherwise => abort!(
ident,
"Unexpected identifier `{}`. Expected `export`.",
otherwise
),
};
Ok(WasmerAttrInner(out))
}
}
impl Parse for WasmerAttr {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let attr_inner;
parenthesized!(attr_inner in input);
Ok(attr_inner.parse::<WasmerAttrInner>()?.0)
}
}

87
lib/derive/tests/basic.rs Normal file
View File

@@ -0,0 +1,87 @@
#![allow(dead_code)]
use wasmer::{Function, Global, LazyInit, Memory, NativeFunc, Table, WasmerEnv};
#[derive(WasmerEnv)]
struct MyEnv {
num: u32,
nums: Vec<i32>,
}
fn impls_wasmer_env<T: WasmerEnv>() -> bool {
true
}
#[test]
fn test_derive() {
let _my_env = MyEnv {
num: 3,
nums: vec![1, 2, 3],
};
assert!(impls_wasmer_env::<MyEnv>());
}
#[derive(WasmerEnv)]
struct MyEnvWithMemory {
num: u32,
nums: Vec<i32>,
#[wasmer(export)]
memory: LazyInit<Memory>,
}
#[derive(WasmerEnv)]
struct MyEnvWithFuncs {
num: u32,
nums: Vec<i32>,
#[wasmer(export)]
memory: LazyInit<Memory>,
#[wasmer(export)]
sum: LazyInit<NativeFunc<(i32, i32), i32>>,
}
#[derive(WasmerEnv)]
struct MyEnvWithEverything {
num: u32,
nums: Vec<i32>,
#[wasmer(export)]
memory: LazyInit<Memory>,
#[wasmer(export)]
sum: LazyInit<NativeFunc<(), i32>>,
#[wasmer(export)]
multiply: LazyInit<Function>,
#[wasmer(export)]
counter: LazyInit<Global>,
#[wasmer(export)]
functions: LazyInit<Table>,
}
#[derive(WasmerEnv)]
struct MyEnvWithLifetime<'a> {
name: &'a str,
#[wasmer(export(name = "memory"))]
memory: LazyInit<Memory>,
}
#[derive(WasmerEnv)]
struct MyUnitStruct;
#[derive(WasmerEnv)]
struct MyTupleStruct(u32);
#[derive(WasmerEnv)]
struct MyTupleStruct2(u32, u32);
#[derive(WasmerEnv)]
struct MyTupleStructWithAttribute(#[wasmer(export(name = "memory"))] LazyInit<Memory>, u32);
#[test]
fn test_derive_with_attribute() {
assert!(impls_wasmer_env::<MyEnvWithMemory>());
assert!(impls_wasmer_env::<MyEnvWithFuncs>());
assert!(impls_wasmer_env::<MyEnvWithEverything>());
assert!(impls_wasmer_env::<MyEnvWithLifetime>());
assert!(impls_wasmer_env::<MyUnitStruct>());
assert!(impls_wasmer_env::<MyTupleStruct>());
assert!(impls_wasmer_env::<MyTupleStruct2>());
assert!(impls_wasmer_env::<MyTupleStructWithAttribute>());
}

View File

@@ -0,0 +1,11 @@
extern crate wasmer;
use wasmer::{LazyInit, WasmerEnv, Memory};
#[derive(WasmerEnv)]
struct BadAttribute {
#[wasmer(extraport)] //~ Unexpected identifier `extraport`. Expected `export`.
memory: LazyInit<Memory>,
}
fn main() {}

View File

@@ -0,0 +1,17 @@
extern crate wasmer;
use wasmer::{LazyInit, WasmerEnv, Memory};
#[derive(WasmerEnv)]
struct BadExportArg {
#[wasmer(export(this_is_not_a_real_argument="hello, world"))] //~ Unrecognized argument in export options: expected `name` found `this_is_not_a_real_argument
memory: LazyInit<Memory>,
}
#[derive(WasmerEnv)]
struct BadExportArgRawString {
#[wasmer(export("hello"))] //~ Failed to parse `wasmer` attribute: unexpected token
memory: LazyInit<Memory>,
}
fn main() {}

View File

@@ -0,0 +1,11 @@
extern crate wasmer;
use wasmer::{LazyInit, WasmerEnv, Memory};
#[derive(WasmerEnv)]
struct ExportNotWrappedInLazyInit {
#[wasmer(export)]
memory: Memory, //~ WasmerEnv derive expects all `export`s to be wrapped in `LazyInit`
}
fn main() {}

View File

@@ -0,0 +1,48 @@
// file is a modified version of https://github.com/AltSysrq/proptest/blob/proptest-derive/proptest-derive/tests/compiletest.rs
// Original copyright and license:
// Copyright 2018 The proptest developers
//
// 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.
// Modifications copyright 2020 Wasmer
// Licensed under the MIT license
extern crate compiletest_rs as ct;
use std::env;
fn run_mode(src: &'static str, mode: &'static str) {
let mut config = ct::Config::default();
config.mode = mode.parse().expect("invalid mode");
config.target_rustcflags = Some("-L ../../target/debug/deps".to_owned());
if let Ok(name) = env::var("TESTNAME") {
config.filter = Some(name);
}
config.src_base = format!("tests/{}", src).into();
// hack to make this work on OSX: we probably don't need it though
/*if std::env::var("DYLD_LIBRARY_PATH").is_err() {
let val = std::env::var("DYLD_FALLBACK_LIBRARY_PATH").unwrap();
std::env::set_var("DYLD_LIBRARY_PATH", val);
}
config.link_deps();*/
// Uncomment this if you have the "multiple crates named `wasmer` issue". Massively slows
// down test iteration though...
config.clean_rmeta();
ct::run_tests(&config);
}
#[test]
#[ignore] // ignored by default because it needs to essentially run `cargo clean` to work correctly
// and that's really, really slow
fn compile_test() {
run_mode("compile-fail", "compile-fail");
}

View File

@@ -138,32 +138,32 @@ pub fn _getnameinfo(
// Macro definitions
macro_rules! invoke {
($ctx: ident, $name:ident, $( $arg:ident ),*) => {{
let sp = get_emscripten_data($ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed");
let result = get_emscripten_data($ctx).$name.as_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*);
($ctx: ident, $name:ident, $name_ref:ident, $( $arg:ident ),*) => {{
let sp = get_emscripten_data($ctx).stack_save_ref().expect("stack_save is None").call().expect("stack_save call failed");
let result = get_emscripten_data($ctx).$name_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*);
match result {
Ok(v) => v,
Err(_e) => {
get_emscripten_data($ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
get_emscripten_data($ctx).stack_restore_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
// TODO: We should check if _e != "longjmp" and if that's the case, re-throw the error
// JS version is: if (e !== e+0 && e !== 'longjmp') throw e;
get_emscripten_data($ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
get_emscripten_data($ctx).set_threw_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
0 as _
}
}
}};
}
macro_rules! invoke_no_return {
($ctx: ident, $name:ident, $( $arg:ident ),*) => {{
let sp = get_emscripten_data($ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed");
let result = get_emscripten_data($ctx).$name.as_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*);
($ctx: ident, $name:ident, $name_ref:ident, $( $arg:ident ),*) => {{
let sp = get_emscripten_data($ctx).stack_save_ref().expect("stack_save is None").call().expect("stack_save call failed");
let result = get_emscripten_data($ctx).$name_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*);
match result {
Ok(v) => v,
Err(_e) => {
get_emscripten_data($ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
get_emscripten_data($ctx).stack_restore_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed");
// TODO: We should check if _e != "longjmp" and if that's the case, re-throw the error
// JS version is: if (e !== e+0 && e !== 'longjmp') throw e;
get_emscripten_data($ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
get_emscripten_data($ctx).set_threw_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed");
}
}
}};
@@ -172,60 +172,97 @@ macro_rules! invoke_no_return {
// Invoke functions
pub fn invoke_i(ctx: &EmEnv, index: i32) -> i32 {
debug!("emscripten::invoke_i");
invoke!(ctx, dyn_call_i, index)
invoke!(ctx, dyn_call_i, dyn_call_i_ref, index)
}
pub fn invoke_ii(ctx: &EmEnv, index: i32, a1: i32) -> i32 {
debug!("emscripten::invoke_ii");
invoke!(ctx, dyn_call_ii, index, a1)
invoke!(ctx, dyn_call_ii, dyn_call_ii_ref, index, a1)
}
pub fn invoke_iii(ctx: &EmEnv, index: i32, a1: i32, a2: i32) -> i32 {
debug!("emscripten::invoke_iii");
invoke!(ctx, dyn_call_iii, index, a1, a2)
invoke!(ctx, dyn_call_iii, dyn_call_iii_ref, index, a1, a2)
}
pub fn invoke_iiii(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_iiii");
invoke!(ctx, dyn_call_iiii, index, a1, a2, a3)
invoke!(ctx, dyn_call_iiii, dyn_call_iiii_ref, index, a1, a2, a3)
}
pub fn invoke_iifi(ctx: &EmEnv, index: i32, a1: i32, a2: f64, a3: i32) -> i32 {
debug!("emscripten::invoke_iifi");
invoke!(ctx, dyn_call_iifi, index, a1, a2, a3)
invoke!(ctx, dyn_call_iifi, dyn_call_iifi_ref, index, a1, a2, a3)
}
pub fn invoke_v(ctx: &EmEnv, index: i32) {
debug!("emscripten::invoke_v");
invoke_no_return!(ctx, dyn_call_v, index);
invoke_no_return!(ctx, dyn_call_v, dyn_call_v_ref, index);
}
pub fn invoke_vi(ctx: &EmEnv, index: i32, a1: i32) {
debug!("emscripten::invoke_vi");
invoke_no_return!(ctx, dyn_call_vi, index, a1);
invoke_no_return!(ctx, dyn_call_vi, dyn_call_vi_ref, index, a1);
}
pub fn invoke_vii(ctx: &EmEnv, index: i32, a1: i32, a2: i32) {
debug!("emscripten::invoke_vii");
invoke_no_return!(ctx, dyn_call_vii, index, a1, a2);
invoke_no_return!(ctx, dyn_call_vii, dyn_call_vii_ref, index, a1, a2);
}
pub fn invoke_viii(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32) {
debug!("emscripten::invoke_viii");
invoke_no_return!(ctx, dyn_call_viii, index, a1, a2, a3);
invoke_no_return!(ctx, dyn_call_viii, dyn_call_viii_ref, index, a1, a2, a3);
}
pub fn invoke_viiii(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
debug!("emscripten::invoke_viiii");
invoke_no_return!(ctx, dyn_call_viiii, index, a1, a2, a3, a4);
invoke_no_return!(
ctx,
dyn_call_viiii,
dyn_call_viiii_ref,
index,
a1,
a2,
a3,
a4
);
}
pub fn invoke_dii(ctx: &EmEnv, index: i32, a1: i32, a2: i32) -> f64 {
debug!("emscripten::invoke_dii");
invoke!(ctx, dyn_call_dii, index, a1, a2)
invoke!(ctx, dyn_call_dii, dyn_call_dii_ref, index, a1, a2)
}
pub fn invoke_diiii(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> f64 {
debug!("emscripten::invoke_diiii");
invoke!(ctx, dyn_call_diiii, index, a1, a2, a3, a4)
invoke!(
ctx,
dyn_call_diiii,
dyn_call_diiii_ref,
index,
a1,
a2,
a3,
a4
)
}
pub fn invoke_iiiii(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
debug!("emscripten::invoke_iiiii");
invoke!(ctx, dyn_call_iiiii, index, a1, a2, a3, a4)
invoke!(
ctx,
dyn_call_iiiii,
dyn_call_iiiii_ref,
index,
a1,
a2,
a3,
a4
)
}
pub fn invoke_iiiiii(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) -> i32 {
debug!("emscripten::invoke_iiiiii");
invoke!(ctx, dyn_call_iiiiii, index, a1, a2, a3, a4, a5)
invoke!(
ctx,
dyn_call_iiiiii,
dyn_call_iiiiii_ref,
index,
a1,
a2,
a3,
a4,
a5
)
}
pub fn invoke_iiiiiii(
ctx: &EmEnv,
@@ -238,7 +275,18 @@ pub fn invoke_iiiiiii(
a6: i32,
) -> i32 {
debug!("emscripten::invoke_iiiiiii");
invoke!(ctx, dyn_call_iiiiiii, index, a1, a2, a3, a4, a5, a6)
invoke!(
ctx,
dyn_call_iiiiiii,
dyn_call_iiiiiii_ref,
index,
a1,
a2,
a3,
a4,
a5,
a6
)
}
pub fn invoke_iiiiiiii(
ctx: &EmEnv,
@@ -252,7 +300,19 @@ pub fn invoke_iiiiiiii(
a7: i32,
) -> i32 {
debug!("emscripten::invoke_iiiiiiii");
invoke!(ctx, dyn_call_iiiiiiii, index, a1, a2, a3, a4, a5, a6, a7)
invoke!(
ctx,
dyn_call_iiiiiiii,
dyn_call_iiiiiiii_ref,
index,
a1,
a2,
a3,
a4,
a5,
a6,
a7
)
}
pub fn invoke_iiiiiiiii(
ctx: &EmEnv,
@@ -270,6 +330,7 @@ pub fn invoke_iiiiiiiii(
invoke!(
ctx,
dyn_call_iiiiiiiii,
dyn_call_iiiiiiiii_ref,
index,
a1,
a2,
@@ -298,6 +359,7 @@ pub fn invoke_iiiiiiiiii(
invoke!(
ctx,
dyn_call_iiiiiiiiii,
dyn_call_iiiiiiiiii_ref,
index,
a1,
a2,
@@ -328,6 +390,7 @@ pub fn invoke_iiiiiiiiiii(
invoke!(
ctx,
dyn_call_iiiiiiiiiii,
dyn_call_iiiiiiiiiii_ref,
index,
a1,
a2,
@@ -343,11 +406,21 @@ pub fn invoke_iiiiiiiiiii(
}
pub fn invoke_vd(ctx: &EmEnv, index: i32, a1: f64) {
debug!("emscripten::invoke_vd");
invoke_no_return!(ctx, dyn_call_vd, index, a1)
invoke_no_return!(ctx, dyn_call_vd, dyn_call_vd_ref, index, a1)
}
pub fn invoke_viiiii(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_viiiii");
invoke_no_return!(ctx, dyn_call_viiiii, index, a1, a2, a3, a4, a5)
invoke_no_return!(
ctx,
dyn_call_viiiii,
dyn_call_viiiii_ref,
index,
a1,
a2,
a3,
a4,
a5
)
}
pub fn invoke_viiiiii(
ctx: &EmEnv,
@@ -360,7 +433,18 @@ pub fn invoke_viiiiii(
a6: i32,
) {
debug!("emscripten::invoke_viiiiii");
invoke_no_return!(ctx, dyn_call_viiiiii, index, a1, a2, a3, a4, a5, a6)
invoke_no_return!(
ctx,
dyn_call_viiiiii,
dyn_call_viiiiii_ref,
index,
a1,
a2,
a3,
a4,
a5,
a6
)
}
pub fn invoke_viiiiiii(
ctx: &EmEnv,
@@ -374,7 +458,19 @@ pub fn invoke_viiiiiii(
a7: i32,
) {
debug!("emscripten::invoke_viiiiiii");
invoke_no_return!(ctx, dyn_call_viiiiiii, index, a1, a2, a3, a4, a5, a6, a7)
invoke_no_return!(
ctx,
dyn_call_viiiiiii,
dyn_call_viiiiiii_ref,
index,
a1,
a2,
a3,
a4,
a5,
a6,
a7
)
}
pub fn invoke_viiiiiiii(
ctx: &EmEnv,
@@ -392,6 +488,7 @@ pub fn invoke_viiiiiiii(
invoke_no_return!(
ctx,
dyn_call_viiiiiiii,
dyn_call_viiiiiiii_ref,
index,
a1,
a2,
@@ -420,6 +517,7 @@ pub fn invoke_viiiiiiiii(
invoke_no_return!(
ctx,
dyn_call_viiiiiiiii,
dyn_call_viiiiiiiii_ref,
index,
a1,
a2,
@@ -450,6 +548,7 @@ pub fn invoke_viiiiiiiiii(
invoke_no_return!(
ctx,
dyn_call_viiiiiiiiii,
dyn_call_viiiiiiiiii_ref,
index,
a1,
a2,
@@ -466,17 +565,17 @@ pub fn invoke_viiiiiiiiii(
pub fn invoke_iij(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_iij");
invoke!(ctx, dyn_call_iij, index, a1, a2, a3)
invoke!(ctx, dyn_call_iij, dyn_call_iij_ref, index, a1, a2, a3)
}
pub fn invoke_iji(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_iji");
invoke!(ctx, dyn_call_iji, index, a1, a2, a3)
invoke!(ctx, dyn_call_iji, dyn_call_iji_ref, index, a1, a2, a3)
}
pub fn invoke_iiji(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
debug!("emscripten::invoke_iiji");
invoke!(ctx, dyn_call_iiji, index, a1, a2, a3, a4)
invoke!(ctx, dyn_call_iiji, dyn_call_iiji_ref, index, a1, a2, a3, a4)
}
pub fn invoke_iiijj(
@@ -490,11 +589,22 @@ pub fn invoke_iiijj(
a6: i32,
) -> i32 {
debug!("emscripten::invoke_iiijj");
invoke!(ctx, dyn_call_iiijj, index, a1, a2, a3, a4, a5, a6)
invoke!(
ctx,
dyn_call_iiijj,
dyn_call_iiijj_ref,
index,
a1,
a2,
a3,
a4,
a5,
a6
)
}
pub fn invoke_j(ctx: &EmEnv, index: i32) -> i32 {
debug!("emscripten::invoke_j");
if let Some(dyn_call_j) = &get_emscripten_data(ctx).dyn_call_j {
if let Some(dyn_call_j) = get_emscripten_data(ctx).dyn_call_j_ref() {
dyn_call_j.call(index).unwrap()
} else {
panic!("dyn_call_j is set to None");
@@ -502,7 +612,7 @@ pub fn invoke_j(ctx: &EmEnv, index: i32) -> i32 {
}
pub fn invoke_ji(ctx: &EmEnv, index: i32, a1: i32) -> i32 {
debug!("emscripten::invoke_ji");
if let Some(dyn_call_ji) = &get_emscripten_data(ctx).dyn_call_ji {
if let Some(dyn_call_ji) = get_emscripten_data(ctx).dyn_call_ji_ref() {
dyn_call_ji.call(index, a1).unwrap()
} else {
panic!("dyn_call_ji is set to None");
@@ -510,7 +620,7 @@ pub fn invoke_ji(ctx: &EmEnv, index: i32, a1: i32) -> i32 {
}
pub fn invoke_jii(ctx: &EmEnv, index: i32, a1: i32, a2: i32) -> i32 {
debug!("emscripten::invoke_jii");
if let Some(dyn_call_jii) = &get_emscripten_data(ctx).dyn_call_jii {
if let Some(dyn_call_jii) = get_emscripten_data(ctx).dyn_call_jii_ref() {
dyn_call_jii.call(index, a1, a2).unwrap()
} else {
panic!("dyn_call_jii is set to None");
@@ -519,7 +629,7 @@ pub fn invoke_jii(ctx: &EmEnv, index: i32, a1: i32, a2: i32) -> i32 {
pub fn invoke_jij(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
debug!("emscripten::invoke_jij");
if let Some(dyn_call_jij) = &get_emscripten_data(ctx).dyn_call_jij {
if let Some(dyn_call_jij) = get_emscripten_data(ctx).dyn_call_jij_ref() {
dyn_call_jij.call(index, a1, a2, a3).unwrap()
} else {
panic!("dyn_call_jij is set to None");
@@ -527,7 +637,7 @@ pub fn invoke_jij(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 {
}
pub fn invoke_jjj(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 {
debug!("emscripten::invoke_jjj");
if let Some(dyn_call_jjj) = &get_emscripten_data(ctx).dyn_call_jjj {
if let Some(dyn_call_jjj) = get_emscripten_data(ctx).dyn_call_jjj_ref() {
dyn_call_jjj.call(index, a1, a2, a3, a4).unwrap()
} else {
panic!("dyn_call_jjj is set to None");
@@ -535,7 +645,7 @@ pub fn invoke_jjj(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -
}
pub fn invoke_viiij(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_viiij");
if let Some(dyn_call_viiij) = &get_emscripten_data(ctx).dyn_call_viiij {
if let Some(dyn_call_viiij) = get_emscripten_data(ctx).dyn_call_viiij_ref() {
dyn_call_viiij.call(index, a1, a2, a3, a4, a5).unwrap();
} else {
panic!("dyn_call_viiij is set to None");
@@ -555,7 +665,7 @@ pub fn invoke_viiijiiii(
a9: i32,
) {
debug!("emscripten::invoke_viiijiiii");
if let Some(dyn_call_viiijiiii) = &get_emscripten_data(ctx).dyn_call_viiijiiii {
if let Some(dyn_call_viiijiiii) = get_emscripten_data(ctx).dyn_call_viiijiiii_ref() {
dyn_call_viiijiiii
.call(index, a1, a2, a3, a4, a5, a6, a7, a8, a9)
.unwrap();
@@ -579,7 +689,7 @@ pub fn invoke_viiijiiiiii(
a11: i32,
) {
debug!("emscripten::invoke_viiijiiiiii");
if let Some(dyn_call_viiijiiiiii) = &get_emscripten_data(ctx).dyn_call_viiijiiiiii {
if let Some(dyn_call_viiijiiiiii) = get_emscripten_data(ctx).dyn_call_viiijiiiiii_ref() {
dyn_call_viiijiiiiii
.call(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11)
.unwrap();
@@ -589,7 +699,7 @@ pub fn invoke_viiijiiiiii(
}
pub fn invoke_viij(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
debug!("emscripten::invoke_viij");
if let Some(dyn_call_viij) = &get_emscripten_data(ctx).dyn_call_viij {
if let Some(dyn_call_viij) = get_emscripten_data(ctx).dyn_call_viij_ref() {
dyn_call_viij.call(index, a1, a2, a3, a4).unwrap();
} else {
panic!("dyn_call_viij is set to None");
@@ -597,7 +707,7 @@ pub fn invoke_viij(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32)
}
pub fn invoke_viiji(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_viiji");
if let Some(dyn_call_viiji) = &get_emscripten_data(ctx).dyn_call_viiji {
if let Some(dyn_call_viiji) = get_emscripten_data(ctx).dyn_call_viiji_ref() {
dyn_call_viiji.call(index, a1, a2, a3, a4, a5).unwrap();
} else {
panic!("dyn_call_viiji is set to None");
@@ -615,7 +725,7 @@ pub fn invoke_viijiii(
a7: i32,
) {
debug!("emscripten::invoke_viijiii");
if let Some(dyn_call_viijiii) = &get_emscripten_data(ctx).dyn_call_viijiii {
if let Some(dyn_call_viijiii) = get_emscripten_data(ctx).dyn_call_viijiii_ref() {
dyn_call_viijiii
.call(index, a1, a2, a3, a4, a5, a6, a7)
.unwrap();
@@ -625,7 +735,7 @@ pub fn invoke_viijiii(
}
pub fn invoke_viijj(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32, a6: i32) {
debug!("emscripten::invoke_viijj");
if let Some(dyn_call_viijj) = &get_emscripten_data(ctx).dyn_call_viijj {
if let Some(dyn_call_viijj) = get_emscripten_data(ctx).dyn_call_viijj_ref() {
dyn_call_viijj.call(index, a1, a2, a3, a4, a5, a6).unwrap();
} else {
panic!("dyn_call_viijj is set to None");
@@ -633,7 +743,7 @@ pub fn invoke_viijj(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32,
}
pub fn invoke_vj(ctx: &EmEnv, index: i32, a1: i32, a2: i32) {
debug!("emscripten::invoke_vj");
if let Some(dyn_call_vj) = &get_emscripten_data(ctx).dyn_call_vj {
if let Some(dyn_call_vj) = get_emscripten_data(ctx).dyn_call_vj_ref() {
dyn_call_vj.call(index, a1, a2).unwrap();
} else {
panic!("dyn_call_vj is set to None");
@@ -641,11 +751,21 @@ pub fn invoke_vj(ctx: &EmEnv, index: i32, a1: i32, a2: i32) {
}
pub fn invoke_vjji(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_vjji");
invoke_no_return!(ctx, dyn_call_vjji, index, a1, a2, a3, a4, a5)
invoke_no_return!(
ctx,
dyn_call_vjji,
dyn_call_vjji_ref,
index,
a1,
a2,
a3,
a4,
a5
)
}
pub fn invoke_vij(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32) {
debug!("emscripten::invoke_vij");
if let Some(dyn_call_vij) = &get_emscripten_data(ctx).dyn_call_vij {
if let Some(dyn_call_vij) = get_emscripten_data(ctx).dyn_call_vij_ref() {
dyn_call_vij.call(index, a1, a2, a3).unwrap();
} else {
panic!("dyn_call_vij is set to None");
@@ -653,7 +773,7 @@ pub fn invoke_vij(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32) {
}
pub fn invoke_viji(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) {
debug!("emscripten::invoke_viji");
if let Some(dyn_call_viji) = &get_emscripten_data(ctx).dyn_call_viji {
if let Some(dyn_call_viji) = get_emscripten_data(ctx).dyn_call_viji_ref() {
dyn_call_viji.call(index, a1, a2, a3, a4).unwrap()
} else {
panic!("dyn_call_viji is set to None");
@@ -670,7 +790,7 @@ pub fn invoke_vijiii(
a6: i32,
) {
debug!("emscripten::invoke_vijiii");
if let Some(dyn_call_vijiii) = &get_emscripten_data(ctx).dyn_call_vijiii {
if let Some(dyn_call_vijiii) = get_emscripten_data(ctx).dyn_call_vijiii_ref() {
dyn_call_vijiii.call(index, a1, a2, a3, a4, a5, a6).unwrap()
} else {
panic!("dyn_call_vijiii is set to None");
@@ -678,7 +798,7 @@ pub fn invoke_vijiii(
}
pub fn invoke_vijj(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_vijj");
if let Some(dyn_call_vijj) = &get_emscripten_data(ctx).dyn_call_vijj {
if let Some(dyn_call_vijj) = get_emscripten_data(ctx).dyn_call_vijj_ref() {
dyn_call_vijj.call(index, a1, a2, a3, a4, a5).unwrap()
} else {
panic!("dyn_call_vijj is set to None");
@@ -686,15 +806,25 @@ pub fn invoke_vijj(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32,
}
pub fn invoke_vidd(ctx: &EmEnv, index: i32, a1: i32, a2: f64, a3: f64) {
debug!("emscripten::invoke_viid");
invoke_no_return!(ctx, dyn_call_vidd, index, a1, a2, a3);
invoke_no_return!(ctx, dyn_call_vidd, dyn_call_vidd_ref, index, a1, a2, a3);
}
pub fn invoke_viid(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: f64) {
debug!("emscripten::invoke_viid");
invoke_no_return!(ctx, dyn_call_viid, index, a1, a2, a3);
invoke_no_return!(ctx, dyn_call_viid, dyn_call_viid_ref, index, a1, a2, a3);
}
pub fn invoke_viidii(ctx: &EmEnv, index: i32, a1: i32, a2: i32, a3: f64, a4: i32, a5: i32) {
debug!("emscripten::invoke_viidii");
invoke_no_return!(ctx, dyn_call_viidii, index, a1, a2, a3, a4, a5);
invoke_no_return!(
ctx,
dyn_call_viidii,
dyn_call_viidii_ref,
index,
a1,
a2,
a3,
a4,
a5
);
}
pub fn invoke_viidddddddd(
ctx: &EmEnv,
@@ -714,6 +844,7 @@ pub fn invoke_viidddddddd(
invoke_no_return!(
ctx,
dyn_call_viidddddddd,
dyn_call_viidddddddd_ref,
index,
a1,
a2,

View File

@@ -19,14 +19,14 @@ use crate::{
};
use std::os::raw::c_int;
use std::sync::MutexGuard;
use crate::EmEnv;
use wasmer::ValueType;
pub fn call_malloc(ctx: &EmEnv, size: u32) -> u32 {
get_emscripten_data(ctx)
.malloc
.as_ref()
.malloc_ref()
.unwrap()
.call(size)
.unwrap()
@@ -38,7 +38,7 @@ pub fn call_malloc_with_cast<T: Copy, Ty>(ctx: &EmEnv, size: u32) -> WasmPtr<T,
}
pub fn call_memalign(ctx: &EmEnv, alignment: u32, size: u32) -> u32 {
if let Some(memalign) = &get_emscripten_data(ctx).memalign {
if let Some(memalign) = &get_emscripten_data(ctx).memalign_ref() {
memalign.call(alignment, size).unwrap()
} else {
panic!("Memalign is set to None");
@@ -47,15 +47,14 @@ pub fn call_memalign(ctx: &EmEnv, alignment: u32, size: u32) -> u32 {
pub fn call_memset(ctx: &EmEnv, pointer: u32, value: u32, size: u32) -> u32 {
get_emscripten_data(ctx)
.memset
.as_ref()
.memset_ref()
.unwrap()
.call(pointer, value, size)
.unwrap()
}
pub(crate) fn get_emscripten_data<'a>(ctx: &'a EmEnv) -> &'a mut EmscriptenData<'static> {
unsafe { &mut **ctx.data }
pub(crate) fn get_emscripten_data(ctx: &EmEnv) -> MutexGuard<EmscriptenData> {
ctx.data.lock().unwrap()
}
pub fn _getpagesize(_ctx: &EmEnv) -> u32 {

View File

@@ -62,8 +62,7 @@ impl Error for LongJumpRet {}
pub fn _longjmp(ctx: &EmEnv, env_addr: i32, val: c_int) {
let val = if val == 0 { 1 } else { val };
get_emscripten_data(ctx)
.set_threw
.as_ref()
.set_threw_ref()
.expect("set_threw is None")
.call(env_addr, val)
.expect("set_threw failed to call");

View File

@@ -16,13 +16,13 @@ extern crate log;
use lazy_static::lazy_static;
use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::f64;
use std::path::PathBuf;
use std::sync::Arc;
use std::{f64, ffi::c_void};
use std::sync::{Arc, Mutex};
use wasmer::{
imports, namespace, Exports, ExternRef, Function, FunctionType, Global, ImportObject, Instance,
Memory, MemoryType, Module, NativeFunc, Pages, RuntimeError, Store, Table, TableType, Val,
ValType,
LazyInit, Memory, MemoryType, Module, NativeFunc, Pages, RuntimeError, Store, Table, TableType,
Val, ValType, WasmerEnv,
};
#[cfg(unix)]
@@ -73,15 +73,22 @@ pub use self::utils::{
/// The environment provided to the Emscripten imports.
pub struct EmEnv {
memory: Arc<Option<Memory>>,
data: *mut *mut EmscriptenData<'static>,
data: Arc<Mutex<EmscriptenData>>,
}
impl WasmerEnv for EmEnv {
fn init_with_instance(&mut self, instance: &Instance) -> Result<(), wasmer::HostEnvInitError> {
let mut ed = self.data.lock().unwrap();
ed.init_with_instance(instance)?;
Ok(())
}
}
impl EmEnv {
pub fn new() -> Self {
pub fn new(data: &EmscriptenGlobalsData, mapped_dirs: HashMap<String, PathBuf>) -> Self {
Self {
memory: Arc::new(None),
// TODO: clean this up
data: Box::into_raw(Box::new(std::ptr::null_mut())),
data: Arc::new(Mutex::new(EmscriptenData::new(data.clone(), mapped_dirs))),
}
}
@@ -92,10 +99,6 @@ impl EmEnv {
}
}
pub fn set_data(&mut self, data: *mut c_void) {
unsafe { *self.data = data as _ };
}
/// Get a reference to the memory
pub fn memory(&self, _mem_idx: u32) -> &Memory {
(*self.memory).as_ref().unwrap()
@@ -119,279 +122,158 @@ lazy_static! {
const GLOBAL_BASE: u32 = 1024;
const STATIC_BASE: u32 = GLOBAL_BASE;
pub struct EmscriptenData<'a> {
pub globals: &'a EmscriptenGlobalsData,
#[derive(WasmerEnv, Default)]
pub struct EmscriptenData {
pub globals: EmscriptenGlobalsData,
pub malloc: Option<NativeFunc<u32, u32>>,
pub free: Option<NativeFunc<u32>>,
pub memalign: Option<NativeFunc<(u32, u32), u32>>,
pub memset: Option<NativeFunc<(u32, u32, u32), u32>>,
pub stack_alloc: Option<NativeFunc<u32, u32>>,
#[wasmer(export)]
pub malloc: LazyInit<NativeFunc<u32, u32>>,
#[wasmer(export)]
pub free: LazyInit<NativeFunc<u32>>,
#[wasmer(export)]
pub memalign: LazyInit<NativeFunc<(u32, u32), u32>>,
#[wasmer(export)]
pub memset: LazyInit<NativeFunc<(u32, u32, u32), u32>>,
#[wasmer(export)]
pub stack_alloc: LazyInit<NativeFunc<u32, u32>>,
pub jumps: Vec<UnsafeCell<[u32; 27]>>,
pub opened_dirs: HashMap<i32, Box<*mut LibcDir>>,
pub dyn_call_i: Option<NativeFunc<i32, i32>>,
pub dyn_call_ii: Option<NativeFunc<(i32, i32), i32>>,
pub dyn_call_iii: Option<NativeFunc<(i32, i32, i32), i32>>,
pub dyn_call_iiii: Option<NativeFunc<(i32, i32, i32, i32), i32>>,
pub dyn_call_iifi: Option<NativeFunc<(i32, i32, f64, i32), i32>>,
pub dyn_call_v: Option<NativeFunc<i32>>,
pub dyn_call_vi: Option<NativeFunc<(i32, i32)>>,
pub dyn_call_vii: Option<NativeFunc<(i32, i32, i32)>>,
pub dyn_call_viii: Option<NativeFunc<(i32, i32, i32, i32)>>,
pub dyn_call_viiii: Option<NativeFunc<(i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_i: LazyInit<NativeFunc<i32, i32>>,
#[wasmer(export)]
pub dyn_call_ii: LazyInit<NativeFunc<(i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iii: LazyInit<NativeFunc<(i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiii: LazyInit<NativeFunc<(i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iifi: LazyInit<NativeFunc<(i32, i32, f64, i32), i32>>,
#[wasmer(export)]
pub dyn_call_v: LazyInit<NativeFunc<i32>>,
#[wasmer(export)]
pub dyn_call_vi: LazyInit<NativeFunc<(i32, i32)>>,
#[wasmer(export)]
pub dyn_call_vii: LazyInit<NativeFunc<(i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viii: LazyInit<NativeFunc<(i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32)>>,
// round 2
pub dyn_call_dii: Option<NativeFunc<(i32, i32, i32), f64>>,
pub dyn_call_diiii: Option<NativeFunc<(i32, i32, i32, i32, i32), f64>>,
pub dyn_call_iiiii: Option<NativeFunc<(i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiiiiiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_dii: LazyInit<NativeFunc<(i32, i32, i32), f64>>,
#[wasmer(export)]
pub dyn_call_diiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32), f64>>,
#[wasmer(export)]
pub dyn_call_iiiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiiiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiiiiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiiiiiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiiiiiiii:
LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiiiiiiiii:
Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiiiiiiiiii:
Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_vd: Option<NativeFunc<(i32, f64)>>,
pub dyn_call_viiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiiiiiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_vd: LazyInit<NativeFunc<(i32, f64)>>,
#[wasmer(export)]
pub dyn_call_viiiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiiiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiiiiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiiiiiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiiiiiiii:
LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiiiiiiiii:
Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_iij: Option<NativeFunc<(i32, i32, i32, i32), i32>>,
pub dyn_call_iji: Option<NativeFunc<(i32, i32, i32, i32), i32>>,
pub dyn_call_iiji: Option<NativeFunc<(i32, i32, i32, i32, i32), i32>>,
pub dyn_call_iiijj: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32), i32>>,
pub dyn_call_j: Option<NativeFunc<i32, i32>>,
pub dyn_call_ji: Option<NativeFunc<(i32, i32), i32>>,
pub dyn_call_jii: Option<NativeFunc<(i32, i32, i32), i32>>,
pub dyn_call_jij: Option<NativeFunc<(i32, i32, i32, i32), i32>>,
pub dyn_call_jjj: Option<NativeFunc<(i32, i32, i32, i32, i32), i32>>,
pub dyn_call_viiij: Option<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viiijiiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_iij: LazyInit<NativeFunc<(i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iji: LazyInit<NativeFunc<(i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiji: LazyInit<NativeFunc<(i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_iiijj: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_j: LazyInit<NativeFunc<i32, i32>>,
#[wasmer(export)]
pub dyn_call_ji: LazyInit<NativeFunc<(i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_jii: LazyInit<NativeFunc<(i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_jij: LazyInit<NativeFunc<(i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_jjj: LazyInit<NativeFunc<(i32, i32, i32, i32, i32), i32>>,
#[wasmer(export)]
pub dyn_call_viiij: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiijiiii:
LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiijiiiiii:
Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viij: Option<NativeFunc<(i32, i32, i32, i32, i32)>>,
pub dyn_call_viiji: Option<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viijiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viijj: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_vj: Option<NativeFunc<(i32, i32, i32)>>,
pub dyn_call_vjji: Option<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_vij: Option<NativeFunc<(i32, i32, i32, i32)>>,
pub dyn_call_viji: Option<NativeFunc<(i32, i32, i32, i32, i32)>>,
pub dyn_call_vijiii: Option<NativeFunc<(i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_vijj: Option<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viid: Option<NativeFunc<(i32, i32, i32, f64)>>,
pub dyn_call_vidd: Option<NativeFunc<(i32, i32, f64, f64)>>,
pub dyn_call_viidii: Option<NativeFunc<(i32, i32, i32, f64, i32, i32)>>,
LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viij: LazyInit<NativeFunc<(i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viiji: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viijiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viijj: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_vj: LazyInit<NativeFunc<(i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_vjji: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_vij: LazyInit<NativeFunc<(i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viji: LazyInit<NativeFunc<(i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_vijiii: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_vijj: LazyInit<NativeFunc<(i32, i32, i32, i32, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viid: LazyInit<NativeFunc<(i32, i32, i32, f64)>>,
#[wasmer(export)]
pub dyn_call_vidd: LazyInit<NativeFunc<(i32, i32, f64, f64)>>,
#[wasmer(export)]
pub dyn_call_viidii: LazyInit<NativeFunc<(i32, i32, i32, f64, i32, i32)>>,
#[wasmer(export)]
pub dyn_call_viidddddddd:
Option<NativeFunc<(i32, i32, i32, f64, f64, f64, f64, f64, f64, f64, f64)>>,
LazyInit<NativeFunc<(i32, i32, i32, f64, f64, f64, f64, f64, f64, f64, f64)>>,
pub temp_ret_0: i32,
pub stack_save: Option<NativeFunc<(), i32>>,
pub stack_restore: Option<NativeFunc<i32>>,
pub set_threw: Option<NativeFunc<(i32, i32)>>,
#[wasmer(export)]
pub stack_save: LazyInit<NativeFunc<(), i32>>,
#[wasmer(export)]
pub stack_restore: LazyInit<NativeFunc<i32>>,
#[wasmer(export)]
pub set_threw: LazyInit<NativeFunc<(i32, i32)>>,
pub mapped_dirs: HashMap<String, PathBuf>,
}
impl<'a> EmscriptenData<'a> {
impl EmscriptenData {
pub fn new(
instance: &'a mut Instance,
globals: &'a EmscriptenGlobalsData,
globals: EmscriptenGlobalsData,
mapped_dirs: HashMap<String, PathBuf>,
) -> EmscriptenData<'a> {
let malloc = instance
.exports
.get_native_function("_malloc")
.or(instance.exports.get_native_function("malloc"))
.ok();
let free = instance
.exports
.get_native_function("_free")
.or(instance.exports.get_native_function("free"))
.ok();
let memalign = instance
.exports
.get_native_function("_memalign")
.or(instance.exports.get_native_function("memalign"))
.ok();
let memset = instance
.exports
.get_native_function("_memset")
.or(instance.exports.get_native_function("memset"))
.ok();
let stack_alloc = instance.exports.get_native_function("stackAlloc").ok();
let dyn_call_i = instance.exports.get_native_function("dynCall_i").ok();
let dyn_call_ii = instance.exports.get_native_function("dynCall_ii").ok();
let dyn_call_iii = instance.exports.get_native_function("dynCall_iii").ok();
let dyn_call_iiii = instance.exports.get_native_function("dynCall_iiii").ok();
let dyn_call_iifi = instance.exports.get_native_function("dynCall_iifi").ok();
let dyn_call_v = instance.exports.get_native_function("dynCall_v").ok();
let dyn_call_vi = instance.exports.get_native_function("dynCall_vi").ok();
let dyn_call_vii = instance.exports.get_native_function("dynCall_vii").ok();
let dyn_call_viii = instance.exports.get_native_function("dynCall_viii").ok();
let dyn_call_viiii = instance.exports.get_native_function("dynCall_viiii").ok();
// round 2
let dyn_call_dii = instance.exports.get_native_function("dynCall_dii").ok();
let dyn_call_diiii = instance.exports.get_native_function("dynCall_diiii").ok();
let dyn_call_iiiii = instance.exports.get_native_function("dynCall_iiiii").ok();
let dyn_call_iiiiii = instance.exports.get_native_function("dynCall_iiiiii").ok();
let dyn_call_iiiiiii = instance.exports.get_native_function("dynCall_iiiiiii").ok();
let dyn_call_iiiiiiii = instance
.exports
.get_native_function("dynCall_iiiiiiii")
.ok();
let dyn_call_iiiiiiiii = instance
.exports
.get_native_function("dynCall_iiiiiiiii")
.ok();
let dyn_call_iiiiiiiiii = instance
.exports
.get_native_function("dynCall_iiiiiiiiii")
.ok();
let dyn_call_iiiiiiiiiii = instance
.exports
.get_native_function("dynCall_iiiiiiiiiii")
.ok();
let dyn_call_vd = instance.exports.get_native_function("dynCall_vd").ok();
let dyn_call_viiiii = instance.exports.get_native_function("dynCall_viiiii").ok();
let dyn_call_viiiiii = instance.exports.get_native_function("dynCall_viiiiii").ok();
let dyn_call_viiiiiii = instance
.exports
.get_native_function("dynCall_viiiiiii")
.ok();
let dyn_call_viiiiiiii = instance
.exports
.get_native_function("dynCall_viiiiiiii")
.ok();
let dyn_call_viiiiiiiii = instance
.exports
.get_native_function("dynCall_viiiiiiiii")
.ok();
let dyn_call_viiiiiiiiii = instance
.exports
.get_native_function("dynCall_viiiiiiiiii")
.ok();
let dyn_call_iij = instance.exports.get_native_function("dynCall_iij").ok();
let dyn_call_iji = instance.exports.get_native_function("dynCall_iji").ok();
let dyn_call_iiji = instance.exports.get_native_function("dynCall_iiji").ok();
let dyn_call_iiijj = instance.exports.get_native_function("dynCall_iiijj").ok();
let dyn_call_j = instance.exports.get_native_function("dynCall_j").ok();
let dyn_call_ji = instance.exports.get_native_function("dynCall_ji").ok();
let dyn_call_jii = instance.exports.get_native_function("dynCall_jii").ok();
let dyn_call_jij = instance.exports.get_native_function("dynCall_jij").ok();
let dyn_call_jjj = instance.exports.get_native_function("dynCall_jjj").ok();
let dyn_call_viiij = instance.exports.get_native_function("dynCall_viiij").ok();
let dyn_call_viiijiiii = instance
.exports
.get_native_function("dynCall_viiijiiii")
.ok();
let dyn_call_viiijiiiiii = instance
.exports
.get_native_function("dynCall_viiijiiiiii")
.ok();
let dyn_call_viij = instance.exports.get_native_function("dynCall_viij").ok();
let dyn_call_viiji = instance.exports.get_native_function("dynCall_viiji").ok();
let dyn_call_viijiii = instance.exports.get_native_function("dynCall_viijiii").ok();
let dyn_call_viijj = instance.exports.get_native_function("dynCall_viijj").ok();
let dyn_call_vj = instance.exports.get_native_function("dynCall_vj").ok();
let dyn_call_vjji = instance.exports.get_native_function("dynCall_vjji").ok();
let dyn_call_vij = instance.exports.get_native_function("dynCall_vij").ok();
let dyn_call_viji = instance.exports.get_native_function("dynCall_viji").ok();
let dyn_call_vijiii = instance.exports.get_native_function("dynCall_vijiii").ok();
let dyn_call_vijj = instance.exports.get_native_function("dynCall_vijj").ok();
let dyn_call_viid = instance.exports.get_native_function("dynCall_viid").ok();
let dyn_call_vidd = instance.exports.get_native_function("dynCall_vidd").ok();
let dyn_call_viidii = instance.exports.get_native_function("dynCall_viidii").ok();
let dyn_call_viidddddddd = instance
.exports
.get_native_function("dynCall_viidddddddd")
.ok();
let stack_save = instance.exports.get_native_function("stackSave").ok();
let stack_restore = instance.exports.get_native_function("stackRestore").ok();
let set_threw = instance
.exports
.get_native_function("_setThrew")
.or(instance.exports.get_native_function("setThrew"))
.ok();
) -> EmscriptenData {
EmscriptenData {
globals,
malloc,
free,
memalign,
memset,
stack_alloc,
jumps: Vec::new(),
opened_dirs: HashMap::new(),
dyn_call_i,
dyn_call_ii,
dyn_call_iii,
dyn_call_iiii,
dyn_call_iifi,
dyn_call_v,
dyn_call_vi,
dyn_call_vii,
dyn_call_viii,
dyn_call_viiii,
// round 2
dyn_call_dii,
dyn_call_diiii,
dyn_call_iiiii,
dyn_call_iiiiii,
dyn_call_iiiiiii,
dyn_call_iiiiiiii,
dyn_call_iiiiiiiii,
dyn_call_iiiiiiiiii,
dyn_call_iiiiiiiiiii,
dyn_call_vd,
dyn_call_viiiii,
dyn_call_viiiiii,
dyn_call_viiiiiii,
dyn_call_viiiiiiii,
dyn_call_viiiiiiiii,
dyn_call_viiiiiiiiii,
dyn_call_iij,
dyn_call_iji,
dyn_call_iiji,
dyn_call_iiijj,
dyn_call_j,
dyn_call_ji,
dyn_call_jii,
dyn_call_jij,
dyn_call_jjj,
dyn_call_viiij,
dyn_call_viiijiiii,
dyn_call_viiijiiiiii,
dyn_call_viij,
dyn_call_viiji,
dyn_call_viijiii,
dyn_call_viijj,
dyn_call_vj,
dyn_call_vjji,
dyn_call_vij,
dyn_call_viji,
dyn_call_vijiii,
dyn_call_vijj,
dyn_call_viid,
dyn_call_vidd,
dyn_call_viidii,
dyn_call_viidddddddd,
temp_ret_0: 0,
stack_save,
stack_restore,
set_threw,
mapped_dirs,
..Default::default()
}
}
}
@@ -473,11 +355,8 @@ pub fn run_emscripten_instance(
path: &str,
args: Vec<&str>,
entrypoint: Option<String>,
mapped_dirs: Vec<(String, PathBuf)>,
) -> Result<(), RuntimeError> {
let mut data = EmscriptenData::new(instance, &globals.data, mapped_dirs.into_iter().collect());
env.set_memory(globals.memory.clone());
env.set_data(&mut data as *mut _ as *mut c_void);
set_up_emscripten(instance)?;
// println!("running emscripten instance");
@@ -533,6 +412,7 @@ pub fn emscripten_set_up_memory(
Ok(())
}
#[derive(Debug, Clone, Default)]
pub struct EmscriptenGlobalsData {
abort: u64,
// Env namespace

View File

@@ -73,8 +73,10 @@ pub fn sbrk(ctx: &EmEnv, increment: i32) -> i32 {
debug!("emscripten::sbrk");
// let old_dynamic_top = 0;
// let new_dynamic_top = 0;
let globals = get_emscripten_data(ctx).globals;
let dynamictop_ptr = (globals.dynamictop_ptr) as usize;
let dynamictop_ptr = {
let globals = &get_emscripten_data(ctx).globals;
(globals.dynamictop_ptr) as usize
};
let old_dynamic_top = ctx.memory(0).view::<u32>()[dynamictop_ptr].get() as i32;
let new_dynamic_top: i32 = old_dynamic_top + increment;
let total_memory = _emscripten_get_heap_size(ctx) as i32;

View File

@@ -124,8 +124,7 @@ pub unsafe fn copy_cstr_into_wasm(ctx: &EmEnv, cstr: *const c_char) -> u32 {
pub unsafe fn allocate_on_stack<'a, T: Copy>(ctx: &'a EmEnv, count: u32) -> (u32, &'a mut [T]) {
let offset = get_emscripten_data(ctx)
.stack_alloc
.as_ref()
.stack_alloc_ref()
.unwrap()
.call(count * (size_of::<T>() as u32))
.unwrap();

View File

@@ -96,14 +96,23 @@ pub trait Artifact: Send + Sync + Upcastable {
let module = self.module();
let (instance_ptr, offsets) = InstanceHandle::allocate_instance(&module);
let imports = resolve_imports(
&module,
resolver,
&self.finished_dynamic_function_trampolines(),
self.memory_styles(),
self.table_styles(),
)
.map_err(InstantiationError::Link)?;
let (imports, import_initializers) = {
let mut imports = resolve_imports(
&module,
resolver,
&self.finished_dynamic_function_trampolines(),
self.memory_styles(),
self.table_styles(),
)
.map_err(InstantiationError::Link)?;
// Get the `WasmerEnv::init_with_instance` function pointers and the pointers
// to the envs to call it on.
let import_initializers: Vec<(_, _)> = imports.get_import_initializers();
(imports, import_initializers)
};
// Get pointers to where metadata about local memories should live in VM memory.
let memory_definition_locations =
InstanceHandle::memory_definition_locations(instance_ptr, &offsets);
@@ -125,7 +134,7 @@ pub trait Artifact: Send + Sync + Upcastable {
self.register_frame_info();
InstanceHandle::new(
let handle = InstanceHandle::new(
instance_ptr,
offsets,
module,
@@ -137,8 +146,10 @@ pub trait Artifact: Send + Sync + Upcastable {
imports,
self.signatures().clone(),
host_state,
import_initializers,
)
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))?;
Ok(handle)
}
/// Finishes the instantiation of a just created `InstanceHandle`.

103
lib/engine/src/export.rs Normal file
View File

@@ -0,0 +1,103 @@
use wasmer_vm::{
ImportInitializerFuncPtr, VMExport, VMExportFunction, VMExportGlobal, VMExportMemory,
VMExportTable,
};
/// The value of an export passed from one instance to another.
#[derive(Debug, Clone)]
pub enum Export {
/// A function export value.
Function(ExportFunction),
/// A table export value.
Table(ExportTable),
/// A memory export value.
Memory(ExportMemory),
/// A global export value.
Global(ExportGlobal),
}
impl From<Export> for VMExport {
fn from(other: Export) -> Self {
match other {
Export::Function(ExportFunction { vm_function, .. }) => VMExport::Function(vm_function),
Export::Memory(ExportMemory { vm_memory }) => VMExport::Memory(vm_memory),
Export::Table(ExportTable { vm_table }) => VMExport::Table(vm_table),
Export::Global(ExportGlobal { vm_global }) => VMExport::Global(vm_global),
}
}
}
impl From<VMExport> for Export {
fn from(other: VMExport) -> Self {
match other {
VMExport::Function(vm_function) => Export::Function(ExportFunction {
vm_function,
import_init_function_ptr: None,
}),
VMExport::Memory(vm_memory) => Export::Memory(ExportMemory { vm_memory }),
VMExport::Table(vm_table) => Export::Table(ExportTable { vm_table }),
VMExport::Global(vm_global) => Export::Global(ExportGlobal { vm_global }),
}
}
}
/// A function export value with an extra function pointer to initialize
/// host environments.
#[derive(Debug, Clone, PartialEq)]
pub struct ExportFunction {
/// The VM function, containing most of the data.
pub vm_function: VMExportFunction,
/// Function pointer to `WasmerEnv::init_with_instance(&mut self, instance: &Instance)`.
///
/// This function is called to finish setting up the environment after
/// we create the `api::Instance`.
pub import_init_function_ptr: Option<ImportInitializerFuncPtr>,
}
impl From<ExportFunction> for Export {
fn from(func: ExportFunction) -> Self {
Self::Function(func)
}
}
/// A table export value.
#[derive(Debug, Clone)]
pub struct ExportTable {
/// The VM table, containing info about the table.
pub vm_table: VMExportTable,
}
impl From<ExportTable> for Export {
fn from(table: ExportTable) -> Self {
Self::Table(table)
}
}
/// A memory export value.
#[derive(Debug, Clone)]
pub struct ExportMemory {
/// The VM memory, containing info about the table.
pub vm_memory: VMExportMemory,
}
impl From<ExportMemory> for Export {
fn from(memory: ExportMemory) -> Self {
Self::Memory(memory)
}
}
/// A global export value.
#[derive(Debug, Clone)]
pub struct ExportGlobal {
/// The VM global, containing info about the global.
pub vm_global: VMExportGlobal,
}
impl From<ExportGlobal> for Export {
fn from(global: ExportGlobal) -> Self {
Self::Global(global)
}
}

View File

@@ -23,6 +23,7 @@
mod artifact;
mod engine;
mod error;
mod export;
mod resolver;
mod serialize;
mod trap;
@@ -33,6 +34,7 @@ pub use crate::engine::{Engine, EngineId};
pub use crate::error::{
DeserializeError, ImportError, InstantiationError, LinkError, SerializeError,
};
pub use crate::export::{Export, ExportFunction, ExportGlobal, ExportMemory, ExportTable};
pub use crate::resolver::{
resolve_imports, ChainableNamedResolver, NamedResolver, NamedResolverChain, NullResolver,
Resolver,

View File

@@ -1,13 +1,13 @@
//! Define the `Resolver` trait, allowing custom resolution for external
//! references.
use crate::{ImportError, LinkError};
use crate::{Export, ImportError, LinkError};
use more_asserts::assert_ge;
use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap};
use wasmer_types::{ExternType, FunctionIndex, ImportIndex, MemoryIndex, TableIndex};
use wasmer_vm::{
Export, FunctionBodyPtr, Imports, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody,
FunctionBodyPtr, Imports, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody,
VMFunctionImport, VMFunctionKind, VMGlobalImport, VMMemoryImport, VMTableImport,
};
@@ -103,11 +103,11 @@ fn get_extern_from_import(module: &ModuleInfo, import_index: &ImportIndex) -> Ex
/// Get an `ExternType` given an export (and Engine signatures in case is a function).
fn get_extern_from_export(_module: &ModuleInfo, export: &Export) -> ExternType {
match export {
Export::Function(ref f) => ExternType::Function(f.signature.clone()),
Export::Table(ref t) => ExternType::Table(*t.ty()),
Export::Memory(ref m) => ExternType::Memory(*m.ty()),
Export::Function(ref f) => ExternType::Function(f.vm_function.signature.clone()),
Export::Table(ref t) => ExternType::Table(*t.vm_table.ty()),
Export::Memory(ref m) => ExternType::Memory(*m.vm_memory.ty()),
Export::Global(ref g) => {
let global = g.from.ty();
let global = g.vm_global.from.ty();
ExternType::Global(*global)
}
}
@@ -125,6 +125,8 @@ pub fn resolve_imports(
_table_styles: &PrimaryMap<TableIndex, TableStyle>,
) -> Result<Imports, LinkError> {
let mut function_imports = PrimaryMap::with_capacity(module.num_imported_functions);
let mut host_function_env_initializers =
PrimaryMap::with_capacity(module.num_imported_functions);
let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables);
let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories);
let mut global_imports = PrimaryMap::with_capacity(module.num_imported_globals);
@@ -152,7 +154,7 @@ pub fn resolve_imports(
}
match resolved {
Export::Function(ref f) => {
let address = match f.kind {
let address = match f.vm_function.kind {
VMFunctionKind::Dynamic => {
// If this is a dynamic imported function,
// the address of the function is the address of the
@@ -168,22 +170,24 @@ pub fn resolve_imports(
// macos (Darwin) with the Apple Silicon ARM chip, for functions with more than 10 args
// TODO: Cranelift should have a good ABI for the ABI
if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
let num_params = f.signature.params().len();
let num_params = f.vm_function.signature.params().len();
assert!(num_params < 9, "Only native functions with less than 9 arguments are allowed in Apple Silicon (for now). Received {} in the import {}.{}", num_params, module_name, field);
}
f.address
f.vm_function.address
}
};
function_imports.push(VMFunctionImport {
body: address,
environment: f.vmctx,
environment: f.vm_function.vmctx,
});
host_function_env_initializers.push(f.import_init_function_ptr);
}
Export::Table(ref t) => {
table_imports.push(VMTableImport {
definition: t.from.vmtable(),
from: t.from.clone(),
definition: t.vm_table.from.vmtable(),
from: t.vm_table.from.clone(),
});
}
Export::Memory(ref m) => {
@@ -191,7 +195,7 @@ pub fn resolve_imports(
ImportIndex::Memory(index) => {
// Sanity-check: Ensure that the imported memory has at least
// guard-page protections the importing module expects it to have.
let export_memory_style = m.style();
let export_memory_style = m.vm_memory.style();
let import_memory_style = &memory_styles[*index];
if let (
MemoryStyle::Static { bound, .. },
@@ -216,15 +220,15 @@ pub fn resolve_imports(
}
memory_imports.push(VMMemoryImport {
definition: m.from.vmmemory(),
from: m.from.clone(),
definition: m.vm_memory.from.vmmemory(),
from: m.vm_memory.from.clone(),
});
}
Export::Global(ref g) => {
global_imports.push(VMGlobalImport {
definition: g.from.vmglobal(),
from: g.from.clone(),
definition: g.vm_global.from.vmglobal(),
from: g.vm_global.from.clone(),
});
}
}
@@ -232,6 +236,7 @@ pub fn resolve_imports(
Ok(Imports::new(
function_imports,
host_function_env_initializers,
table_imports,
memory_imports,
global_imports,

View File

@@ -16,5 +16,5 @@ wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha5", default-feat
"std",
"translator"
] }
object = { version = "0.21", default-features = false, features = ["write"] }
object = { version = "0.22", default-features = false, features = ["write"] }
thiserror = "1.0"

View File

@@ -10,23 +10,23 @@ use wasmer_types::{FunctionType, MemoryType, TableType};
/// The value of an export passed from one instance to another.
#[derive(Debug, Clone)]
pub enum Export {
pub enum VMExport {
/// A function export value.
Function(ExportFunction),
Function(VMExportFunction),
/// A table export value.
Table(ExportTable),
Table(VMExportTable),
/// A memory export value.
Memory(ExportMemory),
Memory(VMExportMemory),
/// A global export value.
Global(ExportGlobal),
Global(VMExportGlobal),
}
/// A function export value.
#[derive(Debug, Clone, PartialEq)]
pub struct ExportFunction {
pub struct VMExportFunction {
/// The address of the native-code function.
pub address: *const VMFunctionBody,
/// Pointer to the containing `VMContext`.
@@ -43,20 +43,20 @@ pub struct ExportFunction {
/// # Safety
/// There is no non-threadsafe logic directly in this type. Calling the function
/// may not be threadsafe.
unsafe impl Send for ExportFunction {}
unsafe impl Send for VMExportFunction {}
/// # Safety
/// The members of an ExportFunction are immutable after construction.
unsafe impl Sync for ExportFunction {}
/// The members of an VMExportFunction are immutable after construction.
unsafe impl Sync for VMExportFunction {}
impl From<ExportFunction> for Export {
fn from(func: ExportFunction) -> Self {
impl From<VMExportFunction> for VMExport {
fn from(func: VMExportFunction) -> Self {
Self::Function(func)
}
}
/// A table export value.
#[derive(Debug, Clone)]
pub struct ExportTable {
pub struct VMExportTable {
/// Pointer to the containing `Table`.
pub from: Arc<dyn Table>,
}
@@ -65,14 +65,14 @@ pub struct ExportTable {
/// This is correct because there is no non-threadsafe logic directly in this type;
/// correct use of the raw table from multiple threads via `definition` requires `unsafe`
/// and is the responsibilty of the user of this type.
unsafe impl Send for ExportTable {}
unsafe impl Send for VMExportTable {}
/// # Safety
/// This is correct because the values directly in `definition` should be considered immutable
/// and the type is both `Send` and `Clone` (thus marking it `Sync` adds no new behavior, it
/// only makes this type easier to use)
unsafe impl Sync for ExportTable {}
unsafe impl Sync for VMExportTable {}
impl ExportTable {
impl VMExportTable {
/// Get the table type for this exported table
pub fn ty(&self) -> &TableType {
self.from.ty()
@@ -83,21 +83,21 @@ impl ExportTable {
self.from.style()
}
/// Returns whether or not the two `ExportTable`s refer to the same Memory.
/// Returns whether or not the two `VMExportTable`s refer to the same Memory.
pub fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.from, &other.from)
}
}
impl From<ExportTable> for Export {
fn from(table: ExportTable) -> Self {
impl From<VMExportTable> for VMExport {
fn from(table: VMExportTable) -> Self {
Self::Table(table)
}
}
/// A memory export value.
#[derive(Debug, Clone)]
pub struct ExportMemory {
pub struct VMExportMemory {
/// Pointer to the containing `Memory`.
pub from: Arc<dyn Memory>,
}
@@ -106,14 +106,14 @@ pub struct ExportMemory {
/// This is correct because there is no non-threadsafe logic directly in this type;
/// correct use of the raw memory from multiple threads via `definition` requires `unsafe`
/// and is the responsibilty of the user of this type.
unsafe impl Send for ExportMemory {}
unsafe impl Send for VMExportMemory {}
/// # Safety
/// This is correct because the values directly in `definition` should be considered immutable
/// and the type is both `Send` and `Clone` (thus marking it `Sync` adds no new behavior, it
/// only makes this type easier to use)
unsafe impl Sync for ExportMemory {}
unsafe impl Sync for VMExportMemory {}
impl ExportMemory {
impl VMExportMemory {
/// Get the type for this exported memory
pub fn ty(&self) -> &MemoryType {
self.from.ty()
@@ -124,21 +124,21 @@ impl ExportMemory {
self.from.style()
}
/// Returns whether or not the two `ExportMemory`s refer to the same Memory.
/// Returns whether or not the two `VMExportMemory`s refer to the same Memory.
pub fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.from, &other.from)
}
}
impl From<ExportMemory> for Export {
fn from(memory: ExportMemory) -> Self {
impl From<VMExportMemory> for VMExport {
fn from(memory: VMExportMemory) -> Self {
Self::Memory(memory)
}
}
/// A global export value.
#[derive(Debug, Clone)]
pub struct ExportGlobal {
pub struct VMExportGlobal {
/// The global declaration, used for compatibility checking.
pub from: Arc<Global>,
}
@@ -147,22 +147,22 @@ pub struct ExportGlobal {
/// This is correct because there is no non-threadsafe logic directly in this type;
/// correct use of the raw global from multiple threads via `definition` requires `unsafe`
/// and is the responsibilty of the user of this type.
unsafe impl Send for ExportGlobal {}
unsafe impl Send for VMExportGlobal {}
/// # Safety
/// This is correct because the values directly in `definition` should be considered immutable
/// from the perspective of users of this type and the type is both `Send` and `Clone` (thus
/// marking it `Sync` adds no new behavior, it only makes this type easier to use)
unsafe impl Sync for ExportGlobal {}
unsafe impl Sync for VMExportGlobal {}
impl ExportGlobal {
/// Returns whether or not the two `ExportGlobal`s refer to the same Global.
impl VMExportGlobal {
/// Returns whether or not the two `VMExportGlobal`s refer to the same Global.
pub fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.from, &other.from)
}
}
impl From<ExportGlobal> for Export {
fn from(global: ExportGlobal) -> Self {
impl From<VMExportGlobal> for VMExport {
fn from(global: VMExportGlobal) -> Self {
Self::Global(global)
}
}

View File

@@ -1,6 +1,7 @@
// This file contains code from external sources.
// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md
use crate::instance::{ImportInitializerFuncPtr, ImportInitializerThunks};
use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
use wasmer_types::{FunctionIndex, GlobalIndex, MemoryIndex, TableIndex};
@@ -11,6 +12,14 @@ pub struct Imports {
/// Resolved addresses for imported functions.
pub functions: BoxedSlice<FunctionIndex, VMFunctionImport>,
/// Initializers for host function environments. This is split out from `functions`
/// because the generated code never needs to touch this and the extra wasted
/// space may affect Wasm runtime performance due to increased cache pressure.
///
/// We make it optional so that we can free the data after use.
pub host_function_env_initializers:
Option<BoxedSlice<FunctionIndex, Option<ImportInitializerFuncPtr>>>,
/// Resolved addresses for imported tables.
pub tables: BoxedSlice<TableIndex, VMTableImport>,
@@ -25,12 +34,14 @@ impl Imports {
/// Construct a new `Imports` instance.
pub fn new(
function_imports: PrimaryMap<FunctionIndex, VMFunctionImport>,
host_function_env_initializers: PrimaryMap<FunctionIndex, Option<ImportInitializerFuncPtr>>,
table_imports: PrimaryMap<TableIndex, VMTableImport>,
memory_imports: PrimaryMap<MemoryIndex, VMMemoryImport>,
global_imports: PrimaryMap<GlobalIndex, VMGlobalImport>,
) -> Self {
Self {
functions: function_imports.into_boxed_slice(),
host_function_env_initializers: Some(host_function_env_initializers.into_boxed_slice()),
tables: table_imports.into_boxed_slice(),
memories: memory_imports.into_boxed_slice(),
globals: global_imports.into_boxed_slice(),
@@ -41,9 +52,40 @@ impl Imports {
pub fn none() -> Self {
Self {
functions: PrimaryMap::new().into_boxed_slice(),
host_function_env_initializers: Some(PrimaryMap::new().into_boxed_slice()),
tables: PrimaryMap::new().into_boxed_slice(),
memories: PrimaryMap::new().into_boxed_slice(),
globals: PrimaryMap::new().into_boxed_slice(),
}
}
/// Get the `WasmerEnv::init_with_instance` function pointers and the pointers
/// to the envs to call it on.
///
/// This function can only be called once, it deletes the data it returns after
/// returning it to ensure that it's not called more than once.
pub fn get_import_initializers(&mut self) -> ImportInitializerThunks {
let result = if let Some(inner) = &self.host_function_env_initializers {
inner
.values()
.cloned()
.zip(self.functions.values())
.map(|(func_init, func)| {
let host_env = if func_init.is_some() {
// this access is correct because we know that only functions with
// host envs have a value in `func_init`.
unsafe { func.environment.host_env }
} else {
std::ptr::null_mut()
};
(func_init, host_env)
})
.collect()
} else {
vec![]
};
// ensure we only call these functions once and free this now useless memory.
self.host_function_env_initializers = None;
result
}
}

View File

@@ -4,7 +4,7 @@
//! An `Instance` contains all the runtime state used by execution of a
//! wasm module (except its callstack and register state). An
//! `InstanceHandle` is a reference-counting handle for an `Instance`.
use crate::export::Export;
use crate::export::VMExport;
use crate::global::Global;
use crate::imports::Imports;
use crate::memory::{Memory, MemoryError};
@@ -16,8 +16,8 @@ use crate::vmcontext::{
VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport,
VMTrampoline,
};
use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable};
use crate::{FunctionBodyPtr, ModuleInfo, VMOffsets};
use crate::{VMExportFunction, VMExportGlobal, VMExportMemory, VMExportTable};
use memoffset::offset_of;
use more_asserts::assert_lt;
use std::alloc::{self, Layout};
@@ -63,6 +63,16 @@ cfg_if::cfg_if! {
}
}
/// The function pointer to call with data and an [`Instance`] pointer to
/// finish initializing the host env.
pub type ImportInitializerFuncPtr =
fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>;
/// This type holds thunks (delayed computations) for initializing the imported
/// function's environments with the [`Instance`].
pub(crate) type ImportInitializerThunks =
Vec<(Option<ImportInitializerFuncPtr>, *mut std::ffi::c_void)>;
/// A WebAssembly instance.
///
/// This is repr(C) to ensure that the vmctx field is last.
@@ -104,6 +114,13 @@ pub(crate) struct Instance {
/// Handler run when `SIGBUS`, `SIGFPE`, `SIGILL`, or `SIGSEGV` are caught by the instance thread.
pub(crate) signal_handler: Cell<Option<Box<SignalHandler>>>,
/// Functions to initialize the host environments in the imports and pointers
/// to the environments.
/// These function pointers all come from `WasmerEnv::init_with_instance`.
///
/// TODO:
/// Be sure to test with serialize/deserialize and imported functions from other Wasm modules.
import_initializers: ImportInitializerThunks,
/// Additional context used by compiled wasm code. This field is last, and
/// represents a dynamically-sized array that extends beyond the nominal
/// end of the struct (similar to a flexible array member).
@@ -145,6 +162,14 @@ impl Instance {
unsafe { &*self.imported_functions_ptr().add(index) }
}
/// Get the import initializer func at the given index if it exists.
fn imported_function_env_initializer(
&self,
index: FunctionIndex,
) -> Option<ImportInitializerFuncPtr> {
self.import_initializers[index.as_u32() as usize].0
}
/// Return a pointer to the `VMFunctionImport`s.
fn imported_functions_ptr(&self) -> *mut VMFunctionImport {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_functions_begin()) }
@@ -283,32 +308,38 @@ impl Instance {
}
/// Lookup an export with the given name.
pub fn lookup(&self, field: &str) -> Option<Export> {
pub fn lookup(&self, field: &str) -> Option<VMExport> {
let export = self.module.exports.get(field)?;
Some(self.lookup_by_declaration(&export))
}
/// Lookup an export with the given export declaration.
pub fn lookup_by_declaration(&self, export: &ExportIndex) -> Export {
// TODO: maybe EngineExport
pub fn lookup_by_declaration(&self, export: &ExportIndex) -> VMExport {
match export {
ExportIndex::Function(index) => {
let sig_index = &self.module.functions[*index];
let (address, vmctx) = if let Some(def_index) = self.module.local_func_index(*index)
{
(
self.functions[def_index].0 as *const _,
VMFunctionEnvironment {
vmctx: self.vmctx_ptr(),
},
)
} else {
let import = self.imported_function(*index);
(import.body, import.environment)
};
let (address, vmctx, _function_ptr) =
if let Some(def_index) = self.module.local_func_index(*index) {
(
self.functions[def_index].0 as *const _,
VMFunctionEnvironment {
vmctx: self.vmctx_ptr(),
},
None,
)
} else {
let import = self.imported_function(*index);
let initializer = self.imported_function_env_initializer(*index);
(import.body, import.environment, initializer)
};
let call_trampoline = Some(self.function_call_trampolines[*sig_index]);
let signature = self.module.signatures[*sig_index].clone();
ExportFunction {
/*EngineExportFunction {
function_ptr,
function: */
VMExportFunction {
address,
// Any function received is already static at this point as:
// 1. All locally defined functions in the Wasm have a static signature.
@@ -319,6 +350,7 @@ impl Instance {
vmctx,
call_trampoline,
}
//}
.into()
}
ExportIndex::Table(index) => {
@@ -328,7 +360,7 @@ impl Instance {
let import = self.imported_table(*index);
import.from.clone()
};
ExportTable { from }.into()
VMExportTable { from }.into()
}
ExportIndex::Memory(index) => {
let from = if let Some(def_index) = self.module.local_memory_index(*index) {
@@ -337,7 +369,7 @@ impl Instance {
let import = self.imported_memory(*index);
import.from.clone()
};
ExportMemory { from }.into()
VMExportMemory { from }.into()
}
ExportIndex::Global(index) => {
let from = {
@@ -348,7 +380,7 @@ impl Instance {
import.from.clone()
}
};
ExportGlobal { from }.into()
VMExportGlobal { from }.into()
}
}
}
@@ -894,6 +926,7 @@ impl InstanceHandle {
imports: Imports,
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
host_state: Box<dyn Any>,
import_initializers: ImportInitializerThunks,
) -> Result<Self, Trap> {
let instance_ptr = instance_ptr.cast::<Instance>().as_ptr();
@@ -918,6 +951,7 @@ impl InstanceHandle {
passive_data,
host_state,
signal_handler: Cell::new(None),
import_initializers,
vmctx: VMContext {},
};
ptr::write(instance_ptr, instance);
@@ -1038,12 +1072,12 @@ impl InstanceHandle {
}
/// Lookup an export with the given name.
pub fn lookup(&self, field: &str) -> Option<Export> {
pub fn lookup(&self, field: &str) -> Option<VMExport> {
self.instance().lookup(field)
}
/// Lookup an export with the given export declaration.
pub fn lookup_by_declaration(&self, export: &ExportIndex) -> Export {
pub fn lookup_by_declaration(&self, export: &ExportIndex) -> VMExport {
self.instance().lookup_by_declaration(export)
}
@@ -1127,6 +1161,34 @@ impl InstanceHandle {
unsafe { &*(self.instance as *const Instance) }
}
/// Initializes the host environments.
///
/// # Safety
/// - This function must be called with the correct `Err` type parameter: the error type is not
/// visible to code in `wasmer_vm`, so it's the caller's responsibility to ensure these
/// functions are called with the correct type.
/// - `instance_ptr` must point to a valid `wasmer::Instance`.
pub unsafe fn initialize_host_envs<Err: Sized>(
&mut self,
instance_ptr: *const std::ffi::c_void,
) -> Result<(), Err> {
use std::ffi;
let instance = &mut *self.instance;
for (func, env) in instance.import_initializers.drain(..) {
if let Some(ref f) = func {
// transmute our function pointer into one with the correct error type
let f = std::mem::transmute::<
&ImportInitializerFuncPtr,
&fn(*mut ffi::c_void, *const ffi::c_void) -> Result<(), Err>,
>(f);
f(env, instance_ptr)?;
}
}
// free memory now that it's empty.
instance.import_initializers.shrink_to_fit();
Ok(())
}
/// Deallocates memory associated with this instance.
///
/// # Safety

View File

@@ -39,7 +39,7 @@ pub mod libcalls;
pub use crate::export::*;
pub use crate::global::*;
pub use crate::imports::Imports;
pub use crate::instance::InstanceHandle;
pub use crate::instance::{ImportInitializerFuncPtr, InstanceHandle};
pub use crate::memory::{LinearMemory, Memory, MemoryError, MemoryStyle};
pub use crate::mmap::Mmap;
pub use crate::module::{ExportsIterator, ImportsIterator, ModuleInfo};

View File

@@ -29,14 +29,10 @@ pub use crate::syscalls::types;
pub use crate::utils::{get_wasi_version, is_wasi_module, WasiVersion};
use thiserror::Error;
use wasmer::{imports, Function, ImportObject, Memory, Module, Store};
use wasmer::{imports, Function, ImportObject, LazyInit, Memory, Module, Store, WasmerEnv};
#[cfg(all(target_os = "macos", target_arch = "aarch64",))]
use wasmer::{FunctionType, ValType};
use std::cell::UnsafeCell;
use std::fmt;
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, MutexGuard};
/// This is returned in `RuntimeError`.
@@ -50,7 +46,7 @@ pub enum WasiError {
}
/// The environment provided to the WASI imports.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, WasmerEnv)]
pub struct WasiEnv {
/// Shared state of the WASI system. Manages all the data that the
/// executing WASI program can see.
@@ -59,96 +55,15 @@ pub struct WasiEnv {
/// if the lock is held and the Wasm calls into a host function that tries
/// to lock this mutex, the program will deadlock.
pub state: Arc<Mutex<WasiState>>,
memory: Arc<WasiMemory>,
}
/// Wrapper type around `Memory` used to delay initialization of the memory.
///
/// The `initialized` field is used to indicate if it's safe to read `memory` as `Memory`.
///
/// The `mutate_lock` is used to prevent access from multiple threads during initialization.
struct WasiMemory {
initialized: AtomicBool,
memory: UnsafeCell<MaybeUninit<Memory>>,
mutate_lock: Mutex<()>,
}
impl fmt::Debug for WasiMemory {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("WasiMemory")
.field("initialized", &self.initialized)
.finish()
}
}
impl WasiMemory {
fn new() -> Self {
Self {
initialized: AtomicBool::new(false),
memory: UnsafeCell::new(MaybeUninit::zeroed()),
mutate_lock: Mutex::new(()),
}
}
/// Initialize the memory, making it safe to read from.
///
/// Returns whether or not the set was successful. If the set failed then
/// the memory has already been initialized.
fn set_memory(&self, memory: Memory) -> bool {
// synchronize it
let _guard = self.mutate_lock.lock();
if self.initialized.load(Ordering::Acquire) {
return false;
}
unsafe {
let ptr = self.memory.get();
let mem_inner: &mut MaybeUninit<Memory> = &mut *ptr;
mem_inner.as_mut_ptr().write(memory);
}
self.initialized.store(true, Ordering::Release);
true
}
/// Returns `None` if the memory has not been initialized yet.
/// Otherwise returns the memory that was used to initialize it.
fn get_memory(&self) -> Option<&Memory> {
// Based on normal usage, `Relaxed` is fine...
// TODO: investigate if it's possible to use the API in a way where `Relaxed`
// is not fine
if self.initialized.load(Ordering::Relaxed) {
unsafe {
let maybe_mem = self.memory.get();
Some(&*(*maybe_mem).as_ptr())
}
} else {
None
}
}
}
impl Drop for WasiMemory {
fn drop(&mut self) {
if self.initialized.load(Ordering::Acquire) {
unsafe {
// We want to get the internal value in memory, so we need to consume
// the `UnsafeCell` and assume the `MapbeInit` is initialized, but because
// we only have a `&mut self` we can't do this directly, so we swap the data
// out so we can drop it (via `assume_init`).
let mut maybe_uninit = UnsafeCell::new(MaybeUninit::zeroed());
std::mem::swap(&mut self.memory, &mut maybe_uninit);
maybe_uninit.into_inner().assume_init();
}
}
}
#[wasmer(export)]
memory: LazyInit<Memory>,
}
impl WasiEnv {
pub fn new(state: WasiState) -> Self {
Self {
state: Arc::new(Mutex::new(state)),
memory: Arc::new(WasiMemory::new()),
memory: LazyInit::new(),
}
}
@@ -161,11 +76,6 @@ impl WasiEnv {
))
}
/// Set the memory
pub fn set_memory(&mut self, memory: Memory) -> bool {
self.memory.set_memory(memory)
}
/// Get the WASI state
///
/// Be careful when using this in host functions that call into Wasm:
@@ -184,7 +94,8 @@ impl WasiEnv {
/// Get a reference to the memory
pub fn memory(&self) -> &Memory {
self.memory.get_memory().expect("The expected Memory is not attached to the `WasiEnv`. Did you forgot to call wasi_env.set_memory(...)?")
self.memory_ref()
.expect("Memory should be set on `WasiEnv` first")
}
pub(crate) fn get_memory_and_wasi_state(

View File

@@ -86,7 +86,17 @@ fn dynamic_function_with_env() -> Result<()> {
let store = get_store(false);
let module = get_module(&store)?;
let env: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
#[derive(WasmerEnv, Clone)]
struct Env(Arc<AtomicUsize>);
impl std::ops::Deref for Env {
type Target = Arc<AtomicUsize>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
let env: Env = Env(Arc::new(AtomicUsize::new(0)));
Instance::new(
&module,
&imports! {
@@ -203,25 +213,35 @@ fn static_function_with_env() -> Result<()> {
let store = get_store(false);
let module = get_module(&store)?;
let env: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
#[derive(WasmerEnv, Clone)]
struct Env(Arc<AtomicUsize>);
impl std::ops::Deref for Env {
type Target = Arc<AtomicUsize>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
let env: Env = Env(Arc::new(AtomicUsize::new(0)));
Instance::new(
&module,
&imports! {
"host" => {
"0" => Function::new_native_with_env(&store, env.clone(), |env: &Arc<AtomicUsize>| {
"0" => Function::new_native_with_env(&store, env.clone(), |env: &Env| {
assert_eq!(env.fetch_add(1, SeqCst), 0);
}),
"1" => Function::new_native_with_env(&store, env.clone(), |env: &Arc<AtomicUsize>, x: i32| -> i32 {
"1" => Function::new_native_with_env(&store, env.clone(), |env: &Env, x: i32| -> i32 {
assert_eq!(x, 0);
assert_eq!(env.fetch_add(1, SeqCst), 1);
1
}),
"2" => Function::new_native_with_env(&store, env.clone(), |env: &Arc<AtomicUsize>, x: i32, y: i64| {
"2" => Function::new_native_with_env(&store, env.clone(), |env: &Env, x: i32, y: i64| {
assert_eq!(x, 2);
assert_eq!(y, 3);
assert_eq!(env.fetch_add(1, SeqCst), 2);
}),
"3" => Function::new_native_with_env(&store, env.clone(), |env: &Arc<AtomicUsize>, a: i32, b: i64, c: i32, d: f32, e: f64| {
"3" => Function::new_native_with_env(&store, env.clone(), |env: &Env, a: i32, b: i64, c: i32, d: f32, e: f64| {
assert_eq!(a, 100);
assert_eq!(b, 200);
assert_eq!(c, 300);

View File

@@ -78,6 +78,90 @@ fn native_function_works_for_wasm() -> Result<()> {
Ok(())
}
#[test]
#[should_panic(
expected = "Closures (functions with captured environments) are currently unsupported with native functions. See: https://github.com/wasmerio/wasmer/issues/1840"
)]
fn native_host_function_closure_panics() {
let store = get_store(false);
let state = 3;
Function::new_native(&store, move |_: i32| {
println!("{}", state);
});
}
#[test]
#[should_panic(
expected = "Closures (functions with captured environments) are currently unsupported with native functions. See: https://github.com/wasmerio/wasmer/issues/1840"
)]
fn native_with_env_host_function_closure_panics() {
let store = get_store(false);
let state = 3;
let env = 4;
Function::new_native_with_env(&store, env, move |_env: &i32, _: i32| {
println!("{}", state);
});
}
#[test]
fn non_native_functions_and_closures_with_no_env_work() -> Result<()> {
let store = get_store(false);
let wat = r#"(module
(func $multiply1 (import "env" "multiply1") (param i32 i32) (result i32))
(func $multiply2 (import "env" "multiply2") (param i32 i32) (result i32))
(func $multiply3 (import "env" "multiply3") (param i32 i32) (result i32))
(func $multiply4 (import "env" "multiply4") (param i32 i32) (result i32))
(func (export "test") (param i32 i32 i32 i32 i32) (result i32)
(call $multiply4
(call $multiply3
(call $multiply2
(call $multiply1
(local.get 0)
(local.get 1))
(local.get 2))
(local.get 3))
(local.get 4)))
)"#;
let module = Module::new(&store, wat).unwrap();
let ty = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
let env = 10;
let captured_by_closure = 20;
let import_object = imports! {
"env" => {
"multiply1" => Function::new(&store, &ty, move |args| {
if let (Value::I32(v1), Value::I32(v2)) = (&args[0], &args[1]) {
Ok(vec![Value::I32(v1 * v2 * captured_by_closure)])
} else {
panic!("Invalid arguments");
}
}),
"multiply2" => Function::new_with_env(&store, &ty, env, move |&env, args| {
if let (Value::I32(v1), Value::I32(v2)) = (&args[0], &args[1]) {
Ok(vec![Value::I32(v1 * v2 * captured_by_closure * env)])
} else {
panic!("Invalid arguments");
}
}),
"multiply3" => Function::new_native(&store, |arg1: i32, arg2: i32| -> i32
{arg1 * arg2 }),
"multiply4" => Function::new_native_with_env(&store, env, |&env: &i32, arg1: i32, arg2: i32| -> i32
{arg1 * arg2 * env }),
},
};
let instance = Instance::new(&module, &import_object)?;
let test: NativeFunc<(i32, i32, i32, i32, i32), i32> =
instance.exports.get_native_function("test")?;
let result = test.call(2, 3, 4, 5, 6)?;
let manually_computed_result = 6 * (5 * (4 * (3 * 2 * 20) * 10 * 20)) * 10;
assert_eq!(result, manually_computed_result);
Ok(())
}
// The native ABI for functions fails when defining a function natively in
// macos (Darwin) with the Apple Silicon ARM chip
// TODO: Cranelift should have a good ABI for the ABI
@@ -244,9 +328,16 @@ fn static_host_function_with_env() -> anyhow::Result<()> {
Ok((d * 4.0, c * 3.0, b * 2, a * 1))
}
#[derive(Clone)]
#[derive(WasmerEnv, Clone)]
struct Env(Rc<RefCell<i32>>);
impl std::ops::Deref for Env {
type Target = Rc<RefCell<i32>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// Native static host function that returns a tuple.
{
let env = Env(Rc::new(RefCell::new(100)));
@@ -311,9 +402,16 @@ fn dynamic_host_function_without_env() -> anyhow::Result<()> {
fn dynamic_host_function_with_env() -> anyhow::Result<()> {
let store = get_store(false);
#[derive(Clone)]
#[derive(WasmerEnv, Clone)]
struct Env(Rc<RefCell<i32>>);
impl std::ops::Deref for Env {
type Target = Rc<RefCell<i32>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
let env = Env(Rc::new(RefCell::new(100)));
let f = Function::new_with_env(
&store,

View File

@@ -288,7 +288,9 @@ fn trap_start_function_import() -> Result<()> {
.err()
.unwrap();
match err {
InstantiationError::Link(_) => panic!("It should be a start error"),
InstantiationError::Link(_) | InstantiationError::HostEnvInitialization(_) => {
panic!("It should be a start error")
}
InstantiationError::Start(err) => {
assert_eq!(err.message(), "user trap");
}

View File

@@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::{self, Read, Seek, Write};
use std::path::PathBuf;
use wasmer::{ImportObject, Instance, Memory, Module, Store};
use wasmer::{ImportObject, Instance, Module, Store};
use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t};
use wasmer_wasi::{
generate_import_object_from_env, get_wasi_version, WasiEnv, WasiFile, WasiFsError, WasiState,
@@ -80,11 +80,9 @@ impl<'a> WasiTest<'a> {
out
};
let module = Module::new(&store, &wasm_bytes)?;
let (mut env, _tempdirs) = self.create_wasi_env()?;
let (env, _tempdirs) = self.create_wasi_env()?;
let imports = self.get_imports(store, &module, env.clone())?;
let instance = Instance::new(&module, &imports)?;
let memory: &Memory = instance.exports.get("memory")?;
env.set_memory(memory.clone());
let start = instance.exports.get_function("_start")?;
// TODO: handle errors here when the error fix gets shipped