mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-06 20:58:28 +00:00
Merge pull request #2489 from wasmerio/js-api-into-api
feat(api) Merge `js-api` into `api`
This commit is contained in:
58
Cargo.lock
generated
58
Cargo.lock
generated
@@ -21,17 +21,6 @@ version = "0.4.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
|
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ahash"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
"once_cell",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.18"
|
version = "0.7.18"
|
||||||
@@ -396,7 +385,7 @@ dependencies = [
|
|||||||
"cranelift-codegen-shared",
|
"cranelift-codegen-shared",
|
||||||
"cranelift-entity",
|
"cranelift-entity",
|
||||||
"gimli",
|
"gimli",
|
||||||
"hashbrown 0.9.1",
|
"hashbrown",
|
||||||
"log",
|
"log",
|
||||||
"regalloc",
|
"regalloc",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@@ -432,7 +421,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c31b783b351f966fce33e3c03498cb116d16d97a8f9978164a60920bd0d3a99c"
|
checksum = "c31b783b351f966fce33e3c03498cb116d16d97a8f9978164a60920bd0d3a99c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
"hashbrown 0.9.1",
|
"hashbrown",
|
||||||
"log",
|
"log",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"target-lexicon 0.12.0",
|
"target-lexicon 0.12.0",
|
||||||
@@ -904,16 +893,7 @@ version = "0.9.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash 0.4.7",
|
"ahash",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
|
||||||
dependencies = [
|
|
||||||
"ahash 0.7.4",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -959,7 +939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
|
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown 0.9.1",
|
"hashbrown",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2428,13 +2408,17 @@ version = "2.0.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
|
"hashbrown",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"loupe",
|
"loupe",
|
||||||
"more-asserts",
|
"more-asserts",
|
||||||
"target-lexicon 0.12.0",
|
"target-lexicon 0.12.0",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-test",
|
||||||
"wasmer-compiler",
|
"wasmer-compiler",
|
||||||
"wasmer-compiler-cranelift",
|
"wasmer-compiler-cranelift",
|
||||||
"wasmer-compiler-llvm",
|
"wasmer-compiler-llvm",
|
||||||
@@ -2445,6 +2429,7 @@ dependencies = [
|
|||||||
"wasmer-engine-universal",
|
"wasmer-engine-universal",
|
||||||
"wasmer-types",
|
"wasmer-types",
|
||||||
"wasmer-vm",
|
"wasmer-vm",
|
||||||
|
"wasmparser",
|
||||||
"wat",
|
"wat",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
@@ -2548,7 +2533,7 @@ name = "wasmer-compiler"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enumset",
|
"enumset",
|
||||||
"hashbrown 0.9.1",
|
"hashbrown",
|
||||||
"loupe",
|
"loupe",
|
||||||
"rkyv",
|
"rkyv",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -2569,7 +2554,7 @@ dependencies = [
|
|||||||
"cranelift-entity",
|
"cranelift-entity",
|
||||||
"cranelift-frontend",
|
"cranelift-frontend",
|
||||||
"gimli",
|
"gimli",
|
||||||
"hashbrown 0.9.1",
|
"hashbrown",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"loupe",
|
"loupe",
|
||||||
"more-asserts",
|
"more-asserts",
|
||||||
@@ -2612,7 +2597,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"dynasm",
|
"dynasm",
|
||||||
"dynasmrt",
|
"dynasmrt",
|
||||||
"hashbrown 0.9.1",
|
"hashbrown",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"loupe",
|
"loupe",
|
||||||
"more-asserts",
|
"more-asserts",
|
||||||
@@ -2745,25 +2730,6 @@ dependencies = [
|
|||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasmer-js"
|
|
||||||
version = "2.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"hashbrown 0.11.2",
|
|
||||||
"indexmap",
|
|
||||||
"js-sys",
|
|
||||||
"more-asserts",
|
|
||||||
"thiserror",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"wasm-bindgen-test",
|
|
||||||
"wasmer-derive",
|
|
||||||
"wasmer-types",
|
|
||||||
"wasmparser",
|
|
||||||
"wat",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmer-middlewares"
|
name = "wasmer-middlewares"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ members = [
|
|||||||
"lib/engine-universal",
|
"lib/engine-universal",
|
||||||
"lib/engine-dylib",
|
"lib/engine-dylib",
|
||||||
"lib/engine-staticlib",
|
"lib/engine-staticlib",
|
||||||
"lib/js-api",
|
|
||||||
"lib/object",
|
"lib/object",
|
||||||
"lib/vm",
|
"lib/vm",
|
||||||
"lib/wasi",
|
"lib/wasi",
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -148,7 +148,7 @@ ifneq ($(ENABLE_LLVM), 0)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
exclude_tests := --exclude wasmer-c-api --exclude wasmer-cli --exclude wasmer-js
|
exclude_tests := --exclude wasmer-c-api --exclude wasmer-cli
|
||||||
# Is failing to compile in Linux for some reason
|
# Is failing to compile in Linux for some reason
|
||||||
exclude_tests += --exclude wasmer-wasi-experimental-io-devices
|
exclude_tests += --exclude wasmer-wasi-experimental-io-devices
|
||||||
# We run integration tests separately (it requires building the c-api)
|
# We run integration tests separately (it requires building the c-api)
|
||||||
@@ -501,7 +501,7 @@ test-packages:
|
|||||||
cargo test --manifest-path lib/cli/Cargo.toml $(compiler_features) --release
|
cargo test --manifest-path lib/cli/Cargo.toml $(compiler_features) --release
|
||||||
|
|
||||||
test-js:
|
test-js:
|
||||||
cd lib/js-api && wasm-pack test --node -- --features=wat
|
cd lib/api && wasm-pack test --node -- --no-default-features --features js-default,wat
|
||||||
|
|
||||||
|
|
||||||
#####
|
#####
|
||||||
|
|||||||
@@ -10,96 +10,208 @@ license = "MIT"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
#####
|
||||||
|
#
|
||||||
|
# This crate comes in 2 major flavors:
|
||||||
|
#
|
||||||
|
# * `sys`, where `wasmer` will be compiled to a native executable
|
||||||
|
# which provides compilers, engines, a full VM etc.
|
||||||
|
# * `js`, where `wasmer` will be compiled to WebAssembly to run in a
|
||||||
|
# JavaScript host.
|
||||||
|
#
|
||||||
|
#####
|
||||||
|
|
||||||
|
#####
|
||||||
|
#
|
||||||
|
# # Shared dependencies.
|
||||||
|
#
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
#
|
||||||
|
# ## Mandatory shared dependencies.
|
||||||
|
#
|
||||||
|
indexmap = { version = "1.6", features = ["serde-1"] }
|
||||||
|
cfg-if = "1.0"
|
||||||
|
thiserror = "1.0"
|
||||||
|
more-asserts = "0.2"
|
||||||
|
#
|
||||||
|
# ## Optional shared dependencies.
|
||||||
|
#
|
||||||
|
wat = { version = "1.0", optional = true }
|
||||||
|
#
|
||||||
|
#####
|
||||||
|
|
||||||
|
#####
|
||||||
|
#
|
||||||
|
# # Dependencies and Development Dependencies for `sys`.
|
||||||
|
#
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
#
|
||||||
|
# ## Mandatory dependencies for `sys`.
|
||||||
|
#
|
||||||
wasmer-vm = { path = "../vm", version = "2.0.0" }
|
wasmer-vm = { path = "../vm", version = "2.0.0" }
|
||||||
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "2.0.0", optional = true }
|
|
||||||
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "2.0.0", optional = true }
|
|
||||||
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "2.0.0", optional = true }
|
|
||||||
wasmer-compiler = { path = "../compiler", version = "2.0.0" }
|
wasmer-compiler = { path = "../compiler", version = "2.0.0" }
|
||||||
wasmer-derive = { path = "../derive", version = "2.0.0" }
|
wasmer-derive = { path = "../derive", version = "2.0.0" }
|
||||||
wasmer-engine = { path = "../engine", version = "2.0.0" }
|
wasmer-engine = { path = "../engine", version = "2.0.0" }
|
||||||
wasmer-engine-universal = { path = "../engine-universal", version = "2.0.0", optional = true }
|
|
||||||
wasmer-engine-dylib = { path = "../engine-dylib", version = "2.0.0", optional = true }
|
|
||||||
wasmer-types = { path = "../types", version = "2.0.0" }
|
wasmer-types = { path = "../types", version = "2.0.0" }
|
||||||
indexmap = { version = "1.6", features = ["serde-1"] }
|
|
||||||
cfg-if = "1.0"
|
|
||||||
wat = { version = "1.0", optional = true }
|
|
||||||
thiserror = "1.0"
|
|
||||||
more-asserts = "0.2"
|
|
||||||
target-lexicon = { version = "0.12", default-features = false }
|
target-lexicon = { version = "0.12", default-features = false }
|
||||||
loupe = "0.1"
|
loupe = "0.1"
|
||||||
|
#
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
# ## Optional dependencies for `sys`.
|
||||||
|
#
|
||||||
|
wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "2.0.0", optional = true }
|
||||||
|
wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "2.0.0", optional = true }
|
||||||
|
wasmer-compiler-llvm = { path = "../compiler-llvm", version = "2.0.0", optional = true }
|
||||||
|
wasmer-engine-universal = { path = "../engine-universal", version = "2.0.0", optional = true }
|
||||||
|
wasmer-engine-dylib = { path = "../engine-dylib", version = "2.0.0", optional = true }
|
||||||
|
#
|
||||||
|
# ## Mandatory dependencies for `sys` on Windows.
|
||||||
|
#
|
||||||
|
[target.'cfg(all(not(target_arch = "wasm32"), target_os = "windows"))'.dependencies]
|
||||||
|
#
|
||||||
winapi = "0.3"
|
winapi = "0.3"
|
||||||
|
#
|
||||||
[dev-dependencies]
|
# ## Development Dependencies for `sys`.
|
||||||
# for the binary wasmer.rs
|
#
|
||||||
libc = { version = "^0.2", default-features = false }
|
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
|
||||||
|
#
|
||||||
|
libc = { version = "^0.2", default-features = false } # for the binary wasmer.rs
|
||||||
wat = "1.0"
|
wat = "1.0"
|
||||||
tempfile = "3.1"
|
tempfile = "3.1"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
#
|
||||||
|
#####
|
||||||
|
|
||||||
|
#####
|
||||||
|
#
|
||||||
|
# # Dependencies and Develoment Dependencies for `js`.
|
||||||
|
#
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
#
|
||||||
|
# ## Mandatory dependencies for `js`.
|
||||||
|
#
|
||||||
|
wasmer-types = { path = "../types", version = "2.0.0", default-features = false, features = ["std"] }
|
||||||
|
wasm-bindgen = "0.2.74"
|
||||||
|
js-sys = "0.3.51"
|
||||||
|
wasmer-derive = { path = "../derive", version = "2.0.0" }
|
||||||
|
#
|
||||||
|
# ## Optional dependencies for `js`.
|
||||||
|
#
|
||||||
|
wasmparser = { version = "0.78", default-features = false, optional = true }
|
||||||
|
hashbrown = { version = "0.9", optional = true }
|
||||||
|
#
|
||||||
|
# ## Development Dependencies for `js`.
|
||||||
|
#
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||||
|
#
|
||||||
|
wat = "1.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
wasm-bindgen-test = "0.3.0"
|
||||||
|
#
|
||||||
|
#####
|
||||||
|
|
||||||
|
#####
|
||||||
|
#
|
||||||
|
# # Specific to `js`.
|
||||||
|
#
|
||||||
|
# `wasm-opt` is on by default in for the release profile, but it can be
|
||||||
|
# disabled by setting it to `false`
|
||||||
|
#
|
||||||
|
[package.metadata.wasm-pack.profile.release]
|
||||||
|
wasm-opt = false
|
||||||
|
#
|
||||||
|
####
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["wat", "default-cranelift", "default-universal"]
|
default = ["sys-default"]
|
||||||
|
|
||||||
|
#####
|
||||||
|
#
|
||||||
|
# # Features for `sys`.
|
||||||
|
#
|
||||||
|
sys = []
|
||||||
|
sys-default = ["sys", "wat", "default-cranelift", "default-universal"]
|
||||||
|
#
|
||||||
|
# ## Compilers.
|
||||||
|
#
|
||||||
compiler = [
|
compiler = [
|
||||||
|
"sys",
|
||||||
"wasmer-compiler/translator",
|
"wasmer-compiler/translator",
|
||||||
"wasmer-engine-universal/compiler",
|
"wasmer-engine-universal/compiler",
|
||||||
"wasmer-engine-dylib/compiler",
|
"wasmer-engine-dylib/compiler",
|
||||||
]
|
]
|
||||||
engine = []
|
singlepass = [
|
||||||
universal = [
|
"compiler",
|
||||||
"wasmer-engine-universal",
|
"wasmer-compiler-singlepass",
|
||||||
"engine"
|
]
|
||||||
]
|
cranelift = [
|
||||||
dylib = [
|
"compiler",
|
||||||
"wasmer-engine-dylib",
|
"wasmer-compiler-cranelift",
|
||||||
"engine"
|
]
|
||||||
]
|
llvm = [
|
||||||
singlepass = [
|
"compiler",
|
||||||
"wasmer-compiler-singlepass",
|
"wasmer-compiler-llvm",
|
||||||
"compiler",
|
]
|
||||||
]
|
|
||||||
cranelift = [
|
|
||||||
"wasmer-compiler-cranelift",
|
|
||||||
"compiler",
|
|
||||||
]
|
|
||||||
llvm = [
|
|
||||||
"wasmer-compiler-llvm",
|
|
||||||
"compiler",
|
|
||||||
]
|
|
||||||
|
|
||||||
default-singlepass = [
|
|
||||||
"singlepass",
|
|
||||||
"default-compiler"
|
|
||||||
]
|
|
||||||
default-cranelift = [
|
|
||||||
"cranelift",
|
|
||||||
"default-compiler"
|
|
||||||
]
|
|
||||||
default-llvm = [
|
|
||||||
"llvm",
|
|
||||||
"default-compiler"
|
|
||||||
]
|
|
||||||
default-universal = [
|
|
||||||
"universal",
|
|
||||||
"default-engine"
|
|
||||||
]
|
|
||||||
default-dylib = [
|
|
||||||
"dylib",
|
|
||||||
"default-engine"
|
|
||||||
]
|
|
||||||
|
|
||||||
default-compiler = []
|
default-compiler = []
|
||||||
|
default-singlepass = [
|
||||||
|
"default-compiler",
|
||||||
|
"singlepass",
|
||||||
|
]
|
||||||
|
default-cranelift = [
|
||||||
|
"default-compiler",
|
||||||
|
"cranelift",
|
||||||
|
]
|
||||||
|
default-llvm = [
|
||||||
|
"default-compiler",
|
||||||
|
"llvm",
|
||||||
|
]
|
||||||
|
#
|
||||||
|
# ## Engines.
|
||||||
|
#
|
||||||
|
engine = ["sys"]
|
||||||
|
universal = [
|
||||||
|
"engine",
|
||||||
|
"wasmer-engine-universal",
|
||||||
|
]
|
||||||
|
dylib = [
|
||||||
|
"engine",
|
||||||
|
"wasmer-engine-dylib",
|
||||||
|
]
|
||||||
default-engine = []
|
default-engine = []
|
||||||
|
default-universal = [
|
||||||
# experimental / in-development features
|
"default-engine",
|
||||||
|
"universal",
|
||||||
|
]
|
||||||
|
default-dylib = [
|
||||||
|
"default-engine",
|
||||||
|
"dylib",
|
||||||
|
]
|
||||||
|
#
|
||||||
|
# ## Experimental / in-development features
|
||||||
|
#
|
||||||
experimental-reference-types-extern-ref = [
|
experimental-reference-types-extern-ref = [
|
||||||
|
"sys",
|
||||||
"wasmer-types/experimental-reference-types-extern-ref",
|
"wasmer-types/experimental-reference-types-extern-ref",
|
||||||
]
|
]
|
||||||
|
#
|
||||||
# Deprecated features.
|
# ## Deprecated features.
|
||||||
|
#
|
||||||
jit = ["universal"]
|
jit = ["universal"]
|
||||||
native = ["dylib"]
|
native = ["dylib"]
|
||||||
|
#
|
||||||
|
#####
|
||||||
|
|
||||||
|
#####
|
||||||
|
#
|
||||||
|
# # Features for `js`.
|
||||||
|
#
|
||||||
|
js = []
|
||||||
|
js-default = ["js", "std", "wasm-types-polyfill", "wat"]
|
||||||
|
#
|
||||||
|
wasm-types-polyfill = ["js", "wasmparser"]
|
||||||
|
std = ["js"]
|
||||||
|
core = ["js", "hashbrown"]
|
||||||
|
#
|
||||||
|
#####
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
# `wasmer` [](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [](https://slack.wasmer.io) [](https://github.com/wasmerio/wasmer/blob/master/LICENSE) [](https://crates.io/crates/wasmer)
|
# `wasmer` [](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [](https://slack.wasmer.io) [](https://github.com/wasmerio/wasmer/blob/master/LICENSE) [](https://crates.io/crates/wasmer)
|
||||||
|
|
||||||
[`Wasmer`](https://wasmer.io/) is the most popular
|
[`Wasmer`](https://wasmer.io/) is the most popular
|
||||||
[WebAssembly](https://webassembly.org/) runtime for Rust (...and also
|
[WebAssembly](https://webassembly.org/) runtime for Rust. It supports
|
||||||
the fastest). It supports JIT (Just in Time) and AOT (Ahead of time)
|
JIT (Just In Time) and AOT (Ahead Of Time) compilation as well as
|
||||||
compilation as well as pluggable compilers suited to your needs.
|
pluggable compilers suited to your needs.
|
||||||
|
|
||||||
It's designed to be safe and secure, and runnable in any kind of environment.
|
It's designed to be safe and secure, and runnable in any kind of environment.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
Here is a small example of using Wasmer to run a WebAssembly module
|
||||||
|
written with its WAT format (textual format):
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use wasmer::{Store, Module, Instance, Value, imports};
|
use wasmer::{Store, Module, Instance, Value, imports};
|
||||||
|
|
||||||
@@ -36,36 +39,70 @@ fn main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[Discover the full collection of examples](https://github.com/wasmerio/wasmer/tree/master/examples).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Wasmer is not only fast, but also designed to be *highly customizable*:
|
Wasmer is not only fast, but also designed to be *highly customizable*:
|
||||||
* **Pluggable Engines**: do you have a fancy `dlopen` implementation? This is for you!
|
|
||||||
* **Pluggable Compilers**: you want to emit code with DynASM or other compiler? We got you!
|
|
||||||
* **Headless mode**: that means that no compilers will be required
|
|
||||||
to run a `serialized` Module (via `Module::deserialize()`).
|
|
||||||
* **Cross-compilation**: You can pre-compile a module and serialize it
|
|
||||||
to then run it in other platform (via `Module::serialize()`).
|
|
||||||
|
|
||||||
## Config flags
|
* **Pluggable engines** — An engine is responsible to drive the
|
||||||
|
compilation process and to store the generated executable code
|
||||||
|
somewhere, either:
|
||||||
|
* in-memory (with [`wasmer-engine-universal`]),
|
||||||
|
* in a native shared object file (with [`wasmer-engine-dylib`],
|
||||||
|
`.dylib`, `.so`, `.dll`), then load it with `dlopen`,
|
||||||
|
* in a native static object file (with [`wasmer-engine-staticlib`]),
|
||||||
|
in addition to emitting a C header file, which both can be linked
|
||||||
|
against a sandboxed WebAssembly runtime environment for the
|
||||||
|
compiled module with no need for runtime compilation.
|
||||||
|
|
||||||
Wasmer has the following configuration flags:
|
* **Pluggable compilers** — A compiler is used by an engine to
|
||||||
* `wat` (enabled by default): It allows to read WebAssembly files in their text format.
|
transform WebAssembly into executable code:
|
||||||
*This feature is normally used only in development environments*
|
* [`wasmer-compiler-singlepass`] provides a fast compilation-time
|
||||||
* Compilers (mutually exclusive):
|
but an unoptimized runtime speed,
|
||||||
- `singlepass`: it will use `wasmer-compiler-singlepass` as the default
|
* [`wasmer-compiler-cranelift`] provides the right balance between
|
||||||
compiler (ideal for **blockchains**).
|
compilation-time and runtime performance, useful for development,
|
||||||
- `cranelift`: it will use `wasmer-compiler-cranelift` as the default
|
* [`wasmer-compiler-llvm`] provides a deeply optimized executable
|
||||||
compiler (ideal for **development**).
|
code with the fastest runtime speed, ideal for production.
|
||||||
- `llvm`: it will use `wasmer-compiler-llvm` as the default
|
|
||||||
compiler (ideal for **production**).
|
* **Headless mode** — Once a WebAssembly module has been compiled, it
|
||||||
|
is possible to serialize it in a file for example, and later execute
|
||||||
|
it with Wasmer with headless mode turned on. Headless Wasmer has no
|
||||||
|
compiler, which makes it more portable and faster to load. It's
|
||||||
|
ideal for constrainted environments.
|
||||||
|
|
||||||
|
* **Cross-compilation** — Most compilers support cross-compilation. It
|
||||||
|
means it possible to pre-compile a WebAssembly module targetting a
|
||||||
|
different architecture or platform and serialize it, to then run it
|
||||||
|
on the targetted architecture and platform later.
|
||||||
|
|
||||||
Wasmer ships by default with the `cranelift` compiler as its great for development proposes.
|
* **Run Wasmer in a JavaScript environment** — With the `js` Cargo
|
||||||
However, we strongly encourage to use the `llvm` backend in production as it performs
|
feature, it is possible to compile a Rust program using Wasmer to
|
||||||
about 50% faster, achieving near-native speeds.
|
WebAssembly. In this context, the resulting WebAssembly module will
|
||||||
|
expect to run in a JavaScript environment, like a browser, Node.js,
|
||||||
|
Deno and so on. In this specific scenario, there is no engines or
|
||||||
|
compilers available, it's the one available in the JavaScript
|
||||||
|
environment that will be used.
|
||||||
|
|
||||||
> Note: if you want to use multiple compilers at the same time, it's also possible!
|
Wasmer ships by default with the Cranelift compiler as its great for
|
||||||
> You will need to import them directly via each of the compiler crates.
|
development purposes. However, we strongly encourage to use the LLVM
|
||||||
|
compiler in production as it performs about 50% faster, achieving
|
||||||
|
near-native speeds.
|
||||||
|
|
||||||
|
Note: if one wants to use multiple compilers at the same time, it's
|
||||||
|
also possible! One will need to import them directly via each of the
|
||||||
|
compiler crates.
|
||||||
|
|
||||||
|
Read [the documentation to learn
|
||||||
|
more](https://wasmerio.github.io/wasmer/crates/doc/wasmer/).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Made with ❤️ by the Wasmer team, for the community
|
Made with ❤️ by the Wasmer team, for the community
|
||||||
|
|
||||||
|
[`wasmer-engine-universal`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-universal
|
||||||
|
[`wasmer-engine-dylib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-dylib
|
||||||
|
[`wasmer-engine-staticlib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-staticlib
|
||||||
|
[`wasmer-compiler-singlepass`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-singlepass
|
||||||
|
[`wasmer-compiler-cranelift`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-cranelift
|
||||||
|
[`wasmer-compiler-llvm`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-llvm
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ impl<'a, T> WasmCell<'a, T> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cell::Cell;
|
/// use std::cell::Cell;
|
||||||
/// use wasmer_js::WasmCell;
|
/// use wasmer::WasmCell;
|
||||||
///
|
///
|
||||||
/// let cell = Cell::new(5);
|
/// let cell = Cell::new(5);
|
||||||
/// let wasm_cell = WasmCell::new(&cell);
|
/// let wasm_cell = WasmCell::new(&cell);
|
||||||
@@ -96,7 +96,7 @@ impl<'a, T: Copy> WasmCell<'a, T> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cell::Cell;
|
/// use std::cell::Cell;
|
||||||
/// use wasmer_js::WasmCell;
|
/// use wasmer::WasmCell;
|
||||||
///
|
///
|
||||||
/// let cell = Cell::new(5);
|
/// let cell = Cell::new(5);
|
||||||
/// let wasm_cell = WasmCell::new(&cell);
|
/// let wasm_cell = WasmCell::new(&cell);
|
||||||
@@ -123,7 +123,7 @@ impl<T: Sized> WasmCell<'_, T> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cell::Cell;
|
/// use std::cell::Cell;
|
||||||
/// use wasmer_js::WasmCell;
|
/// use wasmer::WasmCell;
|
||||||
///
|
///
|
||||||
/// let cell = Cell::new(5);
|
/// let cell = Cell::new(5);
|
||||||
/// let wasm_cell = WasmCell::new(&cell);
|
/// let wasm_cell = WasmCell::new(&cell);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{ExportError, Instance};
|
use crate::js::{ExportError, Instance};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// An error while initializing the user supplied host env with the `WasmerEnv` trait.
|
/// An error while initializing the user supplied host env with the `WasmerEnv` trait.
|
||||||
@@ -28,7 +28,7 @@ impl From<ExportError> for HostEnvInitError {
|
|||||||
/// This trait can be derived like so:
|
/// This trait can be derived like so:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use wasmer_js::{WasmerEnv, LazyInit, Memory, NativeFunc};
|
/// use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc};
|
||||||
///
|
///
|
||||||
/// #[derive(WasmerEnv, Clone)]
|
/// #[derive(WasmerEnv, Clone)]
|
||||||
/// pub struct MyEnvWithNoInstanceData {
|
/// pub struct MyEnvWithNoInstanceData {
|
||||||
@@ -63,7 +63,7 @@ impl From<ExportError> for HostEnvInitError {
|
|||||||
///
|
///
|
||||||
/// This trait may also be implemented manually:
|
/// This trait may also be implemented manually:
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
|
/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
|
||||||
/// #[derive(Clone)]
|
/// #[derive(Clone)]
|
||||||
/// pub struct MyEnv {
|
/// pub struct MyEnv {
|
||||||
/// memory: LazyInit<Memory>,
|
/// memory: LazyInit<Memory>,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::lib::std::string::String;
|
use crate::js::lib::std::string::String;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::instance::Instance;
|
use crate::js::instance::Instance;
|
||||||
use crate::wasm_bindgen_polyfill::Global;
|
use crate::js::wasm_bindgen_polyfill::Global;
|
||||||
use crate::HostEnvInitError;
|
use crate::js::HostEnvInitError;
|
||||||
use crate::WasmerEnv;
|
use crate::js::WasmerEnv;
|
||||||
use js_sys::Function;
|
use js_sys::Function;
|
||||||
use js_sys::WebAssembly::{Memory, Table};
|
use js_sys::WebAssembly::{Memory, Table};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::export::Export;
|
use crate::js::export::Export;
|
||||||
use crate::externals::{Extern, Function, Global, Memory, Table};
|
use crate::js::externals::{Extern, Function, Global, Memory, Table};
|
||||||
use crate::import_object::LikeNamespace;
|
use crate::js::import_object::LikeNamespace;
|
||||||
use crate::native::NativeFunc;
|
use crate::js::native::NativeFunc;
|
||||||
use crate::WasmTypeList;
|
use crate::js::WasmTypeList;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::{ExactSizeIterator, FromIterator};
|
use std::iter::{ExactSizeIterator, FromIterator};
|
||||||
@@ -12,14 +12,14 @@ use thiserror::Error;
|
|||||||
/// The `ExportError` can happen when trying to get a specific
|
/// The `ExportError` can happen when trying to get a specific
|
||||||
/// export [`Extern`] from the [`Instance`] exports.
|
/// export [`Extern`] from the [`Instance`] exports.
|
||||||
///
|
///
|
||||||
/// [`Instance`]: crate::Instance
|
/// [`Instance`]: crate::js::Instance
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ## Incompatible export type
|
/// ## Incompatible export type
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```should_panic
|
||||||
/// # use wasmer_js::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
|
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// # let wasm_bytes = wat2wasm(r#"
|
/// # let wasm_bytes = wat2wasm(r#"
|
||||||
/// # (module
|
/// # (module
|
||||||
@@ -36,7 +36,7 @@ use thiserror::Error;
|
|||||||
/// ## Missing export
|
/// ## Missing export
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```should_panic
|
||||||
/// # use wasmer_js::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
|
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// # let wasm_bytes = wat2wasm("(module)".as_bytes()).unwrap();
|
/// # let wasm_bytes = wat2wasm("(module)".as_bytes()).unwrap();
|
||||||
/// # let module = Module::new(&store, wasm_bytes).unwrap();
|
/// # let module = Module::new(&store, wasm_bytes).unwrap();
|
||||||
@@ -292,18 +292,18 @@ impl LikeNamespace for Exports {
|
|||||||
|
|
||||||
/// This trait is used to mark types as gettable from an [`Instance`].
|
/// This trait is used to mark types as gettable from an [`Instance`].
|
||||||
///
|
///
|
||||||
/// [`Instance`]: crate::Instance
|
/// [`Instance`]: crate::js::Instance
|
||||||
pub trait Exportable<'a>: Sized {
|
pub trait Exportable<'a>: Sized {
|
||||||
/// This function is used when providedd the [`Extern`] as exportable, so it
|
/// This function is used when providedd the [`Extern`] as exportable, so it
|
||||||
/// can be used while instantiating the [`Module`].
|
/// can be used while instantiating the [`Module`].
|
||||||
///
|
///
|
||||||
/// [`Module`]: crate::Module
|
/// [`Module`]: crate::js::Module
|
||||||
fn to_export(&self) -> Export;
|
fn to_export(&self) -> Export;
|
||||||
|
|
||||||
/// Implementation of how to get the export corresponding to the implementing type
|
/// Implementation of how to get the export corresponding to the implementing type
|
||||||
/// from an [`Instance`] by name.
|
/// from an [`Instance`] by name.
|
||||||
///
|
///
|
||||||
/// [`Instance`]: crate::Instance
|
/// [`Instance`]: crate::js::Instance
|
||||||
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>;
|
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
use crate::exports::{ExportError, Exportable};
|
use crate::js::exports::{ExportError, Exportable};
|
||||||
use crate::externals::Extern;
|
use crate::js::externals::Extern;
|
||||||
use crate::store::Store;
|
use crate::js::store::Store;
|
||||||
use crate::types::{param_from_js, AsJs /* ValFuncRef */, Val};
|
use crate::js::types::{param_from_js, AsJs /* ValFuncRef */, Val};
|
||||||
use crate::FunctionType;
|
use crate::js::FunctionType;
|
||||||
use crate::NativeFunc;
|
use crate::js::NativeFunc;
|
||||||
use crate::RuntimeError;
|
use crate::js::RuntimeError;
|
||||||
use crate::WasmerEnv;
|
use crate::js::WasmerEnv;
|
||||||
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
|
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
|
||||||
use js_sys::{Array, Function as JSFunction};
|
use js_sys::{Array, Function as JSFunction};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
use crate::export::{Export, VMFunction};
|
use crate::js::export::{Export, VMFunction};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@@ -71,7 +71,7 @@ impl Function {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Function, FunctionType, Type, Store, Value};
|
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
|
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
|
||||||
@@ -85,7 +85,7 @@ impl Function {
|
|||||||
/// With constant signature:
|
/// With constant signature:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Function, FunctionType, Type, Store, Value};
|
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
|
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
|
||||||
@@ -161,7 +161,7 @@ impl Function {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Function, FunctionType, Type, Store, Value, WasmerEnv};
|
/// # use wasmer::{Function, FunctionType, Type, Store, Value, WasmerEnv};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(WasmerEnv, Clone)]
|
/// #[derive(WasmerEnv, Clone)]
|
||||||
@@ -181,7 +181,7 @@ impl Function {
|
|||||||
/// With constant signature:
|
/// With constant signature:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Function, FunctionType, Type, Store, Value, WasmerEnv};
|
/// # use wasmer::{Function, FunctionType, Type, Store, Value, WasmerEnv};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
|
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
|
||||||
///
|
///
|
||||||
@@ -274,7 +274,7 @@ impl Function {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Store, Function};
|
/// # use wasmer::{Store, Function};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// fn sum(a: i32, b: i32) -> i32 {
|
/// fn sum(a: i32, b: i32) -> i32 {
|
||||||
@@ -315,7 +315,7 @@ impl Function {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Store, Function, WasmerEnv};
|
/// # use wasmer::{Store, Function, WasmerEnv};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(WasmerEnv, Clone)]
|
/// #[derive(WasmerEnv, Clone)]
|
||||||
@@ -364,7 +364,7 @@ impl Function {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Function, Store, Type};
|
/// # use wasmer::{Function, Store, Type};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// fn sum(a: i32, b: i32) -> i32 {
|
/// fn sum(a: i32, b: i32) -> i32 {
|
||||||
@@ -390,7 +390,7 @@ impl Function {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Function, Store, Type};
|
/// # use wasmer::{Function, Store, Type};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// fn sum(a: i32, b: i32) -> i32 {
|
/// fn sum(a: i32, b: i32) -> i32 {
|
||||||
@@ -410,7 +410,7 @@ impl Function {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Function, Store, Type};
|
/// # use wasmer::{Function, Store, Type};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// fn sum(a: i32, b: i32) -> i32 {
|
/// fn sum(a: i32, b: i32) -> i32 {
|
||||||
@@ -436,7 +436,7 @@ impl Function {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// # let wasm_bytes = wat2wasm(r#"
|
/// # let wasm_bytes = wat2wasm(r#"
|
||||||
/// # (module
|
/// # (module
|
||||||
@@ -495,7 +495,7 @@ impl Function {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// # let wasm_bytes = wat2wasm(r#"
|
/// # let wasm_bytes = wat2wasm(r#"
|
||||||
/// # (module
|
/// # (module
|
||||||
@@ -521,7 +521,7 @@ impl Function {
|
|||||||
/// an error will be raised:
|
/// an error will be raised:
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```should_panic
|
||||||
/// # use wasmer_js::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// # let wasm_bytes = wat2wasm(r#"
|
/// # let wasm_bytes = wat2wasm(r#"
|
||||||
/// # (module
|
/// # (module
|
||||||
@@ -545,7 +545,7 @@ impl Function {
|
|||||||
/// an error will be raised:
|
/// an error will be raised:
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```should_panic
|
||||||
/// # use wasmer_js::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// # let wasm_bytes = wat2wasm(r#"
|
/// # let wasm_bytes = wat2wasm(r#"
|
||||||
/// # (module
|
/// # (module
|
||||||
@@ -654,7 +654,7 @@ mod inner {
|
|||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
pub use wasmer_types::{ExternRef, VMExternRef};
|
pub use wasmer_types::{ExternRef, VMExternRef};
|
||||||
use wasmer_types::{FunctionType, NativeWasmType, Type};
|
use wasmer_types::{FunctionType, NativeWasmType, Type};
|
||||||
// use wasmer_js::{raise_user_trap, resume_panic};
|
// use wasmer::{raise_user_trap, resume_panic};
|
||||||
|
|
||||||
/// A trait to convert a Rust value to a `WasmNativeType` value,
|
/// A trait to convert a Rust value to a `WasmNativeType` value,
|
||||||
/// or to convert `WasmNativeType` value to a Rust value.
|
/// or to convert `WasmNativeType` value to a Rust value.
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
use crate::export::Export;
|
use crate::js::export::Export;
|
||||||
use crate::export::VMGlobal;
|
use crate::js::export::VMGlobal;
|
||||||
use crate::exports::{ExportError, Exportable};
|
use crate::js::exports::{ExportError, Exportable};
|
||||||
use crate::externals::Extern;
|
use crate::js::externals::Extern;
|
||||||
use crate::store::Store;
|
use crate::js::store::Store;
|
||||||
use crate::types::{Val, ValType};
|
use crate::js::types::{Val, ValType};
|
||||||
use crate::wasm_bindgen_polyfill::Global as JSGlobal;
|
use crate::js::wasm_bindgen_polyfill::Global as JSGlobal;
|
||||||
use crate::GlobalType;
|
use crate::js::GlobalType;
|
||||||
use crate::Mutability;
|
use crate::js::Mutability;
|
||||||
use crate::RuntimeError;
|
use crate::js::RuntimeError;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
/// A WebAssembly `global` instance.
|
/// A WebAssembly `global` instance.
|
||||||
@@ -28,7 +28,7 @@ impl Global {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Global, Mutability, Store, Value};
|
/// # use wasmer::{Global, Mutability, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let g = Global::new(&store, Value::I32(1));
|
/// let g = Global::new(&store, Value::I32(1));
|
||||||
@@ -45,7 +45,7 @@ impl Global {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Global, Mutability, Store, Value};
|
/// # use wasmer::{Global, Mutability, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let g = Global::new_mut(&store, Value::I32(1));
|
/// let g = Global::new_mut(&store, Value::I32(1));
|
||||||
@@ -94,7 +94,7 @@ impl Global {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Global, Mutability, Store, Type, Value, GlobalType};
|
/// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let c = Global::new(&store, Value::I32(1));
|
/// let c = Global::new(&store, Value::I32(1));
|
||||||
@@ -112,7 +112,7 @@ impl Global {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Global, Store, Value};
|
/// # use wasmer::{Global, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let g = Global::new(&store, Value::I32(1));
|
/// let g = Global::new(&store, Value::I32(1));
|
||||||
@@ -128,7 +128,7 @@ impl Global {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Global, Store, Value};
|
/// # use wasmer::{Global, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let g = Global::new(&store, Value::I32(1));
|
/// let g = Global::new(&store, Value::I32(1));
|
||||||
@@ -150,7 +150,7 @@ impl Global {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Global, Store, Value};
|
/// # use wasmer::{Global, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let g = Global::new_mut(&store, Value::I32(1));
|
/// let g = Global::new_mut(&store, Value::I32(1));
|
||||||
@@ -167,7 +167,7 @@ impl Global {
|
|||||||
/// Trying to mutate a immutable global will raise an error:
|
/// Trying to mutate a immutable global will raise an error:
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```should_panic
|
||||||
/// # use wasmer_js::{Global, Store, Value};
|
/// # use wasmer::{Global, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let g = Global::new(&store, Value::I32(1));
|
/// let g = Global::new(&store, Value::I32(1));
|
||||||
@@ -178,7 +178,7 @@ impl Global {
|
|||||||
/// Trying to set a value of a incompatible type will raise an error:
|
/// Trying to set a value of a incompatible type will raise an error:
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```should_panic
|
||||||
/// # use wasmer_js::{Global, Store, Value};
|
/// # use wasmer::{Global, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let g = Global::new(&store, Value::I32(1));
|
/// let g = Global::new(&store, Value::I32(1));
|
||||||
@@ -216,7 +216,7 @@ impl Global {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Global, Store, Value};
|
/// # use wasmer::{Global, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let g = Global::new(&store, Value::I32(1));
|
/// let g = Global::new(&store, Value::I32(1));
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::export::{Export, VMMemory};
|
use crate::js::export::{Export, VMMemory};
|
||||||
use crate::exports::{ExportError, Exportable};
|
use crate::js::exports::{ExportError, Exportable};
|
||||||
use crate::externals::Extern;
|
use crate::js::externals::Extern;
|
||||||
use crate::store::Store;
|
use crate::js::store::Store;
|
||||||
use crate::{MemoryType, MemoryView};
|
use crate::js::{MemoryType, MemoryView};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -83,12 +83,12 @@ impl Memory {
|
|||||||
/// Creates a new host `Memory` from the provided [`MemoryType`].
|
/// Creates a new host `Memory` from the provided [`MemoryType`].
|
||||||
///
|
///
|
||||||
/// This function will construct the `Memory` using the store
|
/// This function will construct the `Memory` using the store
|
||||||
/// [`BaseTunables`][crate::tunables::BaseTunables].
|
/// [`BaseTunables`][crate::js::tunables::BaseTunables].
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value};
|
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||||
@@ -116,7 +116,7 @@ impl Memory {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value};
|
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let mt = MemoryType::new(1, None, false);
|
/// let mt = MemoryType::new(1, None, false);
|
||||||
@@ -135,7 +135,7 @@ impl Memory {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value};
|
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||||
@@ -189,7 +189,7 @@ impl Memory {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value};
|
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||||
@@ -210,7 +210,7 @@ impl Memory {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
|
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let m = Memory::new(&store, MemoryType::new(1, Some(3), false)).unwrap();
|
/// let m = Memory::new(&store, MemoryType::new(1, Some(3), false)).unwrap();
|
||||||
@@ -226,7 +226,7 @@ impl Memory {
|
|||||||
/// of pages.
|
/// of pages.
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```should_panic
|
||||||
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
|
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let m = Memory::new(&store, MemoryType::new(1, Some(1), false)).unwrap();
|
/// let m = Memory::new(&store, MemoryType::new(1, Some(1), false)).unwrap();
|
||||||
@@ -268,7 +268,7 @@ impl Memory {
|
|||||||
/// # Usage:
|
/// # Usage:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Memory, MemoryView};
|
/// # use wasmer::{Memory, MemoryView};
|
||||||
/// # use std::{cell::Cell, sync::atomic::Ordering};
|
/// # use std::{cell::Cell, sync::atomic::Ordering};
|
||||||
/// # fn view_memory(memory: Memory) {
|
/// # fn view_memory(memory: Memory) {
|
||||||
/// // Without synchronization.
|
/// // Without synchronization.
|
||||||
@@ -305,7 +305,7 @@ impl Memory {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Memory, MemoryType, Store, Value};
|
/// # use wasmer::{Memory, MemoryType, Store, Value};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// #
|
/// #
|
||||||
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||||
@@ -11,10 +11,10 @@ pub use self::global::Global;
|
|||||||
pub use self::memory::{Memory, MemoryError};
|
pub use self::memory::{Memory, MemoryError};
|
||||||
pub use self::table::Table;
|
pub use self::table::Table;
|
||||||
|
|
||||||
use crate::export::Export;
|
use crate::js::export::Export;
|
||||||
use crate::exports::{ExportError, Exportable};
|
use crate::js::exports::{ExportError, Exportable};
|
||||||
use crate::store::{Store, StoreObject};
|
use crate::js::store::{Store, StoreObject};
|
||||||
use crate::ExternType;
|
use crate::js::ExternType;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// An `Extern` is the runtime representation of an entity that
|
/// An `Extern` is the runtime representation of an entity that
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::export::VMFunction;
|
use crate::js::export::VMFunction;
|
||||||
use crate::export::{Export, VMTable};
|
use crate::js::export::{Export, VMTable};
|
||||||
use crate::exports::{ExportError, Exportable};
|
use crate::js::exports::{ExportError, Exportable};
|
||||||
use crate::externals::{Extern, Function as WasmerFunction};
|
use crate::js::externals::{Extern, Function as WasmerFunction};
|
||||||
use crate::store::Store;
|
use crate::js::store::Store;
|
||||||
use crate::types::Val;
|
use crate::js::types::Val;
|
||||||
use crate::RuntimeError;
|
use crate::js::RuntimeError;
|
||||||
use crate::TableType;
|
use crate::js::TableType;
|
||||||
use js_sys::Function;
|
use js_sys::Function;
|
||||||
use wasmer_types::FunctionType;
|
use wasmer_types::FunctionType;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ impl Table {
|
|||||||
/// All the elements in the table will be set to the `init` value.
|
/// All the elements in the table will be set to the `init` value.
|
||||||
///
|
///
|
||||||
/// This function will construct the `Table` using the store
|
/// This function will construct the `Table` using the store
|
||||||
/// [`BaseTunables`][crate::tunables::BaseTunables].
|
/// [`BaseTunables`][crate::js::tunables::BaseTunables].
|
||||||
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> {
|
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> {
|
||||||
let descriptor = js_sys::Object::new();
|
let descriptor = js_sys::Object::new();
|
||||||
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into())?;
|
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into())?;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
//! The import module contains the implementation data structures and helper functions used to
|
//! The import module contains the implementation data structures and helper functions used to
|
||||||
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||||
//! functions.
|
//! functions.
|
||||||
use crate::export::Export;
|
use crate::js::export::Export;
|
||||||
use crate::resolver::NamedResolver;
|
use crate::js::resolver::NamedResolver;
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::collections::{hash_map::Entry, HashMap};
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
@@ -28,7 +28,7 @@ pub trait LikeNamespace {
|
|||||||
///
|
///
|
||||||
/// # Usage:
|
/// # Usage:
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// use wasmer_js::{Exports, ImportObject, Function};
|
/// use wasmer::{Exports, ImportObject, Function};
|
||||||
///
|
///
|
||||||
/// let mut import_object = ImportObject::new();
|
/// let mut import_object = ImportObject::new();
|
||||||
/// let mut env = Exports::new();
|
/// let mut env = Exports::new();
|
||||||
@@ -55,7 +55,7 @@ impl ImportObject {
|
|||||||
///
|
///
|
||||||
/// # Usage
|
/// # Usage
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// # use wasmer_js::{ImportObject, Instance, Namespace};
|
/// # use wasmer::{ImportObject, Instance, Namespace};
|
||||||
/// let mut import_object = ImportObject::new();
|
/// let mut import_object = ImportObject::new();
|
||||||
/// import_object.get_export("module", "name");
|
/// import_object.get_export("module", "name");
|
||||||
/// ```
|
/// ```
|
||||||
@@ -78,7 +78,7 @@ impl ImportObject {
|
|||||||
///
|
///
|
||||||
/// # Usage:
|
/// # Usage:
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// # use wasmer_js::{ImportObject, Instance, Namespace};
|
/// # use wasmer::{ImportObject, Instance, Namespace};
|
||||||
/// let mut import_object = ImportObject::new();
|
/// let mut import_object = ImportObject::new();
|
||||||
///
|
///
|
||||||
/// import_object.register("namespace0", instance);
|
/// import_object.register("namespace0", instance);
|
||||||
@@ -188,9 +188,9 @@ impl fmt::Debug for ImportObject {
|
|||||||
/// # Usage
|
/// # Usage
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{Function, Store};
|
/// # use wasmer::{Function, Store};
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// use wasmer_js::imports;
|
/// use wasmer::imports;
|
||||||
///
|
///
|
||||||
/// let import_object = imports! {
|
/// let import_object = imports! {
|
||||||
/// "env" => {
|
/// "env" => {
|
||||||
@@ -248,9 +248,9 @@ macro_rules! import_namespace {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ChainableNamedResolver;
|
use crate::js::ChainableNamedResolver;
|
||||||
use crate::Type;
|
use crate::js::Type;
|
||||||
use crate::{Global, Store, Val};
|
use crate::js::{Global, Store, Val};
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
@@ -360,7 +360,7 @@ mod test {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn imports_macro_allows_trailing_comma_and_none() {
|
fn imports_macro_allows_trailing_comma_and_none() {
|
||||||
use crate::Function;
|
use crate::js::Function;
|
||||||
|
|
||||||
let store = Default::default();
|
let store = Default::default();
|
||||||
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::env::HostEnvInitError;
|
use crate::js::env::HostEnvInitError;
|
||||||
use crate::export::Export;
|
use crate::js::export::Export;
|
||||||
use crate::exports::Exports;
|
use crate::js::exports::Exports;
|
||||||
use crate::externals::Extern;
|
use crate::js::externals::Extern;
|
||||||
use crate::module::Module;
|
use crate::js::module::Module;
|
||||||
use crate::resolver::Resolver;
|
use crate::js::resolver::Resolver;
|
||||||
use crate::store::Store;
|
use crate::js::store::Store;
|
||||||
use crate::trap::RuntimeError;
|
use crate::js::trap::RuntimeError;
|
||||||
use js_sys::WebAssembly;
|
use js_sys::WebAssembly;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -68,10 +68,10 @@ impl Instance {
|
|||||||
///
|
///
|
||||||
/// The [`ImportObject`] is the easiest way to provide imports to the instance.
|
/// The [`ImportObject`] is the easiest way to provide imports to the instance.
|
||||||
///
|
///
|
||||||
/// [`ImportObject`]: crate::ImportObject
|
/// [`ImportObject`]: crate::js::ImportObject
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::{imports, Store, Module, Global, Value, Instance};
|
/// # use wasmer::{imports, Store, Module, Global, Value, Instance};
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let store = Store::default();
|
/// let store = Store::default();
|
||||||
/// let module = Module::new(&store, "(module)")?;
|
/// let module = Module::new(&store, "(module)")?;
|
||||||
85
lib/api/src/js/mod.rs
Normal file
85
lib/api/src/js/mod.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#[cfg(all(feature = "std", feature = "core"))]
|
||||||
|
compile_error!(
|
||||||
|
"The `std` and `core` features are both enabled, which is an error. Please enable only once."
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "std"), not(feature = "core")))]
|
||||||
|
compile_error!("Both the `std` and `core` features are disabled. Please enable one of them.");
|
||||||
|
|
||||||
|
#[cfg(feature = "core")]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
mod lib {
|
||||||
|
#[cfg(feature = "core")]
|
||||||
|
pub mod std {
|
||||||
|
pub use alloc::{borrow, boxed, str, string, sync, vec};
|
||||||
|
pub use core::fmt;
|
||||||
|
pub use hashbrown as collections;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod std {
|
||||||
|
pub use std::{borrow, boxed, collections, fmt, str, string, sync, vec};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod cell;
|
||||||
|
mod env;
|
||||||
|
mod error;
|
||||||
|
mod export;
|
||||||
|
mod exports;
|
||||||
|
mod externals;
|
||||||
|
mod import_object;
|
||||||
|
mod instance;
|
||||||
|
mod module;
|
||||||
|
#[cfg(feature = "wasm-types-polyfill")]
|
||||||
|
mod module_info_polyfill;
|
||||||
|
mod native;
|
||||||
|
mod ptr;
|
||||||
|
mod resolver;
|
||||||
|
mod store;
|
||||||
|
mod trap;
|
||||||
|
mod types;
|
||||||
|
mod utils;
|
||||||
|
mod wasm_bindgen_polyfill;
|
||||||
|
|
||||||
|
/// Implement [`WasmerEnv`] for your type with `#[derive(WasmerEnv)]`.
|
||||||
|
///
|
||||||
|
/// See the [`WasmerEnv`] trait for more information.
|
||||||
|
pub use wasmer_derive::WasmerEnv;
|
||||||
|
|
||||||
|
pub use crate::js::cell::WasmCell;
|
||||||
|
pub use crate::js::env::{HostEnvInitError, LazyInit, WasmerEnv};
|
||||||
|
pub use crate::js::exports::{ExportError, Exportable, Exports, ExportsIterator};
|
||||||
|
pub use crate::js::externals::{
|
||||||
|
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, Table,
|
||||||
|
WasmTypeList,
|
||||||
|
};
|
||||||
|
pub use crate::js::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
|
||||||
|
pub use crate::js::instance::{Instance, InstantiationError};
|
||||||
|
pub use crate::js::module::{Module, ModuleTypeHints};
|
||||||
|
pub use crate::js::native::NativeFunc;
|
||||||
|
pub use crate::js::ptr::{Array, Item, WasmPtr};
|
||||||
|
pub use crate::js::resolver::{
|
||||||
|
ChainableNamedResolver, NamedResolver, NamedResolverChain, Resolver,
|
||||||
|
};
|
||||||
|
pub use crate::js::trap::RuntimeError;
|
||||||
|
|
||||||
|
pub use crate::js::store::{Store, StoreObject};
|
||||||
|
pub use crate::js::types::{
|
||||||
|
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
|
||||||
|
TableType, Val, ValType,
|
||||||
|
};
|
||||||
|
pub use crate::js::types::{Val as Value, ValType as Type};
|
||||||
|
pub use crate::js::utils::is_wasm;
|
||||||
|
|
||||||
|
pub use wasmer_types::{
|
||||||
|
Atomically, Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
|
||||||
|
WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "wat")]
|
||||||
|
pub use wat::parse_bytes as wat2wasm;
|
||||||
|
|
||||||
|
/// Version number of this crate.
|
||||||
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
use crate::export::{Export, VMFunction};
|
use crate::js::export::{Export, VMFunction};
|
||||||
use crate::resolver::Resolver;
|
use crate::js::resolver::Resolver;
|
||||||
use crate::store::Store;
|
use crate::js::store::Store;
|
||||||
use crate::types::{ExportType, ImportType};
|
use crate::js::types::{ExportType, ImportType};
|
||||||
// use crate::InstantiationError;
|
// use crate::js::InstantiationError;
|
||||||
use crate::error::CompileError;
|
use crate::js::error::CompileError;
|
||||||
#[cfg(feature = "wat")]
|
#[cfg(feature = "wat")]
|
||||||
use crate::error::WasmError;
|
use crate::js::error::WasmError;
|
||||||
use crate::RuntimeError;
|
use crate::js::RuntimeError;
|
||||||
use js_sys::{Reflect, Uint8Array, WebAssembly};
|
use js_sys::{Reflect, Uint8Array, WebAssembly};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -89,7 +89,7 @@ impl Module {
|
|||||||
/// Reading from a WAT file.
|
/// Reading from a WAT file.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use wasmer_js::*;
|
/// use wasmer::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// let wat = "(module)";
|
/// let wat = "(module)";
|
||||||
@@ -101,7 +101,7 @@ impl Module {
|
|||||||
/// Reading from bytes:
|
/// Reading from bytes:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use wasmer_js::*;
|
/// use wasmer::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// // The following is the same as:
|
/// // The following is the same as:
|
||||||
@@ -168,7 +168,7 @@ impl Module {
|
|||||||
// The module is now validated, so we can safely parse it's types
|
// The module is now validated, so we can safely parse it's types
|
||||||
#[cfg(feature = "wasm-types-polyfill")]
|
#[cfg(feature = "wasm-types-polyfill")]
|
||||||
let (type_hints, name) = {
|
let (type_hints, name) = {
|
||||||
let info = crate::module_info_polyfill::translate_module(binary).unwrap();
|
let info = crate::js::module_info_polyfill::translate_module(binary).unwrap();
|
||||||
|
|
||||||
(
|
(
|
||||||
Some(ModuleTypeHints {
|
Some(ModuleTypeHints {
|
||||||
@@ -261,7 +261,7 @@ impl Module {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::*;
|
/// # use wasmer::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// let wat = "(module $moduleName)";
|
/// let wat = "(module $moduleName)";
|
||||||
@@ -285,7 +285,7 @@ impl Module {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::*;
|
/// # use wasmer::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// let wat = "(module)";
|
/// let wat = "(module)";
|
||||||
@@ -320,7 +320,7 @@ impl Module {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::*;
|
/// # use wasmer::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// let wat = r#"(module
|
/// let wat = r#"(module
|
||||||
@@ -418,7 +418,7 @@ impl Module {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::*;
|
/// # use wasmer::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// let wat = r#"(module
|
/// let wat = r#"(module
|
||||||
@@ -9,10 +9,10 @@
|
|||||||
//! ```
|
//! ```
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{FromToNativeWasmType, Function, RuntimeError, Store, WasmTypeList};
|
use crate::js::{FromToNativeWasmType, Function, RuntimeError, Store, WasmTypeList};
|
||||||
// use std::panic::{catch_unwind, AssertUnwindSafe};
|
// use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
use crate::export::VMFunction;
|
use crate::js::export::VMFunction;
|
||||||
use crate::types::param_from_js;
|
use crate::js::types::param_from_js;
|
||||||
use js_sys::Array;
|
use js_sys::Array;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
@@ -107,14 +107,14 @@ macro_rules! impl_native_traits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_parens)]
|
#[allow(unused_parens)]
|
||||||
impl<'a, $( $x, )* Rets> crate::exports::ExportableWithGenerics<'a, ($( $x ),*), Rets> for NativeFunc<( $( $x ),* ), Rets>
|
impl<'a, $( $x, )* Rets> crate::js::exports::ExportableWithGenerics<'a, ($( $x ),*), Rets> for NativeFunc<( $( $x ),* ), Rets>
|
||||||
where
|
where
|
||||||
$( $x: FromToNativeWasmType, )*
|
$( $x: FromToNativeWasmType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
fn get_self_from_extern_with_generics(_extern: &crate::externals::Extern) -> Result<Self, crate::exports::ExportError> {
|
fn get_self_from_extern_with_generics(_extern: &crate::js::externals::Extern) -> Result<Self, crate::js::exports::ExportError> {
|
||||||
use crate::exports::Exportable;
|
use crate::js::exports::Exportable;
|
||||||
crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::exports::ExportError::IncompatibleType)
|
crate::js::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::js::exports::ExportError::IncompatibleType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
//! Therefore, you should use this abstraction whenever possible to avoid memory
|
//! Therefore, you should use this abstraction whenever possible to avoid memory
|
||||||
//! related bugs when implementing an ABI.
|
//! related bugs when implementing an ABI.
|
||||||
|
|
||||||
use crate::cell::WasmCell;
|
use crate::js::cell::WasmCell;
|
||||||
use crate::{externals::Memory, FromToNativeWasmType};
|
use crate::js::{externals::Memory, FromToNativeWasmType};
|
||||||
use std::{fmt, marker::PhantomData, mem};
|
use std::{fmt, marker::PhantomData, mem};
|
||||||
use wasmer_types::ValueType;
|
use wasmer_types::ValueType;
|
||||||
|
|
||||||
@@ -23,8 +23,8 @@ pub struct Item;
|
|||||||
///
|
///
|
||||||
/// This type can be used directly in the host function arguments:
|
/// This type can be used directly in the host function arguments:
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::Memory;
|
/// # use wasmer::Memory;
|
||||||
/// # use wasmer_js::WasmPtr;
|
/// # use wasmer::WasmPtr;
|
||||||
/// pub fn host_import(memory: Memory, ptr: WasmPtr<u32>) {
|
/// pub fn host_import(memory: Memory, ptr: WasmPtr<u32>) {
|
||||||
/// let derefed_ptr = ptr.deref(&memory).expect("pointer in bounds");
|
/// let derefed_ptr = ptr.deref(&memory).expect("pointer in bounds");
|
||||||
/// let inner_val: u32 = derefed_ptr.get();
|
/// let inner_val: u32 = derefed_ptr.get();
|
||||||
@@ -37,9 +37,9 @@ pub struct Item;
|
|||||||
/// This type can also be used with primitive-filled structs, but be careful of
|
/// This type can also be used with primitive-filled structs, but be careful of
|
||||||
/// guarantees required by `ValueType`.
|
/// guarantees required by `ValueType`.
|
||||||
/// ```
|
/// ```
|
||||||
/// # use wasmer_js::Memory;
|
/// # use wasmer::Memory;
|
||||||
/// # use wasmer_js::WasmPtr;
|
/// # use wasmer::WasmPtr;
|
||||||
/// # use wasmer_js::ValueType;
|
/// # use wasmer::ValueType;
|
||||||
///
|
///
|
||||||
/// #[derive(Copy, Clone, Debug)]
|
/// #[derive(Copy, Clone, Debug)]
|
||||||
/// #[repr(C)]
|
/// #[repr(C)]
|
||||||
@@ -246,7 +246,7 @@ impl<T: Copy, Ty> fmt::Debug for WasmPtr<T, Ty> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{Memory, MemoryType, Store};
|
use crate::js::{Memory, MemoryType, Store};
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
/// Ensure that memory accesses work on the edges of memory and that out of
|
/// Ensure that memory accesses work on the edges of memory and that out of
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::export::Export;
|
use crate::js::export::Export;
|
||||||
|
|
||||||
/// Import resolver connects imports with available exported values.
|
/// Import resolver connects imports with available exported values.
|
||||||
pub trait Resolver {
|
pub trait Resolver {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::externals::Function;
|
use crate::js::externals::Function;
|
||||||
// use crate::store::{Store, StoreObject};
|
// use crate::js::store::{Store, StoreObject};
|
||||||
// use crate::RuntimeError;
|
// use crate::js::RuntimeError;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use wasmer_types::Value;
|
use wasmer_types::Value;
|
||||||
pub use wasmer_types::{
|
pub use wasmer_types::{
|
||||||
@@ -26,19 +26,29 @@
|
|||||||
clippy::use_self
|
clippy::use_self
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
|
#![cfg_attr(feature = "js", crate_type = "cdylib")]
|
||||||
|
#![cfg_attr(feature = "js", crate_type = "rlib")]
|
||||||
|
|
||||||
//! This crate contains the `wasmer` API. The `wasmer` API facilitates the efficient,
|
//! [`Wasmer`](https://wasmer.io/) is the most popular
|
||||||
//! sandboxed execution of [WebAssembly (Wasm)][wasm] modules.
|
//! [WebAssembly](https://webassembly.org/) runtime for Rust. It supports
|
||||||
|
//! JIT (Just In Time) and AOT (Ahead Of Time) compilation as well as
|
||||||
|
//! pluggable compilers suited to your needs.
|
||||||
//!
|
//!
|
||||||
//! Here's an example of the `wasmer` API in action:
|
//! It's designed to be safe and secure, and runnable in any kind of environment.
|
||||||
//! ```
|
//!
|
||||||
|
//! # Usage
|
||||||
|
//!
|
||||||
|
//! Here is a small example of using Wasmer to run a WebAssembly module
|
||||||
|
//! written with its WAT format (textual format):
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
//! use wasmer::{Store, Module, Instance, Value, imports};
|
//! use wasmer::{Store, Module, Instance, Value, imports};
|
||||||
//!
|
//!
|
||||||
//! fn main() -> anyhow::Result<()> {
|
//! fn main() -> anyhow::Result<()> {
|
||||||
//! let module_wat = r#"
|
//! let module_wat = r#"
|
||||||
//! (module
|
//! (module
|
||||||
//! (type $t0 (func (param i32) (result i32)))
|
//! (type $t0 (func (param i32) (result i32)))
|
||||||
//! (func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
|
//! (func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
|
||||||
//! get_local $p0
|
//! get_local $p0
|
||||||
//! i32.const 1
|
//! i32.const 1
|
||||||
//! i32.add))
|
//! i32.add))
|
||||||
@@ -58,14 +68,63 @@
|
|||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! For more examples of using the `wasmer` API, check out the
|
//! [Discover the full collection of examples](https://github.com/wasmerio/wasmer/tree/master/examples).
|
||||||
//! [wasmer examples][wasmer-examples].
|
|
||||||
//!
|
//!
|
||||||
//! ---------
|
//! # Overview of the Features
|
||||||
|
//!
|
||||||
|
//! Wasmer is not only fast, but also designed to be *highly customizable*:
|
||||||
|
//!
|
||||||
|
//! * **Pluggable engines** — An engine is responsible to drive the
|
||||||
|
//! compilation process and to store the generated executable code
|
||||||
|
//! somewhere, either:
|
||||||
|
//! * in-memory (with [`wasmer-engine-universal`]),
|
||||||
|
//! * in a native shared object file (with [`wasmer-engine-dylib`],
|
||||||
|
//! `.dylib`, `.so`, `.dll`), then load it with `dlopen`,
|
||||||
|
//! * in a native static object file (with [`wasmer-engine-staticlib`]),
|
||||||
|
//! in addition to emitting a C header file, which both can be linked
|
||||||
|
//! against a sandboxed WebAssembly runtime environment for the
|
||||||
|
//! compiled module with no need for runtime compilation.
|
||||||
|
//!
|
||||||
|
//! * **Pluggable compilers** — A compiler is used by an engine to
|
||||||
|
//! transform WebAssembly into executable code:
|
||||||
|
//! * [`wasmer-compiler-singlepass`] provides a fast compilation-time
|
||||||
|
//! but an unoptimized runtime speed,
|
||||||
|
//! * [`wasmer-compiler-cranelift`] provides the right balance between
|
||||||
|
//! compilation-time and runtime performance, useful for development,
|
||||||
|
//! * [`wasmer-compiler-llvm`] provides a deeply optimized executable
|
||||||
|
//! code with the fastest runtime speed, ideal for production.
|
||||||
|
//!
|
||||||
|
//! * **Headless mode** — Once a WebAssembly module has been compiled, it
|
||||||
|
//! is possible to serialize it in a file for example, and later execute
|
||||||
|
//! it with Wasmer with headless mode turned on. Headless Wasmer has no
|
||||||
|
//! compiler, which makes it more portable and faster to load. It's
|
||||||
|
//! ideal for constrainted environments.
|
||||||
|
//!
|
||||||
|
//! * **Cross-compilation** — Most compilers support cross-compilation. It
|
||||||
|
//! means it possible to pre-compile a WebAssembly module targetting a
|
||||||
|
//! different architecture or platform and serialize it, to then run it
|
||||||
|
//! on the targetted architecture and platform later.
|
||||||
|
//!
|
||||||
|
//! * **Run Wasmer in a JavaScript environment** — With the `js` Cargo
|
||||||
|
//! feature, it is possible to compile a Rust program using Wasmer to
|
||||||
|
//! WebAssembly. In this context, the resulting WebAssembly module will
|
||||||
|
//! expect to run in a JavaScript environment, like a browser, Node.js,
|
||||||
|
//! Deno and so on. In this specific scenario, there is no engines or
|
||||||
|
//! compilers available, it's the one available in the JavaScript
|
||||||
|
//! environment that will be used.
|
||||||
|
//!
|
||||||
|
//! Wasmer ships by default with the Cranelift compiler as its great for
|
||||||
|
//! development purposes. However, we strongly encourage to use the LLVM
|
||||||
|
//! compiler in production as it performs about 50% faster, achieving
|
||||||
|
//! near-native speeds.
|
||||||
|
//!
|
||||||
|
//! Note: if one wants to use multiple compilers at the same time, it's
|
||||||
|
//! also possible! One will need to import them directly via each of the
|
||||||
|
//! compiler crates.
|
||||||
//!
|
//!
|
||||||
//! # Table of Contents
|
//! # Table of Contents
|
||||||
//!
|
//!
|
||||||
//! - [Wasm Primitives](#wasm-primitives)
|
//! - [WebAssembly Primitives](#webassembly-primitives)
|
||||||
//! - [Externs](#externs)
|
//! - [Externs](#externs)
|
||||||
//! - [Functions](#functions)
|
//! - [Functions](#functions)
|
||||||
//! - [Memories](#memories)
|
//! - [Memories](#memories)
|
||||||
@@ -74,10 +133,12 @@
|
|||||||
//! - [Project Layout](#project-layout)
|
//! - [Project Layout](#project-layout)
|
||||||
//! - [Engines](#engines)
|
//! - [Engines](#engines)
|
||||||
//! - [Compilers](#compilers)
|
//! - [Compilers](#compilers)
|
||||||
//! - [Features](#features)
|
//! - [Cargo Features](#cargo-features)
|
||||||
|
//! - [Using Wasmer in a JavaScript environment](#using-wasmer-in-a-javascript-environment)
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
//! # Wasm Primitives
|
//! # WebAssembly Primitives
|
||||||
|
//!
|
||||||
//! In order to make use of the power of the `wasmer` API, it's important
|
//! In order to make use of the power of the `wasmer` API, it's important
|
||||||
//! to understand the primitives around which the API is built.
|
//! to understand the primitives around which the API is built.
|
||||||
//!
|
//!
|
||||||
@@ -88,6 +149,7 @@
|
|||||||
//! referred to as "externs".
|
//! referred to as "externs".
|
||||||
//!
|
//!
|
||||||
//! ## Externs
|
//! ## Externs
|
||||||
|
//!
|
||||||
//! An [`Extern`] is a type that can be imported or exported from a Wasm
|
//! An [`Extern`] is a type that can be imported or exported from a Wasm
|
||||||
//! module.
|
//! module.
|
||||||
//!
|
//!
|
||||||
@@ -125,9 +187,10 @@
|
|||||||
//! These are the primary types that the `wasmer` API uses.
|
//! These are the primary types that the `wasmer` API uses.
|
||||||
//!
|
//!
|
||||||
//! ### Functions
|
//! ### Functions
|
||||||
|
//!
|
||||||
//! There are 2 types of functions in `wasmer`:
|
//! There are 2 types of functions in `wasmer`:
|
||||||
//! 1. Wasm functions
|
//! 1. Wasm functions,
|
||||||
//! 2. Host functions
|
//! 2. Host functions.
|
||||||
//!
|
//!
|
||||||
//! A Wasm function is a function defined in a WebAssembly module that can
|
//! A Wasm function is a function defined in a WebAssembly module that can
|
||||||
//! only perform computation without side effects and call other functions.
|
//! only perform computation without side effects and call other functions.
|
||||||
@@ -148,7 +211,7 @@
|
|||||||
//! give them access to the outside world with [`imports`].
|
//! give them access to the outside world with [`imports`].
|
||||||
//!
|
//!
|
||||||
//! If you're looking for a sandboxed, POSIX-like environment to execute Wasm
|
//! If you're looking for a sandboxed, POSIX-like environment to execute Wasm
|
||||||
//! in, check out the [`wasmer-wasi`][wasmer-wasi] crate for our implementation of WASI,
|
//! in, check out the [`wasmer-wasi`] crate for our implementation of WASI,
|
||||||
//! the WebAssembly System Interface.
|
//! the WebAssembly System Interface.
|
||||||
//!
|
//!
|
||||||
//! In the `wasmer` API we support functions which take their arguments and
|
//! In the `wasmer` API we support functions which take their arguments and
|
||||||
@@ -156,6 +219,7 @@
|
|||||||
//! take their arguments and return their results statically, [`NativeFunc`].
|
//! take their arguments and return their results statically, [`NativeFunc`].
|
||||||
//!
|
//!
|
||||||
//! ### Memories
|
//! ### Memories
|
||||||
|
//!
|
||||||
//! Memories store data.
|
//! Memories store data.
|
||||||
//!
|
//!
|
||||||
//! In most Wasm programs, nearly all data will live in a [`Memory`].
|
//! In most Wasm programs, nearly all data will live in a [`Memory`].
|
||||||
@@ -164,14 +228,15 @@
|
|||||||
//! interesting programs.
|
//! interesting programs.
|
||||||
//!
|
//!
|
||||||
//! ### Globals
|
//! ### Globals
|
||||||
|
//!
|
||||||
//! A [`Global`] is a type that may be either mutable or immutable, and
|
//! A [`Global`] is a type that may be either mutable or immutable, and
|
||||||
//! contains one of the core Wasm types defined in [`Value`].
|
//! contains one of the core Wasm types defined in [`Value`].
|
||||||
//!
|
//!
|
||||||
//! ### Tables
|
//! ### Tables
|
||||||
|
//!
|
||||||
//! A [`Table`] is an indexed list of items.
|
//! A [`Table`] is an indexed list of items.
|
||||||
//!
|
//!
|
||||||
//!
|
//! # Project Layout
|
||||||
//! ## Project Layout
|
|
||||||
//!
|
//!
|
||||||
//! The Wasmer project is divided into a number of crates, below is a dependency
|
//! The Wasmer project is divided into a number of crates, below is a dependency
|
||||||
//! graph with transitive dependencies removed.
|
//! graph with transitive dependencies removed.
|
||||||
@@ -183,202 +248,226 @@
|
|||||||
//! While this crate is the top level API, we also publish crates built
|
//! While this crate is the top level API, we also publish crates built
|
||||||
//! on top of this API that you may be interested in using, including:
|
//! on top of this API that you may be interested in using, including:
|
||||||
//!
|
//!
|
||||||
//! - [wasmer-cache][] for caching compiled Wasm modules.
|
//! - [`wasmer-cache`] for caching compiled Wasm modules,
|
||||||
//! - [wasmer-emscripten][] for running Wasm modules compiled to the
|
//! - [`wasmer-emscripten`] for running Wasm modules compiled to the
|
||||||
//! Emscripten ABI.
|
//! Emscripten ABI,
|
||||||
//! - [wasmer-wasi][] for running Wasm modules compiled to the WASI ABI.
|
//! - [`wasmer-wasi`] for running Wasm modules compiled to the WASI ABI.
|
||||||
//!
|
|
||||||
//! --------
|
|
||||||
//!
|
//!
|
||||||
//! The Wasmer project has two major abstractions:
|
//! The Wasmer project has two major abstractions:
|
||||||
//! 1. [Engines][wasmer-engine]
|
//! 1. [Engines][wasmer-engine],
|
||||||
//! 2. [Compilers][wasmer-compiler]
|
//! 2. [Compilers][wasmer-compiler].
|
||||||
//!
|
//!
|
||||||
//! These two abstractions have multiple options that can be enabled
|
//! These two abstractions have multiple options that can be enabled
|
||||||
//! with features.
|
//! with features.
|
||||||
//!
|
//!
|
||||||
//! ### Engines
|
//! ## Engines
|
||||||
//!
|
//!
|
||||||
//! An engine is a system that uses a compiler to make a WebAssembly
|
//! An engine is a system that uses a compiler to make a WebAssembly
|
||||||
//! module executable.
|
//! module executable.
|
||||||
//!
|
//!
|
||||||
//! ### Compilers
|
//! ## Compilers
|
||||||
//!
|
//!
|
||||||
//! A compiler is a system that handles the details of making a Wasm
|
//! A compiler is a system that handles the details of making a Wasm
|
||||||
//! module executable. For example, by generating native machine code
|
//! module executable. For example, by generating native machine code
|
||||||
//! for each Wasm function.
|
//! for each Wasm function.
|
||||||
//!
|
//!
|
||||||
|
//! # Cargo Features
|
||||||
//!
|
//!
|
||||||
//! ## Features
|
//! This crate comes in 2 flavors:
|
||||||
//!
|
//!
|
||||||
//! This crate's features can be broken down into 2 kinds, features that
|
//! 1. `sys`
|
||||||
//! enable new functionality and features that set defaults.
|
#![cfg_attr(feature = "sys", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "sys"), doc = "(disabled),")]
|
||||||
|
//! where `wasmer` will be compiled to a native executable
|
||||||
|
//! which provides compilers, engines, a full VM etc.
|
||||||
|
//! 2. `js`
|
||||||
|
#![cfg_attr(feature = "js", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "js"), doc = "(disabled),")]
|
||||||
|
//! where `wasmer` will be compiled to WebAssembly to run in a
|
||||||
|
//! JavaScript host (see [Using Wasmer in a JavaScript
|
||||||
|
//! environment](#using-wasmer-in-a-javascript-environment)).
|
||||||
|
//!
|
||||||
|
//! Consequently, we can group the features by the `sys` or `js`
|
||||||
|
//! features.
|
||||||
|
//!
|
||||||
|
#![cfg_attr(
|
||||||
|
feature = "sys",
|
||||||
|
doc = "## Features for the `sys` feature group (enabled)"
|
||||||
|
)]
|
||||||
|
#![cfg_attr(
|
||||||
|
not(feature = "sys"),
|
||||||
|
doc = "## Features for the `sys` feature group (disabled)"
|
||||||
|
)]
|
||||||
|
//!
|
||||||
|
//! The default features can be enabled with the `sys-default` feature.
|
||||||
|
//!
|
||||||
|
//! The features for the `sys` feature group can be broken down into 2
|
||||||
|
//! kinds: features that enable new functionality and features that
|
||||||
|
//! set defaults.
|
||||||
//!
|
//!
|
||||||
//! The features that enable new functionality are:
|
//! The features that enable new functionality are:
|
||||||
//! - `universal` - enable the Universal engine. (See [wasmer-universal][])
|
//! - `cranelift`
|
||||||
//! - `native` - enable the native engine. (See [wasmer-native][])
|
#![cfg_attr(feature = "cranelift", doc = "(enabled),")]
|
||||||
//! - `cranelift` - enable Wasmer's Cranelift compiler. (See [wasmer-cranelift][])
|
#![cfg_attr(not(feature = "cranelift"), doc = "(disabled),")]
|
||||||
//! - `llvm` - enable Wasmer's LLVM compiler. (See [wasmer-llvm][])
|
//! enables Wasmer's [Cranelift compiler][wasmer-compiler-cranelift],
|
||||||
//! - `singlepass` - enable Wasmer's Singlepass compiler. (See [wasmer-singlepass][])
|
//! - `llvm`
|
||||||
//! - `wat` - enable `wasmer` to parse the WebAssembly text format.
|
#![cfg_attr(feature = "llvm", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "llvm"), doc = "(disabled),")]
|
||||||
|
//! enables Wasmer's [LLVM compiler][wasmer-compiler-lvm],
|
||||||
|
//! - `singlepass`
|
||||||
|
#![cfg_attr(feature = "singlepass", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "singlepass"), doc = "(disabled),")]
|
||||||
|
//! enables Wasmer's [Singlepass compiler][wasmer-compiler-singlepass],
|
||||||
|
//! - `wat`
|
||||||
|
#![cfg_attr(feature = "wat", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "wat"), doc = "(disabled),")]
|
||||||
|
//! enables `wasmer` to parse the WebAssembly text format,
|
||||||
|
//! - `universal`
|
||||||
|
#![cfg_attr(feature = "universal", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "universal"), doc = "(disabled),")]
|
||||||
|
//! enables [the Universal engine][`wasmer-engine-universal`],
|
||||||
|
//! - `dylib`
|
||||||
|
#![cfg_attr(feature = "dylib", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "dylib"), doc = "(disabled),")]
|
||||||
|
//! enables [the Dylib engine][`wasmer-engine-dylib`].
|
||||||
//!
|
//!
|
||||||
//! The features that set defaults come in sets that are mutually exclusive.
|
//! The features that set defaults come in sets that are mutually exclusive.
|
||||||
//!
|
//!
|
||||||
//! The first set is the default compiler set:
|
//! The first set is the default compiler set:
|
||||||
//! - `default-cranelift` - set Wasmer's Cranelift compiler as the default.
|
//! - `default-cranelift`
|
||||||
//! - `default-llvm` - set Wasmer's LLVM compiler as the default.
|
#![cfg_attr(feature = "default-cranelift", doc = "(enabled),")]
|
||||||
//! - `default-singlepass` - set Wasmer's Singlepass compiler as the default.
|
#![cfg_attr(not(feature = "default-cranelift"), doc = "(disabled),")]
|
||||||
|
//! set Wasmer's Cranelift compiler as the default,
|
||||||
|
//! - `default-llvm`
|
||||||
|
#![cfg_attr(feature = "default-llvm", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "default-llvm"), doc = "(disabled),")]
|
||||||
|
//! set Wasmer's LLVM compiler as the default,
|
||||||
|
//! - `default-singlepass`
|
||||||
|
#![cfg_attr(feature = "default-singlepass", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "default-singlepass"), doc = "(disabled),")]
|
||||||
|
//! set Wasmer's Singlepass compiler as the default.
|
||||||
//!
|
//!
|
||||||
//! The next set is the default engine set:
|
//! The next set is the default engine set:
|
||||||
//! - `default-universal` - set the Universal engine as the default.
|
//! - `default-universal`
|
||||||
//! - `default-native` - set the native engine as the default.
|
#![cfg_attr(feature = "default-universal", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "default-universal"), doc = "(disabled),")]
|
||||||
|
//! set the Universal engine as the default,
|
||||||
|
//! - `default-dylib`
|
||||||
|
#![cfg_attr(feature = "default-dylib", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "default-dylib"), doc = "(disabled),")]
|
||||||
|
//! set the Dylib engine as the default.
|
||||||
//!
|
//!
|
||||||
//! --------
|
#![cfg_attr(
|
||||||
|
feature = "js",
|
||||||
|
doc = "## Features for the `js` feature group (enabled)"
|
||||||
|
)]
|
||||||
|
#![cfg_attr(
|
||||||
|
not(feature = "js"),
|
||||||
|
doc = "## Features for the `js` feature group (disabled)"
|
||||||
|
)]
|
||||||
//!
|
//!
|
||||||
//! By default the `wat`, `default-cranelift`, and `default-universal` features
|
//! The default features can be enabled with the `js-default` feature.
|
||||||
//! are enabled.
|
|
||||||
//!
|
//!
|
||||||
|
//! Here are the detailed list of features:
|
||||||
//!
|
//!
|
||||||
|
//! - `wasm-types-polyfill`
|
||||||
|
#![cfg_attr(feature = "wasm-types-polyfill", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "wasm-types-polyfill"), doc = "(disabled),")]
|
||||||
|
//! parses the Wasm file, allowing to do type reflection of the
|
||||||
|
//! inner Wasm types. It adds 100kb to the Wasm bundle (28kb
|
||||||
|
//! gzipped). It is possible to disable it and to use
|
||||||
|
//! `Module::set_type_hints` manually instead for a lightweight
|
||||||
|
//! alternative. This is needed until the [Wasm JS introspection API
|
||||||
|
//! proposal](https://github.com/WebAssembly/js-types/blob/master/proposals/js-types/Overview.md)
|
||||||
|
//! is adopted by browsers,
|
||||||
|
//! - `wat`
|
||||||
|
#![cfg_attr(feature = "wat", doc = "(enabled),")]
|
||||||
|
#![cfg_attr(not(feature = "wat"), doc = "(disabled),")]
|
||||||
|
//! allows to read a Wasm file in its text format. This feature is
|
||||||
|
//! normally used only in development environments. It will add
|
||||||
|
//! around 650kb to the Wasm bundle (120Kb gzipped).
|
||||||
|
//!
|
||||||
|
//! # Using Wasmer in a JavaScript environment
|
||||||
|
//!
|
||||||
|
//! Imagine a Rust program that uses this `wasmer` crate to execute a
|
||||||
|
//! WebAssembly module. It is possible to compile this Rust progam to
|
||||||
|
//! WebAssembly by turning on the `js` Cargo feature of this `wasmer`
|
||||||
|
//! crate.
|
||||||
|
//!
|
||||||
|
//! Here is a small example illustrating such a Rust program, and how
|
||||||
|
//! to compile it with [`wasm-pack`] and [`wasm-bindgen`]:
|
||||||
|
//!
|
||||||
|
//! ```ignore
|
||||||
|
//! #[wasm_bindgen]
|
||||||
|
//! pub extern fn do_add_one_in_wasmer() -> i32 {
|
||||||
|
//! let module_wat = r#"
|
||||||
|
//! (module
|
||||||
|
//! (type $t0 (func (param i32) (result i32)))
|
||||||
|
//! (func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
|
||||||
|
//! get_local $p0
|
||||||
|
//! i32.const 1
|
||||||
|
//! i32.add))
|
||||||
|
//! "#;
|
||||||
|
//! let store = Store::default();
|
||||||
|
//! let module = Module::new(&store, &module_wat).unwrap();
|
||||||
|
//! // The module doesn't import anything, so we create an empty import object.
|
||||||
|
//! let import_object = imports! {};
|
||||||
|
//! let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
//!
|
||||||
|
//! let add_one = instance.exports.get_function("add_one").unwrap();
|
||||||
|
//! let result = add_one.call(&[Value::I32(42)]).unwrap();
|
||||||
|
//! assert_eq!(result[0], Value::I32(43));
|
||||||
|
//!
|
||||||
|
//! result[0].unwrap_i32()
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Note that it's the same code as above with the former example. The
|
||||||
|
//! API is the same!
|
||||||
|
//!
|
||||||
|
//! Then, compile with `wasm-pack build`. Take care of using the `js`
|
||||||
|
//! or `js-default` Cargo features.
|
||||||
//!
|
//!
|
||||||
//! [wasm]: https://webassembly.org/
|
//! [wasm]: https://webassembly.org/
|
||||||
//! [wasmer-examples]: https://github.com/wasmerio/wasmer/tree/master/examples
|
//! [wasmer-examples]: https://github.com/wasmerio/wasmer/tree/master/examples
|
||||||
//! [wasmer-cache]: https://docs.rs/wasmer-cache/*/wasmer_cache/
|
//! [`wasmer-cache`]: https://docs.rs/wasmer-cache/
|
||||||
//! [wasmer-compiler]: https://docs.rs/wasmer-compiler/*/wasmer_compiler/
|
//! [wasmer-compiler]: https://docs.rs/wasmer-compiler/
|
||||||
//! [wasmer-cranelift]: https://docs.rs/wasmer-compiler-cranelift/*/wasmer_compiler_cranelift/
|
//! [`wasmer-emscripten`]: https://docs.rs/wasmer-emscripten/
|
||||||
//! [wasmer-emscripten]: https://docs.rs/wasmer-emscripten/*/wasmer_emscripten/
|
//! [wasmer-engine]: https://docs.rs/wasmer-engine/
|
||||||
//! [wasmer-engine]: https://docs.rs/wasmer-engine/*/wasmer_engine/
|
//! [`wasmer-engine-universal`]: https://docs.rs/wasmer-engine-universal/
|
||||||
//! [wasmer-universal]: https://docs.rs/wasmer-engine-universal/*/wasmer_engine_universal/
|
//! [`wasmer-engine-dylib`]: https://docs.rs/wasmer-engine-dylib/
|
||||||
//! [wasmer-native]: https://docs.rs/wasmer-engine-dylib/*/wasmer_engine_dylib/
|
//! [`wasmer-engine-staticlib`]: https://docs.rs/wasmer-engine-staticlib/
|
||||||
//! [wasmer-singlepass]: https://docs.rs/wasmer-compiler-singlepass/*/wasmer_compiler_singlepass/
|
//! [`wasmer-compiler-singlepass`]: https://docs.rs/wasmer-compiler-singlepass/
|
||||||
//! [wasmer-llvm]: https://docs.rs/wasmer-compiler-llvm/*/wasmer_compiler_llvm/
|
//! [`wasmer-compiler-llvm`]: https://docs.rs/wasmer-compiler-llvm/
|
||||||
//! [wasmer-wasi]: https://docs.rs/wasmer-wasi/*/wasmer_wasi/
|
//! [`wasmer-compiler-cranelift`]: https://docs.rs/wasmer-compiler-cranelift/
|
||||||
|
//! [`wasmer-wasi`]: https://docs.rs/wasmer-wasi/
|
||||||
|
//! [`wasm-pack`]: https://github.com/rustwasm/wasm-pack/
|
||||||
|
//! [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen
|
||||||
|
|
||||||
mod cell;
|
#[cfg(all(not(feature = "sys"), not(feature = "js")))]
|
||||||
mod env;
|
compile_error!("At least the `sys` or the `js` feature must be enabled. Please, pick one.");
|
||||||
mod exports;
|
|
||||||
mod externals;
|
|
||||||
mod import_object;
|
|
||||||
mod instance;
|
|
||||||
mod module;
|
|
||||||
mod native;
|
|
||||||
mod ptr;
|
|
||||||
mod store;
|
|
||||||
mod tunables;
|
|
||||||
mod types;
|
|
||||||
mod utils;
|
|
||||||
|
|
||||||
/// Implement [`WasmerEnv`] for your type with `#[derive(WasmerEnv)]`.
|
#[cfg(all(feature = "sys", feature = "js"))]
|
||||||
///
|
|
||||||
/// See the [`WasmerEnv`] trait for more information.
|
|
||||||
pub use wasmer_derive::WasmerEnv;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
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
|
|
||||||
//! `wasmer-vm`. Please don't use any of this types directly, as
|
|
||||||
//! they might change frequently or be removed in the future.
|
|
||||||
|
|
||||||
pub use crate::externals::{WithEnv, WithoutEnv};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use crate::cell::WasmCell;
|
|
||||||
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, InstantiationError};
|
|
||||||
pub use crate::module::Module;
|
|
||||||
pub use crate::native::NativeFunc;
|
|
||||||
pub use crate::ptr::{Array, Item, WasmPtr};
|
|
||||||
pub use crate::store::{Store, StoreObject};
|
|
||||||
pub use crate::tunables::BaseTunables;
|
|
||||||
pub use crate::types::{
|
|
||||||
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
|
|
||||||
TableType, Val, ValType,
|
|
||||||
};
|
|
||||||
pub use crate::types::{Val as Value, ValType as Type};
|
|
||||||
pub use crate::utils::is_wasm;
|
|
||||||
pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST};
|
|
||||||
#[cfg(feature = "compiler")]
|
|
||||||
pub use wasmer_compiler::{
|
|
||||||
wasmparser, CompilerConfig, FunctionMiddleware, MiddlewareError, MiddlewareReaderState,
|
|
||||||
ModuleMiddleware,
|
|
||||||
};
|
|
||||||
pub use wasmer_compiler::{
|
|
||||||
CompileError, CpuFeature, Features, ParseCpuFeatureError, Target, WasmError, WasmResult,
|
|
||||||
};
|
|
||||||
pub use wasmer_engine::{
|
|
||||||
ChainableNamedResolver, DeserializeError, Engine, Export, FrameInfo, LinkError, NamedResolver,
|
|
||||||
NamedResolverChain, Resolver, RuntimeError, SerializeError, Tunables,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
|
||||||
pub use wasmer_types::ExternRef;
|
|
||||||
pub use wasmer_types::{
|
|
||||||
Atomically, Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
|
|
||||||
WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: should those be moved into wasmer::vm as well?
|
|
||||||
pub use wasmer_vm::{raise_user_trap, MemoryError};
|
|
||||||
pub mod vm {
|
|
||||||
//! The vm module re-exports wasmer-vm types.
|
|
||||||
|
|
||||||
pub use wasmer_vm::{
|
|
||||||
Memory, MemoryError, MemoryStyle, Table, TableStyle, VMExtern, VMMemoryDefinition,
|
|
||||||
VMTableDefinition,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "wat")]
|
|
||||||
pub use wat::parse_bytes as wat2wasm;
|
|
||||||
|
|
||||||
// The compilers are mutually exclusive
|
|
||||||
#[cfg(any(
|
|
||||||
all(
|
|
||||||
feature = "default-llvm",
|
|
||||||
any(feature = "default-cranelift", feature = "default-singlepass")
|
|
||||||
),
|
|
||||||
all(feature = "default-cranelift", feature = "default-singlepass")
|
|
||||||
))]
|
|
||||||
compile_error!(
|
compile_error!(
|
||||||
r#"The `default-singlepass`, `default-cranelift` and `default-llvm` features are mutually exclusive.
|
"Cannot have both `sys` and `js` features enabled at the same time. Please, pick one."
|
||||||
If you wish to use more than one compiler, you can simply create the own store. Eg.:
|
|
||||||
|
|
||||||
```
|
|
||||||
use wasmer::{Store, Universal, Singlepass};
|
|
||||||
|
|
||||||
let engine = Universal::new(Singlepass::default()).engine();
|
|
||||||
let store = Store::new(&engine);
|
|
||||||
```"#
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "singlepass")]
|
#[cfg(all(feature = "sys", target_arch = "wasm32"))]
|
||||||
pub use wasmer_compiler_singlepass::Singlepass;
|
compile_error!("The `sys` feature must be enabled only for non-`wasm32` target.");
|
||||||
|
|
||||||
#[cfg(feature = "cranelift")]
|
#[cfg(all(feature = "js", not(target_arch = "wasm32")))]
|
||||||
pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel};
|
compile_error!(
|
||||||
|
"The `js` feature must be enabled only for the `wasm32` target (either `wasm32-unknown-unknown` or `wasm32-wasi`)."
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(feature = "llvm")]
|
#[cfg(feature = "sys")]
|
||||||
pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM};
|
mod sys;
|
||||||
|
|
||||||
#[cfg(feature = "universal")]
|
#[cfg(feature = "sys")]
|
||||||
pub use wasmer_engine_universal::{Universal, UniversalArtifact, UniversalEngine};
|
pub use sys::*;
|
||||||
|
|
||||||
#[cfg(feature = "dylib")]
|
#[cfg(feature = "js")]
|
||||||
pub use wasmer_engine_dylib::{Dylib, DylibArtifact, DylibEngine};
|
mod js;
|
||||||
|
|
||||||
/// Version number of this crate.
|
#[cfg(feature = "js")]
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub use js::*;
|
||||||
|
|
||||||
/// The Deprecated JIT Engine (please use `Universal` instead)
|
|
||||||
#[cfg(feature = "jit")]
|
|
||||||
#[deprecated(since = "2.0.0", note = "Please use the `universal` feature instead")]
|
|
||||||
pub type JIT = Universal;
|
|
||||||
|
|
||||||
/// The Deprecated Native Engine (please use `Dylib` instead)
|
|
||||||
#[cfg(feature = "native")]
|
|
||||||
#[deprecated(since = "2.0.0", note = "Please use the `native` feature instead")]
|
|
||||||
pub type Native = Dylib;
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{ExportError, Instance};
|
use crate::sys::{ExportError, Instance};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// An error while initializing the user supplied host env with the `WasmerEnv` trait.
|
/// An error while initializing the user supplied host env with the `WasmerEnv` trait.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::externals::{Extern, Function, Global, Memory, Table};
|
use crate::sys::externals::{Extern, Function, Global, Memory, Table};
|
||||||
use crate::import_object::LikeNamespace;
|
use crate::sys::import_object::LikeNamespace;
|
||||||
use crate::native::NativeFunc;
|
use crate::sys::native::NativeFunc;
|
||||||
use crate::WasmTypeList;
|
use crate::sys::WasmTypeList;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::exports::{ExportError, Exportable};
|
use crate::sys::exports::{ExportError, Exportable};
|
||||||
use crate::externals::Extern;
|
use crate::sys::externals::Extern;
|
||||||
use crate::store::Store;
|
use crate::sys::store::Store;
|
||||||
use crate::types::{Val, ValFuncRef};
|
use crate::sys::types::{Val, ValFuncRef};
|
||||||
use crate::FunctionType;
|
use crate::sys::FunctionType;
|
||||||
use crate::NativeFunc;
|
use crate::sys::NativeFunc;
|
||||||
use crate::RuntimeError;
|
use crate::sys::RuntimeError;
|
||||||
use crate::WasmerEnv;
|
use crate::sys::WasmerEnv;
|
||||||
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
|
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
|
||||||
|
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::exports::{ExportError, Exportable};
|
use crate::sys::exports::{ExportError, Exportable};
|
||||||
use crate::externals::Extern;
|
use crate::sys::externals::Extern;
|
||||||
use crate::store::{Store, StoreObject};
|
use crate::sys::store::{Store, StoreObject};
|
||||||
use crate::types::Val;
|
use crate::sys::types::Val;
|
||||||
use crate::GlobalType;
|
use crate::sys::GlobalType;
|
||||||
use crate::Mutability;
|
use crate::sys::Mutability;
|
||||||
use crate::RuntimeError;
|
use crate::sys::RuntimeError;
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::exports::{ExportError, Exportable};
|
use crate::sys::exports::{ExportError, Exportable};
|
||||||
use crate::externals::Extern;
|
use crate::sys::externals::Extern;
|
||||||
use crate::store::Store;
|
use crate::sys::store::Store;
|
||||||
use crate::{MemoryType, MemoryView};
|
use crate::sys::{MemoryType, MemoryView};
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
@@ -34,7 +34,7 @@ impl Memory {
|
|||||||
/// Creates a new host `Memory` from the provided [`MemoryType`].
|
/// Creates a new host `Memory` from the provided [`MemoryType`].
|
||||||
///
|
///
|
||||||
/// This function will construct the `Memory` using the store
|
/// This function will construct the `Memory` using the store
|
||||||
/// [`BaseTunables`][crate::tunables::BaseTunables].
|
/// [`BaseTunables`][crate::sys::BaseTunables].
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
@@ -11,9 +11,9 @@ pub use self::global::Global;
|
|||||||
pub use self::memory::Memory;
|
pub use self::memory::Memory;
|
||||||
pub use self::table::Table;
|
pub use self::table::Table;
|
||||||
|
|
||||||
use crate::exports::{ExportError, Exportable};
|
use crate::sys::exports::{ExportError, Exportable};
|
||||||
use crate::store::{Store, StoreObject};
|
use crate::sys::store::{Store, StoreObject};
|
||||||
use crate::ExternType;
|
use crate::sys::ExternType;
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use wasmer_engine::Export;
|
use wasmer_engine::Export;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::exports::{ExportError, Exportable};
|
use crate::sys::exports::{ExportError, Exportable};
|
||||||
use crate::externals::Extern;
|
use crate::sys::externals::Extern;
|
||||||
use crate::store::Store;
|
use crate::sys::store::Store;
|
||||||
use crate::types::{Val, ValFuncRef};
|
use crate::sys::types::{Val, ValFuncRef};
|
||||||
use crate::RuntimeError;
|
use crate::sys::RuntimeError;
|
||||||
use crate::TableType;
|
use crate::sys::TableType;
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmer_engine::Export;
|
use wasmer_engine::Export;
|
||||||
@@ -38,7 +38,7 @@ impl Table {
|
|||||||
/// All the elements in the table will be set to the `init` value.
|
/// All the elements in the table will be set to the `init` value.
|
||||||
///
|
///
|
||||||
/// This function will construct the `Table` using the store
|
/// This function will construct the `Table` using the store
|
||||||
/// [`BaseTunables`][crate::tunables::BaseTunables].
|
/// [`BaseTunables`][crate::sys::BaseTunables].
|
||||||
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> {
|
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> {
|
||||||
let item = init.into_table_reference(store)?;
|
let item = init.into_table_reference(store)?;
|
||||||
let tunables = store.tunables();
|
let tunables = store.tunables();
|
||||||
@@ -247,7 +247,7 @@ macro_rules! import_namespace {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{Global, Store, Val};
|
use crate::sys::{Global, Store, Val};
|
||||||
use wasmer_engine::ChainableNamedResolver;
|
use wasmer_engine::ChainableNamedResolver;
|
||||||
use wasmer_types::Type;
|
use wasmer_types::Type;
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn imports_macro_allows_trailing_comma_and_none() {
|
fn imports_macro_allows_trailing_comma_and_none() {
|
||||||
use crate::Function;
|
use crate::sys::Function;
|
||||||
|
|
||||||
let store = Default::default();
|
let store = Default::default();
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::exports::Exports;
|
use crate::sys::exports::Exports;
|
||||||
use crate::externals::Extern;
|
use crate::sys::externals::Extern;
|
||||||
use crate::module::Module;
|
use crate::sys::module::Module;
|
||||||
use crate::store::Store;
|
use crate::sys::store::Store;
|
||||||
use crate::{HostEnvInitError, LinkError, RuntimeError};
|
use crate::sys::{HostEnvInitError, LinkError, RuntimeError};
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
129
lib/api/src/sys/mod.rs
Normal file
129
lib/api/src/sys/mod.rs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
mod cell;
|
||||||
|
mod env;
|
||||||
|
mod exports;
|
||||||
|
mod externals;
|
||||||
|
mod import_object;
|
||||||
|
mod instance;
|
||||||
|
mod module;
|
||||||
|
mod native;
|
||||||
|
mod ptr;
|
||||||
|
mod store;
|
||||||
|
mod tunables;
|
||||||
|
mod types;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
/// Implement [`WasmerEnv`] for your type with `#[derive(WasmerEnv)]`.
|
||||||
|
///
|
||||||
|
/// See the [`WasmerEnv`] trait for more information.
|
||||||
|
pub use wasmer_derive::WasmerEnv;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
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
|
||||||
|
//! `wasmer-vm`. Please don't use any of this types directly, as
|
||||||
|
//! they might change frequently or be removed in the future.
|
||||||
|
|
||||||
|
pub use crate::sys::externals::{WithEnv, WithoutEnv};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use crate::sys::cell::WasmCell;
|
||||||
|
pub use crate::sys::env::{HostEnvInitError, LazyInit, WasmerEnv};
|
||||||
|
pub use crate::sys::exports::{ExportError, Exportable, Exports, ExportsIterator};
|
||||||
|
pub use crate::sys::externals::{
|
||||||
|
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList,
|
||||||
|
};
|
||||||
|
pub use crate::sys::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
|
||||||
|
pub use crate::sys::instance::{Instance, InstantiationError};
|
||||||
|
pub use crate::sys::module::Module;
|
||||||
|
pub use crate::sys::native::NativeFunc;
|
||||||
|
pub use crate::sys::ptr::{Array, Item, WasmPtr};
|
||||||
|
pub use crate::sys::store::{Store, StoreObject};
|
||||||
|
pub use crate::sys::tunables::BaseTunables;
|
||||||
|
pub use crate::sys::types::{
|
||||||
|
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
|
||||||
|
TableType, Val, ValType,
|
||||||
|
};
|
||||||
|
pub use crate::sys::types::{Val as Value, ValType as Type};
|
||||||
|
pub use crate::sys::utils::is_wasm;
|
||||||
|
pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST};
|
||||||
|
#[cfg(feature = "compiler")]
|
||||||
|
pub use wasmer_compiler::{
|
||||||
|
wasmparser, CompilerConfig, FunctionMiddleware, MiddlewareError, MiddlewareReaderState,
|
||||||
|
ModuleMiddleware,
|
||||||
|
};
|
||||||
|
pub use wasmer_compiler::{
|
||||||
|
CompileError, CpuFeature, Features, ParseCpuFeatureError, Target, WasmError, WasmResult,
|
||||||
|
};
|
||||||
|
pub use wasmer_engine::{
|
||||||
|
ChainableNamedResolver, DeserializeError, Engine, Export, FrameInfo, LinkError, NamedResolver,
|
||||||
|
NamedResolverChain, Resolver, RuntimeError, SerializeError, Tunables,
|
||||||
|
};
|
||||||
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
pub use wasmer_types::ExternRef;
|
||||||
|
pub use wasmer_types::{
|
||||||
|
Atomically, Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
|
||||||
|
WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: should those be moved into wasmer::vm as well?
|
||||||
|
pub use wasmer_vm::{raise_user_trap, MemoryError};
|
||||||
|
pub mod vm {
|
||||||
|
//! The `vm` module re-exports wasmer-vm types.
|
||||||
|
|
||||||
|
pub use wasmer_vm::{
|
||||||
|
Memory, MemoryError, MemoryStyle, Table, TableStyle, VMExtern, VMMemoryDefinition,
|
||||||
|
VMTableDefinition,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wat")]
|
||||||
|
pub use wat::parse_bytes as wat2wasm;
|
||||||
|
|
||||||
|
// The compilers are mutually exclusive
|
||||||
|
#[cfg(any(
|
||||||
|
all(
|
||||||
|
feature = "default-llvm",
|
||||||
|
any(feature = "default-cranelift", feature = "default-singlepass")
|
||||||
|
),
|
||||||
|
all(feature = "default-cranelift", feature = "default-singlepass")
|
||||||
|
))]
|
||||||
|
compile_error!(
|
||||||
|
r#"The `default-singlepass`, `default-cranelift` and `default-llvm` features are mutually exclusive.
|
||||||
|
If you wish to use more than one compiler, you can simply create the own store. Eg.:
|
||||||
|
|
||||||
|
```
|
||||||
|
use wasmer::{Store, Universal, Singlepass};
|
||||||
|
|
||||||
|
let engine = Universal::new(Singlepass::default()).engine();
|
||||||
|
let store = Store::new(&engine);
|
||||||
|
```"#
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "singlepass")]
|
||||||
|
pub use wasmer_compiler_singlepass::Singlepass;
|
||||||
|
|
||||||
|
#[cfg(feature = "cranelift")]
|
||||||
|
pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel};
|
||||||
|
|
||||||
|
#[cfg(feature = "llvm")]
|
||||||
|
pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM};
|
||||||
|
|
||||||
|
#[cfg(feature = "universal")]
|
||||||
|
pub use wasmer_engine_universal::{Universal, UniversalArtifact, UniversalEngine};
|
||||||
|
|
||||||
|
#[cfg(feature = "dylib")]
|
||||||
|
pub use wasmer_engine_dylib::{Dylib, DylibArtifact, DylibEngine};
|
||||||
|
|
||||||
|
/// Version number of this crate.
|
||||||
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
/// The Deprecated JIT Engine (please use `Universal` instead)
|
||||||
|
#[cfg(feature = "jit")]
|
||||||
|
#[deprecated(since = "2.0.0", note = "Please use the `universal` feature instead")]
|
||||||
|
pub type JIT = Universal;
|
||||||
|
|
||||||
|
/// The Deprecated Native Engine (please use `Dylib` instead)
|
||||||
|
#[cfg(feature = "native")]
|
||||||
|
#[deprecated(since = "2.0.0", note = "Please use the `native` feature instead")]
|
||||||
|
pub type Native = Dylib;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::store::Store;
|
use crate::sys::store::Store;
|
||||||
use crate::types::{ExportType, ImportType};
|
use crate::sys::types::{ExportType, ImportType};
|
||||||
use crate::InstantiationError;
|
use crate::sys::InstantiationError;
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
//! ```
|
//! ```
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::externals::function::{DynamicFunction, VMDynamicFunction};
|
use crate::sys::externals::function::{DynamicFunction, VMDynamicFunction};
|
||||||
use crate::{FromToNativeWasmType, Function, RuntimeError, Store, WasmTypeList};
|
use crate::sys::{FromToNativeWasmType, Function, RuntimeError, Store, WasmTypeList};
|
||||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
use wasmer_engine::ExportFunction;
|
use wasmer_engine::ExportFunction;
|
||||||
use wasmer_types::NativeWasmType;
|
use wasmer_types::NativeWasmType;
|
||||||
@@ -223,14 +223,14 @@ macro_rules! impl_native_traits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_parens)]
|
#[allow(unused_parens)]
|
||||||
impl<'a, $( $x, )* Rets> crate::exports::ExportableWithGenerics<'a, ($( $x ),*), Rets> for NativeFunc<( $( $x ),* ), Rets>
|
impl<'a, $( $x, )* Rets> crate::sys::exports::ExportableWithGenerics<'a, ($( $x ),*), Rets> for NativeFunc<( $( $x ),* ), Rets>
|
||||||
where
|
where
|
||||||
$( $x: FromToNativeWasmType, )*
|
$( $x: FromToNativeWasmType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
fn get_self_from_extern_with_generics(_extern: &crate::externals::Extern) -> Result<Self, crate::exports::ExportError> {
|
fn get_self_from_extern_with_generics(_extern: &crate::sys::externals::Extern) -> Result<Self, crate::sys::exports::ExportError> {
|
||||||
use crate::exports::Exportable;
|
use crate::sys::exports::Exportable;
|
||||||
crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::exports::ExportError::IncompatibleType)
|
crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::sys::exports::ExportError::IncompatibleType)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_weak_instance_ref(&mut self) {
|
fn into_weak_instance_ref(&mut self) {
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
//! Therefore, you should use this abstraction whenever possible to avoid memory
|
//! Therefore, you should use this abstraction whenever possible to avoid memory
|
||||||
//! related bugs when implementing an ABI.
|
//! related bugs when implementing an ABI.
|
||||||
|
|
||||||
use crate::cell::WasmCell;
|
use crate::sys::cell::WasmCell;
|
||||||
use crate::{externals::Memory, FromToNativeWasmType};
|
use crate::sys::{externals::Memory, FromToNativeWasmType};
|
||||||
use std::{cell::Cell, fmt, marker::PhantomData, mem};
|
use std::{cell::Cell, fmt, marker::PhantomData, mem};
|
||||||
use wasmer_types::ValueType;
|
use wasmer_types::ValueType;
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ impl<T: Copy, Ty> fmt::Debug for WasmPtr<T, Ty> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{Memory, MemoryType, Store};
|
use crate::sys::{Memory, MemoryType, Store};
|
||||||
|
|
||||||
/// Ensure that memory accesses work on the edges of memory and that out of
|
/// Ensure that memory accesses work on the edges of memory and that out of
|
||||||
/// bounds errors are caught with `deref`
|
/// bounds errors are caught with `deref`
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::tunables::BaseTunables;
|
use crate::sys::tunables::BaseTunables;
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{MemoryType, Pages, TableType};
|
use crate::sys::{MemoryType, Pages, TableType};
|
||||||
use loupe::MemoryUsage;
|
use loupe::MemoryUsage;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::externals::Function;
|
use crate::sys::externals::Function;
|
||||||
use crate::store::{Store, StoreObject};
|
use crate::sys::store::{Store, StoreObject};
|
||||||
use crate::RuntimeError;
|
use crate::sys::RuntimeError;
|
||||||
use wasmer_types::Value;
|
use wasmer_types::Value;
|
||||||
pub use wasmer_types::{
|
pub use wasmer_types::{
|
||||||
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
|
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
|
||||||
@@ -1,334 +0,0 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use wasmer::*;
|
|
||||||
use wasmer_vm::WeakOrStrongInstanceRef;
|
|
||||||
|
|
||||||
const MEM_WAT: &str = "
|
|
||||||
(module
|
|
||||||
(func $host_fn (import \"env\" \"host_fn\") (param) (result))
|
|
||||||
(func (export \"call_host_fn\") (param) (result)
|
|
||||||
(call $host_fn))
|
|
||||||
|
|
||||||
(memory $mem 0)
|
|
||||||
(export \"memory\" (memory $mem))
|
|
||||||
)
|
|
||||||
";
|
|
||||||
|
|
||||||
const GLOBAL_WAT: &str = "
|
|
||||||
(module
|
|
||||||
(func $host_fn (import \"env\" \"host_fn\") (param) (result))
|
|
||||||
(func (export \"call_host_fn\") (param) (result)
|
|
||||||
(call $host_fn))
|
|
||||||
|
|
||||||
(global $global i32 (i32.const 11))
|
|
||||||
(export \"global\" (global $global))
|
|
||||||
)
|
|
||||||
";
|
|
||||||
|
|
||||||
const TABLE_WAT: &str = "
|
|
||||||
(module
|
|
||||||
(func $host_fn (import \"env\" \"host_fn\") (param) (result))
|
|
||||||
(func (export \"call_host_fn\") (param) (result)
|
|
||||||
(call $host_fn))
|
|
||||||
|
|
||||||
(table $table 4 4 funcref)
|
|
||||||
(export \"table\" (table $table))
|
|
||||||
)
|
|
||||||
";
|
|
||||||
|
|
||||||
const FUNCTION_WAT: &str = "
|
|
||||||
(module
|
|
||||||
(func $host_fn (import \"env\" \"host_fn\") (param) (result))
|
|
||||||
(func (export \"call_host_fn\") (param) (result)
|
|
||||||
(call $host_fn))
|
|
||||||
)
|
|
||||||
";
|
|
||||||
|
|
||||||
fn is_memory_instance_ref_strong(memory: &Memory) -> Option<bool> {
|
|
||||||
// This is safe because we're calling it from a test to test the internals
|
|
||||||
unsafe {
|
|
||||||
memory
|
|
||||||
.get_vm_memory()
|
|
||||||
.instance_ref
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_table_instance_ref_strong(table: &Table) -> Option<bool> {
|
|
||||||
// This is safe because we're calling it from a test to test the internals
|
|
||||||
unsafe {
|
|
||||||
table
|
|
||||||
.get_vm_table()
|
|
||||||
.instance_ref
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_global_instance_ref_strong(global: &Global) -> Option<bool> {
|
|
||||||
// This is safe because we're calling it from a test to test the internals
|
|
||||||
unsafe {
|
|
||||||
global
|
|
||||||
.get_vm_global()
|
|
||||||
.instance_ref
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_function_instance_ref_strong(f: &Function) -> Option<bool> {
|
|
||||||
// This is safe because we're calling it from a test to test the internals
|
|
||||||
unsafe {
|
|
||||||
f.get_vm_function()
|
|
||||||
.instance_ref
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_native_function_instance_ref_strong<Args, Rets>(f: &NativeFunc<Args, Rets>) -> Option<bool>
|
|
||||||
where
|
|
||||||
Args: WasmTypeList,
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
{
|
|
||||||
// This is safe because we're calling it from a test to test the internals
|
|
||||||
unsafe {
|
|
||||||
f.get_vm_function()
|
|
||||||
.instance_ref
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn strong_weak_behavior_works_memory() -> Result<()> {
|
|
||||||
#[derive(Clone, Debug, WasmerEnv, Default)]
|
|
||||||
struct MemEnv {
|
|
||||||
#[wasmer(export)]
|
|
||||||
memory: LazyInit<Memory>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let host_fn = |env: &MemEnv| {
|
|
||||||
let mem = env.memory_ref().unwrap();
|
|
||||||
assert_eq!(is_memory_instance_ref_strong(&mem), Some(false));
|
|
||||||
let mem_clone = mem.clone();
|
|
||||||
assert_eq!(is_memory_instance_ref_strong(&mem_clone), Some(true));
|
|
||||||
assert_eq!(is_memory_instance_ref_strong(&mem), Some(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(&store, MEM_WAT)?;
|
|
||||||
let env = MemEnv::default();
|
|
||||||
|
|
||||||
let instance = Instance::new(
|
|
||||||
&module,
|
|
||||||
&imports! {
|
|
||||||
"env" => {
|
|
||||||
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mem = instance.exports.get_memory("memory")?;
|
|
||||||
assert_eq!(is_memory_instance_ref_strong(&mem), Some(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
|
||||||
f.call()?;
|
|
||||||
f
|
|
||||||
};
|
|
||||||
f.call()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn strong_weak_behavior_works_global() -> Result<()> {
|
|
||||||
#[derive(Clone, Debug, WasmerEnv, Default)]
|
|
||||||
struct GlobalEnv {
|
|
||||||
#[wasmer(export)]
|
|
||||||
global: LazyInit<Global>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let host_fn = |env: &GlobalEnv| {
|
|
||||||
let global = env.global_ref().unwrap();
|
|
||||||
assert_eq!(is_global_instance_ref_strong(&global), Some(false));
|
|
||||||
let global_clone = global.clone();
|
|
||||||
assert_eq!(is_global_instance_ref_strong(&global_clone), Some(true));
|
|
||||||
assert_eq!(is_global_instance_ref_strong(&global), Some(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(&store, GLOBAL_WAT)?;
|
|
||||||
let env = GlobalEnv::default();
|
|
||||||
|
|
||||||
let instance = Instance::new(
|
|
||||||
&module,
|
|
||||||
&imports! {
|
|
||||||
"env" => {
|
|
||||||
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
{
|
|
||||||
let global = instance.exports.get_global("global")?;
|
|
||||||
assert_eq!(is_global_instance_ref_strong(&global), Some(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
|
||||||
f.call()?;
|
|
||||||
f
|
|
||||||
};
|
|
||||||
f.call()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn strong_weak_behavior_works_table() -> Result<()> {
|
|
||||||
#[derive(Clone, WasmerEnv, Default)]
|
|
||||||
struct TableEnv {
|
|
||||||
#[wasmer(export)]
|
|
||||||
table: LazyInit<Table>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let host_fn = |env: &TableEnv| {
|
|
||||||
let table = env.table_ref().unwrap();
|
|
||||||
assert_eq!(is_table_instance_ref_strong(&table), Some(false));
|
|
||||||
let table_clone = table.clone();
|
|
||||||
assert_eq!(is_table_instance_ref_strong(&table_clone), Some(true));
|
|
||||||
assert_eq!(is_table_instance_ref_strong(&table), Some(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(&store, TABLE_WAT)?;
|
|
||||||
let env = TableEnv::default();
|
|
||||||
|
|
||||||
let instance = Instance::new(
|
|
||||||
&module,
|
|
||||||
&imports! {
|
|
||||||
"env" => {
|
|
||||||
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
{
|
|
||||||
let table = instance.exports.get_table("table")?;
|
|
||||||
assert_eq!(is_table_instance_ref_strong(&table), Some(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
|
||||||
f.call()?;
|
|
||||||
f
|
|
||||||
};
|
|
||||||
f.call()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn strong_weak_behavior_works_function() -> Result<()> {
|
|
||||||
#[derive(Clone, WasmerEnv, Default)]
|
|
||||||
struct FunctionEnv {
|
|
||||||
#[wasmer(export)]
|
|
||||||
call_host_fn: LazyInit<Function>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let host_fn = |env: &FunctionEnv| {
|
|
||||||
let function = env.call_host_fn_ref().unwrap();
|
|
||||||
assert_eq!(is_function_instance_ref_strong(&function), Some(false));
|
|
||||||
let function_clone = function.clone();
|
|
||||||
assert_eq!(is_function_instance_ref_strong(&function_clone), Some(true));
|
|
||||||
assert_eq!(is_function_instance_ref_strong(&function), Some(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(&store, FUNCTION_WAT)?;
|
|
||||||
let env = FunctionEnv::default();
|
|
||||||
|
|
||||||
let instance = Instance::new(
|
|
||||||
&module,
|
|
||||||
&imports! {
|
|
||||||
"env" => {
|
|
||||||
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
{
|
|
||||||
let function = instance.exports.get_function("call_host_fn")?;
|
|
||||||
assert_eq!(is_function_instance_ref_strong(&function), Some(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
|
||||||
f.call()?;
|
|
||||||
f
|
|
||||||
};
|
|
||||||
f.call()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn strong_weak_behavior_works_native_function() -> Result<()> {
|
|
||||||
#[derive(Clone, WasmerEnv, Default)]
|
|
||||||
struct FunctionEnv {
|
|
||||||
#[wasmer(export)]
|
|
||||||
call_host_fn: LazyInit<NativeFunc<(), ()>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let host_fn = |env: &FunctionEnv| {
|
|
||||||
let function = env.call_host_fn_ref().unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
is_native_function_instance_ref_strong(&function),
|
|
||||||
Some(false)
|
|
||||||
);
|
|
||||||
let function_clone = function.clone();
|
|
||||||
assert_eq!(
|
|
||||||
is_native_function_instance_ref_strong(&function_clone),
|
|
||||||
Some(true)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
is_native_function_instance_ref_strong(&function),
|
|
||||||
Some(false)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(&store, FUNCTION_WAT)?;
|
|
||||||
let env = FunctionEnv::default();
|
|
||||||
|
|
||||||
let instance = Instance::new(
|
|
||||||
&module,
|
|
||||||
&imports! {
|
|
||||||
"env" => {
|
|
||||||
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
{
|
|
||||||
let function: NativeFunc<(), ()> =
|
|
||||||
instance.exports.get_native_function("call_host_fn")?;
|
|
||||||
assert_eq!(
|
|
||||||
is_native_function_instance_ref_strong(&function),
|
|
||||||
Some(true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
|
||||||
f.call()?;
|
|
||||||
f
|
|
||||||
};
|
|
||||||
f.call()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,458 +0,0 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use wasmer::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn global_new() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let global = Global::new(&store, Value::I32(10));
|
|
||||||
assert_eq!(
|
|
||||||
*global.ty(),
|
|
||||||
GlobalType {
|
|
||||||
ty: Type::I32,
|
|
||||||
mutability: Mutability::Const
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let global_mut = Global::new_mut(&store, Value::I32(10));
|
|
||||||
assert_eq!(
|
|
||||||
*global_mut.ty(),
|
|
||||||
GlobalType {
|
|
||||||
ty: Type::I32,
|
|
||||||
mutability: Mutability::Var
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn global_get() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let global_i32 = Global::new(&store, Value::I32(10));
|
|
||||||
assert_eq!(global_i32.get(), Value::I32(10));
|
|
||||||
let global_i64 = Global::new(&store, Value::I64(20));
|
|
||||||
assert_eq!(global_i64.get(), Value::I64(20));
|
|
||||||
let global_f32 = Global::new(&store, Value::F32(10.0));
|
|
||||||
assert_eq!(global_f32.get(), Value::F32(10.0));
|
|
||||||
let global_f64 = Global::new(&store, Value::F64(20.0));
|
|
||||||
assert_eq!(global_f64.get(), Value::F64(20.0));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn global_set() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let global_i32 = Global::new(&store, Value::I32(10));
|
|
||||||
// Set on a constant should error
|
|
||||||
assert!(global_i32.set(Value::I32(20)).is_err());
|
|
||||||
|
|
||||||
let global_i32_mut = Global::new_mut(&store, Value::I32(10));
|
|
||||||
// Set on different type should error
|
|
||||||
assert!(global_i32_mut.set(Value::I64(20)).is_err());
|
|
||||||
|
|
||||||
// Set on same type should succeed
|
|
||||||
global_i32_mut.set(Value::I32(20))?;
|
|
||||||
assert_eq!(global_i32_mut.get(), Value::I32(20));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn table_new() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let table_type = TableType {
|
|
||||||
ty: Type::FuncRef,
|
|
||||||
minimum: 0,
|
|
||||||
maximum: None,
|
|
||||||
};
|
|
||||||
let f = Function::new_native(&store, || {});
|
|
||||||
let table = Table::new(&store, table_type, Value::FuncRef(Some(f)))?;
|
|
||||||
assert_eq!(*table.ty(), table_type);
|
|
||||||
|
|
||||||
// Anyrefs not yet supported
|
|
||||||
// let table_type = TableType {
|
|
||||||
// ty: Type::ExternRef,
|
|
||||||
// minimum: 0,
|
|
||||||
// maximum: None,
|
|
||||||
// };
|
|
||||||
// let table = Table::new(&store, table_type, Value::ExternRef(ExternRef::Null))?;
|
|
||||||
// assert_eq!(*table.ty(), table_type);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn table_get() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let table_type = TableType {
|
|
||||||
ty: Type::FuncRef,
|
|
||||||
minimum: 0,
|
|
||||||
maximum: Some(1),
|
|
||||||
};
|
|
||||||
let f = Function::new_native(&store, |num: i32| num + 1);
|
|
||||||
let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
|
||||||
assert_eq!(*table.ty(), table_type);
|
|
||||||
let _elem = table.get(0).unwrap();
|
|
||||||
// assert_eq!(elem.funcref().unwrap(), f);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn table_set() -> Result<()> {
|
|
||||||
// Table set not yet tested
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn table_grow() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let table_type = TableType {
|
|
||||||
ty: Type::FuncRef,
|
|
||||||
minimum: 0,
|
|
||||||
maximum: Some(10),
|
|
||||||
};
|
|
||||||
let f = Function::new_native(&store, |num: i32| num + 1);
|
|
||||||
let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
|
||||||
// Growing to a bigger maximum should return None
|
|
||||||
let old_len = table.grow(12, Value::FuncRef(Some(f.clone())));
|
|
||||||
assert!(old_len.is_err());
|
|
||||||
|
|
||||||
// Growing to a bigger maximum should return None
|
|
||||||
let old_len = table.grow(5, Value::FuncRef(Some(f.clone())))?;
|
|
||||||
assert_eq!(old_len, 0);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn table_copy() -> Result<()> {
|
|
||||||
// TODO: table copy test not yet implemented
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn memory_new() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let memory_type = MemoryType {
|
|
||||||
shared: false,
|
|
||||||
minimum: Pages(0),
|
|
||||||
maximum: Some(Pages(10)),
|
|
||||||
};
|
|
||||||
let memory = Memory::new(&store, memory_type)?;
|
|
||||||
assert_eq!(memory.size(), Pages(0));
|
|
||||||
assert_eq!(memory.ty(), memory_type);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn memory_grow() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
|
|
||||||
let desc = MemoryType::new(Pages(10), Some(Pages(16)), false);
|
|
||||||
let memory = Memory::new(&store, desc)?;
|
|
||||||
assert_eq!(memory.size(), Pages(10));
|
|
||||||
|
|
||||||
let result = memory.grow(Pages(2)).unwrap();
|
|
||||||
assert_eq!(result, Pages(10));
|
|
||||||
assert_eq!(memory.size(), Pages(12));
|
|
||||||
|
|
||||||
let result = memory.grow(Pages(10));
|
|
||||||
assert_eq!(
|
|
||||||
result,
|
|
||||||
Err(MemoryError::CouldNotGrow {
|
|
||||||
current: 12.into(),
|
|
||||||
attempted_delta: 10.into()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
let bad_desc = MemoryType::new(Pages(15), Some(Pages(10)), false);
|
|
||||||
let bad_result = Memory::new(&store, bad_desc);
|
|
||||||
|
|
||||||
assert!(matches!(bad_result, Err(MemoryError::InvalidMemory { .. })));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn function_new() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let function = Function::new_native(&store, || {});
|
|
||||||
assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
|
|
||||||
let function = Function::new_native(&store, |_a: i32| {});
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![Type::I32], vec![])
|
|
||||||
);
|
|
||||||
let function = Function::new_native(&store, |_a: i32, _b: i64, _c: f32, _d: f64| {});
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
|
||||||
);
|
|
||||||
let function = Function::new_native(&store, || -> i32 { 1 });
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32])
|
|
||||||
);
|
|
||||||
let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn function_new_env() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
#[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![]));
|
|
||||||
let function =
|
|
||||||
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv, _a: i32| {});
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![Type::I32], vec![])
|
|
||||||
);
|
|
||||||
let function = Function::new_native_with_env(
|
|
||||||
&store,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _a: i32, _b: i64, _c: f32, _d: f64| {},
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
|
||||||
);
|
|
||||||
let function =
|
|
||||||
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| -> i32 { 1 });
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32])
|
|
||||||
);
|
|
||||||
let function = Function::new_native_with_env(
|
|
||||||
&store,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn function_new_dynamic() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
|
|
||||||
// Using &FunctionType signature
|
|
||||||
let function_type = FunctionType::new(vec![], vec![]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
|
|
||||||
// Using array signature
|
|
||||||
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
|
||||||
let function = Function::new(&store, function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().params(), [Type::V128]);
|
|
||||||
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn function_new_dynamic_env() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
#[derive(Clone, WasmerEnv)]
|
|
||||||
struct MyEnv {}
|
|
||||||
let my_env = MyEnv {};
|
|
||||||
|
|
||||||
// Using &FunctionType signature
|
|
||||||
let function_type = FunctionType::new(vec![], vec![]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
|
|
||||||
// Using array signature
|
|
||||||
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().params(), [Type::V128]);
|
|
||||||
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn native_function_works() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let function = Function::new_native(&store, || {});
|
|
||||||
let native_function: NativeFunc<(), ()> = function.native().unwrap();
|
|
||||||
let result = native_function.call();
|
|
||||||
assert!(result.is_ok());
|
|
||||||
|
|
||||||
let function = Function::new_native(&store, |a: i32| -> i32 { a + 1 });
|
|
||||||
let native_function: NativeFunc<i32, i32> = function.native().unwrap();
|
|
||||||
assert_eq!(native_function.call(3).unwrap(), 4);
|
|
||||||
|
|
||||||
fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
|
|
||||||
(a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
|
|
||||||
}
|
|
||||||
let function = Function::new_native(&store, rust_abi);
|
|
||||||
let native_function: NativeFunc<(i32, i64, f32, f64), u64> = function.native().unwrap();
|
|
||||||
assert_eq!(native_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
|
|
||||||
|
|
||||||
let function = Function::new_native(&store, || -> i32 { 1 });
|
|
||||||
let native_function: NativeFunc<(), i32> = function.native().unwrap();
|
|
||||||
assert_eq!(native_function.call().unwrap(), 1);
|
|
||||||
|
|
||||||
let function = Function::new_native(&store, |_a: i32| {});
|
|
||||||
let native_function: NativeFunc<i32, ()> = function.native().unwrap();
|
|
||||||
assert!(native_function.call(4).is_ok());
|
|
||||||
|
|
||||||
let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
|
||||||
let native_function: NativeFunc<(), (i32, i64, f32, f64)> = function.native().unwrap();
|
|
||||||
assert_eq!(native_function.call().unwrap(), (1, 2, 3.0, 4.0));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn function_outlives_instance() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(type $sum_t (func (param i32 i32) (result i32)))
|
|
||||||
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
|
||||||
local.get $x
|
|
||||||
local.get $y
|
|
||||||
i32.add)
|
|
||||||
(export "sum" (func $sum_f)))
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let f = {
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let instance = Instance::new(&module, &imports! {})?;
|
|
||||||
let f: NativeFunc<(i32, i32), i32> = instance.exports.get_native_function("sum")?;
|
|
||||||
|
|
||||||
assert_eq!(f.call(4, 5)?, 9);
|
|
||||||
f
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(f.call(4, 5)?, 9);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn weak_instance_ref_externs_after_instance() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(memory (export "mem") 1)
|
|
||||||
(type $sum_t (func (param i32 i32) (result i32)))
|
|
||||||
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
|
||||||
local.get $x
|
|
||||||
local.get $y
|
|
||||||
i32.add)
|
|
||||||
(export "sum" (func $sum_f)))
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let f = {
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let instance = Instance::new(&module, &imports! {})?;
|
|
||||||
let f: NativeFunc<(i32, i32), i32> = instance.exports.get_with_generics_weak("sum")?;
|
|
||||||
|
|
||||||
assert_eq!(f.call(4, 5)?, 9);
|
|
||||||
f
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(f.call(4, 5)?, 9);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn manually_generate_wasmer_env() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
#[derive(WasmerEnv, Clone)]
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use wasmer::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exports_work_after_multiple_instances_have_been_freed() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(
|
|
||||||
&store,
|
|
||||||
"
|
|
||||||
(module
|
|
||||||
(type $sum_t (func (param i32 i32) (result i32)))
|
|
||||||
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
|
||||||
local.get $x
|
|
||||||
local.get $y
|
|
||||||
i32.add)
|
|
||||||
(export \"sum\" (func $sum_f)))
|
|
||||||
",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let import_object = ImportObject::new();
|
|
||||||
let instance = Instance::new(&module, &import_object)?;
|
|
||||||
let instance2 = instance.clone();
|
|
||||||
let instance3 = instance.clone();
|
|
||||||
|
|
||||||
// The function is cloned to “break” the connection with `instance`.
|
|
||||||
let sum = instance.exports.get_function("sum")?.clone();
|
|
||||||
|
|
||||||
drop(instance);
|
|
||||||
drop(instance2);
|
|
||||||
drop(instance3);
|
|
||||||
|
|
||||||
// All instances have been dropped, but `sum` continues to work!
|
|
||||||
assert_eq!(
|
|
||||||
sum.call(&[Value::I32(1), Value::I32(2)])?.into_vec(),
|
|
||||||
vec![Value::I32(3)],
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
425
lib/api/tests/js_externals.rs
Normal file
425
lib/api/tests/js_externals.rs
Normal file
@@ -0,0 +1,425 @@
|
|||||||
|
#[cfg(feature = "js")]
|
||||||
|
mod js {
|
||||||
|
use wasm_bindgen_test::*;
|
||||||
|
use wasmer::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn global_new() {
|
||||||
|
let store = Store::default();
|
||||||
|
let global = Global::new(&store, Value::I32(10));
|
||||||
|
assert_eq!(
|
||||||
|
*global.ty(),
|
||||||
|
GlobalType {
|
||||||
|
ty: Type::I32,
|
||||||
|
mutability: Mutability::Const
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let global_mut = Global::new_mut(&store, Value::I32(10));
|
||||||
|
assert_eq!(
|
||||||
|
*global_mut.ty(),
|
||||||
|
GlobalType {
|
||||||
|
ty: Type::I32,
|
||||||
|
mutability: Mutability::Var
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn global_get() {
|
||||||
|
let store = Store::default();
|
||||||
|
let global_i32 = Global::new(&store, Value::I32(10));
|
||||||
|
assert_eq!(global_i32.get(), Value::I32(10));
|
||||||
|
// 64-bit values are not yet fully supported in some versions of Node
|
||||||
|
// Commenting this tests for now:
|
||||||
|
|
||||||
|
// let global_i64 = Global::new(&store, Value::I64(20));
|
||||||
|
// assert_eq!(global_i64.get(), Value::I64(20));
|
||||||
|
let global_f32 = Global::new(&store, Value::F32(10.0));
|
||||||
|
assert_eq!(global_f32.get(), Value::F32(10.0));
|
||||||
|
// let global_f64 = Global::new(&store, Value::F64(20.0));
|
||||||
|
// assert_eq!(global_f64.get(), Value::F64(20.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn global_set() {
|
||||||
|
let store = Store::default();
|
||||||
|
let global_i32 = Global::new(&store, Value::I32(10));
|
||||||
|
// Set on a constant should error
|
||||||
|
assert!(global_i32.set(Value::I32(20)).is_err());
|
||||||
|
|
||||||
|
let global_i32_mut = Global::new_mut(&store, Value::I32(10));
|
||||||
|
// Set on different type should error
|
||||||
|
assert!(global_i32_mut.set(Value::I64(20)).is_err());
|
||||||
|
|
||||||
|
// Set on same type should succeed
|
||||||
|
global_i32_mut.set(Value::I32(20)).unwrap();
|
||||||
|
assert_eq!(global_i32_mut.get(), Value::I32(20));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn table_new() {
|
||||||
|
let store = Store::default();
|
||||||
|
let table_type = TableType {
|
||||||
|
ty: Type::FuncRef,
|
||||||
|
minimum: 0,
|
||||||
|
maximum: None,
|
||||||
|
};
|
||||||
|
let f = Function::new_native(&store, || {});
|
||||||
|
let table = Table::new(&store, table_type, Value::FuncRef(Some(f))).unwrap();
|
||||||
|
assert_eq!(*table.ty(), table_type);
|
||||||
|
|
||||||
|
// table.get()
|
||||||
|
// Anyrefs not yet supported
|
||||||
|
// let table_type = TableType {
|
||||||
|
// ty: Type::ExternRef,
|
||||||
|
// minimum: 0,
|
||||||
|
// maximum: None,
|
||||||
|
// };
|
||||||
|
// let table = Table::new(&store, table_type, Value::ExternRef(ExternRef::Null))?;
|
||||||
|
// assert_eq!(*table.ty(), table_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tables are not yet fully supported in Wasm
|
||||||
|
// Commenting this tests for now
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// #[ignore]
|
||||||
|
// fn table_get() -> Result<()> {
|
||||||
|
// let store = Store::default();
|
||||||
|
// let table_type = TableType {
|
||||||
|
// ty: Type::FuncRef,
|
||||||
|
// minimum: 0,
|
||||||
|
// maximum: Some(1),
|
||||||
|
// };
|
||||||
|
// let f = Function::new_native(&store, |num: i32| num + 1);
|
||||||
|
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
||||||
|
// assert_eq!(*table.ty(), table_type);
|
||||||
|
// let _elem = table.get(0).unwrap();
|
||||||
|
// // assert_eq!(elem.funcref().unwrap(), f);
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// #[ignore]
|
||||||
|
// fn table_set() -> Result<()> {
|
||||||
|
// // Table set not yet tested
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn table_grow() -> Result<()> {
|
||||||
|
// let store = Store::default();
|
||||||
|
// let table_type = TableType {
|
||||||
|
// ty: Type::FuncRef,
|
||||||
|
// minimum: 0,
|
||||||
|
// maximum: Some(10),
|
||||||
|
// };
|
||||||
|
// let f = Function::new_native(&store, |num: i32| num + 1);
|
||||||
|
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
||||||
|
// // Growing to a bigger maximum should return None
|
||||||
|
// let old_len = table.grow(12, Value::FuncRef(Some(f.clone())));
|
||||||
|
// assert!(old_len.is_err());
|
||||||
|
|
||||||
|
// // Growing to a bigger maximum should return None
|
||||||
|
// let old_len = table.grow(5, Value::FuncRef(Some(f.clone())))?;
|
||||||
|
// assert_eq!(old_len, 0);
|
||||||
|
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// #[ignore]
|
||||||
|
// fn table_copy() -> Result<()> {
|
||||||
|
// // TODO: table copy test not yet implemented
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn memory_new() {
|
||||||
|
let store = Store::default();
|
||||||
|
let memory_type = MemoryType {
|
||||||
|
shared: false,
|
||||||
|
minimum: Pages(0),
|
||||||
|
maximum: Some(Pages(10)),
|
||||||
|
};
|
||||||
|
let memory = Memory::new(&store, memory_type).unwrap();
|
||||||
|
assert_eq!(memory.size(), Pages(0));
|
||||||
|
assert_eq!(memory.ty(), memory_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn memory_grow() {
|
||||||
|
let store = Store::default();
|
||||||
|
|
||||||
|
let desc = MemoryType::new(Pages(10), Some(Pages(16)), false);
|
||||||
|
let memory = Memory::new(&store, desc).unwrap();
|
||||||
|
assert_eq!(memory.size(), Pages(10));
|
||||||
|
|
||||||
|
let result = memory.grow(Pages(2)).unwrap();
|
||||||
|
assert_eq!(result, Pages(10));
|
||||||
|
assert_eq!(memory.size(), Pages(12));
|
||||||
|
|
||||||
|
let result = memory.grow(Pages(10));
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
Err(MemoryError::CouldNotGrow {
|
||||||
|
current: 12.into(),
|
||||||
|
attempted_delta: 10.into()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn function_new() {
|
||||||
|
let store = Store::default();
|
||||||
|
let function = Function::new_native(&store, || {});
|
||||||
|
assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
|
||||||
|
let function = Function::new_native(&store, |_a: i32| {});
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![Type::I32], vec![])
|
||||||
|
);
|
||||||
|
let function = Function::new_native(&store, |_a: i32, _b: i64, _c: f32, _d: f64| {});
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
||||||
|
);
|
||||||
|
let function = Function::new_native(&store, || -> i32 { 1 });
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32])
|
||||||
|
);
|
||||||
|
let function =
|
||||||
|
Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn function_new_env() {
|
||||||
|
let store = Store::default();
|
||||||
|
#[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![]));
|
||||||
|
let function =
|
||||||
|
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv, _a: i32| {});
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![Type::I32], vec![])
|
||||||
|
);
|
||||||
|
let function = Function::new_native_with_env(
|
||||||
|
&store,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _a: i32, _b: i64, _c: f32, _d: f64| {},
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
||||||
|
);
|
||||||
|
let function =
|
||||||
|
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| -> i32 { 1 });
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32])
|
||||||
|
);
|
||||||
|
let function = Function::new_native_with_env(
|
||||||
|
&store,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn function_new_dynamic() {
|
||||||
|
let store = Store::default();
|
||||||
|
|
||||||
|
// Using &FunctionType signature
|
||||||
|
let function_type = FunctionType::new(vec![], vec![]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type =
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type =
|
||||||
|
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
|
||||||
|
// Using array signature
|
||||||
|
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
||||||
|
let function = Function::new(&store, function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().params(), [Type::V128]);
|
||||||
|
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn function_new_dynamic_env() {
|
||||||
|
let store = Store::default();
|
||||||
|
#[derive(Clone, WasmerEnv)]
|
||||||
|
struct MyEnv {}
|
||||||
|
let my_env = MyEnv {};
|
||||||
|
|
||||||
|
// Using &FunctionType signature
|
||||||
|
let function_type = FunctionType::new(vec![], vec![]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type =
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type =
|
||||||
|
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
|
||||||
|
// Using array signature
|
||||||
|
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().params(), [Type::V128]);
|
||||||
|
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn native_function_works() {
|
||||||
|
let store = Store::default();
|
||||||
|
let function = Function::new_native(&store, || {});
|
||||||
|
let native_function: NativeFunc<(), ()> = function.native().unwrap();
|
||||||
|
let result = native_function.call();
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
let function = Function::new_native(&store, |a: i32| -> i32 { a + 1 });
|
||||||
|
let native_function: NativeFunc<i32, i32> = function.native().unwrap();
|
||||||
|
assert_eq!(native_function.call(3).unwrap(), 4);
|
||||||
|
|
||||||
|
// fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
|
||||||
|
// (a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
|
||||||
|
// }
|
||||||
|
// let function = Function::new_native(&store, rust_abi);
|
||||||
|
// let native_function: NativeFunc<(i32, i64, f32, f64), u64> = function.native().unwrap();
|
||||||
|
// assert_eq!(native_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
|
||||||
|
|
||||||
|
let function = Function::new_native(&store, || -> i32 { 1 });
|
||||||
|
let native_function: NativeFunc<(), i32> = function.native().unwrap();
|
||||||
|
assert_eq!(native_function.call().unwrap(), 1);
|
||||||
|
|
||||||
|
let function = Function::new_native(&store, |_a: i32| {});
|
||||||
|
let native_function: NativeFunc<i32, ()> = function.native().unwrap();
|
||||||
|
assert!(native_function.call(4).is_ok());
|
||||||
|
|
||||||
|
// let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
||||||
|
// let native_function: NativeFunc<(), (i32, i64, f32, f64)> = function.native().unwrap();
|
||||||
|
// assert_eq!(native_function.call().unwrap(), (1, 2, 3.0, 4.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn function_outlives_instance() {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(type $sum_t (func (param i32 i32) (result i32)))
|
||||||
|
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
||||||
|
local.get $x
|
||||||
|
local.get $y
|
||||||
|
i32.add)
|
||||||
|
(export "sum" (func $sum_f)))
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let f = {
|
||||||
|
let module = Module::new(&store, wat).unwrap();
|
||||||
|
let instance = Instance::new(&module, &imports! {}).unwrap();
|
||||||
|
let f = instance.exports.get_function("sum").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
f.call(&[Val::I32(4), Val::I32(5)]).unwrap(),
|
||||||
|
vec![Val::I32(9)].into_boxed_slice()
|
||||||
|
);
|
||||||
|
f.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
f.call(&[Val::I32(4), Val::I32(5)]).unwrap(),
|
||||||
|
vec![Val::I32(9)].into_boxed_slice()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn manually_generate_wasmer_env() {
|
||||||
|
let store = Store::default();
|
||||||
|
#[derive(WasmerEnv, Clone)]
|
||||||
|
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)).unwrap();
|
||||||
|
env.memory.initialize(memory);
|
||||||
|
|
||||||
|
let result = host_function(&mut env, 1, 2);
|
||||||
|
assert_eq!(result, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
735
lib/api/tests/js_instance.rs
Normal file
735
lib/api/tests/js_instance.rs
Normal file
@@ -0,0 +1,735 @@
|
|||||||
|
#[cfg(feature = "js")]
|
||||||
|
mod js {
|
||||||
|
use anyhow::Result;
|
||||||
|
use wasm_bindgen_test::*;
|
||||||
|
use wasmer::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_exported_memory() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![],
|
||||||
|
exports: vec![ExternType::Memory(MemoryType::new(Pages(1), None, false))],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let import_object = imports! {};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let memory = instance.exports.get_memory("mem").unwrap();
|
||||||
|
assert_eq!(memory.ty(), MemoryType::new(Pages(1), None, false));
|
||||||
|
assert_eq!(memory.size(), Pages(1));
|
||||||
|
assert_eq!(memory.data_size(), 65536);
|
||||||
|
|
||||||
|
memory.grow(Pages(1)).unwrap();
|
||||||
|
assert_eq!(memory.ty(), MemoryType::new(Pages(2), None, false));
|
||||||
|
assert_eq!(memory.size(), Pages(2));
|
||||||
|
assert_eq!(memory.data_size(), 65536 * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_exported_function() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func (export "get_magic") (result i32)
|
||||||
|
(i32.const 42)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![],
|
||||||
|
exports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let import_object = imports! {};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let get_magic = instance.exports.get_function("get_magic").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
get_magic.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32])
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = vec![Val::I32(42)].into_boxed_slice();
|
||||||
|
assert_eq!(get_magic.call(&[]), Ok(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_imported_function_dynamic() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func $imported (import "env" "imported") (param i32) (result i32))
|
||||||
|
(func (export "exported") (param i32) (result i32)
|
||||||
|
(call $imported (local.get 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
exports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
|
||||||
|
let imported = Function::new(&store, &imported_signature, |args| {
|
||||||
|
println!("Calling `imported`...");
|
||||||
|
let result = args[0].unwrap_i32() * 2;
|
||||||
|
println!("Result of `imported`: {:?}", result);
|
||||||
|
Ok(vec![Value::I32(result)])
|
||||||
|
});
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"imported" => imported,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let exported = instance.exports.get_function("exported").unwrap();
|
||||||
|
|
||||||
|
let expected = vec![Val::I32(6)].into_boxed_slice();
|
||||||
|
assert_eq!(exported.call(&[Val::I32(3)]), Ok(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We comment it for now because in old versions of Node, only single return values are supported
|
||||||
|
|
||||||
|
// #[wasm_bindgen_test]
|
||||||
|
// fn test_imported_function_dynamic_multivalue() {
|
||||||
|
// let store = Store::default();
|
||||||
|
// let mut module = Module::new(
|
||||||
|
// &store,
|
||||||
|
// br#"
|
||||||
|
// (module
|
||||||
|
// (func $multivalue (import "env" "multivalue") (param i32 i32) (result i32 i32))
|
||||||
|
// (func (export "multivalue") (param i32 i32) (result i32 i32)
|
||||||
|
// (call $multivalue (local.get 0) (local.get 1))
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// "#,
|
||||||
|
// )
|
||||||
|
// .unwrap();
|
||||||
|
// module.set_type_hints(ModuleTypeHints {
|
||||||
|
// imports: vec![
|
||||||
|
// ExternType::Function(FunctionType::new(
|
||||||
|
// vec![Type::I32, Type::I32],
|
||||||
|
// vec![Type::I32, Type::I32],
|
||||||
|
// )),
|
||||||
|
// ],
|
||||||
|
// exports: vec![
|
||||||
|
// ExternType::Function(FunctionType::new(
|
||||||
|
// vec![Type::I32, Type::I32],
|
||||||
|
// vec![Type::I32, Type::I32],
|
||||||
|
// )),
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let multivalue_signature =
|
||||||
|
// FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]);
|
||||||
|
// let multivalue = Function::new(&store, &multivalue_signature, |args| {
|
||||||
|
// println!("Calling `imported`...");
|
||||||
|
// // let result = args[0].unwrap_i32() * ;
|
||||||
|
// // println!("Result of `imported`: {:?}", result);
|
||||||
|
// Ok(vec![args[1].clone(), args[0].clone()])
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let import_object = imports! {
|
||||||
|
// "env" => {
|
||||||
|
// "multivalue" => multivalue,
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
// let exported_multivalue = instance
|
||||||
|
// .exports
|
||||||
|
// .get_function("multivalue")
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
|
// let expected = vec![Val::I32(2), Val::I32(3)].into_boxed_slice();
|
||||||
|
// assert_eq!(
|
||||||
|
// exported_multivalue.call(&[Val::I32(3), Val::I32(2)]),
|
||||||
|
// Ok(expected)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_imported_function_dynamic_with_env() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func $imported (import "env" "imported") (param i32) (result i32))
|
||||||
|
(func (export "exported") (param i32) (result i32)
|
||||||
|
(call $imported (local.get 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
exports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
#[derive(WasmerEnv, Clone)]
|
||||||
|
struct Env {
|
||||||
|
multiplier: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
|
||||||
|
let imported = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&imported_signature,
|
||||||
|
Env { multiplier: 3 },
|
||||||
|
|env, args| {
|
||||||
|
println!("Calling `imported`...");
|
||||||
|
let result = args[0].unwrap_i32() * env.multiplier;
|
||||||
|
println!("Result of `imported`: {:?}", result);
|
||||||
|
Ok(vec![Value::I32(result)])
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"imported" => imported,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let exported = instance.exports.get_function("exported").unwrap();
|
||||||
|
|
||||||
|
let expected = vec![Val::I32(9)].into_boxed_slice();
|
||||||
|
assert_eq!(exported.call(&[Val::I32(3)]), Ok(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_imported_function_native() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func $imported (import "env" "imported") (param i32) (result i32))
|
||||||
|
(func (export "exported") (param i32) (result i32)
|
||||||
|
(call $imported (local.get 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
exports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
fn imported_fn(arg: u32) -> u32 {
|
||||||
|
return arg + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let imported = Function::new_native(&store, imported_fn);
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"imported" => imported,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let exported = instance.exports.get_function("exported").unwrap();
|
||||||
|
|
||||||
|
let expected = vec![Val::I32(5)].into_boxed_slice();
|
||||||
|
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_imported_function_native_with_env() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func $imported (import "env" "imported") (param i32) (result i32))
|
||||||
|
(func (export "exported") (param i32) (result i32)
|
||||||
|
(call $imported (local.get 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
exports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
#[derive(WasmerEnv, Clone)]
|
||||||
|
struct Env {
|
||||||
|
multiplier: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_fn(env: &Env, arg: u32) -> u32 {
|
||||||
|
return env.multiplier * arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
let imported = Function::new_native_with_env(&store, Env { multiplier: 3 }, imported_fn);
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"imported" => imported,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let exported = instance.exports.get_function("exported").unwrap();
|
||||||
|
|
||||||
|
let expected = vec![Val::I32(12)].into_boxed_slice();
|
||||||
|
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_imported_function_native_with_wasmer_env() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func $imported (import "env" "imported") (param i32) (result i32))
|
||||||
|
(func (export "exported") (param i32) (result i32)
|
||||||
|
(call $imported (local.get 0))
|
||||||
|
)
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
exports: vec![
|
||||||
|
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])),
|
||||||
|
ExternType::Memory(MemoryType::new(Pages(1), None, false)),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
#[derive(WasmerEnv, Clone)]
|
||||||
|
struct Env {
|
||||||
|
multiplier: u32,
|
||||||
|
#[wasmer(export)]
|
||||||
|
memory: LazyInit<Memory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_fn(env: &Env, arg: u32) -> u32 {
|
||||||
|
let memory = env.memory_ref().unwrap();
|
||||||
|
let memory_val = memory.uint8view().get_index(0);
|
||||||
|
return (memory_val as u32) * env.multiplier * arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
let imported = Function::new_native_with_env(
|
||||||
|
&store,
|
||||||
|
Env {
|
||||||
|
multiplier: 3,
|
||||||
|
memory: LazyInit::new(),
|
||||||
|
},
|
||||||
|
imported_fn,
|
||||||
|
);
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"imported" => imported,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let memory = instance.exports.get_memory("memory").unwrap();
|
||||||
|
assert_eq!(memory.data_size(), 65536);
|
||||||
|
let memory_val = memory.uint8view().get_index(0);
|
||||||
|
assert_eq!(memory_val, 0);
|
||||||
|
|
||||||
|
memory.uint8view().set_index(0, 2);
|
||||||
|
let memory_val = memory.uint8view().get_index(0);
|
||||||
|
assert_eq!(memory_val, 2);
|
||||||
|
|
||||||
|
let exported = instance.exports.get_function("exported").unwrap();
|
||||||
|
|
||||||
|
// It works with the provided memory
|
||||||
|
let expected = vec![Val::I32(24)].into_boxed_slice();
|
||||||
|
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
||||||
|
|
||||||
|
// It works if we update the memory
|
||||||
|
memory.uint8view().set_index(0, 3);
|
||||||
|
let expected = vec![Val::I32(36)].into_boxed_slice();
|
||||||
|
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_imported_function_with_wasmer_env() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func $imported (import "env" "imported") (param i32) (result i32))
|
||||||
|
(func (export "exported") (param i32) (result i32)
|
||||||
|
(call $imported (local.get 0))
|
||||||
|
)
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![ExternType::Function(FunctionType::new(
|
||||||
|
vec![Type::I32],
|
||||||
|
vec![Type::I32],
|
||||||
|
))],
|
||||||
|
exports: vec![
|
||||||
|
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])),
|
||||||
|
ExternType::Memory(MemoryType::new(Pages(1), None, false)),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
#[derive(WasmerEnv, Clone)]
|
||||||
|
struct Env {
|
||||||
|
multiplier: u32,
|
||||||
|
#[wasmer(export)]
|
||||||
|
memory: LazyInit<Memory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_fn(env: &Env, args: &[Val]) -> Result<Vec<Val>, RuntimeError> {
|
||||||
|
let memory = env.memory_ref().unwrap();
|
||||||
|
let memory_val = memory.uint8view().get_index(0);
|
||||||
|
let value = (memory_val as u32) * env.multiplier * args[0].unwrap_i32() as u32;
|
||||||
|
return Ok(vec![Val::I32(value as _)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
|
||||||
|
let imported = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
imported_signature,
|
||||||
|
Env {
|
||||||
|
multiplier: 3,
|
||||||
|
memory: LazyInit::new(),
|
||||||
|
},
|
||||||
|
imported_fn,
|
||||||
|
);
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"imported" => imported,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let memory = instance.exports.get_memory("memory").unwrap();
|
||||||
|
assert_eq!(memory.data_size(), 65536);
|
||||||
|
let memory_val = memory.uint8view().get_index(0);
|
||||||
|
assert_eq!(memory_val, 0);
|
||||||
|
|
||||||
|
memory.uint8view().set_index(0, 2);
|
||||||
|
let memory_val = memory.uint8view().get_index(0);
|
||||||
|
assert_eq!(memory_val, 2);
|
||||||
|
|
||||||
|
let exported = instance.exports.get_function("exported").unwrap();
|
||||||
|
|
||||||
|
// It works with the provided memory
|
||||||
|
let expected = vec![Val::I32(24)].into_boxed_slice();
|
||||||
|
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
||||||
|
|
||||||
|
// It works if we update the memory
|
||||||
|
memory.uint8view().set_index(0, 3);
|
||||||
|
let expected = vec![Val::I32(36)].into_boxed_slice();
|
||||||
|
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_imported_exported_global() {
|
||||||
|
let store = Store::default();
|
||||||
|
let mut module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(global $mut_i32_import (import "" "global") (mut i32))
|
||||||
|
(func (export "getGlobal") (result i32) (global.get $mut_i32_import))
|
||||||
|
(func (export "incGlobal") (global.set $mut_i32_import (
|
||||||
|
i32.add (i32.const 1) (global.get $mut_i32_import)
|
||||||
|
)))
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
imports: vec![ExternType::Global(GlobalType::new(
|
||||||
|
ValType::I32,
|
||||||
|
Mutability::Var,
|
||||||
|
))],
|
||||||
|
exports: vec![
|
||||||
|
ExternType::Function(FunctionType::new(vec![], vec![Type::I32])),
|
||||||
|
ExternType::Function(FunctionType::new(vec![], vec![])),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let global = Global::new_mut(&store, Value::I32(0));
|
||||||
|
let import_object = imports! {
|
||||||
|
"" => {
|
||||||
|
"global" => global.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let get_global = instance.exports.get_function("getGlobal").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
get_global.call(&[]),
|
||||||
|
Ok(vec![Val::I32(0)].into_boxed_slice())
|
||||||
|
);
|
||||||
|
|
||||||
|
global.set(Value::I32(42)).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
get_global.call(&[]),
|
||||||
|
Ok(vec![Val::I32(42)].into_boxed_slice())
|
||||||
|
);
|
||||||
|
|
||||||
|
let inc_global = instance.exports.get_function("incGlobal").unwrap();
|
||||||
|
inc_global.call(&[]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
get_global.call(&[]),
|
||||||
|
Ok(vec![Val::I32(43)].into_boxed_slice())
|
||||||
|
);
|
||||||
|
assert_eq!(global.get(), Val::I32(43));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_native_function() {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"(module
|
||||||
|
(func $add (import "env" "sum") (param i32 i32) (result i32))
|
||||||
|
(func (export "add_one") (param i32) (result i32)
|
||||||
|
(call $add (local.get 0) (i32.const 1))
|
||||||
|
)
|
||||||
|
)"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
fn sum(a: i32, b: i32) -> i32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"sum" => Function::new_native(&store, sum),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let add_one: NativeFunc<i32, i32> =
|
||||||
|
instance.exports.get_native_function("add_one").unwrap();
|
||||||
|
assert_eq!(add_one.call(1), Ok(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_panic() {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(type $run_t (func (param i32 i32) (result i32)))
|
||||||
|
(type $early_exit_t (func (param) (result)))
|
||||||
|
(import "env" "early_exit" (func $early_exit (type $early_exit_t)))
|
||||||
|
(func $run (type $run_t) (param $x i32) (param $y i32) (result i32)
|
||||||
|
(call $early_exit)
|
||||||
|
(i32.add
|
||||||
|
local.get $x
|
||||||
|
local.get $y))
|
||||||
|
(export "run" (func $run)))
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
fn early_exit() {
|
||||||
|
panic!("Do panic")
|
||||||
|
}
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"early_exit" => Function::new_native(&store, early_exit),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
let run_func: NativeFunc<(i32, i32), i32> =
|
||||||
|
instance.exports.get_native_function("run").unwrap();
|
||||||
|
|
||||||
|
assert!(run_func.call(1, 7).is_err(), "Expected early termination",);
|
||||||
|
let run_func = instance.exports.get_function("run").unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
run_func.call(&[Val::I32(1), Val::I32(7)]).is_err(),
|
||||||
|
"Expected early termination",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_custom_error() {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(type $run_t (func (param i32 i32) (result i32)))
|
||||||
|
(type $early_exit_t (func (param) (result)))
|
||||||
|
(import "env" "early_exit" (func $early_exit (type $early_exit_t)))
|
||||||
|
(func $run (type $run_t) (param $x i32) (param $y i32) (result i32)
|
||||||
|
(call $early_exit)
|
||||||
|
(i32.add
|
||||||
|
local.get $x
|
||||||
|
local.get $y))
|
||||||
|
(export "run" (func $run)))
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct ExitCode(u32);
|
||||||
|
|
||||||
|
impl fmt::Display for ExitCode {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ExitCode {}
|
||||||
|
|
||||||
|
fn early_exit() {
|
||||||
|
RuntimeError::raise(Box::new(ExitCode(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let import_object = imports! {
|
||||||
|
"env" => {
|
||||||
|
"early_exit" => Function::new_native(&store, early_exit),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object).unwrap();
|
||||||
|
|
||||||
|
fn test_result<T: core::fmt::Debug>(result: Result<T, RuntimeError>) {
|
||||||
|
match result {
|
||||||
|
Ok(result) => {
|
||||||
|
assert!(
|
||||||
|
false,
|
||||||
|
"Expected early termination with `ExitCode`, found: {:?}",
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
match e.downcast::<ExitCode>() {
|
||||||
|
// We found the exit code used to terminate execution.
|
||||||
|
Ok(exit_code) => {
|
||||||
|
assert_eq!(exit_code.0, 1);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
assert!(false, "Unknown error `{:?}` found. expected `ErrorCode`", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let run_func: NativeFunc<(i32, i32), i32> =
|
||||||
|
instance.exports.get_native_function("run").unwrap();
|
||||||
|
test_result(run_func.call(1, 7));
|
||||||
|
|
||||||
|
let run_func = instance.exports.get_function("run").unwrap();
|
||||||
|
test_result(run_func.call(&[Val::I32(1), Val::I32(7)]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn test_start_function_fails() {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(
|
||||||
|
&store,
|
||||||
|
br#"
|
||||||
|
(module
|
||||||
|
(func $start_function
|
||||||
|
(i32.div_u
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
drop
|
||||||
|
)
|
||||||
|
(start $start_function)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let import_object = imports! {};
|
||||||
|
let result = Instance::new(&module, &import_object);
|
||||||
|
let err = result.unwrap_err();
|
||||||
|
assert!(format!("{:?}", err).contains("zero"))
|
||||||
|
}
|
||||||
|
}
|
||||||
294
lib/api/tests/js_module.rs
Normal file
294
lib/api/tests/js_module.rs
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
#[cfg(feature = "js")]
|
||||||
|
mod js {
|
||||||
|
use js_sys::{Uint8Array, WebAssembly};
|
||||||
|
use wasm_bindgen_test::*;
|
||||||
|
use wasmer::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn module_get_name() {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module)"#;
|
||||||
|
let module = Module::new(&store, wat).unwrap();
|
||||||
|
assert_eq!(module.name(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn module_set_name() {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module $name)"#;
|
||||||
|
let mut module = Module::new(&store, wat).unwrap();
|
||||||
|
|
||||||
|
#[cfg(feature = "wasm-types-polyfill")]
|
||||||
|
assert_eq!(module.name(), Some("name"));
|
||||||
|
|
||||||
|
module.set_name("new_name");
|
||||||
|
assert_eq!(module.name(), Some("new_name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn module_from_jsmodule() {
|
||||||
|
let wat = br#"(module $name)"#;
|
||||||
|
let binary = wat2wasm(wat).unwrap();
|
||||||
|
let js_bytes = unsafe { Uint8Array::view(&binary) };
|
||||||
|
let js_module = WebAssembly::Module::new(&js_bytes.into()).unwrap();
|
||||||
|
let module: Module = js_module.into();
|
||||||
|
assert_eq!(module.store(), &Store::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn imports() {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(import "host" "func" (func))
|
||||||
|
(import "host" "memory" (memory 1))
|
||||||
|
(import "host" "table" (table 1 anyfunc))
|
||||||
|
(import "host" "global" (global i32))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().collect::<Vec<_>>(),
|
||||||
|
vec![
|
||||||
|
ImportType::new(
|
||||||
|
"host",
|
||||||
|
"func",
|
||||||
|
ExternType::Function(FunctionType::new(vec![], vec![]))
|
||||||
|
),
|
||||||
|
ImportType::new(
|
||||||
|
"host",
|
||||||
|
"memory",
|
||||||
|
ExternType::Memory(MemoryType::new(Pages(1), None, false))
|
||||||
|
),
|
||||||
|
ImportType::new(
|
||||||
|
"host",
|
||||||
|
"table",
|
||||||
|
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
|
||||||
|
),
|
||||||
|
ImportType::new(
|
||||||
|
"host",
|
||||||
|
"global",
|
||||||
|
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now we test the iterators
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().functions().collect::<Vec<_>>(),
|
||||||
|
vec![ImportType::new(
|
||||||
|
"host",
|
||||||
|
"func",
|
||||||
|
FunctionType::new(vec![], vec![])
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().memories().collect::<Vec<_>>(),
|
||||||
|
vec![ImportType::new(
|
||||||
|
"host",
|
||||||
|
"memory",
|
||||||
|
MemoryType::new(Pages(1), None, false)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().tables().collect::<Vec<_>>(),
|
||||||
|
vec![ImportType::new(
|
||||||
|
"host",
|
||||||
|
"table",
|
||||||
|
TableType::new(Type::FuncRef, 1, None)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().globals().collect::<Vec<_>>(),
|
||||||
|
vec![ImportType::new(
|
||||||
|
"host",
|
||||||
|
"global",
|
||||||
|
GlobalType::new(Type::I32, Mutability::Const)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn exports() {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(func (export "func") nop)
|
||||||
|
(memory (export "memory") 2)
|
||||||
|
(table (export "table") 2 funcref)
|
||||||
|
(global (export "global") i32 (i32.const 0))
|
||||||
|
)"#;
|
||||||
|
let mut module = Module::new(&store, wat).unwrap();
|
||||||
|
module
|
||||||
|
.set_type_hints(ModuleTypeHints {
|
||||||
|
exports: vec![
|
||||||
|
ExternType::Function(FunctionType::new(vec![], vec![])),
|
||||||
|
ExternType::Memory(MemoryType::new(Pages(2), None, false)),
|
||||||
|
ExternType::Table(TableType::new(Type::FuncRef, 2, None)),
|
||||||
|
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const)),
|
||||||
|
],
|
||||||
|
imports: vec![],
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().collect::<Vec<_>>(),
|
||||||
|
vec![
|
||||||
|
ExportType::new(
|
||||||
|
"func",
|
||||||
|
ExternType::Function(FunctionType::new(vec![], vec![]))
|
||||||
|
),
|
||||||
|
ExportType::new(
|
||||||
|
"memory",
|
||||||
|
ExternType::Memory(MemoryType::new(Pages(2), None, false))
|
||||||
|
),
|
||||||
|
ExportType::new(
|
||||||
|
"table",
|
||||||
|
ExternType::Table(TableType::new(Type::FuncRef, 2, None))
|
||||||
|
),
|
||||||
|
ExportType::new(
|
||||||
|
"global",
|
||||||
|
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now we test the iterators
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().functions().collect::<Vec<_>>(),
|
||||||
|
vec![ExportType::new("func", FunctionType::new(vec![], vec![])),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().memories().collect::<Vec<_>>(),
|
||||||
|
vec![ExportType::new(
|
||||||
|
"memory",
|
||||||
|
MemoryType::new(Pages(2), None, false)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().tables().collect::<Vec<_>>(),
|
||||||
|
vec![ExportType::new(
|
||||||
|
"table",
|
||||||
|
TableType::new(Type::FuncRef, 2, None)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().globals().collect::<Vec<_>>(),
|
||||||
|
vec![ExportType::new(
|
||||||
|
"global",
|
||||||
|
GlobalType::new(Type::I32, Mutability::Const)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test commented because it doesn't work in old versions of Node
|
||||||
|
// which makes the CI to fail.
|
||||||
|
|
||||||
|
// #[wasm_bindgen_test]
|
||||||
|
// fn calling_host_functions_with_negative_values_works() {
|
||||||
|
// let store = Store::default();
|
||||||
|
// let wat = r#"(module
|
||||||
|
// (import "host" "host_func1" (func (param i64)))
|
||||||
|
// (import "host" "host_func2" (func (param i32)))
|
||||||
|
// (import "host" "host_func3" (func (param i64)))
|
||||||
|
// (import "host" "host_func4" (func (param i32)))
|
||||||
|
// (import "host" "host_func5" (func (param i32)))
|
||||||
|
// (import "host" "host_func6" (func (param i32)))
|
||||||
|
// (import "host" "host_func7" (func (param i32)))
|
||||||
|
// (import "host" "host_func8" (func (param i32)))
|
||||||
|
|
||||||
|
// (func (export "call_host_func1")
|
||||||
|
// (call 0 (i64.const -1)))
|
||||||
|
// (func (export "call_host_func2")
|
||||||
|
// (call 1 (i32.const -1)))
|
||||||
|
// (func (export "call_host_func3")
|
||||||
|
// (call 2 (i64.const -1)))
|
||||||
|
// (func (export "call_host_func4")
|
||||||
|
// (call 3 (i32.const -1)))
|
||||||
|
// (func (export "call_host_func5")
|
||||||
|
// (call 4 (i32.const -1)))
|
||||||
|
// (func (export "call_host_func6")
|
||||||
|
// (call 5 (i32.const -1)))
|
||||||
|
// (func (export "call_host_func7")
|
||||||
|
// (call 6 (i32.const -1)))
|
||||||
|
// (func (export "call_host_func8")
|
||||||
|
// (call 7 (i32.const -1)))
|
||||||
|
// )"#;
|
||||||
|
// let module = Module::new(&store, wat).unwrap();
|
||||||
|
// let imports = imports! {
|
||||||
|
// "host" => {
|
||||||
|
// "host_func1" => Function::new_native(&store, |p: u64| {
|
||||||
|
// println!("host_func1: Found number {}", p);
|
||||||
|
// assert_eq!(p, u64::max_value());
|
||||||
|
// }),
|
||||||
|
// "host_func2" => Function::new_native(&store, |p: u32| {
|
||||||
|
// println!("host_func2: Found number {}", p);
|
||||||
|
// assert_eq!(p, u32::max_value());
|
||||||
|
// }),
|
||||||
|
// "host_func3" => Function::new_native(&store, |p: i64| {
|
||||||
|
// println!("host_func3: Found number {}", p);
|
||||||
|
// assert_eq!(p, -1);
|
||||||
|
// }),
|
||||||
|
// "host_func4" => Function::new_native(&store, |p: i32| {
|
||||||
|
// println!("host_func4: Found number {}", p);
|
||||||
|
// assert_eq!(p, -1);
|
||||||
|
// }),
|
||||||
|
// "host_func5" => Function::new_native(&store, |p: i16| {
|
||||||
|
// println!("host_func5: Found number {}", p);
|
||||||
|
// assert_eq!(p, -1);
|
||||||
|
// }),
|
||||||
|
// "host_func6" => Function::new_native(&store, |p: u16| {
|
||||||
|
// println!("host_func6: Found number {}", p);
|
||||||
|
// assert_eq!(p, u16::max_value());
|
||||||
|
// }),
|
||||||
|
// "host_func7" => Function::new_native(&store, |p: i8| {
|
||||||
|
// println!("host_func7: Found number {}", p);
|
||||||
|
// assert_eq!(p, -1);
|
||||||
|
// }),
|
||||||
|
// "host_func8" => Function::new_native(&store, |p: u8| {
|
||||||
|
// println!("host_func8: Found number {}", p);
|
||||||
|
// assert_eq!(p, u8::max_value());
|
||||||
|
// }),
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// let instance = Instance::new(&module, &imports).unwrap();
|
||||||
|
|
||||||
|
// let f1: NativeFunc<(), ()> = instance
|
||||||
|
// .exports
|
||||||
|
// .get_native_function("call_host_func1")
|
||||||
|
// .unwrap();
|
||||||
|
// let f2: NativeFunc<(), ()> = instance
|
||||||
|
// .exports
|
||||||
|
// .get_native_function("call_host_func2")
|
||||||
|
// .unwrap();
|
||||||
|
// let f3: NativeFunc<(), ()> = instance
|
||||||
|
// .exports
|
||||||
|
// .get_native_function("call_host_func3")
|
||||||
|
// .unwrap();
|
||||||
|
// let f4: NativeFunc<(), ()> = instance
|
||||||
|
// .exports
|
||||||
|
// .get_native_function("call_host_func4")
|
||||||
|
// .unwrap();
|
||||||
|
// let f5: NativeFunc<(), ()> = instance
|
||||||
|
// .exports
|
||||||
|
// .get_native_function("call_host_func5")
|
||||||
|
// .unwrap();
|
||||||
|
// let f6: NativeFunc<(), ()> = instance
|
||||||
|
// .exports
|
||||||
|
// .get_native_function("call_host_func6")
|
||||||
|
// .unwrap();
|
||||||
|
// let f7: NativeFunc<(), ()> = instance
|
||||||
|
// .exports
|
||||||
|
// .get_native_function("call_host_func7")
|
||||||
|
// .unwrap();
|
||||||
|
// let f8: NativeFunc<(), ()> = instance
|
||||||
|
// .exports
|
||||||
|
// .get_native_function("call_host_func8")
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
|
// f1.call().unwrap();
|
||||||
|
// f2.call().unwrap();
|
||||||
|
// f3.call().unwrap();
|
||||||
|
// f4.call().unwrap();
|
||||||
|
// f5.call().unwrap();
|
||||||
|
// f6.call().unwrap();
|
||||||
|
// f7.call().unwrap();
|
||||||
|
// f8.call().unwrap();
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -1,248 +0,0 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use wasmer::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn module_get_name() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
assert_eq!(module.name(), None);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn module_set_name() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module $name)"#;
|
|
||||||
let mut module = Module::new(&store, wat)?;
|
|
||||||
assert_eq!(module.name(), Some("name"));
|
|
||||||
|
|
||||||
module.set_name("new_name");
|
|
||||||
assert_eq!(module.name(), Some("new_name"));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn imports() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(import "host" "func" (func))
|
|
||||||
(import "host" "memory" (memory 1))
|
|
||||||
(import "host" "table" (table 1 anyfunc))
|
|
||||||
(import "host" "global" (global i32))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().collect::<Vec<_>>(),
|
|
||||||
vec![
|
|
||||||
ImportType::new(
|
|
||||||
"host",
|
|
||||||
"func",
|
|
||||||
ExternType::Function(FunctionType::new(vec![], vec![]))
|
|
||||||
),
|
|
||||||
ImportType::new(
|
|
||||||
"host",
|
|
||||||
"memory",
|
|
||||||
ExternType::Memory(MemoryType::new(Pages(1), None, false))
|
|
||||||
),
|
|
||||||
ImportType::new(
|
|
||||||
"host",
|
|
||||||
"table",
|
|
||||||
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
|
|
||||||
),
|
|
||||||
ImportType::new(
|
|
||||||
"host",
|
|
||||||
"global",
|
|
||||||
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now we test the iterators
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().functions().collect::<Vec<_>>(),
|
|
||||||
vec![ImportType::new(
|
|
||||||
"host",
|
|
||||||
"func",
|
|
||||||
FunctionType::new(vec![], vec![])
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().memories().collect::<Vec<_>>(),
|
|
||||||
vec![ImportType::new(
|
|
||||||
"host",
|
|
||||||
"memory",
|
|
||||||
MemoryType::new(Pages(1), None, false)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().tables().collect::<Vec<_>>(),
|
|
||||||
vec![ImportType::new(
|
|
||||||
"host",
|
|
||||||
"table",
|
|
||||||
TableType::new(Type::FuncRef, 1, None)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().globals().collect::<Vec<_>>(),
|
|
||||||
vec![ImportType::new(
|
|
||||||
"host",
|
|
||||||
"global",
|
|
||||||
GlobalType::new(Type::I32, Mutability::Const)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exports() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(func (export "func") nop)
|
|
||||||
(memory (export "memory") 1)
|
|
||||||
(table (export "table") 1 funcref)
|
|
||||||
(global (export "global") i32 (i32.const 0))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().collect::<Vec<_>>(),
|
|
||||||
vec![
|
|
||||||
ExportType::new(
|
|
||||||
"func",
|
|
||||||
ExternType::Function(FunctionType::new(vec![], vec![]))
|
|
||||||
),
|
|
||||||
ExportType::new(
|
|
||||||
"memory",
|
|
||||||
ExternType::Memory(MemoryType::new(Pages(1), None, false))
|
|
||||||
),
|
|
||||||
ExportType::new(
|
|
||||||
"table",
|
|
||||||
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
|
|
||||||
),
|
|
||||||
ExportType::new(
|
|
||||||
"global",
|
|
||||||
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now we test the iterators
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().functions().collect::<Vec<_>>(),
|
|
||||||
vec![ExportType::new("func", FunctionType::new(vec![], vec![])),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().memories().collect::<Vec<_>>(),
|
|
||||||
vec![ExportType::new(
|
|
||||||
"memory",
|
|
||||||
MemoryType::new(Pages(1), None, false)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().tables().collect::<Vec<_>>(),
|
|
||||||
vec![ExportType::new(
|
|
||||||
"table",
|
|
||||||
TableType::new(Type::FuncRef, 1, None)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().globals().collect::<Vec<_>>(),
|
|
||||||
vec![ExportType::new(
|
|
||||||
"global",
|
|
||||||
GlobalType::new(Type::I32, Mutability::Const)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn calling_host_functions_with_negative_values_works() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(import "host" "host_func1" (func (param i64)))
|
|
||||||
(import "host" "host_func2" (func (param i32)))
|
|
||||||
(import "host" "host_func3" (func (param i64)))
|
|
||||||
(import "host" "host_func4" (func (param i32)))
|
|
||||||
(import "host" "host_func5" (func (param i32)))
|
|
||||||
(import "host" "host_func6" (func (param i32)))
|
|
||||||
(import "host" "host_func7" (func (param i32)))
|
|
||||||
(import "host" "host_func8" (func (param i32)))
|
|
||||||
|
|
||||||
(func (export "call_host_func1")
|
|
||||||
(call 0 (i64.const -1)))
|
|
||||||
(func (export "call_host_func2")
|
|
||||||
(call 1 (i32.const -1)))
|
|
||||||
(func (export "call_host_func3")
|
|
||||||
(call 2 (i64.const -1)))
|
|
||||||
(func (export "call_host_func4")
|
|
||||||
(call 3 (i32.const -1)))
|
|
||||||
(func (export "call_host_func5")
|
|
||||||
(call 4 (i32.const -1)))
|
|
||||||
(func (export "call_host_func6")
|
|
||||||
(call 5 (i32.const -1)))
|
|
||||||
(func (export "call_host_func7")
|
|
||||||
(call 6 (i32.const -1)))
|
|
||||||
(func (export "call_host_func8")
|
|
||||||
(call 7 (i32.const -1)))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let imports = imports! {
|
|
||||||
"host" => {
|
|
||||||
"host_func1" => Function::new_native(&store, |p: u64| {
|
|
||||||
println!("host_func1: Found number {}", p);
|
|
||||||
assert_eq!(p, u64::max_value());
|
|
||||||
}),
|
|
||||||
"host_func2" => Function::new_native(&store, |p: u32| {
|
|
||||||
println!("host_func2: Found number {}", p);
|
|
||||||
assert_eq!(p, u32::max_value());
|
|
||||||
}),
|
|
||||||
"host_func3" => Function::new_native(&store, |p: i64| {
|
|
||||||
println!("host_func3: Found number {}", p);
|
|
||||||
assert_eq!(p, -1);
|
|
||||||
}),
|
|
||||||
"host_func4" => Function::new_native(&store, |p: i32| {
|
|
||||||
println!("host_func4: Found number {}", p);
|
|
||||||
assert_eq!(p, -1);
|
|
||||||
}),
|
|
||||||
"host_func5" => Function::new_native(&store, |p: i16| {
|
|
||||||
println!("host_func5: Found number {}", p);
|
|
||||||
assert_eq!(p, -1);
|
|
||||||
}),
|
|
||||||
"host_func6" => Function::new_native(&store, |p: u16| {
|
|
||||||
println!("host_func6: Found number {}", p);
|
|
||||||
assert_eq!(p, u16::max_value());
|
|
||||||
}),
|
|
||||||
"host_func7" => Function::new_native(&store, |p: i8| {
|
|
||||||
println!("host_func7: Found number {}", p);
|
|
||||||
assert_eq!(p, -1);
|
|
||||||
}),
|
|
||||||
"host_func8" => Function::new_native(&store, |p: u8| {
|
|
||||||
println!("host_func8: Found number {}", p);
|
|
||||||
assert_eq!(p, u8::max_value());
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &imports)?;
|
|
||||||
|
|
||||||
let f1: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func1")?;
|
|
||||||
let f2: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func2")?;
|
|
||||||
let f3: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func3")?;
|
|
||||||
let f4: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func4")?;
|
|
||||||
let f5: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func5")?;
|
|
||||||
let f6: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func6")?;
|
|
||||||
let f7: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func7")?;
|
|
||||||
let f8: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func8")?;
|
|
||||||
|
|
||||||
f1.call()?;
|
|
||||||
f2.call()?;
|
|
||||||
f3.call()?;
|
|
||||||
f4.call()?;
|
|
||||||
f5.call()?;
|
|
||||||
f6.call()?;
|
|
||||||
f7.call()?;
|
|
||||||
f8.call()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,497 +0,0 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use wasmer::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn func_ref_passed_and_returned() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(import "env" "func_ref_identity" (func (param funcref) (result funcref)))
|
|
||||||
(type $ret_i32_ty (func (result i32)))
|
|
||||||
(table $table (export "table") 2 2 funcref)
|
|
||||||
|
|
||||||
(func (export "run") (param) (result funcref)
|
|
||||||
(call 0 (ref.null func)))
|
|
||||||
(func (export "call_set_value") (param $fr funcref) (result i32)
|
|
||||||
(table.set $table (i32.const 0) (local.get $fr))
|
|
||||||
(call_indirect $table (type $ret_i32_ty) (i32.const 0)))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let imports = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func_ref_identity" => Function::new(&store, FunctionType::new([Type::FuncRef], [Type::FuncRef]), |values| -> Result<Vec<_>, _> {
|
|
||||||
Ok(vec![values[0].clone()])
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let instance = Instance::new(&module, &imports)?;
|
|
||||||
|
|
||||||
let f: &Function = instance.exports.get_function("run")?;
|
|
||||||
let results = f.call(&[]).unwrap();
|
|
||||||
if let Value::FuncRef(fr) = &results[0] {
|
|
||||||
assert!(fr.is_none());
|
|
||||||
} else {
|
|
||||||
panic!("funcref not found!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, WasmerEnv)]
|
|
||||||
pub struct Env(Arc<AtomicBool>);
|
|
||||||
let env = Env(Arc::new(AtomicBool::new(false)));
|
|
||||||
|
|
||||||
let func_to_call = Function::new_native_with_env(&store, env.clone(), |env: &Env| -> i32 {
|
|
||||||
env.0.store(true, Ordering::SeqCst);
|
|
||||||
343
|
|
||||||
});
|
|
||||||
let call_set_value: &Function = instance.exports.get_function("call_set_value")?;
|
|
||||||
let results: Box<[Value]> = call_set_value.call(&[Value::FuncRef(Some(func_to_call))])?;
|
|
||||||
assert!(env.0.load(Ordering::SeqCst));
|
|
||||||
assert_eq!(&*results, &[Value::I32(343)]);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn func_ref_passed_and_called() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(func $func_ref_call (import "env" "func_ref_call") (param funcref) (result i32))
|
|
||||||
(type $ret_i32_ty (func (result i32)))
|
|
||||||
(table $table (export "table") 2 2 funcref)
|
|
||||||
|
|
||||||
(func $product (param $x i32) (param $y i32) (result i32)
|
|
||||||
(i32.mul (local.get $x) (local.get $y)))
|
|
||||||
;; TODO: figure out exactly why this statement is needed
|
|
||||||
(elem declare func $product)
|
|
||||||
(func (export "call_set_value") (param $fr funcref) (result i32)
|
|
||||||
(table.set $table (i32.const 0) (local.get $fr))
|
|
||||||
(call_indirect $table (type $ret_i32_ty) (i32.const 0)))
|
|
||||||
(func (export "call_func") (param $fr funcref) (result i32)
|
|
||||||
(call $func_ref_call (local.get $fr)))
|
|
||||||
(func (export "call_host_func_with_wasm_func") (result i32)
|
|
||||||
(call $func_ref_call (ref.func $product)))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
|
|
||||||
fn func_ref_call(values: &[Value]) -> Result<Vec<Value>, RuntimeError> {
|
|
||||||
// TODO: look into `Box<[Value]>` being returned breakage
|
|
||||||
let f = values[0].unwrap_funcref().as_ref().unwrap();
|
|
||||||
let f: NativeFunc<(i32, i32), i32> = f.native()?;
|
|
||||||
Ok(vec![Value::I32(f.call(7, 9)?)])
|
|
||||||
}
|
|
||||||
|
|
||||||
let imports = imports! {
|
|
||||||
"env" => {
|
|
||||||
"func_ref_call" => Function::new(
|
|
||||||
&store,
|
|
||||||
FunctionType::new([Type::FuncRef], [Type::I32]),
|
|
||||||
func_ref_call
|
|
||||||
),
|
|
||||||
// TODO(reftypes): this should work
|
|
||||||
/*
|
|
||||||
"func_ref_call_native" => Function::new_native(&store, |f: Function| -> Result<i32, RuntimeError> {
|
|
||||||
let f: NativeFunc::<(i32, i32), i32> = f.native()?;
|
|
||||||
f.call(7, 9)
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let instance = Instance::new(&module, &imports)?;
|
|
||||||
{
|
|
||||||
fn sum(a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
let sum_func = Function::new_native(&store, sum);
|
|
||||||
|
|
||||||
let call_func: &Function = instance.exports.get_function("call_func")?;
|
|
||||||
let result = call_func.call(&[Value::FuncRef(Some(sum_func))])?;
|
|
||||||
assert_eq!(result[0].unwrap_i32(), 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let f: NativeFunc<(), i32> = instance
|
|
||||||
.exports
|
|
||||||
.get_native_function("call_host_func_with_wasm_func")?;
|
|
||||||
let result = f.call()?;
|
|
||||||
assert_eq!(result, 63);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
|
||||||
#[test]
|
|
||||||
fn extern_ref_passed_and_returned() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(func $extern_ref_identity (import "env" "extern_ref_identity") (param externref) (result externref))
|
|
||||||
(func $extern_ref_identity_native (import "env" "extern_ref_identity_native") (param externref) (result externref))
|
|
||||||
(func $get_new_extern_ref (import "env" "get_new_extern_ref") (result externref))
|
|
||||||
(func $get_new_extern_ref_native (import "env" "get_new_extern_ref_native") (result externref))
|
|
||||||
|
|
||||||
(func (export "run") (param) (result externref)
|
|
||||||
(call $extern_ref_identity (ref.null extern)))
|
|
||||||
(func (export "run_native") (param) (result externref)
|
|
||||||
(call $extern_ref_identity_native (ref.null extern)))
|
|
||||||
(func (export "get_hashmap") (param) (result externref)
|
|
||||||
(call $get_new_extern_ref))
|
|
||||||
(func (export "get_hashmap_native") (param) (result externref)
|
|
||||||
(call $get_new_extern_ref_native))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let imports = imports! {
|
|
||||||
"env" => {
|
|
||||||
"extern_ref_identity" => Function::new(&store, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |values| -> Result<Vec<_>, _> {
|
|
||||||
Ok(vec![values[0].clone()])
|
|
||||||
}),
|
|
||||||
"extern_ref_identity_native" => Function::new_native(&store, |er: ExternRef| -> ExternRef {
|
|
||||||
er
|
|
||||||
}),
|
|
||||||
"get_new_extern_ref" => Function::new(&store, FunctionType::new([], [Type::ExternRef]), |_| -> Result<Vec<_>, _> {
|
|
||||||
let inner =
|
|
||||||
[("hello".to_string(), "world".to_string()),
|
|
||||||
("color".to_string(), "orange".to_string())]
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.collect::<HashMap<String, String>>();
|
|
||||||
let new_extern_ref = ExternRef::new(inner);
|
|
||||||
Ok(vec![Value::ExternRef(new_extern_ref)])
|
|
||||||
}),
|
|
||||||
"get_new_extern_ref_native" => Function::new_native(&store, || -> ExternRef {
|
|
||||||
let inner =
|
|
||||||
[("hello".to_string(), "world".to_string()),
|
|
||||||
("color".to_string(), "orange".to_string())]
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.collect::<HashMap<String, String>>();
|
|
||||||
ExternRef::new(inner)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let instance = Instance::new(&module, &imports)?;
|
|
||||||
for run in &["run", "run_native"] {
|
|
||||||
let f: &Function = instance.exports.get_function(run)?;
|
|
||||||
let results = f.call(&[]).unwrap();
|
|
||||||
if let Value::ExternRef(er) = &results[0] {
|
|
||||||
assert!(er.is_null());
|
|
||||||
} else {
|
|
||||||
panic!("result is not an extern ref!");
|
|
||||||
}
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ExternRef> = instance.exports.get_native_function(run)?;
|
|
||||||
let result: ExternRef = f.call()?;
|
|
||||||
assert!(result.is_null());
|
|
||||||
}
|
|
||||||
|
|
||||||
for get_hashmap in &["get_hashmap", "get_hashmap_native"] {
|
|
||||||
let f: &Function = instance.exports.get_function(get_hashmap)?;
|
|
||||||
let results = f.call(&[]).unwrap();
|
|
||||||
if let Value::ExternRef(er) = &results[0] {
|
|
||||||
let inner: &HashMap<String, String> = er.downcast().unwrap();
|
|
||||||
assert_eq!(inner["hello"], "world");
|
|
||||||
assert_eq!(inner["color"], "orange");
|
|
||||||
} else {
|
|
||||||
panic!("result is not an extern ref!");
|
|
||||||
}
|
|
||||||
|
|
||||||
let f: NativeFunc<(), ExternRef> = instance.exports.get_native_function(get_hashmap)?;
|
|
||||||
|
|
||||||
let result: ExternRef = f.call()?;
|
|
||||||
let inner: &HashMap<String, String> = result.downcast().unwrap();
|
|
||||||
assert_eq!(inner["hello"], "world");
|
|
||||||
assert_eq!(inner["color"], "orange");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
|
||||||
#[test]
|
|
||||||
// TODO(reftypes): reenable this test
|
|
||||||
#[ignore]
|
|
||||||
fn extern_ref_ref_counting_basic() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(func (export "drop") (param $er externref) (result)
|
|
||||||
(drop (local.get $er)))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let instance = Instance::new(&module, &imports! {})?;
|
|
||||||
let f: NativeFunc<ExternRef, ()> = instance.exports.get_native_function("drop")?;
|
|
||||||
|
|
||||||
let er = ExternRef::new(3u32);
|
|
||||||
f.call(er.clone())?;
|
|
||||||
|
|
||||||
assert_eq!(er.downcast::<u32>().unwrap(), &3);
|
|
||||||
assert_eq!(er.strong_count(), 1);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
|
||||||
#[test]
|
|
||||||
fn refs_in_globals() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(global $er_global (export "er_global") (mut externref) (ref.null extern))
|
|
||||||
(global $fr_global (export "fr_global") (mut funcref) (ref.null func))
|
|
||||||
(global $fr_immutable_global (export "fr_immutable_global") funcref (ref.func $hello))
|
|
||||||
(func $hello (param) (result i32)
|
|
||||||
(i32.const 73))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let instance = Instance::new(&module, &imports! {})?;
|
|
||||||
{
|
|
||||||
let er_global: &Global = instance.exports.get_global("er_global")?;
|
|
||||||
|
|
||||||
if let Value::ExternRef(er) = er_global.get() {
|
|
||||||
assert!(er.is_null());
|
|
||||||
} else {
|
|
||||||
panic!("Did not find extern ref in the global");
|
|
||||||
}
|
|
||||||
|
|
||||||
er_global.set(Val::ExternRef(ExternRef::new(3u32)))?;
|
|
||||||
|
|
||||||
if let Value::ExternRef(er) = er_global.get() {
|
|
||||||
assert_eq!(er.downcast::<u32>().unwrap(), &3);
|
|
||||||
assert_eq!(er.strong_count(), 1);
|
|
||||||
} else {
|
|
||||||
panic!("Did not find extern ref in the global");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let fr_global: &Global = instance.exports.get_global("fr_immutable_global")?;
|
|
||||||
|
|
||||||
if let Value::FuncRef(Some(f)) = fr_global.get() {
|
|
||||||
let native_func: NativeFunc<(), u32> = f.native()?;
|
|
||||||
assert_eq!(native_func.call()?, 73);
|
|
||||||
} else {
|
|
||||||
panic!("Did not find non-null func ref in the global");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let fr_global: &Global = instance.exports.get_global("fr_global")?;
|
|
||||||
|
|
||||||
if let Value::FuncRef(None) = fr_global.get() {
|
|
||||||
} else {
|
|
||||||
panic!("Did not find a null func ref in the global");
|
|
||||||
}
|
|
||||||
|
|
||||||
let f = Function::new_native(&store, |arg1: i32, arg2: i32| -> i32 { arg1 + arg2 });
|
|
||||||
|
|
||||||
fr_global.set(Val::FuncRef(Some(f)))?;
|
|
||||||
|
|
||||||
if let Value::FuncRef(Some(f)) = fr_global.get() {
|
|
||||||
let native: NativeFunc<(i32, i32), i32> = f.native()?;
|
|
||||||
assert_eq!(native.call(5, 7)?, 12);
|
|
||||||
} else {
|
|
||||||
panic!("Did not find extern ref in the global");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
|
||||||
#[test]
|
|
||||||
fn extern_ref_ref_counting_table_basic() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(global $global (export "global") (mut externref) (ref.null extern))
|
|
||||||
(table $table (export "table") 4 4 externref)
|
|
||||||
(func $insert (param $er externref) (param $idx i32)
|
|
||||||
(table.set $table (local.get $idx) (local.get $er)))
|
|
||||||
(func $intermediate (param $er externref) (param $idx i32)
|
|
||||||
(call $insert (local.get $er) (local.get $idx)))
|
|
||||||
(func $insert_into_table (export "insert_into_table") (param $er externref) (param $idx i32) (result externref)
|
|
||||||
(call $intermediate (local.get $er) (local.get $idx))
|
|
||||||
(local.get $er))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let instance = Instance::new(&module, &imports! {})?;
|
|
||||||
|
|
||||||
let f: NativeFunc<(ExternRef, i32), ExternRef> =
|
|
||||||
instance.exports.get_native_function("insert_into_table")?;
|
|
||||||
|
|
||||||
let er = ExternRef::new(3usize);
|
|
||||||
|
|
||||||
let er = f.call(er, 1)?;
|
|
||||||
assert_eq!(er.strong_count(), 2);
|
|
||||||
|
|
||||||
let table: &Table = instance.exports.get_table("table")?;
|
|
||||||
|
|
||||||
{
|
|
||||||
let er2 = table.get(1).unwrap().externref().unwrap();
|
|
||||||
assert_eq!(er2.strong_count(), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(er.strong_count(), 2);
|
|
||||||
table.set(1, Val::ExternRef(ExternRef::null()))?;
|
|
||||||
|
|
||||||
assert_eq!(er.strong_count(), 1);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
|
||||||
#[test]
|
|
||||||
// TODO(reftypes): reenable this test
|
|
||||||
#[ignore]
|
|
||||||
fn extern_ref_ref_counting_global_basic() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(global $global (export "global") (mut externref) (ref.null extern))
|
|
||||||
(func $get_from_global (export "get_from_global") (result externref)
|
|
||||||
(drop (global.get $global))
|
|
||||||
(global.get $global))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let instance = Instance::new(&module, &imports! {})?;
|
|
||||||
|
|
||||||
let global: &Global = instance.exports.get_global("global")?;
|
|
||||||
{
|
|
||||||
let er = ExternRef::new(3usize);
|
|
||||||
global.set(Val::ExternRef(er.clone()))?;
|
|
||||||
assert_eq!(er.strong_count(), 2);
|
|
||||||
}
|
|
||||||
let get_from_global: NativeFunc<(), ExternRef> =
|
|
||||||
instance.exports.get_native_function("get_from_global")?;
|
|
||||||
|
|
||||||
let er = get_from_global.call()?;
|
|
||||||
assert_eq!(er.strong_count(), 2);
|
|
||||||
global.set(Val::ExternRef(ExternRef::null()))?;
|
|
||||||
assert_eq!(er.strong_count(), 1);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
|
||||||
#[test]
|
|
||||||
// TODO(reftypes): reenable this test
|
|
||||||
#[ignore]
|
|
||||||
fn extern_ref_ref_counting_traps() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(func $pass_er (export "pass_extern_ref") (param externref)
|
|
||||||
(local.get 0)
|
|
||||||
(unreachable))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let instance = Instance::new(&module, &imports! {})?;
|
|
||||||
|
|
||||||
let pass_extern_ref: NativeFunc<ExternRef, ()> =
|
|
||||||
instance.exports.get_native_function("pass_extern_ref")?;
|
|
||||||
|
|
||||||
let er = ExternRef::new(3usize);
|
|
||||||
assert_eq!(er.strong_count(), 1);
|
|
||||||
|
|
||||||
let result = pass_extern_ref.call(er.clone());
|
|
||||||
assert!(result.is_err());
|
|
||||||
assert_eq!(er.strong_count(), 1);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
|
||||||
#[test]
|
|
||||||
fn extern_ref_ref_counting_table_instructions() -> Result<()> {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(table $table1 (export "table1") 2 12 externref)
|
|
||||||
(table $table2 (export "table2") 6 12 externref)
|
|
||||||
(func $grow_table_with_ref (export "grow_table_with_ref") (param $er externref) (param $size i32) (result i32)
|
|
||||||
(table.grow $table1 (local.get $er) (local.get $size)))
|
|
||||||
(func $fill_table_with_ref (export "fill_table_with_ref") (param $er externref) (param $start i32) (param $end i32)
|
|
||||||
(table.fill $table1 (local.get $start) (local.get $er) (local.get $end)))
|
|
||||||
(func $copy_into_table2 (export "copy_into_table2")
|
|
||||||
(table.copy $table2 $table1 (i32.const 0) (i32.const 0) (i32.const 4)))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat)?;
|
|
||||||
let instance = Instance::new(&module, &imports! {})?;
|
|
||||||
|
|
||||||
let grow_table_with_ref: NativeFunc<(ExternRef, i32), i32> = instance
|
|
||||||
.exports
|
|
||||||
.get_native_function("grow_table_with_ref")?;
|
|
||||||
let fill_table_with_ref: NativeFunc<(ExternRef, i32, i32), ()> = instance
|
|
||||||
.exports
|
|
||||||
.get_native_function("fill_table_with_ref")?;
|
|
||||||
let copy_into_table2: NativeFunc<(), ()> =
|
|
||||||
instance.exports.get_native_function("copy_into_table2")?;
|
|
||||||
let table1: &Table = instance.exports.get_table("table1")?;
|
|
||||||
let table2: &Table = instance.exports.get_table("table2")?;
|
|
||||||
|
|
||||||
let er1 = ExternRef::new(3usize);
|
|
||||||
let er2 = ExternRef::new(5usize);
|
|
||||||
let er3 = ExternRef::new(7usize);
|
|
||||||
{
|
|
||||||
let result = grow_table_with_ref.call(er1.clone(), 0)?;
|
|
||||||
assert_eq!(result, 2);
|
|
||||||
assert_eq!(er1.strong_count(), 1);
|
|
||||||
|
|
||||||
let result = grow_table_with_ref.call(er1.clone(), 10_000)?;
|
|
||||||
assert_eq!(result, -1);
|
|
||||||
assert_eq!(er1.strong_count(), 1);
|
|
||||||
|
|
||||||
let result = grow_table_with_ref.call(er1.clone(), 8)?;
|
|
||||||
assert_eq!(result, 2);
|
|
||||||
assert_eq!(er1.strong_count(), 9);
|
|
||||||
|
|
||||||
for i in 2..10 {
|
|
||||||
let e = table1.get(i).unwrap().unwrap_externref();
|
|
||||||
assert_eq!(*e.downcast::<usize>().unwrap(), 3);
|
|
||||||
assert_eq!(&e, &er1);
|
|
||||||
}
|
|
||||||
assert_eq!(er1.strong_count(), 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
fill_table_with_ref.call(er2.clone(), 0, 2)?;
|
|
||||||
assert_eq!(er2.strong_count(), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
table2.set(0, Val::ExternRef(er3.clone()))?;
|
|
||||||
table2.set(1, Val::ExternRef(er3.clone()))?;
|
|
||||||
table2.set(2, Val::ExternRef(er3.clone()))?;
|
|
||||||
table2.set(3, Val::ExternRef(er3.clone()))?;
|
|
||||||
table2.set(4, Val::ExternRef(er3.clone()))?;
|
|
||||||
assert_eq!(er3.strong_count(), 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
copy_into_table2.call()?;
|
|
||||||
assert_eq!(er3.strong_count(), 2);
|
|
||||||
assert_eq!(er2.strong_count(), 5);
|
|
||||||
assert_eq!(er1.strong_count(), 11);
|
|
||||||
for i in 1..5 {
|
|
||||||
let e = table2.get(i).unwrap().unwrap_externref();
|
|
||||||
let value = e.downcast::<usize>().unwrap();
|
|
||||||
match i {
|
|
||||||
0 | 1 => assert_eq!(*value, 5),
|
|
||||||
4 => assert_eq!(*value, 7),
|
|
||||||
_ => assert_eq!(*value, 3),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
for i in 0..table1.size() {
|
|
||||||
table1.set(i, Val::ExternRef(ExternRef::null()))?;
|
|
||||||
}
|
|
||||||
for i in 0..table2.size() {
|
|
||||||
table2.set(i, Val::ExternRef(ExternRef::null()))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(er1.strong_count(), 1);
|
|
||||||
assert_eq!(er2.strong_count(), 1);
|
|
||||||
assert_eq!(er3.strong_count(), 1);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
339
lib/api/tests/sys/export.rs
Normal file
339
lib/api/tests/sys/export.rs
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
#[cfg(feature = "sys")]
|
||||||
|
mod sys {
|
||||||
|
use anyhow::Result;
|
||||||
|
use wasmer::*;
|
||||||
|
use wasmer_vm::WeakOrStrongInstanceRef;
|
||||||
|
|
||||||
|
const MEM_WAT: &str = "
|
||||||
|
(module
|
||||||
|
(func $host_fn (import \"env\" \"host_fn\") (param) (result))
|
||||||
|
(func (export \"call_host_fn\") (param) (result)
|
||||||
|
(call $host_fn))
|
||||||
|
|
||||||
|
(memory $mem 0)
|
||||||
|
(export \"memory\" (memory $mem))
|
||||||
|
)
|
||||||
|
";
|
||||||
|
|
||||||
|
const GLOBAL_WAT: &str = "
|
||||||
|
(module
|
||||||
|
(func $host_fn (import \"env\" \"host_fn\") (param) (result))
|
||||||
|
(func (export \"call_host_fn\") (param) (result)
|
||||||
|
(call $host_fn))
|
||||||
|
|
||||||
|
(global $global i32 (i32.const 11))
|
||||||
|
(export \"global\" (global $global))
|
||||||
|
)
|
||||||
|
";
|
||||||
|
|
||||||
|
const TABLE_WAT: &str = "
|
||||||
|
(module
|
||||||
|
(func $host_fn (import \"env\" \"host_fn\") (param) (result))
|
||||||
|
(func (export \"call_host_fn\") (param) (result)
|
||||||
|
(call $host_fn))
|
||||||
|
|
||||||
|
(table $table 4 4 funcref)
|
||||||
|
(export \"table\" (table $table))
|
||||||
|
)
|
||||||
|
";
|
||||||
|
|
||||||
|
const FUNCTION_WAT: &str = "
|
||||||
|
(module
|
||||||
|
(func $host_fn (import \"env\" \"host_fn\") (param) (result))
|
||||||
|
(func (export \"call_host_fn\") (param) (result)
|
||||||
|
(call $host_fn))
|
||||||
|
)
|
||||||
|
";
|
||||||
|
|
||||||
|
fn is_memory_instance_ref_strong(memory: &Memory) -> Option<bool> {
|
||||||
|
// This is safe because we're calling it from a test to test the internals
|
||||||
|
unsafe {
|
||||||
|
memory
|
||||||
|
.get_vm_memory()
|
||||||
|
.instance_ref
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_table_instance_ref_strong(table: &Table) -> Option<bool> {
|
||||||
|
// This is safe because we're calling it from a test to test the internals
|
||||||
|
unsafe {
|
||||||
|
table
|
||||||
|
.get_vm_table()
|
||||||
|
.instance_ref
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_global_instance_ref_strong(global: &Global) -> Option<bool> {
|
||||||
|
// This is safe because we're calling it from a test to test the internals
|
||||||
|
unsafe {
|
||||||
|
global
|
||||||
|
.get_vm_global()
|
||||||
|
.instance_ref
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_function_instance_ref_strong(f: &Function) -> Option<bool> {
|
||||||
|
// This is safe because we're calling it from a test to test the internals
|
||||||
|
unsafe {
|
||||||
|
f.get_vm_function()
|
||||||
|
.instance_ref
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_native_function_instance_ref_strong<Args, Rets>(
|
||||||
|
f: &NativeFunc<Args, Rets>,
|
||||||
|
) -> Option<bool>
|
||||||
|
where
|
||||||
|
Args: WasmTypeList,
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
{
|
||||||
|
// This is safe because we're calling it from a test to test the internals
|
||||||
|
unsafe {
|
||||||
|
f.get_vm_function()
|
||||||
|
.instance_ref
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strong_weak_behavior_works_memory() -> Result<()> {
|
||||||
|
#[derive(Clone, Debug, WasmerEnv, Default)]
|
||||||
|
struct MemEnv {
|
||||||
|
#[wasmer(export)]
|
||||||
|
memory: LazyInit<Memory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_fn = |env: &MemEnv| {
|
||||||
|
let mem = env.memory_ref().unwrap();
|
||||||
|
assert_eq!(is_memory_instance_ref_strong(&mem), Some(false));
|
||||||
|
let mem_clone = mem.clone();
|
||||||
|
assert_eq!(is_memory_instance_ref_strong(&mem_clone), Some(true));
|
||||||
|
assert_eq!(is_memory_instance_ref_strong(&mem), Some(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(&store, MEM_WAT)?;
|
||||||
|
let env = MemEnv::default();
|
||||||
|
|
||||||
|
let instance = Instance::new(
|
||||||
|
&module,
|
||||||
|
&imports! {
|
||||||
|
"env" => {
|
||||||
|
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mem = instance.exports.get_memory("memory")?;
|
||||||
|
assert_eq!(is_memory_instance_ref_strong(&mem), Some(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
||||||
|
f.call()?;
|
||||||
|
f
|
||||||
|
};
|
||||||
|
f.call()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strong_weak_behavior_works_global() -> Result<()> {
|
||||||
|
#[derive(Clone, Debug, WasmerEnv, Default)]
|
||||||
|
struct GlobalEnv {
|
||||||
|
#[wasmer(export)]
|
||||||
|
global: LazyInit<Global>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_fn = |env: &GlobalEnv| {
|
||||||
|
let global = env.global_ref().unwrap();
|
||||||
|
assert_eq!(is_global_instance_ref_strong(&global), Some(false));
|
||||||
|
let global_clone = global.clone();
|
||||||
|
assert_eq!(is_global_instance_ref_strong(&global_clone), Some(true));
|
||||||
|
assert_eq!(is_global_instance_ref_strong(&global), Some(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(&store, GLOBAL_WAT)?;
|
||||||
|
let env = GlobalEnv::default();
|
||||||
|
|
||||||
|
let instance = Instance::new(
|
||||||
|
&module,
|
||||||
|
&imports! {
|
||||||
|
"env" => {
|
||||||
|
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let global = instance.exports.get_global("global")?;
|
||||||
|
assert_eq!(is_global_instance_ref_strong(&global), Some(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
||||||
|
f.call()?;
|
||||||
|
f
|
||||||
|
};
|
||||||
|
f.call()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strong_weak_behavior_works_table() -> Result<()> {
|
||||||
|
#[derive(Clone, WasmerEnv, Default)]
|
||||||
|
struct TableEnv {
|
||||||
|
#[wasmer(export)]
|
||||||
|
table: LazyInit<Table>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_fn = |env: &TableEnv| {
|
||||||
|
let table = env.table_ref().unwrap();
|
||||||
|
assert_eq!(is_table_instance_ref_strong(&table), Some(false));
|
||||||
|
let table_clone = table.clone();
|
||||||
|
assert_eq!(is_table_instance_ref_strong(&table_clone), Some(true));
|
||||||
|
assert_eq!(is_table_instance_ref_strong(&table), Some(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(&store, TABLE_WAT)?;
|
||||||
|
let env = TableEnv::default();
|
||||||
|
|
||||||
|
let instance = Instance::new(
|
||||||
|
&module,
|
||||||
|
&imports! {
|
||||||
|
"env" => {
|
||||||
|
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let table = instance.exports.get_table("table")?;
|
||||||
|
assert_eq!(is_table_instance_ref_strong(&table), Some(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
||||||
|
f.call()?;
|
||||||
|
f
|
||||||
|
};
|
||||||
|
f.call()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strong_weak_behavior_works_function() -> Result<()> {
|
||||||
|
#[derive(Clone, WasmerEnv, Default)]
|
||||||
|
struct FunctionEnv {
|
||||||
|
#[wasmer(export)]
|
||||||
|
call_host_fn: LazyInit<Function>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_fn = |env: &FunctionEnv| {
|
||||||
|
let function = env.call_host_fn_ref().unwrap();
|
||||||
|
assert_eq!(is_function_instance_ref_strong(&function), Some(false));
|
||||||
|
let function_clone = function.clone();
|
||||||
|
assert_eq!(is_function_instance_ref_strong(&function_clone), Some(true));
|
||||||
|
assert_eq!(is_function_instance_ref_strong(&function), Some(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(&store, FUNCTION_WAT)?;
|
||||||
|
let env = FunctionEnv::default();
|
||||||
|
|
||||||
|
let instance = Instance::new(
|
||||||
|
&module,
|
||||||
|
&imports! {
|
||||||
|
"env" => {
|
||||||
|
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let function = instance.exports.get_function("call_host_fn")?;
|
||||||
|
assert_eq!(is_function_instance_ref_strong(&function), Some(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
||||||
|
f.call()?;
|
||||||
|
f
|
||||||
|
};
|
||||||
|
f.call()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strong_weak_behavior_works_native_function() -> Result<()> {
|
||||||
|
#[derive(Clone, WasmerEnv, Default)]
|
||||||
|
struct FunctionEnv {
|
||||||
|
#[wasmer(export)]
|
||||||
|
call_host_fn: LazyInit<NativeFunc<(), ()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_fn = |env: &FunctionEnv| {
|
||||||
|
let function = env.call_host_fn_ref().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
is_native_function_instance_ref_strong(&function),
|
||||||
|
Some(false)
|
||||||
|
);
|
||||||
|
let function_clone = function.clone();
|
||||||
|
assert_eq!(
|
||||||
|
is_native_function_instance_ref_strong(&function_clone),
|
||||||
|
Some(true)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
is_native_function_instance_ref_strong(&function),
|
||||||
|
Some(false)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(&store, FUNCTION_WAT)?;
|
||||||
|
let env = FunctionEnv::default();
|
||||||
|
|
||||||
|
let instance = Instance::new(
|
||||||
|
&module,
|
||||||
|
&imports! {
|
||||||
|
"env" => {
|
||||||
|
"host_fn" => Function::new_native_with_env(&store, env, host_fn)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let function: NativeFunc<(), ()> =
|
||||||
|
instance.exports.get_native_function("call_host_fn")?;
|
||||||
|
assert_eq!(
|
||||||
|
is_native_function_instance_ref_strong(&function),
|
||||||
|
Some(true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
|
||||||
|
f.call()?;
|
||||||
|
f
|
||||||
|
};
|
||||||
|
f.call()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
467
lib/api/tests/sys/externals.rs
Normal file
467
lib/api/tests/sys/externals.rs
Normal file
@@ -0,0 +1,467 @@
|
|||||||
|
#[cfg(feature = "sys")]
|
||||||
|
mod sys {
|
||||||
|
use anyhow::Result;
|
||||||
|
use wasmer::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_new() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let global = Global::new(&store, Value::I32(10));
|
||||||
|
assert_eq!(
|
||||||
|
*global.ty(),
|
||||||
|
GlobalType {
|
||||||
|
ty: Type::I32,
|
||||||
|
mutability: Mutability::Const
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let global_mut = Global::new_mut(&store, Value::I32(10));
|
||||||
|
assert_eq!(
|
||||||
|
*global_mut.ty(),
|
||||||
|
GlobalType {
|
||||||
|
ty: Type::I32,
|
||||||
|
mutability: Mutability::Var
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_get() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let global_i32 = Global::new(&store, Value::I32(10));
|
||||||
|
assert_eq!(global_i32.get(), Value::I32(10));
|
||||||
|
let global_i64 = Global::new(&store, Value::I64(20));
|
||||||
|
assert_eq!(global_i64.get(), Value::I64(20));
|
||||||
|
let global_f32 = Global::new(&store, Value::F32(10.0));
|
||||||
|
assert_eq!(global_f32.get(), Value::F32(10.0));
|
||||||
|
let global_f64 = Global::new(&store, Value::F64(20.0));
|
||||||
|
assert_eq!(global_f64.get(), Value::F64(20.0));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_set() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let global_i32 = Global::new(&store, Value::I32(10));
|
||||||
|
// Set on a constant should error
|
||||||
|
assert!(global_i32.set(Value::I32(20)).is_err());
|
||||||
|
|
||||||
|
let global_i32_mut = Global::new_mut(&store, Value::I32(10));
|
||||||
|
// Set on different type should error
|
||||||
|
assert!(global_i32_mut.set(Value::I64(20)).is_err());
|
||||||
|
|
||||||
|
// Set on same type should succeed
|
||||||
|
global_i32_mut.set(Value::I32(20))?;
|
||||||
|
assert_eq!(global_i32_mut.get(), Value::I32(20));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn table_new() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let table_type = TableType {
|
||||||
|
ty: Type::FuncRef,
|
||||||
|
minimum: 0,
|
||||||
|
maximum: None,
|
||||||
|
};
|
||||||
|
let f = Function::new_native(&store, || {});
|
||||||
|
let table = Table::new(&store, table_type, Value::FuncRef(Some(f)))?;
|
||||||
|
assert_eq!(*table.ty(), table_type);
|
||||||
|
|
||||||
|
// Anyrefs not yet supported
|
||||||
|
// let table_type = TableType {
|
||||||
|
// ty: Type::ExternRef,
|
||||||
|
// minimum: 0,
|
||||||
|
// maximum: None,
|
||||||
|
// };
|
||||||
|
// let table = Table::new(&store, table_type, Value::ExternRef(ExternRef::Null))?;
|
||||||
|
// assert_eq!(*table.ty(), table_type);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn table_get() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let table_type = TableType {
|
||||||
|
ty: Type::FuncRef,
|
||||||
|
minimum: 0,
|
||||||
|
maximum: Some(1),
|
||||||
|
};
|
||||||
|
let f = Function::new_native(&store, |num: i32| num + 1);
|
||||||
|
let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
||||||
|
assert_eq!(*table.ty(), table_type);
|
||||||
|
let _elem = table.get(0).unwrap();
|
||||||
|
// assert_eq!(elem.funcref().unwrap(), f);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn table_set() -> Result<()> {
|
||||||
|
// Table set not yet tested
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn table_grow() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let table_type = TableType {
|
||||||
|
ty: Type::FuncRef,
|
||||||
|
minimum: 0,
|
||||||
|
maximum: Some(10),
|
||||||
|
};
|
||||||
|
let f = Function::new_native(&store, |num: i32| num + 1);
|
||||||
|
let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
||||||
|
// Growing to a bigger maximum should return None
|
||||||
|
let old_len = table.grow(12, Value::FuncRef(Some(f.clone())));
|
||||||
|
assert!(old_len.is_err());
|
||||||
|
|
||||||
|
// Growing to a bigger maximum should return None
|
||||||
|
let old_len = table.grow(5, Value::FuncRef(Some(f.clone())))?;
|
||||||
|
assert_eq!(old_len, 0);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn table_copy() -> Result<()> {
|
||||||
|
// TODO: table copy test not yet implemented
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memory_new() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let memory_type = MemoryType {
|
||||||
|
shared: false,
|
||||||
|
minimum: Pages(0),
|
||||||
|
maximum: Some(Pages(10)),
|
||||||
|
};
|
||||||
|
let memory = Memory::new(&store, memory_type)?;
|
||||||
|
assert_eq!(memory.size(), Pages(0));
|
||||||
|
assert_eq!(memory.ty(), memory_type);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memory_grow() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
|
||||||
|
let desc = MemoryType::new(Pages(10), Some(Pages(16)), false);
|
||||||
|
let memory = Memory::new(&store, desc)?;
|
||||||
|
assert_eq!(memory.size(), Pages(10));
|
||||||
|
|
||||||
|
let result = memory.grow(Pages(2)).unwrap();
|
||||||
|
assert_eq!(result, Pages(10));
|
||||||
|
assert_eq!(memory.size(), Pages(12));
|
||||||
|
|
||||||
|
let result = memory.grow(Pages(10));
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
Err(MemoryError::CouldNotGrow {
|
||||||
|
current: 12.into(),
|
||||||
|
attempted_delta: 10.into()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
let bad_desc = MemoryType::new(Pages(15), Some(Pages(10)), false);
|
||||||
|
let bad_result = Memory::new(&store, bad_desc);
|
||||||
|
|
||||||
|
assert!(matches!(bad_result, Err(MemoryError::InvalidMemory { .. })));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_new() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let function = Function::new_native(&store, || {});
|
||||||
|
assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
|
||||||
|
let function = Function::new_native(&store, |_a: i32| {});
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![Type::I32], vec![])
|
||||||
|
);
|
||||||
|
let function = Function::new_native(&store, |_a: i32, _b: i64, _c: f32, _d: f64| {});
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
||||||
|
);
|
||||||
|
let function = Function::new_native(&store, || -> i32 { 1 });
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32])
|
||||||
|
);
|
||||||
|
let function =
|
||||||
|
Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_new_env() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
#[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![]));
|
||||||
|
let function =
|
||||||
|
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv, _a: i32| {});
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![Type::I32], vec![])
|
||||||
|
);
|
||||||
|
let function = Function::new_native_with_env(
|
||||||
|
&store,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _a: i32, _b: i64, _c: f32, _d: f64| {},
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
||||||
|
);
|
||||||
|
let function =
|
||||||
|
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| -> i32 { 1 });
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32])
|
||||||
|
);
|
||||||
|
let function = Function::new_native_with_env(
|
||||||
|
&store,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
function.ty().clone(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_new_dynamic() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
|
||||||
|
// Using &FunctionType signature
|
||||||
|
let function_type = FunctionType::new(vec![], vec![]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type =
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type =
|
||||||
|
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
||||||
|
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
|
||||||
|
// Using array signature
|
||||||
|
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
||||||
|
let function = Function::new(&store, function_type, |_values: &[Value]| unimplemented!());
|
||||||
|
assert_eq!(function.ty().params(), [Type::V128]);
|
||||||
|
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_new_dynamic_env() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
#[derive(Clone, WasmerEnv)]
|
||||||
|
struct MyEnv {}
|
||||||
|
let my_env = MyEnv {};
|
||||||
|
|
||||||
|
// Using &FunctionType signature
|
||||||
|
let function_type = FunctionType::new(vec![], vec![]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type =
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
let function_type =
|
||||||
|
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
&function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().clone(), function_type);
|
||||||
|
|
||||||
|
// Using array signature
|
||||||
|
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
||||||
|
let function = Function::new_with_env(
|
||||||
|
&store,
|
||||||
|
function_type,
|
||||||
|
my_env.clone(),
|
||||||
|
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
||||||
|
);
|
||||||
|
assert_eq!(function.ty().params(), [Type::V128]);
|
||||||
|
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn native_function_works() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let function = Function::new_native(&store, || {});
|
||||||
|
let native_function: NativeFunc<(), ()> = function.native().unwrap();
|
||||||
|
let result = native_function.call();
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
let function = Function::new_native(&store, |a: i32| -> i32 { a + 1 });
|
||||||
|
let native_function: NativeFunc<i32, i32> = function.native().unwrap();
|
||||||
|
assert_eq!(native_function.call(3).unwrap(), 4);
|
||||||
|
|
||||||
|
fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
|
||||||
|
(a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
|
||||||
|
}
|
||||||
|
let function = Function::new_native(&store, rust_abi);
|
||||||
|
let native_function: NativeFunc<(i32, i64, f32, f64), u64> = function.native().unwrap();
|
||||||
|
assert_eq!(native_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
|
||||||
|
|
||||||
|
let function = Function::new_native(&store, || -> i32 { 1 });
|
||||||
|
let native_function: NativeFunc<(), i32> = function.native().unwrap();
|
||||||
|
assert_eq!(native_function.call().unwrap(), 1);
|
||||||
|
|
||||||
|
let function = Function::new_native(&store, |_a: i32| {});
|
||||||
|
let native_function: NativeFunc<i32, ()> = function.native().unwrap();
|
||||||
|
assert!(native_function.call(4).is_ok());
|
||||||
|
|
||||||
|
let function =
|
||||||
|
Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
||||||
|
let native_function: NativeFunc<(), (i32, i64, f32, f64)> = function.native().unwrap();
|
||||||
|
assert_eq!(native_function.call().unwrap(), (1, 2, 3.0, 4.0));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_outlives_instance() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(type $sum_t (func (param i32 i32) (result i32)))
|
||||||
|
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
||||||
|
local.get $x
|
||||||
|
local.get $y
|
||||||
|
i32.add)
|
||||||
|
(export "sum" (func $sum_f)))
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let f = {
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let instance = Instance::new(&module, &imports! {})?;
|
||||||
|
let f: NativeFunc<(i32, i32), i32> = instance.exports.get_native_function("sum")?;
|
||||||
|
|
||||||
|
assert_eq!(f.call(4, 5)?, 9);
|
||||||
|
f
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(f.call(4, 5)?, 9);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn weak_instance_ref_externs_after_instance() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(type $sum_t (func (param i32 i32) (result i32)))
|
||||||
|
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
||||||
|
local.get $x
|
||||||
|
local.get $y
|
||||||
|
i32.add)
|
||||||
|
(export "sum" (func $sum_f)))
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let f = {
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let instance = Instance::new(&module, &imports! {})?;
|
||||||
|
let f: NativeFunc<(i32, i32), i32> = instance.exports.get_with_generics_weak("sum")?;
|
||||||
|
|
||||||
|
assert_eq!(f.call(4, 5)?, 9);
|
||||||
|
f
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(f.call(4, 5)?, 9);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn manually_generate_wasmer_env() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
#[derive(WasmerEnv, Clone)]
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
42
lib/api/tests/sys/instance.rs
Normal file
42
lib/api/tests/sys/instance.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#[cfg(feature = "sys")]
|
||||||
|
mod sys {
|
||||||
|
use anyhow::Result;
|
||||||
|
use wasmer::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exports_work_after_multiple_instances_have_been_freed() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let module = Module::new(
|
||||||
|
&store,
|
||||||
|
"
|
||||||
|
(module
|
||||||
|
(type $sum_t (func (param i32 i32) (result i32)))
|
||||||
|
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
||||||
|
local.get $x
|
||||||
|
local.get $y
|
||||||
|
i32.add)
|
||||||
|
(export \"sum\" (func $sum_f)))
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let import_object = ImportObject::new();
|
||||||
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
|
let instance2 = instance.clone();
|
||||||
|
let instance3 = instance.clone();
|
||||||
|
|
||||||
|
// The function is cloned to “break” the connection with `instance`.
|
||||||
|
let sum = instance.exports.get_function("sum")?.clone();
|
||||||
|
|
||||||
|
drop(instance);
|
||||||
|
drop(instance2);
|
||||||
|
drop(instance3);
|
||||||
|
|
||||||
|
// All instances have been dropped, but `sum` continues to work!
|
||||||
|
assert_eq!(
|
||||||
|
sum.call(&[Value::I32(1), Value::I32(2)])?.into_vec(),
|
||||||
|
vec![Value::I32(3)],
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
251
lib/api/tests/sys/module.rs
Normal file
251
lib/api/tests/sys/module.rs
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
#[cfg(feature = "sys")]
|
||||||
|
mod sys {
|
||||||
|
use anyhow::Result;
|
||||||
|
use wasmer::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn module_get_name() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
assert_eq!(module.name(), None);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn module_set_name() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module $name)"#;
|
||||||
|
let mut module = Module::new(&store, wat)?;
|
||||||
|
assert_eq!(module.name(), Some("name"));
|
||||||
|
|
||||||
|
module.set_name("new_name");
|
||||||
|
assert_eq!(module.name(), Some("new_name"));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn imports() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(import "host" "func" (func))
|
||||||
|
(import "host" "memory" (memory 1))
|
||||||
|
(import "host" "table" (table 1 anyfunc))
|
||||||
|
(import "host" "global" (global i32))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().collect::<Vec<_>>(),
|
||||||
|
vec![
|
||||||
|
ImportType::new(
|
||||||
|
"host",
|
||||||
|
"func",
|
||||||
|
ExternType::Function(FunctionType::new(vec![], vec![]))
|
||||||
|
),
|
||||||
|
ImportType::new(
|
||||||
|
"host",
|
||||||
|
"memory",
|
||||||
|
ExternType::Memory(MemoryType::new(Pages(1), None, false))
|
||||||
|
),
|
||||||
|
ImportType::new(
|
||||||
|
"host",
|
||||||
|
"table",
|
||||||
|
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
|
||||||
|
),
|
||||||
|
ImportType::new(
|
||||||
|
"host",
|
||||||
|
"global",
|
||||||
|
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now we test the iterators
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().functions().collect::<Vec<_>>(),
|
||||||
|
vec![ImportType::new(
|
||||||
|
"host",
|
||||||
|
"func",
|
||||||
|
FunctionType::new(vec![], vec![])
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().memories().collect::<Vec<_>>(),
|
||||||
|
vec![ImportType::new(
|
||||||
|
"host",
|
||||||
|
"memory",
|
||||||
|
MemoryType::new(Pages(1), None, false)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().tables().collect::<Vec<_>>(),
|
||||||
|
vec![ImportType::new(
|
||||||
|
"host",
|
||||||
|
"table",
|
||||||
|
TableType::new(Type::FuncRef, 1, None)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.imports().globals().collect::<Vec<_>>(),
|
||||||
|
vec![ImportType::new(
|
||||||
|
"host",
|
||||||
|
"global",
|
||||||
|
GlobalType::new(Type::I32, Mutability::Const)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exports() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(func (export "func") nop)
|
||||||
|
(memory (export "memory") 1)
|
||||||
|
(table (export "table") 1 funcref)
|
||||||
|
(global (export "global") i32 (i32.const 0))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().collect::<Vec<_>>(),
|
||||||
|
vec![
|
||||||
|
ExportType::new(
|
||||||
|
"func",
|
||||||
|
ExternType::Function(FunctionType::new(vec![], vec![]))
|
||||||
|
),
|
||||||
|
ExportType::new(
|
||||||
|
"memory",
|
||||||
|
ExternType::Memory(MemoryType::new(Pages(1), None, false))
|
||||||
|
),
|
||||||
|
ExportType::new(
|
||||||
|
"table",
|
||||||
|
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
|
||||||
|
),
|
||||||
|
ExportType::new(
|
||||||
|
"global",
|
||||||
|
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now we test the iterators
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().functions().collect::<Vec<_>>(),
|
||||||
|
vec![ExportType::new("func", FunctionType::new(vec![], vec![])),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().memories().collect::<Vec<_>>(),
|
||||||
|
vec![ExportType::new(
|
||||||
|
"memory",
|
||||||
|
MemoryType::new(Pages(1), None, false)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().tables().collect::<Vec<_>>(),
|
||||||
|
vec![ExportType::new(
|
||||||
|
"table",
|
||||||
|
TableType::new(Type::FuncRef, 1, None)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
module.exports().globals().collect::<Vec<_>>(),
|
||||||
|
vec![ExportType::new(
|
||||||
|
"global",
|
||||||
|
GlobalType::new(Type::I32, Mutability::Const)
|
||||||
|
),]
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn calling_host_functions_with_negative_values_works() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(import "host" "host_func1" (func (param i64)))
|
||||||
|
(import "host" "host_func2" (func (param i32)))
|
||||||
|
(import "host" "host_func3" (func (param i64)))
|
||||||
|
(import "host" "host_func4" (func (param i32)))
|
||||||
|
(import "host" "host_func5" (func (param i32)))
|
||||||
|
(import "host" "host_func6" (func (param i32)))
|
||||||
|
(import "host" "host_func7" (func (param i32)))
|
||||||
|
(import "host" "host_func8" (func (param i32)))
|
||||||
|
|
||||||
|
(func (export "call_host_func1")
|
||||||
|
(call 0 (i64.const -1)))
|
||||||
|
(func (export "call_host_func2")
|
||||||
|
(call 1 (i32.const -1)))
|
||||||
|
(func (export "call_host_func3")
|
||||||
|
(call 2 (i64.const -1)))
|
||||||
|
(func (export "call_host_func4")
|
||||||
|
(call 3 (i32.const -1)))
|
||||||
|
(func (export "call_host_func5")
|
||||||
|
(call 4 (i32.const -1)))
|
||||||
|
(func (export "call_host_func6")
|
||||||
|
(call 5 (i32.const -1)))
|
||||||
|
(func (export "call_host_func7")
|
||||||
|
(call 6 (i32.const -1)))
|
||||||
|
(func (export "call_host_func8")
|
||||||
|
(call 7 (i32.const -1)))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let imports = imports! {
|
||||||
|
"host" => {
|
||||||
|
"host_func1" => Function::new_native(&store, |p: u64| {
|
||||||
|
println!("host_func1: Found number {}", p);
|
||||||
|
assert_eq!(p, u64::max_value());
|
||||||
|
}),
|
||||||
|
"host_func2" => Function::new_native(&store, |p: u32| {
|
||||||
|
println!("host_func2: Found number {}", p);
|
||||||
|
assert_eq!(p, u32::max_value());
|
||||||
|
}),
|
||||||
|
"host_func3" => Function::new_native(&store, |p: i64| {
|
||||||
|
println!("host_func3: Found number {}", p);
|
||||||
|
assert_eq!(p, -1);
|
||||||
|
}),
|
||||||
|
"host_func4" => Function::new_native(&store, |p: i32| {
|
||||||
|
println!("host_func4: Found number {}", p);
|
||||||
|
assert_eq!(p, -1);
|
||||||
|
}),
|
||||||
|
"host_func5" => Function::new_native(&store, |p: i16| {
|
||||||
|
println!("host_func5: Found number {}", p);
|
||||||
|
assert_eq!(p, -1);
|
||||||
|
}),
|
||||||
|
"host_func6" => Function::new_native(&store, |p: u16| {
|
||||||
|
println!("host_func6: Found number {}", p);
|
||||||
|
assert_eq!(p, u16::max_value());
|
||||||
|
}),
|
||||||
|
"host_func7" => Function::new_native(&store, |p: i8| {
|
||||||
|
println!("host_func7: Found number {}", p);
|
||||||
|
assert_eq!(p, -1);
|
||||||
|
}),
|
||||||
|
"host_func8" => Function::new_native(&store, |p: u8| {
|
||||||
|
println!("host_func8: Found number {}", p);
|
||||||
|
assert_eq!(p, u8::max_value());
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &imports)?;
|
||||||
|
|
||||||
|
let f1: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func1")?;
|
||||||
|
let f2: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func2")?;
|
||||||
|
let f3: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func3")?;
|
||||||
|
let f4: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func4")?;
|
||||||
|
let f5: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func5")?;
|
||||||
|
let f6: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func6")?;
|
||||||
|
let f7: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func7")?;
|
||||||
|
let f8: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func8")?;
|
||||||
|
|
||||||
|
f1.call()?;
|
||||||
|
f2.call()?;
|
||||||
|
f3.call()?;
|
||||||
|
f4.call()?;
|
||||||
|
f5.call()?;
|
||||||
|
f6.call()?;
|
||||||
|
f7.call()?;
|
||||||
|
f8.call()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
500
lib/api/tests/sys/reference_types.rs
Normal file
500
lib/api/tests/sys/reference_types.rs
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
#[cfg(feature = "sys")]
|
||||||
|
mod sys {
|
||||||
|
use anyhow::Result;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use wasmer::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn func_ref_passed_and_returned() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(import "env" "func_ref_identity" (func (param funcref) (result funcref)))
|
||||||
|
(type $ret_i32_ty (func (result i32)))
|
||||||
|
(table $table (export "table") 2 2 funcref)
|
||||||
|
|
||||||
|
(func (export "run") (param) (result funcref)
|
||||||
|
(call 0 (ref.null func)))
|
||||||
|
(func (export "call_set_value") (param $fr funcref) (result i32)
|
||||||
|
(table.set $table (i32.const 0) (local.get $fr))
|
||||||
|
(call_indirect $table (type $ret_i32_ty) (i32.const 0)))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let imports = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func_ref_identity" => Function::new(&store, FunctionType::new([Type::FuncRef], [Type::FuncRef]), |values| -> Result<Vec<_>, _> {
|
||||||
|
Ok(vec![values[0].clone()])
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let instance = Instance::new(&module, &imports)?;
|
||||||
|
|
||||||
|
let f: &Function = instance.exports.get_function("run")?;
|
||||||
|
let results = f.call(&[]).unwrap();
|
||||||
|
if let Value::FuncRef(fr) = &results[0] {
|
||||||
|
assert!(fr.is_none());
|
||||||
|
} else {
|
||||||
|
panic!("funcref not found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, WasmerEnv)]
|
||||||
|
pub struct Env(Arc<AtomicBool>);
|
||||||
|
let env = Env(Arc::new(AtomicBool::new(false)));
|
||||||
|
|
||||||
|
let func_to_call = Function::new_native_with_env(&store, env.clone(), |env: &Env| -> i32 {
|
||||||
|
env.0.store(true, Ordering::SeqCst);
|
||||||
|
343
|
||||||
|
});
|
||||||
|
let call_set_value: &Function = instance.exports.get_function("call_set_value")?;
|
||||||
|
let results: Box<[Value]> = call_set_value.call(&[Value::FuncRef(Some(func_to_call))])?;
|
||||||
|
assert!(env.0.load(Ordering::SeqCst));
|
||||||
|
assert_eq!(&*results, &[Value::I32(343)]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn func_ref_passed_and_called() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(func $func_ref_call (import "env" "func_ref_call") (param funcref) (result i32))
|
||||||
|
(type $ret_i32_ty (func (result i32)))
|
||||||
|
(table $table (export "table") 2 2 funcref)
|
||||||
|
|
||||||
|
(func $product (param $x i32) (param $y i32) (result i32)
|
||||||
|
(i32.mul (local.get $x) (local.get $y)))
|
||||||
|
;; TODO: figure out exactly why this statement is needed
|
||||||
|
(elem declare func $product)
|
||||||
|
(func (export "call_set_value") (param $fr funcref) (result i32)
|
||||||
|
(table.set $table (i32.const 0) (local.get $fr))
|
||||||
|
(call_indirect $table (type $ret_i32_ty) (i32.const 0)))
|
||||||
|
(func (export "call_func") (param $fr funcref) (result i32)
|
||||||
|
(call $func_ref_call (local.get $fr)))
|
||||||
|
(func (export "call_host_func_with_wasm_func") (result i32)
|
||||||
|
(call $func_ref_call (ref.func $product)))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
|
||||||
|
fn func_ref_call(values: &[Value]) -> Result<Vec<Value>, RuntimeError> {
|
||||||
|
// TODO: look into `Box<[Value]>` being returned breakage
|
||||||
|
let f = values[0].unwrap_funcref().as_ref().unwrap();
|
||||||
|
let f: NativeFunc<(i32, i32), i32> = f.native()?;
|
||||||
|
Ok(vec![Value::I32(f.call(7, 9)?)])
|
||||||
|
}
|
||||||
|
|
||||||
|
let imports = imports! {
|
||||||
|
"env" => {
|
||||||
|
"func_ref_call" => Function::new(
|
||||||
|
&store,
|
||||||
|
FunctionType::new([Type::FuncRef], [Type::I32]),
|
||||||
|
func_ref_call
|
||||||
|
),
|
||||||
|
// TODO(reftypes): this should work
|
||||||
|
/*
|
||||||
|
"func_ref_call_native" => Function::new_native(&store, |f: Function| -> Result<i32, RuntimeError> {
|
||||||
|
let f: NativeFunc::<(i32, i32), i32> = f.native()?;
|
||||||
|
f.call(7, 9)
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let instance = Instance::new(&module, &imports)?;
|
||||||
|
{
|
||||||
|
fn sum(a: i32, b: i32) -> i32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
let sum_func = Function::new_native(&store, sum);
|
||||||
|
|
||||||
|
let call_func: &Function = instance.exports.get_function("call_func")?;
|
||||||
|
let result = call_func.call(&[Value::FuncRef(Some(sum_func))])?;
|
||||||
|
assert_eq!(result[0].unwrap_i32(), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let f: NativeFunc<(), i32> = instance
|
||||||
|
.exports
|
||||||
|
.get_native_function("call_host_func_with_wasm_func")?;
|
||||||
|
let result = f.call()?;
|
||||||
|
assert_eq!(result, 63);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
#[test]
|
||||||
|
fn extern_ref_passed_and_returned() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(func $extern_ref_identity (import "env" "extern_ref_identity") (param externref) (result externref))
|
||||||
|
(func $extern_ref_identity_native (import "env" "extern_ref_identity_native") (param externref) (result externref))
|
||||||
|
(func $get_new_extern_ref (import "env" "get_new_extern_ref") (result externref))
|
||||||
|
(func $get_new_extern_ref_native (import "env" "get_new_extern_ref_native") (result externref))
|
||||||
|
|
||||||
|
(func (export "run") (param) (result externref)
|
||||||
|
(call $extern_ref_identity (ref.null extern)))
|
||||||
|
(func (export "run_native") (param) (result externref)
|
||||||
|
(call $extern_ref_identity_native (ref.null extern)))
|
||||||
|
(func (export "get_hashmap") (param) (result externref)
|
||||||
|
(call $get_new_extern_ref))
|
||||||
|
(func (export "get_hashmap_native") (param) (result externref)
|
||||||
|
(call $get_new_extern_ref_native))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let imports = imports! {
|
||||||
|
"env" => {
|
||||||
|
"extern_ref_identity" => Function::new(&store, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |values| -> Result<Vec<_>, _> {
|
||||||
|
Ok(vec![values[0].clone()])
|
||||||
|
}),
|
||||||
|
"extern_ref_identity_native" => Function::new_native(&store, |er: ExternRef| -> ExternRef {
|
||||||
|
er
|
||||||
|
}),
|
||||||
|
"get_new_extern_ref" => Function::new(&store, FunctionType::new([], [Type::ExternRef]), |_| -> Result<Vec<_>, _> {
|
||||||
|
let inner =
|
||||||
|
[("hello".to_string(), "world".to_string()),
|
||||||
|
("color".to_string(), "orange".to_string())]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashMap<String, String>>();
|
||||||
|
let new_extern_ref = ExternRef::new(inner);
|
||||||
|
Ok(vec![Value::ExternRef(new_extern_ref)])
|
||||||
|
}),
|
||||||
|
"get_new_extern_ref_native" => Function::new_native(&store, || -> ExternRef {
|
||||||
|
let inner =
|
||||||
|
[("hello".to_string(), "world".to_string()),
|
||||||
|
("color".to_string(), "orange".to_string())]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashMap<String, String>>();
|
||||||
|
ExternRef::new(inner)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let instance = Instance::new(&module, &imports)?;
|
||||||
|
for run in &["run", "run_native"] {
|
||||||
|
let f: &Function = instance.exports.get_function(run)?;
|
||||||
|
let results = f.call(&[]).unwrap();
|
||||||
|
if let Value::ExternRef(er) = &results[0] {
|
||||||
|
assert!(er.is_null());
|
||||||
|
} else {
|
||||||
|
panic!("result is not an extern ref!");
|
||||||
|
}
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ExternRef> = instance.exports.get_native_function(run)?;
|
||||||
|
let result: ExternRef = f.call()?;
|
||||||
|
assert!(result.is_null());
|
||||||
|
}
|
||||||
|
|
||||||
|
for get_hashmap in &["get_hashmap", "get_hashmap_native"] {
|
||||||
|
let f: &Function = instance.exports.get_function(get_hashmap)?;
|
||||||
|
let results = f.call(&[]).unwrap();
|
||||||
|
if let Value::ExternRef(er) = &results[0] {
|
||||||
|
let inner: &HashMap<String, String> = er.downcast().unwrap();
|
||||||
|
assert_eq!(inner["hello"], "world");
|
||||||
|
assert_eq!(inner["color"], "orange");
|
||||||
|
} else {
|
||||||
|
panic!("result is not an extern ref!");
|
||||||
|
}
|
||||||
|
|
||||||
|
let f: NativeFunc<(), ExternRef> = instance.exports.get_native_function(get_hashmap)?;
|
||||||
|
|
||||||
|
let result: ExternRef = f.call()?;
|
||||||
|
let inner: &HashMap<String, String> = result.downcast().unwrap();
|
||||||
|
assert_eq!(inner["hello"], "world");
|
||||||
|
assert_eq!(inner["color"], "orange");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
#[test]
|
||||||
|
// TODO(reftypes): reenable this test
|
||||||
|
#[ignore]
|
||||||
|
fn extern_ref_ref_counting_basic() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(func (export "drop") (param $er externref) (result)
|
||||||
|
(drop (local.get $er)))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let instance = Instance::new(&module, &imports! {})?;
|
||||||
|
let f: NativeFunc<ExternRef, ()> = instance.exports.get_native_function("drop")?;
|
||||||
|
|
||||||
|
let er = ExternRef::new(3u32);
|
||||||
|
f.call(er.clone())?;
|
||||||
|
|
||||||
|
assert_eq!(er.downcast::<u32>().unwrap(), &3);
|
||||||
|
assert_eq!(er.strong_count(), 1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
#[test]
|
||||||
|
fn refs_in_globals() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(global $er_global (export "er_global") (mut externref) (ref.null extern))
|
||||||
|
(global $fr_global (export "fr_global") (mut funcref) (ref.null func))
|
||||||
|
(global $fr_immutable_global (export "fr_immutable_global") funcref (ref.func $hello))
|
||||||
|
(func $hello (param) (result i32)
|
||||||
|
(i32.const 73))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let instance = Instance::new(&module, &imports! {})?;
|
||||||
|
{
|
||||||
|
let er_global: &Global = instance.exports.get_global("er_global")?;
|
||||||
|
|
||||||
|
if let Value::ExternRef(er) = er_global.get() {
|
||||||
|
assert!(er.is_null());
|
||||||
|
} else {
|
||||||
|
panic!("Did not find extern ref in the global");
|
||||||
|
}
|
||||||
|
|
||||||
|
er_global.set(Val::ExternRef(ExternRef::new(3u32)))?;
|
||||||
|
|
||||||
|
if let Value::ExternRef(er) = er_global.get() {
|
||||||
|
assert_eq!(er.downcast::<u32>().unwrap(), &3);
|
||||||
|
assert_eq!(er.strong_count(), 1);
|
||||||
|
} else {
|
||||||
|
panic!("Did not find extern ref in the global");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let fr_global: &Global = instance.exports.get_global("fr_immutable_global")?;
|
||||||
|
|
||||||
|
if let Value::FuncRef(Some(f)) = fr_global.get() {
|
||||||
|
let native_func: NativeFunc<(), u32> = f.native()?;
|
||||||
|
assert_eq!(native_func.call()?, 73);
|
||||||
|
} else {
|
||||||
|
panic!("Did not find non-null func ref in the global");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let fr_global: &Global = instance.exports.get_global("fr_global")?;
|
||||||
|
|
||||||
|
if let Value::FuncRef(None) = fr_global.get() {
|
||||||
|
} else {
|
||||||
|
panic!("Did not find a null func ref in the global");
|
||||||
|
}
|
||||||
|
|
||||||
|
let f = Function::new_native(&store, |arg1: i32, arg2: i32| -> i32 { arg1 + arg2 });
|
||||||
|
|
||||||
|
fr_global.set(Val::FuncRef(Some(f)))?;
|
||||||
|
|
||||||
|
if let Value::FuncRef(Some(f)) = fr_global.get() {
|
||||||
|
let native: NativeFunc<(i32, i32), i32> = f.native()?;
|
||||||
|
assert_eq!(native.call(5, 7)?, 12);
|
||||||
|
} else {
|
||||||
|
panic!("Did not find extern ref in the global");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
#[test]
|
||||||
|
fn extern_ref_ref_counting_table_basic() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(global $global (export "global") (mut externref) (ref.null extern))
|
||||||
|
(table $table (export "table") 4 4 externref)
|
||||||
|
(func $insert (param $er externref) (param $idx i32)
|
||||||
|
(table.set $table (local.get $idx) (local.get $er)))
|
||||||
|
(func $intermediate (param $er externref) (param $idx i32)
|
||||||
|
(call $insert (local.get $er) (local.get $idx)))
|
||||||
|
(func $insert_into_table (export "insert_into_table") (param $er externref) (param $idx i32) (result externref)
|
||||||
|
(call $intermediate (local.get $er) (local.get $idx))
|
||||||
|
(local.get $er))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let instance = Instance::new(&module, &imports! {})?;
|
||||||
|
|
||||||
|
let f: NativeFunc<(ExternRef, i32), ExternRef> =
|
||||||
|
instance.exports.get_native_function("insert_into_table")?;
|
||||||
|
|
||||||
|
let er = ExternRef::new(3usize);
|
||||||
|
|
||||||
|
let er = f.call(er, 1)?;
|
||||||
|
assert_eq!(er.strong_count(), 2);
|
||||||
|
|
||||||
|
let table: &Table = instance.exports.get_table("table")?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let er2 = table.get(1).unwrap().externref().unwrap();
|
||||||
|
assert_eq!(er2.strong_count(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(er.strong_count(), 2);
|
||||||
|
table.set(1, Val::ExternRef(ExternRef::null()))?;
|
||||||
|
|
||||||
|
assert_eq!(er.strong_count(), 1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
#[test]
|
||||||
|
// TODO(reftypes): reenable this test
|
||||||
|
#[ignore]
|
||||||
|
fn extern_ref_ref_counting_global_basic() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(global $global (export "global") (mut externref) (ref.null extern))
|
||||||
|
(func $get_from_global (export "get_from_global") (result externref)
|
||||||
|
(drop (global.get $global))
|
||||||
|
(global.get $global))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let instance = Instance::new(&module, &imports! {})?;
|
||||||
|
|
||||||
|
let global: &Global = instance.exports.get_global("global")?;
|
||||||
|
{
|
||||||
|
let er = ExternRef::new(3usize);
|
||||||
|
global.set(Val::ExternRef(er.clone()))?;
|
||||||
|
assert_eq!(er.strong_count(), 2);
|
||||||
|
}
|
||||||
|
let get_from_global: NativeFunc<(), ExternRef> =
|
||||||
|
instance.exports.get_native_function("get_from_global")?;
|
||||||
|
|
||||||
|
let er = get_from_global.call()?;
|
||||||
|
assert_eq!(er.strong_count(), 2);
|
||||||
|
global.set(Val::ExternRef(ExternRef::null()))?;
|
||||||
|
assert_eq!(er.strong_count(), 1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
#[test]
|
||||||
|
// TODO(reftypes): reenable this test
|
||||||
|
#[ignore]
|
||||||
|
fn extern_ref_ref_counting_traps() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(func $pass_er (export "pass_extern_ref") (param externref)
|
||||||
|
(local.get 0)
|
||||||
|
(unreachable))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let instance = Instance::new(&module, &imports! {})?;
|
||||||
|
|
||||||
|
let pass_extern_ref: NativeFunc<ExternRef, ()> =
|
||||||
|
instance.exports.get_native_function("pass_extern_ref")?;
|
||||||
|
|
||||||
|
let er = ExternRef::new(3usize);
|
||||||
|
assert_eq!(er.strong_count(), 1);
|
||||||
|
|
||||||
|
let result = pass_extern_ref.call(er.clone());
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(er.strong_count(), 1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "experimental-reference-types-extern-ref")]
|
||||||
|
#[test]
|
||||||
|
fn extern_ref_ref_counting_table_instructions() -> Result<()> {
|
||||||
|
let store = Store::default();
|
||||||
|
let wat = r#"(module
|
||||||
|
(table $table1 (export "table1") 2 12 externref)
|
||||||
|
(table $table2 (export "table2") 6 12 externref)
|
||||||
|
(func $grow_table_with_ref (export "grow_table_with_ref") (param $er externref) (param $size i32) (result i32)
|
||||||
|
(table.grow $table1 (local.get $er) (local.get $size)))
|
||||||
|
(func $fill_table_with_ref (export "fill_table_with_ref") (param $er externref) (param $start i32) (param $end i32)
|
||||||
|
(table.fill $table1 (local.get $start) (local.get $er) (local.get $end)))
|
||||||
|
(func $copy_into_table2 (export "copy_into_table2")
|
||||||
|
(table.copy $table2 $table1 (i32.const 0) (i32.const 0) (i32.const 4)))
|
||||||
|
)"#;
|
||||||
|
let module = Module::new(&store, wat)?;
|
||||||
|
let instance = Instance::new(&module, &imports! {})?;
|
||||||
|
|
||||||
|
let grow_table_with_ref: NativeFunc<(ExternRef, i32), i32> = instance
|
||||||
|
.exports
|
||||||
|
.get_native_function("grow_table_with_ref")?;
|
||||||
|
let fill_table_with_ref: NativeFunc<(ExternRef, i32, i32), ()> = instance
|
||||||
|
.exports
|
||||||
|
.get_native_function("fill_table_with_ref")?;
|
||||||
|
let copy_into_table2: NativeFunc<(), ()> =
|
||||||
|
instance.exports.get_native_function("copy_into_table2")?;
|
||||||
|
let table1: &Table = instance.exports.get_table("table1")?;
|
||||||
|
let table2: &Table = instance.exports.get_table("table2")?;
|
||||||
|
|
||||||
|
let er1 = ExternRef::new(3usize);
|
||||||
|
let er2 = ExternRef::new(5usize);
|
||||||
|
let er3 = ExternRef::new(7usize);
|
||||||
|
{
|
||||||
|
let result = grow_table_with_ref.call(er1.clone(), 0)?;
|
||||||
|
assert_eq!(result, 2);
|
||||||
|
assert_eq!(er1.strong_count(), 1);
|
||||||
|
|
||||||
|
let result = grow_table_with_ref.call(er1.clone(), 10_000)?;
|
||||||
|
assert_eq!(result, -1);
|
||||||
|
assert_eq!(er1.strong_count(), 1);
|
||||||
|
|
||||||
|
let result = grow_table_with_ref.call(er1.clone(), 8)?;
|
||||||
|
assert_eq!(result, 2);
|
||||||
|
assert_eq!(er1.strong_count(), 9);
|
||||||
|
|
||||||
|
for i in 2..10 {
|
||||||
|
let e = table1.get(i).unwrap().unwrap_externref();
|
||||||
|
assert_eq!(*e.downcast::<usize>().unwrap(), 3);
|
||||||
|
assert_eq!(&e, &er1);
|
||||||
|
}
|
||||||
|
assert_eq!(er1.strong_count(), 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
fill_table_with_ref.call(er2.clone(), 0, 2)?;
|
||||||
|
assert_eq!(er2.strong_count(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
table2.set(0, Val::ExternRef(er3.clone()))?;
|
||||||
|
table2.set(1, Val::ExternRef(er3.clone()))?;
|
||||||
|
table2.set(2, Val::ExternRef(er3.clone()))?;
|
||||||
|
table2.set(3, Val::ExternRef(er3.clone()))?;
|
||||||
|
table2.set(4, Val::ExternRef(er3.clone()))?;
|
||||||
|
assert_eq!(er3.strong_count(), 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
copy_into_table2.call()?;
|
||||||
|
assert_eq!(er3.strong_count(), 2);
|
||||||
|
assert_eq!(er2.strong_count(), 5);
|
||||||
|
assert_eq!(er1.strong_count(), 11);
|
||||||
|
for i in 1..5 {
|
||||||
|
let e = table2.get(i).unwrap().unwrap_externref();
|
||||||
|
let value = e.downcast::<usize>().unwrap();
|
||||||
|
match i {
|
||||||
|
0 | 1 => assert_eq!(*value, 5),
|
||||||
|
4 => assert_eq!(*value, 7),
|
||||||
|
_ => assert_eq!(*value, 3),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
for i in 0..table1.size() {
|
||||||
|
table1.set(i, Val::ExternRef(ExternRef::null()))?;
|
||||||
|
}
|
||||||
|
for i in 0..table2.size() {
|
||||||
|
table2.set(i, Val::ExternRef(ExternRef::null()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(er1.strong_count(), 1);
|
||||||
|
assert_eq!(er2.strong_count(), 1);
|
||||||
|
assert_eq!(er3.strong_count(), 1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
2
lib/cache/Cargo.toml
vendored
2
lib/cache/Cargo.toml
vendored
@@ -11,7 +11,7 @@ readme = "README.md"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer = { path = "../api", version = "2.0.0", default-features = false }
|
wasmer = { path = "../api", version = "2.0.0", default-features = false, features = ["sys"] }
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
blake3 = "0.3"
|
blake3 = "0.3"
|
||||||
|
|||||||
@@ -10,10 +10,6 @@ edition = "2018"
|
|||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[features]
|
|
||||||
# It will make imports from `wasmer_js::` instead of `wasmer::`
|
|
||||||
js = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
syn = { version = "1.0.72", features = ["full", "extra-traits"] }
|
syn = { version = "1.0.72", features = ["full", "extra-traits"] }
|
||||||
quote = "1"
|
quote = "1"
|
||||||
@@ -22,4 +18,4 @@ proc-macro-error = "1.0.0"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasmer = { path = "../api", version = "2.0.0" }
|
wasmer = { path = "../api", version = "2.0.0" }
|
||||||
compiletest_rs = "0.6"
|
compiletest_rs = "0.6"
|
||||||
@@ -13,26 +13,21 @@ use crate::parse::WasmerAttr;
|
|||||||
#[proc_macro_derive(WasmerEnv, attributes(wasmer))]
|
#[proc_macro_derive(WasmerEnv, attributes(wasmer))]
|
||||||
pub fn derive_wasmer_env(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_wasmer_env(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let input: DeriveInput = syn::parse(input).unwrap();
|
let input: DeriveInput = syn::parse(input).unwrap();
|
||||||
#[cfg(feature = "js")]
|
let gen = impl_wasmer_env(&input);
|
||||||
let root = Ident::new("wasmer_js", proc_macro2::Span::call_site());
|
|
||||||
#[cfg(not(feature = "js"))]
|
|
||||||
let root = Ident::new("wasmer", proc_macro2::Span::call_site());
|
|
||||||
let gen = impl_wasmer_env(&root, &input);
|
|
||||||
gen.into()
|
gen.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_wasmer_env_for_struct(
|
fn impl_wasmer_env_for_struct(
|
||||||
root: &Ident,
|
|
||||||
name: &Ident,
|
name: &Ident,
|
||||||
data: &DataStruct,
|
data: &DataStruct,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
_attrs: &[Attribute],
|
_attrs: &[Attribute],
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let (trait_methods, helper_methods) = derive_struct_fields(root, data);
|
let (trait_methods, helper_methods) = derive_struct_fields(data);
|
||||||
let lifetimes_and_generics = generics.params.clone();
|
let lifetimes_and_generics = generics.params.clone();
|
||||||
let where_clause = generics.where_clause.clone();
|
let where_clause = generics.where_clause.clone();
|
||||||
quote! {
|
quote! {
|
||||||
impl < #lifetimes_and_generics > ::#root::WasmerEnv for #name < #lifetimes_and_generics > #where_clause{
|
impl < #lifetimes_and_generics > ::wasmer::WasmerEnv for #name < #lifetimes_and_generics > #where_clause{
|
||||||
#trait_methods
|
#trait_methods
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,12 +38,12 @@ fn impl_wasmer_env_for_struct(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_wasmer_env(root: &Ident, input: &DeriveInput) -> TokenStream {
|
fn impl_wasmer_env(input: &DeriveInput) -> TokenStream {
|
||||||
let struct_name = &input.ident;
|
let struct_name = &input.ident;
|
||||||
|
|
||||||
set_dummy(quote! {
|
set_dummy(quote! {
|
||||||
impl ::#root::WasmerEnv for #struct_name {
|
impl ::wasmer::WasmerEnv for #struct_name {
|
||||||
fn init_with_instance(&mut self, instance: &::#root::Instance) -> Result<(), ::#root::HostEnvInitError> {
|
fn init_with_instance(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +51,7 @@ fn impl_wasmer_env(root: &Ident, input: &DeriveInput) -> TokenStream {
|
|||||||
|
|
||||||
match &input.data {
|
match &input.data {
|
||||||
Data::Struct(ds) => {
|
Data::Struct(ds) => {
|
||||||
impl_wasmer_env_for_struct(root, struct_name, ds, &input.generics, &input.attrs)
|
impl_wasmer_env_for_struct(struct_name, ds, &input.generics, &input.attrs)
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
@@ -70,7 +65,7 @@ fn impl_wasmer_env(root: &Ident, input: &DeriveInput) -> TokenStream {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_struct_fields(root: &Ident, data: &DataStruct) -> (TokenStream, TokenStream) {
|
fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) {
|
||||||
let mut finish = vec![];
|
let mut finish = vec![];
|
||||||
let mut helpers = vec![];
|
let mut helpers = vec![];
|
||||||
//let mut assign_tokens = vec![];
|
//let mut assign_tokens = vec![];
|
||||||
@@ -210,7 +205,7 @@ fn derive_struct_fields(root: &Ident, data: &DataStruct) -> (TokenStream, TokenS
|
|||||||
}
|
}
|
||||||
|
|
||||||
let trait_methods = quote! {
|
let trait_methods = quote! {
|
||||||
fn init_with_instance(&mut self, instance: &::#root::Instance) -> Result<(), ::#root::HostEnvInitError> {
|
fn init_with_instance(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> {
|
||||||
#(#finish)*
|
#(#finish)*
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ lazy_static = "1.4"
|
|||||||
libc = "^0.2"
|
libc = "^0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
wasmer = { path = "../api", version = "2.0.0", default-features = false }
|
wasmer = { path = "../api", version = "2.0.0", default-features = false, features = ["sys"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
getrandom = "0.2"
|
getrandom = "0.2"
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "wasmer-js"
|
|
||||||
version = "2.0.0"
|
|
||||||
description = "A crate to compile Wasmer to WebAssembly and make it run in a JavaScript host"
|
|
||||||
categories = ["wasm"]
|
|
||||||
keywords = ["wasm", "webassembly", "runtime", "vm", "javascript"]
|
|
||||||
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
|
|
||||||
repository = "https://github.com/wasmerio/wasmer"
|
|
||||||
license = "MIT"
|
|
||||||
readme = "README.md"
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
# `wasm-opt` is on by default in for the release profile, but it can be
|
|
||||||
# disabled by setting it to `false`
|
|
||||||
[package.metadata.wasm-pack.profile.release]
|
|
||||||
wasm-opt = false
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
crate-type = ["cdylib", "rlib"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
wasm-bindgen = { version = "0.2.74" }
|
|
||||||
js-sys = { version = "0.3.51" }
|
|
||||||
wasmer-types = { path = "../types", version = "2.0.0", default-features = false, features = ["std"] }
|
|
||||||
indexmap = { version = "1.6", features = ["serde-1"] }
|
|
||||||
cfg-if = "1.0"
|
|
||||||
wat = { version = "1.0", optional = true }
|
|
||||||
thiserror = "1.0"
|
|
||||||
more-asserts = "0.2"
|
|
||||||
wasmer-derive = { path = "../derive", version = "2.0.0", features = ["js"] }
|
|
||||||
wasmparser = { version = "0.78", optional = true, default-features = false }
|
|
||||||
hashbrown = { version = "0.11", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
wat = "1.0"
|
|
||||||
anyhow = "1.0"
|
|
||||||
wasm-bindgen-test = "0.3.0"
|
|
||||||
# wasm-bindgen-test = { version= "0.3.0", path = "../../../wasm-bindgen/crates/test"}
|
|
||||||
|
|
||||||
[badges]
|
|
||||||
maintenance = { status = "actively-developed" }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["std", "wasm-types-polyfill", "wat"]
|
|
||||||
wasm-types-polyfill = ["wasmparser"]
|
|
||||||
std = []
|
|
||||||
core = ["hashbrown"]
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
# `wasmer-js` [](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [](https://slack.wasmer.io) [](https://github.com/wasmerio/wasmer/blob/master/LICENSE) [](https://crates.io/crates/wasmer-js)
|
|
||||||
|
|
||||||
[`Wasmer`](https://wasmer.io/) is the most popular
|
|
||||||
[WebAssembly](https://webassembly.org/) runtime for Rust. This crate mimics the same Rust
|
|
||||||
API than the `wasmer` crate, but when compiled to WebAssembly, it only targets
|
|
||||||
a JavaScript host. It means that it is possible to write a Rust program that uses Wasmer,
|
|
||||||
and compiles everything to WebAssembly to run in a browser, Node.js, Deno and so on.
|
|
||||||
|
|
||||||
This crate doesn't ship with any compilers or engines, as it leverages the Javascript VM to
|
|
||||||
compile and run WebAssembly.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
We recommend aliasing `wasmer_js` to `wasmer` at the top of your crate.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[cfg(feature = "js")]
|
|
||||||
extern crate wasmer_js as wasmer;
|
|
||||||
```
|
|
||||||
|
|
||||||
And then:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use wasmer::{Store, Module, Instance, Value, imports};
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub extern fn do_add_one_in_wasmer() -> i32 {
|
|
||||||
let module_wat = r#"
|
|
||||||
(module
|
|
||||||
(type $t0 (func (param i32) (result i32)))
|
|
||||||
(func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
|
|
||||||
get_local $p0
|
|
||||||
i32.const 1
|
|
||||||
i32.add))
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(&store, &module_wat).unwrap();
|
|
||||||
// The module doesn't import anything, so we create an empty import object.
|
|
||||||
let import_object = imports! {};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let add_one = instance.exports.get_function("add_one").unwrap();
|
|
||||||
let result = add_one.call(&[Value::I32(42)]).unwrap();
|
|
||||||
assert_eq!(result[0], Value::I32(43));
|
|
||||||
result[0].unwrap_i32()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Feature flags
|
|
||||||
|
|
||||||
`wasmer-js` has the following feature flags:
|
|
||||||
* `wasm-types-polyfill` (enabled by default): it parses the Wasm file, allowing to do type reflection of the inner WebAssembly types.
|
|
||||||
__It adds 100Kb to the Wasm bundle__ (28Kb gzipped). You can disable it and use `Module::set_type_hints` manually instead if you want a lightweight alternative.
|
|
||||||
This is needed until the [Wasm JS introspection API proposal](https://github.com/WebAssembly/js-types/blob/master/proposals/js-types/Overview.md) is adopted by browsers
|
|
||||||
|
|
||||||
* `wat`: It allows to read WebAssembly files in their text format.
|
|
||||||
*This feature is normally used only in development environments, __it will add around 650Kb to the Wasm bundle__* (120Kb gzipped).
|
|
||||||
|
|
||||||
# Build
|
|
||||||
|
|
||||||
You can use [`wasm-pack`](https://github.com/rustwasm/wasm-pack/) to build `wasmer-js-api`:
|
|
||||||
|
|
||||||
```
|
|
||||||
wasm-pack build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
> The provided `wasmer_js.wasm` file should weight around 60kB (27Kb gzipped) when optmized via `wasm-opt` and stripped via `wasm-strip`, so it's quite slim.
|
|
||||||
|
|
||||||
# Test
|
|
||||||
|
|
||||||
```
|
|
||||||
wasm-pack test --node
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Made with ❤️ by the Wasmer team, for the community
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
#![doc(
|
|
||||||
html_logo_url = "https://github.com/wasmerio.png?size=200",
|
|
||||||
html_favicon_url = "https://wasmer.io/images/icons/favicon-32x32.png"
|
|
||||||
)]
|
|
||||||
#![deny(
|
|
||||||
missing_docs,
|
|
||||||
trivial_numeric_casts,
|
|
||||||
unused_extern_crates,
|
|
||||||
broken_intra_doc_links
|
|
||||||
)]
|
|
||||||
#![warn(unused_import_braces)]
|
|
||||||
#![cfg_attr(
|
|
||||||
feature = "cargo-clippy",
|
|
||||||
allow(clippy::new_without_default, clippy::vtable_address_comparisons)
|
|
||||||
)]
|
|
||||||
#![cfg_attr(
|
|
||||||
feature = "cargo-clippy",
|
|
||||||
warn(
|
|
||||||
clippy::float_arithmetic,
|
|
||||||
clippy::mut_mut,
|
|
||||||
clippy::nonminimal_bool,
|
|
||||||
clippy::map_unwrap_or,
|
|
||||||
clippy::print_stdout,
|
|
||||||
clippy::unicode_not_nfc,
|
|
||||||
clippy::use_self
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
|
|
||||||
//! This crate contains the `wasmer-js` API. The `wasmer-js` API facilitates the efficient,
|
|
||||||
//! sandboxed execution of [WebAssembly (Wasm)][wasm] modules, leveraging on the same
|
|
||||||
//! API as the `wasmer` crate, but targeting Javascript.
|
|
||||||
//!
|
|
||||||
//! This crate uses the same WebAssembly engine as the Javascript VM where it's used.
|
|
||||||
//!
|
|
||||||
//! Here's an example of the `wasmer-js` API in action:
|
|
||||||
//! ```
|
|
||||||
//! #[wasm_bindgen]
|
|
||||||
//! pub extern fn do_add_one_in_wasmer() -> i32 {
|
|
||||||
//! let module_wat = r#"
|
|
||||||
//! (module
|
|
||||||
//! (type $t0 (func (param i32) (result i32)))
|
|
||||||
//! (func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
|
|
||||||
//! get_local $p0
|
|
||||||
//! i32.const 1
|
|
||||||
//! i32.add))
|
|
||||||
//! "#;
|
|
||||||
//! let store = Store::default();
|
|
||||||
//! let module = Module::new(&store, &module_wat).unwrap();
|
|
||||||
//! // The module doesn't import anything, so we create an empty import object.
|
|
||||||
//! let import_object = imports! {};
|
|
||||||
//! let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
//! let add_one = instance.exports.get_function("add_one").unwrap();
|
|
||||||
//! let result = add_one.call(&[Value::I32(42)]).unwrap();
|
|
||||||
//! assert_eq!(result[0], Value::I32(43));
|
|
||||||
//! result[0].unwrap_i32()
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! For more examples of using the `wasmer` API, check out the
|
|
||||||
//! [wasmer examples][wasmer-examples].
|
|
||||||
|
|
||||||
#[cfg(all(feature = "std", feature = "core"))]
|
|
||||||
compile_error!(
|
|
||||||
"The `std` and `core` features are both enabled, which is an error. Please enable only once."
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(all(not(feature = "std"), not(feature = "core")))]
|
|
||||||
compile_error!("Both the `std` and `core` features are disabled. Please enable one of them.");
|
|
||||||
|
|
||||||
#[cfg(feature = "core")]
|
|
||||||
extern crate alloc;
|
|
||||||
|
|
||||||
mod lib {
|
|
||||||
#[cfg(feature = "core")]
|
|
||||||
pub mod std {
|
|
||||||
pub use alloc::{borrow, boxed, str, string, sync, vec};
|
|
||||||
pub use core::fmt;
|
|
||||||
pub use hashbrown as collections;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub mod std {
|
|
||||||
pub use std::{borrow, boxed, collections, fmt, str, string, sync, vec};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod cell;
|
|
||||||
mod env;
|
|
||||||
mod error;
|
|
||||||
mod export;
|
|
||||||
mod exports;
|
|
||||||
mod externals;
|
|
||||||
mod import_object;
|
|
||||||
mod instance;
|
|
||||||
mod module;
|
|
||||||
#[cfg(feature = "wasm-types-polyfill")]
|
|
||||||
mod module_info_polyfill;
|
|
||||||
mod native;
|
|
||||||
mod ptr;
|
|
||||||
mod resolver;
|
|
||||||
mod store;
|
|
||||||
mod trap;
|
|
||||||
mod types;
|
|
||||||
mod utils;
|
|
||||||
mod wasm_bindgen_polyfill;
|
|
||||||
|
|
||||||
/// Implement [`WasmerEnv`] for your type with `#[derive(WasmerEnv)]`.
|
|
||||||
///
|
|
||||||
/// See the [`WasmerEnv`] trait for more information.
|
|
||||||
pub use wasmer_derive::WasmerEnv;
|
|
||||||
|
|
||||||
pub use crate::cell::WasmCell;
|
|
||||||
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, MemoryError, Table,
|
|
||||||
WasmTypeList,
|
|
||||||
};
|
|
||||||
pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
|
|
||||||
pub use crate::instance::{Instance, InstantiationError};
|
|
||||||
pub use crate::module::{Module, ModuleTypeHints};
|
|
||||||
pub use crate::native::NativeFunc;
|
|
||||||
pub use crate::ptr::{Array, Item, WasmPtr};
|
|
||||||
pub use crate::resolver::{ChainableNamedResolver, NamedResolver, NamedResolverChain, Resolver};
|
|
||||||
pub use crate::trap::RuntimeError;
|
|
||||||
|
|
||||||
pub use crate::store::{Store, StoreObject};
|
|
||||||
pub use crate::types::{
|
|
||||||
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
|
|
||||||
TableType, Val, ValType,
|
|
||||||
};
|
|
||||||
pub use crate::types::{Val as Value, ValType as Type};
|
|
||||||
pub use crate::utils::is_wasm;
|
|
||||||
|
|
||||||
pub use wasmer_types::{
|
|
||||||
Atomically, Bytes, ExportIndex, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType,
|
|
||||||
WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "wat")]
|
|
||||||
pub use wat::parse_bytes as wat2wasm;
|
|
||||||
|
|
||||||
/// Version number of this crate.
|
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
||||||
@@ -1,418 +0,0 @@
|
|||||||
use wasm_bindgen_test::*;
|
|
||||||
// use anyhow::Result;
|
|
||||||
use wasmer_js::*;
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn global_new() {
|
|
||||||
let store = Store::default();
|
|
||||||
let global = Global::new(&store, Value::I32(10));
|
|
||||||
assert_eq!(
|
|
||||||
*global.ty(),
|
|
||||||
GlobalType {
|
|
||||||
ty: Type::I32,
|
|
||||||
mutability: Mutability::Const
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let global_mut = Global::new_mut(&store, Value::I32(10));
|
|
||||||
assert_eq!(
|
|
||||||
*global_mut.ty(),
|
|
||||||
GlobalType {
|
|
||||||
ty: Type::I32,
|
|
||||||
mutability: Mutability::Var
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn global_get() {
|
|
||||||
let store = Store::default();
|
|
||||||
let global_i32 = Global::new(&store, Value::I32(10));
|
|
||||||
assert_eq!(global_i32.get(), Value::I32(10));
|
|
||||||
// 64-bit values are not yet fully supported in some versions of Node
|
|
||||||
// Commenting this tests for now:
|
|
||||||
|
|
||||||
// let global_i64 = Global::new(&store, Value::I64(20));
|
|
||||||
// assert_eq!(global_i64.get(), Value::I64(20));
|
|
||||||
let global_f32 = Global::new(&store, Value::F32(10.0));
|
|
||||||
assert_eq!(global_f32.get(), Value::F32(10.0));
|
|
||||||
// let global_f64 = Global::new(&store, Value::F64(20.0));
|
|
||||||
// assert_eq!(global_f64.get(), Value::F64(20.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn global_set() {
|
|
||||||
let store = Store::default();
|
|
||||||
let global_i32 = Global::new(&store, Value::I32(10));
|
|
||||||
// Set on a constant should error
|
|
||||||
assert!(global_i32.set(Value::I32(20)).is_err());
|
|
||||||
|
|
||||||
let global_i32_mut = Global::new_mut(&store, Value::I32(10));
|
|
||||||
// Set on different type should error
|
|
||||||
assert!(global_i32_mut.set(Value::I64(20)).is_err());
|
|
||||||
|
|
||||||
// Set on same type should succeed
|
|
||||||
global_i32_mut.set(Value::I32(20)).unwrap();
|
|
||||||
assert_eq!(global_i32_mut.get(), Value::I32(20));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn table_new() {
|
|
||||||
let store = Store::default();
|
|
||||||
let table_type = TableType {
|
|
||||||
ty: Type::FuncRef,
|
|
||||||
minimum: 0,
|
|
||||||
maximum: None,
|
|
||||||
};
|
|
||||||
let f = Function::new_native(&store, || {});
|
|
||||||
let table = Table::new(&store, table_type, Value::FuncRef(Some(f))).unwrap();
|
|
||||||
assert_eq!(*table.ty(), table_type);
|
|
||||||
|
|
||||||
// table.get()
|
|
||||||
// Anyrefs not yet supported
|
|
||||||
// let table_type = TableType {
|
|
||||||
// ty: Type::ExternRef,
|
|
||||||
// minimum: 0,
|
|
||||||
// maximum: None,
|
|
||||||
// };
|
|
||||||
// let table = Table::new(&store, table_type, Value::ExternRef(ExternRef::Null))?;
|
|
||||||
// assert_eq!(*table.ty(), table_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tables are not yet fully supported in Wasm
|
|
||||||
// Commenting this tests for now
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// #[ignore]
|
|
||||||
// fn table_get() -> Result<()> {
|
|
||||||
// let store = Store::default();
|
|
||||||
// let table_type = TableType {
|
|
||||||
// ty: Type::FuncRef,
|
|
||||||
// minimum: 0,
|
|
||||||
// maximum: Some(1),
|
|
||||||
// };
|
|
||||||
// let f = Function::new_native(&store, |num: i32| num + 1);
|
|
||||||
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
|
||||||
// assert_eq!(*table.ty(), table_type);
|
|
||||||
// let _elem = table.get(0).unwrap();
|
|
||||||
// // assert_eq!(elem.funcref().unwrap(), f);
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// #[ignore]
|
|
||||||
// fn table_set() -> Result<()> {
|
|
||||||
// // Table set not yet tested
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn table_grow() -> Result<()> {
|
|
||||||
// let store = Store::default();
|
|
||||||
// let table_type = TableType {
|
|
||||||
// ty: Type::FuncRef,
|
|
||||||
// minimum: 0,
|
|
||||||
// maximum: Some(10),
|
|
||||||
// };
|
|
||||||
// let f = Function::new_native(&store, |num: i32| num + 1);
|
|
||||||
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
|
||||||
// // Growing to a bigger maximum should return None
|
|
||||||
// let old_len = table.grow(12, Value::FuncRef(Some(f.clone())));
|
|
||||||
// assert!(old_len.is_err());
|
|
||||||
|
|
||||||
// // Growing to a bigger maximum should return None
|
|
||||||
// let old_len = table.grow(5, Value::FuncRef(Some(f.clone())))?;
|
|
||||||
// assert_eq!(old_len, 0);
|
|
||||||
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// #[ignore]
|
|
||||||
// fn table_copy() -> Result<()> {
|
|
||||||
// // TODO: table copy test not yet implemented
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn memory_new() {
|
|
||||||
let store = Store::default();
|
|
||||||
let memory_type = MemoryType {
|
|
||||||
shared: false,
|
|
||||||
minimum: Pages(0),
|
|
||||||
maximum: Some(Pages(10)),
|
|
||||||
};
|
|
||||||
let memory = Memory::new(&store, memory_type).unwrap();
|
|
||||||
assert_eq!(memory.size(), Pages(0));
|
|
||||||
assert_eq!(memory.ty(), memory_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn memory_grow() {
|
|
||||||
let store = Store::default();
|
|
||||||
|
|
||||||
let desc = MemoryType::new(Pages(10), Some(Pages(16)), false);
|
|
||||||
let memory = Memory::new(&store, desc).unwrap();
|
|
||||||
assert_eq!(memory.size(), Pages(10));
|
|
||||||
|
|
||||||
let result = memory.grow(Pages(2)).unwrap();
|
|
||||||
assert_eq!(result, Pages(10));
|
|
||||||
assert_eq!(memory.size(), Pages(12));
|
|
||||||
|
|
||||||
let result = memory.grow(Pages(10));
|
|
||||||
assert!(result.is_err());
|
|
||||||
assert_eq!(
|
|
||||||
result,
|
|
||||||
Err(MemoryError::CouldNotGrow {
|
|
||||||
current: 12.into(),
|
|
||||||
attempted_delta: 10.into()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn function_new() {
|
|
||||||
let store = Store::default();
|
|
||||||
let function = Function::new_native(&store, || {});
|
|
||||||
assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
|
|
||||||
let function = Function::new_native(&store, |_a: i32| {});
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![Type::I32], vec![])
|
|
||||||
);
|
|
||||||
let function = Function::new_native(&store, |_a: i32, _b: i64, _c: f32, _d: f64| {});
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
|
||||||
);
|
|
||||||
let function = Function::new_native(&store, || -> i32 { 1 });
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32])
|
|
||||||
);
|
|
||||||
let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn function_new_env() {
|
|
||||||
let store = Store::default();
|
|
||||||
#[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![]));
|
|
||||||
let function =
|
|
||||||
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv, _a: i32| {});
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![Type::I32], vec![])
|
|
||||||
);
|
|
||||||
let function = Function::new_native_with_env(
|
|
||||||
&store,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _a: i32, _b: i64, _c: f32, _d: f64| {},
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
|
|
||||||
);
|
|
||||||
let function =
|
|
||||||
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| -> i32 { 1 });
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32])
|
|
||||||
);
|
|
||||||
let function = Function::new_native_with_env(
|
|
||||||
&store,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
function.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn function_new_dynamic() {
|
|
||||||
let store = Store::default();
|
|
||||||
|
|
||||||
// Using &FunctionType signature
|
|
||||||
let function_type = FunctionType::new(vec![], vec![]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
|
||||||
let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
|
|
||||||
// Using array signature
|
|
||||||
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
|
||||||
let function = Function::new(&store, function_type, |_values: &[Value]| unimplemented!());
|
|
||||||
assert_eq!(function.ty().params(), [Type::V128]);
|
|
||||||
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn function_new_dynamic_env() {
|
|
||||||
let store = Store::default();
|
|
||||||
#[derive(Clone, WasmerEnv)]
|
|
||||||
struct MyEnv {}
|
|
||||||
let my_env = MyEnv {};
|
|
||||||
|
|
||||||
// Using &FunctionType signature
|
|
||||||
let function_type = FunctionType::new(vec![], vec![]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![Type::I32], vec![]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![], vec![Type::I32]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().clone(), function_type);
|
|
||||||
|
|
||||||
// Using array signature
|
|
||||||
let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
|
|
||||||
let function = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
function_type,
|
|
||||||
my_env.clone(),
|
|
||||||
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
|
|
||||||
);
|
|
||||||
assert_eq!(function.ty().params(), [Type::V128]);
|
|
||||||
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn native_function_works() {
|
|
||||||
let store = Store::default();
|
|
||||||
let function = Function::new_native(&store, || {});
|
|
||||||
let native_function: NativeFunc<(), ()> = function.native().unwrap();
|
|
||||||
let result = native_function.call();
|
|
||||||
assert!(result.is_ok());
|
|
||||||
|
|
||||||
let function = Function::new_native(&store, |a: i32| -> i32 { a + 1 });
|
|
||||||
let native_function: NativeFunc<i32, i32> = function.native().unwrap();
|
|
||||||
assert_eq!(native_function.call(3).unwrap(), 4);
|
|
||||||
|
|
||||||
// fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
|
|
||||||
// (a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
|
|
||||||
// }
|
|
||||||
// let function = Function::new_native(&store, rust_abi);
|
|
||||||
// let native_function: NativeFunc<(i32, i64, f32, f64), u64> = function.native().unwrap();
|
|
||||||
// assert_eq!(native_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
|
|
||||||
|
|
||||||
let function = Function::new_native(&store, || -> i32 { 1 });
|
|
||||||
let native_function: NativeFunc<(), i32> = function.native().unwrap();
|
|
||||||
assert_eq!(native_function.call().unwrap(), 1);
|
|
||||||
|
|
||||||
let function = Function::new_native(&store, |_a: i32| {});
|
|
||||||
let native_function: NativeFunc<i32, ()> = function.native().unwrap();
|
|
||||||
assert!(native_function.call(4).is_ok());
|
|
||||||
|
|
||||||
// let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
|
||||||
// let native_function: NativeFunc<(), (i32, i64, f32, f64)> = function.native().unwrap();
|
|
||||||
// assert_eq!(native_function.call().unwrap(), (1, 2, 3.0, 4.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn function_outlives_instance() {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(type $sum_t (func (param i32 i32) (result i32)))
|
|
||||||
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
|
|
||||||
local.get $x
|
|
||||||
local.get $y
|
|
||||||
i32.add)
|
|
||||||
(export "sum" (func $sum_f)))
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let f = {
|
|
||||||
let module = Module::new(&store, wat).unwrap();
|
|
||||||
let instance = Instance::new(&module, &imports! {}).unwrap();
|
|
||||||
let f = instance.exports.get_function("sum").unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
f.call(&[Val::I32(4), Val::I32(5)]).unwrap(),
|
|
||||||
vec![Val::I32(9)].into_boxed_slice()
|
|
||||||
);
|
|
||||||
f.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
f.call(&[Val::I32(4), Val::I32(5)]).unwrap(),
|
|
||||||
vec![Val::I32(9)].into_boxed_slice()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn manually_generate_wasmer_env() {
|
|
||||||
let store = Store::default();
|
|
||||||
#[derive(WasmerEnv, Clone)]
|
|
||||||
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)).unwrap();
|
|
||||||
env.memory.initialize(memory);
|
|
||||||
|
|
||||||
let result = host_function(&mut env, 1, 2);
|
|
||||||
assert_eq!(result, 8);
|
|
||||||
}
|
|
||||||
@@ -1,731 +0,0 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use wasm_bindgen_test::*;
|
|
||||||
use wasmer_js::*;
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_exported_memory() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(memory (export "mem") 1)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![],
|
|
||||||
exports: vec![ExternType::Memory(MemoryType::new(Pages(1), None, false))],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let import_object = imports! {};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let memory = instance.exports.get_memory("mem").unwrap();
|
|
||||||
assert_eq!(memory.ty(), MemoryType::new(Pages(1), None, false));
|
|
||||||
assert_eq!(memory.size(), Pages(1));
|
|
||||||
assert_eq!(memory.data_size(), 65536);
|
|
||||||
|
|
||||||
memory.grow(Pages(1)).unwrap();
|
|
||||||
assert_eq!(memory.ty(), MemoryType::new(Pages(2), None, false));
|
|
||||||
assert_eq!(memory.size(), Pages(2));
|
|
||||||
assert_eq!(memory.data_size(), 65536 * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_exported_function() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(func (export "get_magic") (result i32)
|
|
||||||
(i32.const 42)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![],
|
|
||||||
exports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let import_object = imports! {};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let get_magic = instance.exports.get_function("get_magic").unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
get_magic.ty().clone(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32])
|
|
||||||
);
|
|
||||||
|
|
||||||
let expected = vec![Val::I32(42)].into_boxed_slice();
|
|
||||||
assert_eq!(get_magic.call(&[]), Ok(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_imported_function_dynamic() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(func $imported (import "env" "imported") (param i32) (result i32))
|
|
||||||
(func (export "exported") (param i32) (result i32)
|
|
||||||
(call $imported (local.get 0))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
exports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
|
|
||||||
let imported = Function::new(&store, &imported_signature, |args| {
|
|
||||||
println!("Calling `imported`...");
|
|
||||||
let result = args[0].unwrap_i32() * 2;
|
|
||||||
println!("Result of `imported`: {:?}", result);
|
|
||||||
Ok(vec![Value::I32(result)])
|
|
||||||
});
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"imported" => imported,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let exported = instance.exports.get_function("exported").unwrap();
|
|
||||||
|
|
||||||
let expected = vec![Val::I32(6)].into_boxed_slice();
|
|
||||||
assert_eq!(exported.call(&[Val::I32(3)]), Ok(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We comment it for now because in old versions of Node, only single return values are supported
|
|
||||||
|
|
||||||
// #[wasm_bindgen_test]
|
|
||||||
// fn test_imported_function_dynamic_multivalue() {
|
|
||||||
// let store = Store::default();
|
|
||||||
// let mut module = Module::new(
|
|
||||||
// &store,
|
|
||||||
// br#"
|
|
||||||
// (module
|
|
||||||
// (func $multivalue (import "env" "multivalue") (param i32 i32) (result i32 i32))
|
|
||||||
// (func (export "multivalue") (param i32 i32) (result i32 i32)
|
|
||||||
// (call $multivalue (local.get 0) (local.get 1))
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// "#,
|
|
||||||
// )
|
|
||||||
// .unwrap();
|
|
||||||
// module.set_type_hints(ModuleTypeHints {
|
|
||||||
// imports: vec![
|
|
||||||
// ExternType::Function(FunctionType::new(
|
|
||||||
// vec![Type::I32, Type::I32],
|
|
||||||
// vec![Type::I32, Type::I32],
|
|
||||||
// )),
|
|
||||||
// ],
|
|
||||||
// exports: vec![
|
|
||||||
// ExternType::Function(FunctionType::new(
|
|
||||||
// vec![Type::I32, Type::I32],
|
|
||||||
// vec![Type::I32, Type::I32],
|
|
||||||
// )),
|
|
||||||
// ],
|
|
||||||
// });
|
|
||||||
|
|
||||||
// let multivalue_signature =
|
|
||||||
// FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]);
|
|
||||||
// let multivalue = Function::new(&store, &multivalue_signature, |args| {
|
|
||||||
// println!("Calling `imported`...");
|
|
||||||
// // let result = args[0].unwrap_i32() * ;
|
|
||||||
// // println!("Result of `imported`: {:?}", result);
|
|
||||||
// Ok(vec![args[1].clone(), args[0].clone()])
|
|
||||||
// });
|
|
||||||
|
|
||||||
// let import_object = imports! {
|
|
||||||
// "env" => {
|
|
||||||
// "multivalue" => multivalue,
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
// let exported_multivalue = instance
|
|
||||||
// .exports
|
|
||||||
// .get_function("multivalue")
|
|
||||||
// .unwrap();
|
|
||||||
|
|
||||||
// let expected = vec![Val::I32(2), Val::I32(3)].into_boxed_slice();
|
|
||||||
// assert_eq!(
|
|
||||||
// exported_multivalue.call(&[Val::I32(3), Val::I32(2)]),
|
|
||||||
// Ok(expected)
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_imported_function_dynamic_with_env() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(func $imported (import "env" "imported") (param i32) (result i32))
|
|
||||||
(func (export "exported") (param i32) (result i32)
|
|
||||||
(call $imported (local.get 0))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
exports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
#[derive(WasmerEnv, Clone)]
|
|
||||||
struct Env {
|
|
||||||
multiplier: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
|
|
||||||
let imported = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
&imported_signature,
|
|
||||||
Env { multiplier: 3 },
|
|
||||||
|env, args| {
|
|
||||||
println!("Calling `imported`...");
|
|
||||||
let result = args[0].unwrap_i32() * env.multiplier;
|
|
||||||
println!("Result of `imported`: {:?}", result);
|
|
||||||
Ok(vec![Value::I32(result)])
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"imported" => imported,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let exported = instance.exports.get_function("exported").unwrap();
|
|
||||||
|
|
||||||
let expected = vec![Val::I32(9)].into_boxed_slice();
|
|
||||||
assert_eq!(exported.call(&[Val::I32(3)]), Ok(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_imported_function_native() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(func $imported (import "env" "imported") (param i32) (result i32))
|
|
||||||
(func (export "exported") (param i32) (result i32)
|
|
||||||
(call $imported (local.get 0))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
exports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
fn imported_fn(arg: u32) -> u32 {
|
|
||||||
return arg + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let imported = Function::new_native(&store, imported_fn);
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"imported" => imported,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let exported = instance.exports.get_function("exported").unwrap();
|
|
||||||
|
|
||||||
let expected = vec![Val::I32(5)].into_boxed_slice();
|
|
||||||
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_imported_function_native_with_env() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(func $imported (import "env" "imported") (param i32) (result i32))
|
|
||||||
(func (export "exported") (param i32) (result i32)
|
|
||||||
(call $imported (local.get 0))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
exports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
#[derive(WasmerEnv, Clone)]
|
|
||||||
struct Env {
|
|
||||||
multiplier: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn imported_fn(env: &Env, arg: u32) -> u32 {
|
|
||||||
return env.multiplier * arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
let imported = Function::new_native_with_env(&store, Env { multiplier: 3 }, imported_fn);
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"imported" => imported,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let exported = instance.exports.get_function("exported").unwrap();
|
|
||||||
|
|
||||||
let expected = vec![Val::I32(12)].into_boxed_slice();
|
|
||||||
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_imported_function_native_with_wasmer_env() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(func $imported (import "env" "imported") (param i32) (result i32))
|
|
||||||
(func (export "exported") (param i32) (result i32)
|
|
||||||
(call $imported (local.get 0))
|
|
||||||
)
|
|
||||||
(memory (export "memory") 1)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
exports: vec![
|
|
||||||
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])),
|
|
||||||
ExternType::Memory(MemoryType::new(Pages(1), None, false)),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
#[derive(WasmerEnv, Clone)]
|
|
||||||
struct Env {
|
|
||||||
multiplier: u32,
|
|
||||||
#[wasmer(export)]
|
|
||||||
memory: LazyInit<Memory>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn imported_fn(env: &Env, arg: u32) -> u32 {
|
|
||||||
let memory = env.memory_ref().unwrap();
|
|
||||||
let memory_val = memory.uint8view().get_index(0);
|
|
||||||
return (memory_val as u32) * env.multiplier * arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
let imported = Function::new_native_with_env(
|
|
||||||
&store,
|
|
||||||
Env {
|
|
||||||
multiplier: 3,
|
|
||||||
memory: LazyInit::new(),
|
|
||||||
},
|
|
||||||
imported_fn,
|
|
||||||
);
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"imported" => imported,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let memory = instance.exports.get_memory("memory").unwrap();
|
|
||||||
assert_eq!(memory.data_size(), 65536);
|
|
||||||
let memory_val = memory.uint8view().get_index(0);
|
|
||||||
assert_eq!(memory_val, 0);
|
|
||||||
|
|
||||||
memory.uint8view().set_index(0, 2);
|
|
||||||
let memory_val = memory.uint8view().get_index(0);
|
|
||||||
assert_eq!(memory_val, 2);
|
|
||||||
|
|
||||||
let exported = instance.exports.get_function("exported").unwrap();
|
|
||||||
|
|
||||||
// It works with the provided memory
|
|
||||||
let expected = vec![Val::I32(24)].into_boxed_slice();
|
|
||||||
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
|
||||||
|
|
||||||
// It works if we update the memory
|
|
||||||
memory.uint8view().set_index(0, 3);
|
|
||||||
let expected = vec![Val::I32(36)].into_boxed_slice();
|
|
||||||
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_imported_function_with_wasmer_env() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(func $imported (import "env" "imported") (param i32) (result i32))
|
|
||||||
(func (export "exported") (param i32) (result i32)
|
|
||||||
(call $imported (local.get 0))
|
|
||||||
)
|
|
||||||
(memory (export "memory") 1)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![ExternType::Function(FunctionType::new(
|
|
||||||
vec![Type::I32],
|
|
||||||
vec![Type::I32],
|
|
||||||
))],
|
|
||||||
exports: vec![
|
|
||||||
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])),
|
|
||||||
ExternType::Memory(MemoryType::new(Pages(1), None, false)),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
#[derive(WasmerEnv, Clone)]
|
|
||||||
struct Env {
|
|
||||||
multiplier: u32,
|
|
||||||
#[wasmer(export)]
|
|
||||||
memory: LazyInit<Memory>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn imported_fn(env: &Env, args: &[Val]) -> Result<Vec<Val>, RuntimeError> {
|
|
||||||
let memory = env.memory_ref().unwrap();
|
|
||||||
let memory_val = memory.uint8view().get_index(0);
|
|
||||||
let value = (memory_val as u32) * env.multiplier * args[0].unwrap_i32() as u32;
|
|
||||||
return Ok(vec![Val::I32(value as _)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
|
|
||||||
let imported = Function::new_with_env(
|
|
||||||
&store,
|
|
||||||
imported_signature,
|
|
||||||
Env {
|
|
||||||
multiplier: 3,
|
|
||||||
memory: LazyInit::new(),
|
|
||||||
},
|
|
||||||
imported_fn,
|
|
||||||
);
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"imported" => imported,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let memory = instance.exports.get_memory("memory").unwrap();
|
|
||||||
assert_eq!(memory.data_size(), 65536);
|
|
||||||
let memory_val = memory.uint8view().get_index(0);
|
|
||||||
assert_eq!(memory_val, 0);
|
|
||||||
|
|
||||||
memory.uint8view().set_index(0, 2);
|
|
||||||
let memory_val = memory.uint8view().get_index(0);
|
|
||||||
assert_eq!(memory_val, 2);
|
|
||||||
|
|
||||||
let exported = instance.exports.get_function("exported").unwrap();
|
|
||||||
|
|
||||||
// It works with the provided memory
|
|
||||||
let expected = vec![Val::I32(24)].into_boxed_slice();
|
|
||||||
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
|
||||||
|
|
||||||
// It works if we update the memory
|
|
||||||
memory.uint8view().set_index(0, 3);
|
|
||||||
let expected = vec![Val::I32(36)].into_boxed_slice();
|
|
||||||
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_imported_exported_global() {
|
|
||||||
let store = Store::default();
|
|
||||||
let mut module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(global $mut_i32_import (import "" "global") (mut i32))
|
|
||||||
(func (export "getGlobal") (result i32) (global.get $mut_i32_import))
|
|
||||||
(func (export "incGlobal") (global.set $mut_i32_import (
|
|
||||||
i32.add (i32.const 1) (global.get $mut_i32_import)
|
|
||||||
)))
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
imports: vec![ExternType::Global(GlobalType::new(
|
|
||||||
ValType::I32,
|
|
||||||
Mutability::Var,
|
|
||||||
))],
|
|
||||||
exports: vec![
|
|
||||||
ExternType::Function(FunctionType::new(vec![], vec![Type::I32])),
|
|
||||||
ExternType::Function(FunctionType::new(vec![], vec![])),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
let global = Global::new_mut(&store, Value::I32(0));
|
|
||||||
let import_object = imports! {
|
|
||||||
"" => {
|
|
||||||
"global" => global.clone()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let get_global = instance.exports.get_function("getGlobal").unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
get_global.call(&[]),
|
|
||||||
Ok(vec![Val::I32(0)].into_boxed_slice())
|
|
||||||
);
|
|
||||||
|
|
||||||
global.set(Value::I32(42)).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
get_global.call(&[]),
|
|
||||||
Ok(vec![Val::I32(42)].into_boxed_slice())
|
|
||||||
);
|
|
||||||
|
|
||||||
let inc_global = instance.exports.get_function("incGlobal").unwrap();
|
|
||||||
inc_global.call(&[]).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
get_global.call(&[]),
|
|
||||||
Ok(vec![Val::I32(43)].into_boxed_slice())
|
|
||||||
);
|
|
||||||
assert_eq!(global.get(), Val::I32(43));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_native_function() {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"(module
|
|
||||||
(func $add (import "env" "sum") (param i32 i32) (result i32))
|
|
||||||
(func (export "add_one") (param i32) (result i32)
|
|
||||||
(call $add (local.get 0) (i32.const 1))
|
|
||||||
)
|
|
||||||
)"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
fn sum(a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"sum" => Function::new_native(&store, sum),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let add_one: NativeFunc<i32, i32> = instance.exports.get_native_function("add_one").unwrap();
|
|
||||||
assert_eq!(add_one.call(1), Ok(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_panic() {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(type $run_t (func (param i32 i32) (result i32)))
|
|
||||||
(type $early_exit_t (func (param) (result)))
|
|
||||||
(import "env" "early_exit" (func $early_exit (type $early_exit_t)))
|
|
||||||
(func $run (type $run_t) (param $x i32) (param $y i32) (result i32)
|
|
||||||
(call $early_exit)
|
|
||||||
(i32.add
|
|
||||||
local.get $x
|
|
||||||
local.get $y))
|
|
||||||
(export "run" (func $run)))
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
fn early_exit() {
|
|
||||||
panic!("Do panic")
|
|
||||||
}
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"early_exit" => Function::new_native(&store, early_exit),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
let run_func: NativeFunc<(i32, i32), i32> =
|
|
||||||
instance.exports.get_native_function("run").unwrap();
|
|
||||||
|
|
||||||
assert!(run_func.call(1, 7).is_err(), "Expected early termination",);
|
|
||||||
let run_func = instance.exports.get_function("run").unwrap();
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
run_func.call(&[Val::I32(1), Val::I32(7)]).is_err(),
|
|
||||||
"Expected early termination",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_custom_error() {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(type $run_t (func (param i32 i32) (result i32)))
|
|
||||||
(type $early_exit_t (func (param) (result)))
|
|
||||||
(import "env" "early_exit" (func $early_exit (type $early_exit_t)))
|
|
||||||
(func $run (type $run_t) (param $x i32) (param $y i32) (result i32)
|
|
||||||
(call $early_exit)
|
|
||||||
(i32.add
|
|
||||||
local.get $x
|
|
||||||
local.get $y))
|
|
||||||
(export "run" (func $run)))
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
struct ExitCode(u32);
|
|
||||||
|
|
||||||
impl fmt::Display for ExitCode {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for ExitCode {}
|
|
||||||
|
|
||||||
fn early_exit() {
|
|
||||||
RuntimeError::raise(Box::new(ExitCode(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let import_object = imports! {
|
|
||||||
"env" => {
|
|
||||||
"early_exit" => Function::new_native(&store, early_exit),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instance = Instance::new(&module, &import_object).unwrap();
|
|
||||||
|
|
||||||
fn test_result<T: core::fmt::Debug>(result: Result<T, RuntimeError>) {
|
|
||||||
match result {
|
|
||||||
Ok(result) => {
|
|
||||||
assert!(
|
|
||||||
false,
|
|
||||||
"Expected early termination with `ExitCode`, found: {:?}",
|
|
||||||
result
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
match e.downcast::<ExitCode>() {
|
|
||||||
// We found the exit code used to terminate execution.
|
|
||||||
Ok(exit_code) => {
|
|
||||||
assert_eq!(exit_code.0, 1);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
assert!(false, "Unknown error `{:?}` found. expected `ErrorCode`", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let run_func: NativeFunc<(i32, i32), i32> =
|
|
||||||
instance.exports.get_native_function("run").unwrap();
|
|
||||||
test_result(run_func.call(1, 7));
|
|
||||||
|
|
||||||
let run_func = instance.exports.get_function("run").unwrap();
|
|
||||||
test_result(run_func.call(&[Val::I32(1), Val::I32(7)]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn test_start_function_fails() {
|
|
||||||
let store = Store::default();
|
|
||||||
let module = Module::new(
|
|
||||||
&store,
|
|
||||||
br#"
|
|
||||||
(module
|
|
||||||
(func $start_function
|
|
||||||
(i32.div_u
|
|
||||||
(i32.const 1)
|
|
||||||
(i32.const 0)
|
|
||||||
)
|
|
||||||
drop
|
|
||||||
)
|
|
||||||
(start $start_function)
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let import_object = imports! {};
|
|
||||||
let result = Instance::new(&module, &import_object);
|
|
||||||
let err = result.unwrap_err();
|
|
||||||
assert!(format!("{:?}", err).contains("zero"))
|
|
||||||
}
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
use js_sys::{Uint8Array, WebAssembly};
|
|
||||||
use wasm_bindgen_test::*;
|
|
||||||
use wasmer_js::*;
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn module_get_name() {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module)"#;
|
|
||||||
let module = Module::new(&store, wat).unwrap();
|
|
||||||
assert_eq!(module.name(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn module_set_name() {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module $name)"#;
|
|
||||||
let mut module = Module::new(&store, wat).unwrap();
|
|
||||||
|
|
||||||
#[cfg(feature = "wasm-types-polyfill")]
|
|
||||||
assert_eq!(module.name(), Some("name"));
|
|
||||||
|
|
||||||
module.set_name("new_name");
|
|
||||||
assert_eq!(module.name(), Some("new_name"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn module_from_jsmodule() {
|
|
||||||
let wat = br#"(module $name)"#;
|
|
||||||
let binary = wat2wasm(wat).unwrap();
|
|
||||||
let js_bytes = unsafe { Uint8Array::view(&binary) };
|
|
||||||
let js_module = WebAssembly::Module::new(&js_bytes.into()).unwrap();
|
|
||||||
let module: Module = js_module.into();
|
|
||||||
assert_eq!(module.store(), &Store::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn imports() {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(import "host" "func" (func))
|
|
||||||
(import "host" "memory" (memory 1))
|
|
||||||
(import "host" "table" (table 1 anyfunc))
|
|
||||||
(import "host" "global" (global i32))
|
|
||||||
)"#;
|
|
||||||
let module = Module::new(&store, wat).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().collect::<Vec<_>>(),
|
|
||||||
vec![
|
|
||||||
ImportType::new(
|
|
||||||
"host",
|
|
||||||
"func",
|
|
||||||
ExternType::Function(FunctionType::new(vec![], vec![]))
|
|
||||||
),
|
|
||||||
ImportType::new(
|
|
||||||
"host",
|
|
||||||
"memory",
|
|
||||||
ExternType::Memory(MemoryType::new(Pages(1), None, false))
|
|
||||||
),
|
|
||||||
ImportType::new(
|
|
||||||
"host",
|
|
||||||
"table",
|
|
||||||
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
|
|
||||||
),
|
|
||||||
ImportType::new(
|
|
||||||
"host",
|
|
||||||
"global",
|
|
||||||
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now we test the iterators
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().functions().collect::<Vec<_>>(),
|
|
||||||
vec![ImportType::new(
|
|
||||||
"host",
|
|
||||||
"func",
|
|
||||||
FunctionType::new(vec![], vec![])
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().memories().collect::<Vec<_>>(),
|
|
||||||
vec![ImportType::new(
|
|
||||||
"host",
|
|
||||||
"memory",
|
|
||||||
MemoryType::new(Pages(1), None, false)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().tables().collect::<Vec<_>>(),
|
|
||||||
vec![ImportType::new(
|
|
||||||
"host",
|
|
||||||
"table",
|
|
||||||
TableType::new(Type::FuncRef, 1, None)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.imports().globals().collect::<Vec<_>>(),
|
|
||||||
vec![ImportType::new(
|
|
||||||
"host",
|
|
||||||
"global",
|
|
||||||
GlobalType::new(Type::I32, Mutability::Const)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
|
||||||
fn exports() {
|
|
||||||
let store = Store::default();
|
|
||||||
let wat = r#"(module
|
|
||||||
(func (export "func") nop)
|
|
||||||
(memory (export "memory") 2)
|
|
||||||
(table (export "table") 2 funcref)
|
|
||||||
(global (export "global") i32 (i32.const 0))
|
|
||||||
)"#;
|
|
||||||
let mut module = Module::new(&store, wat).unwrap();
|
|
||||||
module
|
|
||||||
.set_type_hints(ModuleTypeHints {
|
|
||||||
exports: vec![
|
|
||||||
ExternType::Function(FunctionType::new(vec![], vec![])),
|
|
||||||
ExternType::Memory(MemoryType::new(Pages(2), None, false)),
|
|
||||||
ExternType::Table(TableType::new(Type::FuncRef, 2, None)),
|
|
||||||
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const)),
|
|
||||||
],
|
|
||||||
imports: vec![],
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().collect::<Vec<_>>(),
|
|
||||||
vec![
|
|
||||||
ExportType::new(
|
|
||||||
"func",
|
|
||||||
ExternType::Function(FunctionType::new(vec![], vec![]))
|
|
||||||
),
|
|
||||||
ExportType::new(
|
|
||||||
"memory",
|
|
||||||
ExternType::Memory(MemoryType::new(Pages(2), None, false))
|
|
||||||
),
|
|
||||||
ExportType::new(
|
|
||||||
"table",
|
|
||||||
ExternType::Table(TableType::new(Type::FuncRef, 2, None))
|
|
||||||
),
|
|
||||||
ExportType::new(
|
|
||||||
"global",
|
|
||||||
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now we test the iterators
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().functions().collect::<Vec<_>>(),
|
|
||||||
vec![ExportType::new("func", FunctionType::new(vec![], vec![])),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().memories().collect::<Vec<_>>(),
|
|
||||||
vec![ExportType::new(
|
|
||||||
"memory",
|
|
||||||
MemoryType::new(Pages(2), None, false)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().tables().collect::<Vec<_>>(),
|
|
||||||
vec![ExportType::new(
|
|
||||||
"table",
|
|
||||||
TableType::new(Type::FuncRef, 2, None)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
module.exports().globals().collect::<Vec<_>>(),
|
|
||||||
vec![ExportType::new(
|
|
||||||
"global",
|
|
||||||
GlobalType::new(Type::I32, Mutability::Const)
|
|
||||||
),]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test commented because it doesn't work in old versions of Node
|
|
||||||
// which makes the CI to fail.
|
|
||||||
|
|
||||||
// #[wasm_bindgen_test]
|
|
||||||
// fn calling_host_functions_with_negative_values_works() {
|
|
||||||
// let store = Store::default();
|
|
||||||
// let wat = r#"(module
|
|
||||||
// (import "host" "host_func1" (func (param i64)))
|
|
||||||
// (import "host" "host_func2" (func (param i32)))
|
|
||||||
// (import "host" "host_func3" (func (param i64)))
|
|
||||||
// (import "host" "host_func4" (func (param i32)))
|
|
||||||
// (import "host" "host_func5" (func (param i32)))
|
|
||||||
// (import "host" "host_func6" (func (param i32)))
|
|
||||||
// (import "host" "host_func7" (func (param i32)))
|
|
||||||
// (import "host" "host_func8" (func (param i32)))
|
|
||||||
|
|
||||||
// (func (export "call_host_func1")
|
|
||||||
// (call 0 (i64.const -1)))
|
|
||||||
// (func (export "call_host_func2")
|
|
||||||
// (call 1 (i32.const -1)))
|
|
||||||
// (func (export "call_host_func3")
|
|
||||||
// (call 2 (i64.const -1)))
|
|
||||||
// (func (export "call_host_func4")
|
|
||||||
// (call 3 (i32.const -1)))
|
|
||||||
// (func (export "call_host_func5")
|
|
||||||
// (call 4 (i32.const -1)))
|
|
||||||
// (func (export "call_host_func6")
|
|
||||||
// (call 5 (i32.const -1)))
|
|
||||||
// (func (export "call_host_func7")
|
|
||||||
// (call 6 (i32.const -1)))
|
|
||||||
// (func (export "call_host_func8")
|
|
||||||
// (call 7 (i32.const -1)))
|
|
||||||
// )"#;
|
|
||||||
// let module = Module::new(&store, wat).unwrap();
|
|
||||||
// let imports = imports! {
|
|
||||||
// "host" => {
|
|
||||||
// "host_func1" => Function::new_native(&store, |p: u64| {
|
|
||||||
// println!("host_func1: Found number {}", p);
|
|
||||||
// assert_eq!(p, u64::max_value());
|
|
||||||
// }),
|
|
||||||
// "host_func2" => Function::new_native(&store, |p: u32| {
|
|
||||||
// println!("host_func2: Found number {}", p);
|
|
||||||
// assert_eq!(p, u32::max_value());
|
|
||||||
// }),
|
|
||||||
// "host_func3" => Function::new_native(&store, |p: i64| {
|
|
||||||
// println!("host_func3: Found number {}", p);
|
|
||||||
// assert_eq!(p, -1);
|
|
||||||
// }),
|
|
||||||
// "host_func4" => Function::new_native(&store, |p: i32| {
|
|
||||||
// println!("host_func4: Found number {}", p);
|
|
||||||
// assert_eq!(p, -1);
|
|
||||||
// }),
|
|
||||||
// "host_func5" => Function::new_native(&store, |p: i16| {
|
|
||||||
// println!("host_func5: Found number {}", p);
|
|
||||||
// assert_eq!(p, -1);
|
|
||||||
// }),
|
|
||||||
// "host_func6" => Function::new_native(&store, |p: u16| {
|
|
||||||
// println!("host_func6: Found number {}", p);
|
|
||||||
// assert_eq!(p, u16::max_value());
|
|
||||||
// }),
|
|
||||||
// "host_func7" => Function::new_native(&store, |p: i8| {
|
|
||||||
// println!("host_func7: Found number {}", p);
|
|
||||||
// assert_eq!(p, -1);
|
|
||||||
// }),
|
|
||||||
// "host_func8" => Function::new_native(&store, |p: u8| {
|
|
||||||
// println!("host_func8: Found number {}", p);
|
|
||||||
// assert_eq!(p, u8::max_value());
|
|
||||||
// }),
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// let instance = Instance::new(&module, &imports).unwrap();
|
|
||||||
|
|
||||||
// let f1: NativeFunc<(), ()> = instance
|
|
||||||
// .exports
|
|
||||||
// .get_native_function("call_host_func1")
|
|
||||||
// .unwrap();
|
|
||||||
// let f2: NativeFunc<(), ()> = instance
|
|
||||||
// .exports
|
|
||||||
// .get_native_function("call_host_func2")
|
|
||||||
// .unwrap();
|
|
||||||
// let f3: NativeFunc<(), ()> = instance
|
|
||||||
// .exports
|
|
||||||
// .get_native_function("call_host_func3")
|
|
||||||
// .unwrap();
|
|
||||||
// let f4: NativeFunc<(), ()> = instance
|
|
||||||
// .exports
|
|
||||||
// .get_native_function("call_host_func4")
|
|
||||||
// .unwrap();
|
|
||||||
// let f5: NativeFunc<(), ()> = instance
|
|
||||||
// .exports
|
|
||||||
// .get_native_function("call_host_func5")
|
|
||||||
// .unwrap();
|
|
||||||
// let f6: NativeFunc<(), ()> = instance
|
|
||||||
// .exports
|
|
||||||
// .get_native_function("call_host_func6")
|
|
||||||
// .unwrap();
|
|
||||||
// let f7: NativeFunc<(), ()> = instance
|
|
||||||
// .exports
|
|
||||||
// .get_native_function("call_host_func7")
|
|
||||||
// .unwrap();
|
|
||||||
// let f8: NativeFunc<(), ()> = instance
|
|
||||||
// .exports
|
|
||||||
// .get_native_function("call_host_func8")
|
|
||||||
// .unwrap();
|
|
||||||
|
|
||||||
// f1.call().unwrap();
|
|
||||||
// f2.call().unwrap();
|
|
||||||
// f3.call().unwrap();
|
|
||||||
// f4.call().unwrap();
|
|
||||||
// f5.call().unwrap();
|
|
||||||
// f6.call().unwrap();
|
|
||||||
// f7.call().unwrap();
|
|
||||||
// f8.call().unwrap();
|
|
||||||
// }
|
|
||||||
@@ -20,7 +20,7 @@ getrandom = "0.2"
|
|||||||
typetag = "0.1"
|
typetag = "0.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
wasmer-wasi-types = { path = "../wasi-types", version = "2.0.0" }
|
wasmer-wasi-types = { path = "../wasi-types", version = "2.0.0" }
|
||||||
wasmer = { path = "../api", version = "2.0.0", default-features = false }
|
wasmer = { path = "../api", version = "2.0.0", default-features = false, features = ["sys"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = "0.3"
|
winapi = "0.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user