mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-07 21:28:21 +00:00
Merge branch 'master' into test-c-api
This commit is contained in:
25
.github/workflows/main.yaml
vendored
25
.github/workflows/main.yaml
vendored
@@ -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:
|
||||
|
||||
@@ -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
297
Cargo.lock
generated
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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",
|
||||
|
||||
4
Makefile
4
Makefile
@@ -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
|
||||
|
||||
@@ -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>>,
|
||||
}
|
||||
|
||||
@@ -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")?;
|
||||
|
||||
@@ -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
208
lib/api/src/env.rs
Normal 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> {}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
148
lib/api/src/externals/function.rs
vendored
148
lib/api/src/externals/function.rs
vendored
@@ -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 {
|
||||
|
||||
9
lib/api/src/externals/global.rs
vendored
9
lib/api/src/externals/global.rs
vendored
@@ -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()
|
||||
}
|
||||
|
||||
9
lib/api/src/externals/memory.rs
vendored
9
lib/api/src/externals/memory.rs
vendored
@@ -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()
|
||||
}
|
||||
|
||||
2
lib/api/src/externals/mod.rs
vendored
2
lib/api/src/externals/mod.rs
vendored
@@ -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.
|
||||
|
||||
9
lib/api/src/externals/table.rs
vendored
9
lib/api/src/externals/table.rs
vendored
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
@@ -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.
|
||||
|
||||
31
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
31
lib/c-api/src/wasm_c_api/externals/function.rs
vendored
@@ -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,
|
||||
|
||||
@@ -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 }))
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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(());
|
||||
}
|
||||
|
||||
@@ -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(&[]);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
11
lib/deprecated/runtime-core/Cargo.lock
generated
11
lib/deprecated/runtime-core/Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
pub use crate::new::{
|
||||
wasmer::Export as RuntimeExport,
|
||||
wasmer::{Exportable, Extern as Export},
|
||||
wasmer_vm::Export as RuntimeExport,
|
||||
};
|
||||
|
||||
@@ -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
|
||||
/// }),
|
||||
/// },
|
||||
/// };
|
||||
/// ```
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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 _;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
11
lib/deprecated/runtime/Cargo.lock
generated
11
lib/deprecated/runtime/Cargo.lock
generated
@@ -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
21
lib/derive/Cargo.toml
Normal 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
214
lib/derive/src/lib.rs
Normal 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
103
lib/derive/src/parse.rs
Normal 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
87
lib/derive/tests/basic.rs
Normal 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>());
|
||||
}
|
||||
11
lib/derive/tests/compile-fail/bad-attribute.rs
Normal file
11
lib/derive/tests/compile-fail/bad-attribute.rs
Normal 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() {}
|
||||
17
lib/derive/tests/compile-fail/bad-export-arg.rs
Normal file
17
lib/derive/tests/compile-fail/bad-export-arg.rs
Normal 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() {}
|
||||
11
lib/derive/tests/compile-fail/no-lazy-init.rs
Normal file
11
lib/derive/tests/compile-fail/no-lazy-init.rs
Normal 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() {}
|
||||
48
lib/derive/tests/compiletest.rs
Normal file
48
lib/derive/tests/compiletest.rs
Normal 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");
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
13
lib/emscripten/src/env/mod.rs
vendored
13
lib/emscripten/src/env/mod.rs
vendored
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
103
lib/engine/src/export.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user