Merge pull request #2489 from wasmerio/js-api-into-api

feat(api) Merge `js-api` into `api`
This commit is contained in:
Syrus Akbary
2021-07-23 13:08:39 -05:00
committed by GitHub
71 changed files with 4000 additions and 3824 deletions

58
Cargo.lock generated
View File

@@ -21,17 +21,6 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "aho-corasick"
version = "0.7.18"
@@ -396,7 +385,7 @@ dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
"gimli",
"hashbrown 0.9.1",
"hashbrown",
"log",
"regalloc",
"smallvec",
@@ -432,7 +421,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b783b351f966fce33e3c03498cb116d16d97a8f9978164a60920bd0d3a99c"
dependencies = [
"cranelift-codegen",
"hashbrown 0.9.1",
"hashbrown",
"log",
"smallvec",
"target-lexicon 0.12.0",
@@ -904,16 +893,7 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
dependencies = [
"ahash 0.4.7",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash 0.7.4",
"ahash",
]
[[package]]
@@ -959,7 +939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
dependencies = [
"autocfg",
"hashbrown 0.9.1",
"hashbrown",
"serde",
]
@@ -2428,13 +2408,17 @@ version = "2.0.0"
dependencies = [
"anyhow",
"cfg-if 1.0.0",
"hashbrown",
"indexmap",
"js-sys",
"libc",
"loupe",
"more-asserts",
"target-lexicon 0.12.0",
"tempfile",
"thiserror",
"wasm-bindgen",
"wasm-bindgen-test",
"wasmer-compiler",
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
@@ -2445,6 +2429,7 @@ dependencies = [
"wasmer-engine-universal",
"wasmer-types",
"wasmer-vm",
"wasmparser",
"wat",
"winapi",
]
@@ -2548,7 +2533,7 @@ name = "wasmer-compiler"
version = "2.0.0"
dependencies = [
"enumset",
"hashbrown 0.9.1",
"hashbrown",
"loupe",
"rkyv",
"serde",
@@ -2569,7 +2554,7 @@ dependencies = [
"cranelift-entity",
"cranelift-frontend",
"gimli",
"hashbrown 0.9.1",
"hashbrown",
"lazy_static",
"loupe",
"more-asserts",
@@ -2612,7 +2597,7 @@ dependencies = [
"byteorder",
"dynasm",
"dynasmrt",
"hashbrown 0.9.1",
"hashbrown",
"lazy_static",
"loupe",
"more-asserts",
@@ -2745,25 +2730,6 @@ dependencies = [
"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]]
name = "wasmer-middlewares"
version = "2.0.0"

View File

@@ -43,7 +43,6 @@ members = [
"lib/engine-universal",
"lib/engine-dylib",
"lib/engine-staticlib",
"lib/js-api",
"lib/object",
"lib/vm",
"lib/wasi",

View File

@@ -148,7 +148,7 @@ ifneq ($(ENABLE_LLVM), 0)
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
exclude_tests += --exclude wasmer-wasi-experimental-io-devices
# 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
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
#####

View File

@@ -10,96 +10,208 @@ license = "MIT"
readme = "README.md"
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]
#
# ## 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-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-derive = { path = "../derive", 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" }
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 }
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"
[dev-dependencies]
# for the binary wasmer.rs
libc = { version = "^0.2", default-features = false }
#
# ## Development Dependencies for `sys`.
#
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
#
libc = { version = "^0.2", default-features = false } # for the binary wasmer.rs
wat = "1.0"
tempfile = "3.1"
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]
maintenance = { status = "actively-developed" }
[features]
default = ["wat", "default-cranelift", "default-universal"]
default = ["sys-default"]
#####
#
# # Features for `sys`.
#
sys = []
sys-default = ["sys", "wat", "default-cranelift", "default-universal"]
#
# ## Compilers.
#
compiler = [
"sys",
"wasmer-compiler/translator",
"wasmer-engine-universal/compiler",
"wasmer-engine-dylib/compiler",
]
engine = []
universal = [
"wasmer-engine-universal",
"engine"
]
dylib = [
"wasmer-engine-dylib",
"engine"
]
singlepass = [
"wasmer-compiler-singlepass",
"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"
]
singlepass = [
"compiler",
"wasmer-compiler-singlepass",
]
cranelift = [
"compiler",
"wasmer-compiler-cranelift",
]
llvm = [
"compiler",
"wasmer-compiler-llvm",
]
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 = []
# experimental / in-development features
default-universal = [
"default-engine",
"universal",
]
default-dylib = [
"default-engine",
"dylib",
]
#
# ## Experimental / in-development features
#
experimental-reference-types-extern-ref = [
"sys",
"wasmer-types/experimental-reference-types-extern-ref",
]
# Deprecated features.
#
# ## Deprecated features.
#
jit = ["universal"]
native = ["dylib"]
#
#####
#####
#
# # Features for `js`.
#
js = []
js-default = ["js", "std", "wasm-types-polyfill", "wat"]
#
wasm-types-polyfill = ["js", "wasmparser"]
std = ["js"]
core = ["js", "hashbrown"]
#
#####

View File

@@ -1,14 +1,17 @@
# `wasmer` [![Build Status](https://github.com/wasmerio/wasmer/workflows/build/badge.svg?style=flat-square)](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [![Join Wasmer Slack](https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square)](https://slack.wasmer.io) [![MIT License](https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square)](https://github.com/wasmerio/wasmer/blob/master/LICENSE) [![crates.io](https://img.shields.io/crates/v/wasmer.svg)](https://crates.io/crates/wasmer)
[`Wasmer`](https://wasmer.io/) is the most popular
[WebAssembly](https://webassembly.org/) runtime for Rust (...and also
the fastest). It supports JIT (Just in Time) and AOT (Ahead of time)
compilation as well as pluggable compilers suited to your needs.
[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.
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};
@@ -36,36 +39,70 @@ fn main() -> anyhow::Result<()> {
}
```
[Discover the full collection of examples](https://github.com/wasmerio/wasmer/tree/master/examples).
## Features
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:
* `wat` (enabled by default): It allows to read WebAssembly files in their text format.
*This feature is normally used only in development environments*
* Compilers (mutually exclusive):
- `singlepass`: it will use `wasmer-compiler-singlepass` as the default
compiler (ideal for **blockchains**).
- `cranelift`: it will use `wasmer-compiler-cranelift` as the default
compiler (ideal for **development**).
- `llvm`: it will use `wasmer-compiler-llvm` as the default
compiler (ideal for **production**).
* **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.
Wasmer ships by default with the `cranelift` compiler as its great for development proposes.
However, we strongly encourage to use the `llvm` backend in production as it performs
about 50% faster, achieving near-native speeds.
* **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.
> Note: if you want to use multiple compilers at the same time, it's also possible!
> You will need to import them directly via each of the compiler crates.
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.
Read [the documentation to learn
more](https://wasmerio.github.io/wasmer/crates/doc/wasmer/).
---
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

View File

@@ -75,7 +75,7 @@ impl<'a, T> WasmCell<'a, T> {
///
/// ```
/// use std::cell::Cell;
/// use wasmer_js::WasmCell;
/// use wasmer::WasmCell;
///
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);
@@ -96,7 +96,7 @@ impl<'a, T: Copy> WasmCell<'a, T> {
///
/// ```
/// use std::cell::Cell;
/// use wasmer_js::WasmCell;
/// use wasmer::WasmCell;
///
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);
@@ -123,7 +123,7 @@ impl<T: Sized> WasmCell<'_, T> {
///
/// ```
/// use std::cell::Cell;
/// use wasmer_js::WasmCell;
/// use wasmer::WasmCell;
///
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);

View File

@@ -1,4 +1,4 @@
use crate::{ExportError, Instance};
use crate::js::{ExportError, Instance};
use thiserror::Error;
/// 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:
///
/// ```
/// use wasmer_js::{WasmerEnv, LazyInit, Memory, NativeFunc};
/// use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc};
///
/// #[derive(WasmerEnv, Clone)]
/// pub struct MyEnvWithNoInstanceData {
@@ -63,7 +63,7 @@ impl From<ExportError> for HostEnvInitError {
///
/// This trait may also be implemented manually:
/// ```
/// # use wasmer_js::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
/// #[derive(Clone)]
/// pub struct MyEnv {
/// memory: LazyInit<Memory>,

View File

@@ -1,4 +1,4 @@
use crate::lib::std::string::String;
use crate::js::lib::std::string::String;
#[cfg(feature = "std")]
use thiserror::Error;

View File

@@ -1,7 +1,7 @@
use crate::instance::Instance;
use crate::wasm_bindgen_polyfill::Global;
use crate::HostEnvInitError;
use crate::WasmerEnv;
use crate::js::instance::Instance;
use crate::js::wasm_bindgen_polyfill::Global;
use crate::js::HostEnvInitError;
use crate::js::WasmerEnv;
use js_sys::Function;
use js_sys::WebAssembly::{Memory, Table};
use std::cell::RefCell;

View File

@@ -1,8 +1,8 @@
use crate::export::Export;
use crate::externals::{Extern, Function, Global, Memory, Table};
use crate::import_object::LikeNamespace;
use crate::native::NativeFunc;
use crate::WasmTypeList;
use crate::js::export::Export;
use crate::js::externals::{Extern, Function, Global, Memory, Table};
use crate::js::import_object::LikeNamespace;
use crate::js::native::NativeFunc;
use crate::js::WasmTypeList;
use indexmap::IndexMap;
use std::fmt;
use std::iter::{ExactSizeIterator, FromIterator};
@@ -12,14 +12,14 @@ use thiserror::Error;
/// The `ExportError` can happen when trying to get a specific
/// export [`Extern`] from the [`Instance`] exports.
///
/// [`Instance`]: crate::Instance
/// [`Instance`]: crate::js::Instance
///
/// # Examples
///
/// ## Incompatible export type
///
/// ```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 wasm_bytes = wat2wasm(r#"
/// # (module
@@ -36,7 +36,7 @@ use thiserror::Error;
/// ## Missing export
///
/// ```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 wasm_bytes = wat2wasm("(module)".as_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`].
///
/// [`Instance`]: crate::Instance
/// [`Instance`]: crate::js::Instance
pub trait Exportable<'a>: Sized {
/// This function is used when providedd the [`Extern`] as exportable, so it
/// can be used while instantiating the [`Module`].
///
/// [`Module`]: crate::Module
/// [`Module`]: crate::js::Module
fn to_export(&self) -> Export;
/// Implementation of how to get the export corresponding to the implementing type
/// from an [`Instance`] by name.
///
/// [`Instance`]: crate::Instance
/// [`Instance`]: crate::js::Instance
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>;
}

View File

@@ -1,18 +1,18 @@
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::Store;
use crate::types::{param_from_js, AsJs /* ValFuncRef */, Val};
use crate::FunctionType;
use crate::NativeFunc;
use crate::RuntimeError;
use crate::WasmerEnv;
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::Extern;
use crate::js::store::Store;
use crate::js::types::{param_from_js, AsJs /* ValFuncRef */, Val};
use crate::js::FunctionType;
use crate::js::NativeFunc;
use crate::js::RuntimeError;
use crate::js::WasmerEnv;
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
use js_sys::{Array, Function as JSFunction};
use std::iter::FromIterator;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use crate::export::{Export, VMFunction};
use crate::js::export::{Export, VMFunction};
use std::fmt;
#[repr(C)]
@@ -71,7 +71,7 @@ impl Function {
/// # Examples
///
/// ```
/// # use wasmer_js::{Function, FunctionType, Type, Store, Value};
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # let store = Store::default();
/// #
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
@@ -85,7 +85,7 @@ impl Function {
/// With constant signature:
///
/// ```
/// # use wasmer_js::{Function, FunctionType, Type, Store, Value};
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # let store = Store::default();
/// #
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
@@ -161,7 +161,7 @@ impl Function {
/// # Examples
///
/// ```
/// # use wasmer_js::{Function, FunctionType, Type, Store, Value, WasmerEnv};
/// # use wasmer::{Function, FunctionType, Type, Store, Value, WasmerEnv};
/// # let store = Store::default();
/// #
/// #[derive(WasmerEnv, Clone)]
@@ -181,7 +181,7 @@ impl Function {
/// With constant signature:
///
/// ```
/// # use wasmer_js::{Function, FunctionType, Type, Store, Value, WasmerEnv};
/// # use wasmer::{Function, FunctionType, Type, Store, Value, WasmerEnv};
/// # let store = Store::default();
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
///
@@ -274,7 +274,7 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer_js::{Store, Function};
/// # use wasmer::{Store, Function};
/// # let store = Store::default();
/// #
/// fn sum(a: i32, b: i32) -> i32 {
@@ -315,7 +315,7 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer_js::{Store, Function, WasmerEnv};
/// # use wasmer::{Store, Function, WasmerEnv};
/// # let store = Store::default();
/// #
/// #[derive(WasmerEnv, Clone)]
@@ -364,7 +364,7 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer_js::{Function, Store, Type};
/// # use wasmer::{Function, Store, Type};
/// # let store = Store::default();
/// #
/// fn sum(a: i32, b: i32) -> i32 {
@@ -390,7 +390,7 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer_js::{Function, Store, Type};
/// # use wasmer::{Function, Store, Type};
/// # let store = Store::default();
/// #
/// fn sum(a: i32, b: i32) -> i32 {
@@ -410,7 +410,7 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer_js::{Function, Store, Type};
/// # use wasmer::{Function, Store, Type};
/// # let store = Store::default();
/// #
/// fn sum(a: i32, b: i32) -> i32 {
@@ -436,7 +436,7 @@ impl Function {
/// # 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 wasm_bytes = wat2wasm(r#"
/// # (module
@@ -495,7 +495,7 @@ impl Function {
/// # 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 wasm_bytes = wat2wasm(r#"
/// # (module
@@ -521,7 +521,7 @@ impl Function {
/// an error will be raised:
///
/// ```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 wasm_bytes = wat2wasm(r#"
/// # (module
@@ -545,7 +545,7 @@ impl Function {
/// an error will be raised:
///
/// ```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 wasm_bytes = wat2wasm(r#"
/// # (module
@@ -654,7 +654,7 @@ mod inner {
#[cfg(feature = "experimental-reference-types-extern-ref")]
pub use wasmer_types::{ExternRef, VMExternRef};
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,
/// or to convert `WasmNativeType` value to a Rust value.

View File

@@ -1,13 +1,13 @@
use crate::export::Export;
use crate::export::VMGlobal;
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::Store;
use crate::types::{Val, ValType};
use crate::wasm_bindgen_polyfill::Global as JSGlobal;
use crate::GlobalType;
use crate::Mutability;
use crate::RuntimeError;
use crate::js::export::Export;
use crate::js::export::VMGlobal;
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::Extern;
use crate::js::store::Store;
use crate::js::types::{Val, ValType};
use crate::js::wasm_bindgen_polyfill::Global as JSGlobal;
use crate::js::GlobalType;
use crate::js::Mutability;
use crate::js::RuntimeError;
use wasm_bindgen::JsValue;
/// A WebAssembly `global` instance.
@@ -28,7 +28,7 @@ impl Global {
/// # Example
///
/// ```
/// # use wasmer_js::{Global, Mutability, Store, Value};
/// # use wasmer::{Global, Mutability, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
@@ -45,7 +45,7 @@ impl Global {
/// # Example
///
/// ```
/// # use wasmer_js::{Global, Mutability, Store, Value};
/// # use wasmer::{Global, Mutability, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new_mut(&store, Value::I32(1));
@@ -94,7 +94,7 @@ impl Global {
/// # Example
///
/// ```
/// # use wasmer_js::{Global, Mutability, Store, Type, Value, GlobalType};
/// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType};
/// # let store = Store::default();
/// #
/// let c = Global::new(&store, Value::I32(1));
@@ -112,7 +112,7 @@ impl Global {
/// # Example
///
/// ```
/// # use wasmer_js::{Global, Store, Value};
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
@@ -128,7 +128,7 @@ impl Global {
/// # Example
///
/// ```
/// # use wasmer_js::{Global, Store, Value};
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
@@ -150,7 +150,7 @@ impl Global {
/// # Example
///
/// ```
/// # use wasmer_js::{Global, Store, Value};
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// 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:
///
/// ```should_panic
/// # use wasmer_js::{Global, Store, Value};
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// 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:
///
/// ```should_panic
/// # use wasmer_js::{Global, Store, Value};
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
@@ -216,7 +216,7 @@ impl Global {
/// # Example
///
/// ```
/// # use wasmer_js::{Global, Store, Value};
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));

View File

@@ -1,8 +1,8 @@
use crate::export::{Export, VMMemory};
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::Store;
use crate::{MemoryType, MemoryView};
use crate::js::export::{Export, VMMemory};
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::Extern;
use crate::js::store::Store;
use crate::js::{MemoryType, MemoryView};
use std::convert::TryInto;
use thiserror::Error;
@@ -83,12 +83,12 @@ impl Memory {
/// Creates a new host `Memory` from the provided [`MemoryType`].
///
/// This function will construct the `Memory` using the store
/// [`BaseTunables`][crate::tunables::BaseTunables].
/// [`BaseTunables`][crate::js::tunables::BaseTunables].
///
/// # Example
///
/// ```
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value};
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
@@ -116,7 +116,7 @@ impl Memory {
/// # Example
///
/// ```
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value};
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// #
/// let mt = MemoryType::new(1, None, false);
@@ -135,7 +135,7 @@ impl Memory {
/// # Example
///
/// ```
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value};
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
@@ -189,7 +189,7 @@ impl Memory {
/// # Example
///
/// ```
/// # use wasmer_js::{Memory, MemoryType, Pages, Store, Type, Value};
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
@@ -210,7 +210,7 @@ impl Memory {
/// # 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 m = Memory::new(&store, MemoryType::new(1, Some(3), false)).unwrap();
@@ -226,7 +226,7 @@ impl Memory {
/// of pages.
///
/// ```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 m = Memory::new(&store, MemoryType::new(1, Some(1), false)).unwrap();
@@ -268,7 +268,7 @@ impl Memory {
/// # Usage:
///
/// ```
/// # use wasmer_js::{Memory, MemoryView};
/// # use wasmer::{Memory, MemoryView};
/// # use std::{cell::Cell, sync::atomic::Ordering};
/// # fn view_memory(memory: Memory) {
/// // Without synchronization.
@@ -305,7 +305,7 @@ impl Memory {
/// # Example
///
/// ```
/// # use wasmer_js::{Memory, MemoryType, Store, Value};
/// # use wasmer::{Memory, MemoryType, Store, Value};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();

View File

@@ -11,10 +11,10 @@ pub use self::global::Global;
pub use self::memory::{Memory, MemoryError};
pub use self::table::Table;
use crate::export::Export;
use crate::exports::{ExportError, Exportable};
use crate::store::{Store, StoreObject};
use crate::ExternType;
use crate::js::export::Export;
use crate::js::exports::{ExportError, Exportable};
use crate::js::store::{Store, StoreObject};
use crate::js::ExternType;
use std::fmt;
/// An `Extern` is the runtime representation of an entity that

View File

@@ -1,11 +1,11 @@
use crate::export::VMFunction;
use crate::export::{Export, VMTable};
use crate::exports::{ExportError, Exportable};
use crate::externals::{Extern, Function as WasmerFunction};
use crate::store::Store;
use crate::types::Val;
use crate::RuntimeError;
use crate::TableType;
use crate::js::export::VMFunction;
use crate::js::export::{Export, VMTable};
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::{Extern, Function as WasmerFunction};
use crate::js::store::Store;
use crate::js::types::Val;
use crate::js::RuntimeError;
use crate::js::TableType;
use js_sys::Function;
use wasmer_types::FunctionType;
@@ -42,7 +42,7 @@ impl Table {
/// All the elements in the table will be set to the `init` value.
///
/// 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> {
let descriptor = js_sys::Object::new();
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into())?;

View File

@@ -1,8 +1,8 @@
//! 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
//! functions.
use crate::export::Export;
use crate::resolver::NamedResolver;
use crate::js::export::Export;
use crate::js::resolver::NamedResolver;
use std::borrow::{Borrow, BorrowMut};
use std::collections::VecDeque;
use std::collections::{hash_map::Entry, HashMap};
@@ -28,7 +28,7 @@ pub trait LikeNamespace {
///
/// # Usage:
/// ```ignore
/// use wasmer_js::{Exports, ImportObject, Function};
/// use wasmer::{Exports, ImportObject, Function};
///
/// let mut import_object = ImportObject::new();
/// let mut env = Exports::new();
@@ -55,7 +55,7 @@ impl ImportObject {
///
/// # Usage
/// ```ignore
/// # use wasmer_js::{ImportObject, Instance, Namespace};
/// # use wasmer::{ImportObject, Instance, Namespace};
/// let mut import_object = ImportObject::new();
/// import_object.get_export("module", "name");
/// ```
@@ -78,7 +78,7 @@ impl ImportObject {
///
/// # Usage:
/// ```ignore
/// # use wasmer_js::{ImportObject, Instance, Namespace};
/// # use wasmer::{ImportObject, Instance, Namespace};
/// let mut import_object = ImportObject::new();
///
/// import_object.register("namespace0", instance);
@@ -188,9 +188,9 @@ impl fmt::Debug for ImportObject {
/// # Usage
///
/// ```
/// # use wasmer_js::{Function, Store};
/// # use wasmer::{Function, Store};
/// # let store = Store::default();
/// use wasmer_js::imports;
/// use wasmer::imports;
///
/// let import_object = imports! {
/// "env" => {
@@ -248,9 +248,9 @@ macro_rules! import_namespace {
#[cfg(test)]
mod test {
use super::*;
use crate::ChainableNamedResolver;
use crate::Type;
use crate::{Global, Store, Val};
use crate::js::ChainableNamedResolver;
use crate::js::Type;
use crate::js::{Global, Store, Val};
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
@@ -360,7 +360,7 @@ mod test {
#[wasm_bindgen_test]
fn imports_macro_allows_trailing_comma_and_none() {
use crate::Function;
use crate::js::Function;
let store = Default::default();

View File

@@ -1,11 +1,11 @@
use crate::env::HostEnvInitError;
use crate::export::Export;
use crate::exports::Exports;
use crate::externals::Extern;
use crate::module::Module;
use crate::resolver::Resolver;
use crate::store::Store;
use crate::trap::RuntimeError;
use crate::js::env::HostEnvInitError;
use crate::js::export::Export;
use crate::js::exports::Exports;
use crate::js::externals::Extern;
use crate::js::module::Module;
use crate::js::resolver::Resolver;
use crate::js::store::Store;
use crate::js::trap::RuntimeError;
use js_sys::WebAssembly;
use std::fmt;
#[cfg(feature = "std")]
@@ -68,10 +68,10 @@ impl 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<()> {
/// let store = Store::default();
/// let module = Module::new(&store, "(module)")?;

85
lib/api/src/js/mod.rs Normal file
View 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");

View File

@@ -1,12 +1,12 @@
use crate::export::{Export, VMFunction};
use crate::resolver::Resolver;
use crate::store::Store;
use crate::types::{ExportType, ImportType};
// use crate::InstantiationError;
use crate::error::CompileError;
use crate::js::export::{Export, VMFunction};
use crate::js::resolver::Resolver;
use crate::js::store::Store;
use crate::js::types::{ExportType, ImportType};
// use crate::js::InstantiationError;
use crate::js::error::CompileError;
#[cfg(feature = "wat")]
use crate::error::WasmError;
use crate::RuntimeError;
use crate::js::error::WasmError;
use crate::js::RuntimeError;
use js_sys::{Reflect, Uint8Array, WebAssembly};
use std::fmt;
use std::io;
@@ -89,7 +89,7 @@ impl Module {
/// Reading from a WAT file.
///
/// ```
/// use wasmer_js::*;
/// use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// let wat = "(module)";
@@ -101,7 +101,7 @@ impl Module {
/// Reading from bytes:
///
/// ```
/// use wasmer_js::*;
/// use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// // 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
#[cfg(feature = "wasm-types-polyfill")]
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 {
@@ -261,7 +261,7 @@ impl Module {
/// # Example
///
/// ```
/// # use wasmer_js::*;
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// let wat = "(module $moduleName)";
@@ -285,7 +285,7 @@ impl Module {
/// # Example
///
/// ```
/// # use wasmer_js::*;
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// let wat = "(module)";
@@ -320,7 +320,7 @@ impl Module {
/// # Example
///
/// ```
/// # use wasmer_js::*;
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// let wat = r#"(module
@@ -418,7 +418,7 @@ impl Module {
/// # Example
///
/// ```
/// # use wasmer_js::*;
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let store = Store::default();
/// let wat = r#"(module

View File

@@ -9,10 +9,10 @@
//! ```
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 crate::export::VMFunction;
use crate::types::param_from_js;
use crate::js::export::VMFunction;
use crate::js::types::param_from_js;
use js_sys::Array;
use std::iter::FromIterator;
use wasm_bindgen::JsValue;
@@ -107,14 +107,14 @@ macro_rules! impl_native_traits {
}
#[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
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
{
fn get_self_from_extern_with_generics(_extern: &crate::externals::Extern) -> Result<Self, crate::exports::ExportError> {
use crate::exports::Exportable;
crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::exports::ExportError::IncompatibleType)
fn get_self_from_extern_with_generics(_extern: &crate::js::externals::Extern) -> Result<Self, crate::js::exports::ExportError> {
use crate::js::exports::Exportable;
crate::js::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::js::exports::ExportError::IncompatibleType)
}
}
};

View File

@@ -6,8 +6,8 @@
//! Therefore, you should use this abstraction whenever possible to avoid memory
//! related bugs when implementing an ABI.
use crate::cell::WasmCell;
use crate::{externals::Memory, FromToNativeWasmType};
use crate::js::cell::WasmCell;
use crate::js::{externals::Memory, FromToNativeWasmType};
use std::{fmt, marker::PhantomData, mem};
use wasmer_types::ValueType;
@@ -23,8 +23,8 @@ pub struct Item;
///
/// This type can be used directly in the host function arguments:
/// ```
/// # use wasmer_js::Memory;
/// # use wasmer_js::WasmPtr;
/// # use wasmer::Memory;
/// # use wasmer::WasmPtr;
/// pub fn host_import(memory: Memory, ptr: WasmPtr<u32>) {
/// let derefed_ptr = ptr.deref(&memory).expect("pointer in bounds");
/// 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
/// guarantees required by `ValueType`.
/// ```
/// # use wasmer_js::Memory;
/// # use wasmer_js::WasmPtr;
/// # use wasmer_js::ValueType;
/// # use wasmer::Memory;
/// # use wasmer::WasmPtr;
/// # use wasmer::ValueType;
///
/// #[derive(Copy, Clone, Debug)]
/// #[repr(C)]
@@ -246,7 +246,7 @@ impl<T: Copy, Ty> fmt::Debug for WasmPtr<T, Ty> {
#[cfg(test)]
mod test {
use super::*;
use crate::{Memory, MemoryType, Store};
use crate::js::{Memory, MemoryType, Store};
use wasm_bindgen_test::*;
/// Ensure that memory accesses work on the edges of memory and that out of

View File

@@ -1,4 +1,4 @@
use crate::export::Export;
use crate::js::export::Export;
/// Import resolver connects imports with available exported values.
pub trait Resolver {

View File

@@ -1,6 +1,6 @@
use crate::externals::Function;
// use crate::store::{Store, StoreObject};
// use crate::RuntimeError;
use crate::js::externals::Function;
// use crate::js::store::{Store, StoreObject};
// use crate::js::RuntimeError;
use wasm_bindgen::JsValue;
use wasmer_types::Value;
pub use wasmer_types::{

View File

@@ -26,19 +26,29 @@
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,
//! sandboxed execution of [WebAssembly (Wasm)][wasm] modules.
//! [`Wasmer`](https://wasmer.io/) is the most popular
//! [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};
//!
//! fn main() -> anyhow::Result<()> {
//! 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)
//! (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))
@@ -58,14 +68,63 @@
//! }
//! ```
//!
//! For more examples of using the `wasmer` API, check out the
//! [wasmer examples][wasmer-examples].
//! [Discover the full collection of examples](https://github.com/wasmerio/wasmer/tree/master/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
//!
//! - [Wasm Primitives](#wasm-primitives)
//! - [WebAssembly Primitives](#webassembly-primitives)
//! - [Externs](#externs)
//! - [Functions](#functions)
//! - [Memories](#memories)
@@ -74,10 +133,12 @@
//! - [Project Layout](#project-layout)
//! - [Engines](#engines)
//! - [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
//! to understand the primitives around which the API is built.
//!
@@ -88,6 +149,7 @@
//! referred to as "externs".
//!
//! ## Externs
//!
//! An [`Extern`] is a type that can be imported or exported from a Wasm
//! module.
//!
@@ -125,9 +187,10 @@
//! These are the primary types that the `wasmer` API uses.
//!
//! ### Functions
//!
//! There are 2 types of functions in `wasmer`:
//! 1. Wasm functions
//! 2. Host functions
//! 1. Wasm functions,
//! 2. Host functions.
//!
//! A Wasm function is a function defined in a WebAssembly module that can
//! only perform computation without side effects and call other functions.
@@ -148,7 +211,7 @@
//! give them access to the outside world with [`imports`].
//!
//! 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.
//!
//! 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`].
//!
//! ### Memories
//!
//! Memories store data.
//!
//! In most Wasm programs, nearly all data will live in a [`Memory`].
@@ -164,14 +228,15 @@
//! interesting programs.
//!
//! ### Globals
//!
//! A [`Global`] is a type that may be either mutable or immutable, and
//! contains one of the core Wasm types defined in [`Value`].
//!
//! ### Tables
//!
//! 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
//! graph with transitive dependencies removed.
@@ -183,202 +248,226 @@
//! 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:
//!
//! - [wasmer-cache][] for caching compiled Wasm modules.
//! - [wasmer-emscripten][] for running Wasm modules compiled to the
//! Emscripten ABI.
//! - [wasmer-wasi][] for running Wasm modules compiled to the WASI ABI.
//!
//! --------
//! - [`wasmer-cache`] for caching compiled Wasm modules,
//! - [`wasmer-emscripten`] for running Wasm modules compiled to the
//! Emscripten ABI,
//! - [`wasmer-wasi`] for running Wasm modules compiled to the WASI ABI.
//!
//! The Wasmer project has two major abstractions:
//! 1. [Engines][wasmer-engine]
//! 2. [Compilers][wasmer-compiler]
//! 1. [Engines][wasmer-engine],
//! 2. [Compilers][wasmer-compiler].
//!
//! These two abstractions have multiple options that can be enabled
//! with features.
//!
//! ### Engines
//! ## Engines
//!
//! An engine is a system that uses a compiler to make a WebAssembly
//! module executable.
//!
//! ### Compilers
//! ## Compilers
//!
//! A compiler is a system that handles the details of making a Wasm
//! module executable. For example, by generating native machine code
//! 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
//! enable new functionality and features that set defaults.
//! 1. `sys`
#![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:
//! - `universal` - enable the Universal engine. (See [wasmer-universal][])
//! - `native` - enable the native engine. (See [wasmer-native][])
//! - `cranelift` - enable Wasmer's Cranelift compiler. (See [wasmer-cranelift][])
//! - `llvm` - enable Wasmer's LLVM compiler. (See [wasmer-llvm][])
//! - `singlepass` - enable Wasmer's Singlepass compiler. (See [wasmer-singlepass][])
//! - `wat` - enable `wasmer` to parse the WebAssembly text format.
//! - `cranelift`
#![cfg_attr(feature = "cranelift", doc = "(enabled),")]
#![cfg_attr(not(feature = "cranelift"), doc = "(disabled),")]
//! enables Wasmer's [Cranelift compiler][wasmer-compiler-cranelift],
//! - `llvm`
#![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 first set is the default compiler set:
//! - `default-cranelift` - set Wasmer's Cranelift compiler as the default.
//! - `default-llvm` - set Wasmer's LLVM compiler as the default.
//! - `default-singlepass` - set Wasmer's Singlepass compiler as the default.
//! - `default-cranelift`
#![cfg_attr(feature = "default-cranelift", doc = "(enabled),")]
#![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:
//! - `default-universal` - set the Universal engine as the default.
//! - `default-native` - set the native engine as the default.
//! - `default-universal`
#![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
//! are enabled.
//! The default features can be enabled with the `js-default` feature.
//!
//! 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/
//! [wasmer-examples]: https://github.com/wasmerio/wasmer/tree/master/examples
//! [wasmer-cache]: https://docs.rs/wasmer-cache/*/wasmer_cache/
//! [wasmer-compiler]: https://docs.rs/wasmer-compiler/*/wasmer_compiler/
//! [wasmer-cranelift]: https://docs.rs/wasmer-compiler-cranelift/*/wasmer_compiler_cranelift/
//! [wasmer-emscripten]: https://docs.rs/wasmer-emscripten/*/wasmer_emscripten/
//! [wasmer-engine]: https://docs.rs/wasmer-engine/*/wasmer_engine/
//! [wasmer-universal]: https://docs.rs/wasmer-engine-universal/*/wasmer_engine_universal/
//! [wasmer-native]: https://docs.rs/wasmer-engine-dylib/*/wasmer_engine_dylib/
//! [wasmer-singlepass]: https://docs.rs/wasmer-compiler-singlepass/*/wasmer_compiler_singlepass/
//! [wasmer-llvm]: https://docs.rs/wasmer-compiler-llvm/*/wasmer_compiler_llvm/
//! [wasmer-wasi]: https://docs.rs/wasmer-wasi/*/wasmer_wasi/
//! [`wasmer-cache`]: https://docs.rs/wasmer-cache/
//! [wasmer-compiler]: https://docs.rs/wasmer-compiler/
//! [`wasmer-emscripten`]: https://docs.rs/wasmer-emscripten/
//! [wasmer-engine]: https://docs.rs/wasmer-engine/
//! [`wasmer-engine-universal`]: https://docs.rs/wasmer-engine-universal/
//! [`wasmer-engine-dylib`]: https://docs.rs/wasmer-engine-dylib/
//! [`wasmer-engine-staticlib`]: https://docs.rs/wasmer-engine-staticlib/
//! [`wasmer-compiler-singlepass`]: https://docs.rs/wasmer-compiler-singlepass/
//! [`wasmer-compiler-llvm`]: https://docs.rs/wasmer-compiler-llvm/
//! [`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;
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;
#[cfg(all(not(feature = "sys"), not(feature = "js")))]
compile_error!("At least the `sys` or the `js` feature must be enabled. Please, pick one.");
/// 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::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")
))]
#[cfg(all(feature = "sys", feature = "js"))]
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);
```"#
"Cannot have both `sys` and `js` features enabled at the same time. Please, pick one."
);
#[cfg(feature = "singlepass")]
pub use wasmer_compiler_singlepass::Singlepass;
#[cfg(all(feature = "sys", target_arch = "wasm32"))]
compile_error!("The `sys` feature must be enabled only for non-`wasm32` target.");
#[cfg(feature = "cranelift")]
pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel};
#[cfg(all(feature = "js", not(target_arch = "wasm32")))]
compile_error!(
"The `js` feature must be enabled only for the `wasm32` target (either `wasm32-unknown-unknown` or `wasm32-wasi`)."
);
#[cfg(feature = "llvm")]
pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM};
#[cfg(feature = "sys")]
mod sys;
#[cfg(feature = "universal")]
pub use wasmer_engine_universal::{Universal, UniversalArtifact, UniversalEngine};
#[cfg(feature = "sys")]
pub use sys::*;
#[cfg(feature = "dylib")]
pub use wasmer_engine_dylib::{Dylib, DylibArtifact, DylibEngine};
#[cfg(feature = "js")]
mod js;
/// 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;
#[cfg(feature = "js")]
pub use js::*;

View File

@@ -1,4 +1,4 @@
use crate::{ExportError, Instance};
use crate::sys::{ExportError, Instance};
use thiserror::Error;
/// An error while initializing the user supplied host env with the `WasmerEnv` trait.

View File

@@ -1,7 +1,7 @@
use crate::externals::{Extern, Function, Global, Memory, Table};
use crate::import_object::LikeNamespace;
use crate::native::NativeFunc;
use crate::WasmTypeList;
use crate::sys::externals::{Extern, Function, Global, Memory, Table};
use crate::sys::import_object::LikeNamespace;
use crate::sys::native::NativeFunc;
use crate::sys::WasmTypeList;
use indexmap::IndexMap;
use loupe::MemoryUsage;
use std::fmt;

View File

@@ -1,11 +1,11 @@
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::Store;
use crate::types::{Val, ValFuncRef};
use crate::FunctionType;
use crate::NativeFunc;
use crate::RuntimeError;
use crate::WasmerEnv;
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::Store;
use crate::sys::types::{Val, ValFuncRef};
use crate::sys::FunctionType;
use crate::sys::NativeFunc;
use crate::sys::RuntimeError;
use crate::sys::WasmerEnv;
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
use loupe::MemoryUsage;

View File

@@ -1,10 +1,10 @@
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::{Store, StoreObject};
use crate::types::Val;
use crate::GlobalType;
use crate::Mutability;
use crate::RuntimeError;
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::{Store, StoreObject};
use crate::sys::types::Val;
use crate::sys::GlobalType;
use crate::sys::Mutability;
use crate::sys::RuntimeError;
use loupe::MemoryUsage;
use std::fmt;
use std::sync::Arc;

View File

@@ -1,7 +1,7 @@
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::Store;
use crate::{MemoryType, MemoryView};
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::Store;
use crate::sys::{MemoryType, MemoryView};
use loupe::MemoryUsage;
use std::convert::TryInto;
use std::slice;
@@ -34,7 +34,7 @@ impl Memory {
/// Creates a new host `Memory` from the provided [`MemoryType`].
///
/// This function will construct the `Memory` using the store
/// [`BaseTunables`][crate::tunables::BaseTunables].
/// [`BaseTunables`][crate::sys::BaseTunables].
///
/// # Example
///

View File

@@ -11,9 +11,9 @@ pub use self::global::Global;
pub use self::memory::Memory;
pub use self::table::Table;
use crate::exports::{ExportError, Exportable};
use crate::store::{Store, StoreObject};
use crate::ExternType;
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::store::{Store, StoreObject};
use crate::sys::ExternType;
use loupe::MemoryUsage;
use std::fmt;
use wasmer_engine::Export;

View File

@@ -1,9 +1,9 @@
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::Store;
use crate::types::{Val, ValFuncRef};
use crate::RuntimeError;
use crate::TableType;
use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::Store;
use crate::sys::types::{Val, ValFuncRef};
use crate::sys::RuntimeError;
use crate::sys::TableType;
use loupe::MemoryUsage;
use std::sync::Arc;
use wasmer_engine::Export;
@@ -38,7 +38,7 @@ impl Table {
/// All the elements in the table will be set to the `init` value.
///
/// 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> {
let item = init.into_table_reference(store)?;
let tunables = store.tunables();

View File

@@ -247,7 +247,7 @@ macro_rules! import_namespace {
#[cfg(test)]
mod test {
use super::*;
use crate::{Global, Store, Val};
use crate::sys::{Global, Store, Val};
use wasmer_engine::ChainableNamedResolver;
use wasmer_types::Type;
@@ -358,7 +358,7 @@ mod test {
#[test]
fn imports_macro_allows_trailing_comma_and_none() {
use crate::Function;
use crate::sys::Function;
let store = Default::default();

View File

@@ -1,8 +1,8 @@
use crate::exports::Exports;
use crate::externals::Extern;
use crate::module::Module;
use crate::store::Store;
use crate::{HostEnvInitError, LinkError, RuntimeError};
use crate::sys::exports::Exports;
use crate::sys::externals::Extern;
use crate::sys::module::Module;
use crate::sys::store::Store;
use crate::sys::{HostEnvInitError, LinkError, RuntimeError};
use loupe::MemoryUsage;
use std::fmt;
use std::sync::{Arc, Mutex};

129
lib/api/src/sys/mod.rs Normal file
View 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;

View File

@@ -1,6 +1,6 @@
use crate::store::Store;
use crate::types::{ExportType, ImportType};
use crate::InstantiationError;
use crate::sys::store::Store;
use crate::sys::types::{ExportType, ImportType};
use crate::sys::InstantiationError;
use loupe::MemoryUsage;
use std::fmt;
use std::io;

View File

@@ -9,8 +9,8 @@
//! ```
use std::marker::PhantomData;
use crate::externals::function::{DynamicFunction, VMDynamicFunction};
use crate::{FromToNativeWasmType, Function, RuntimeError, Store, WasmTypeList};
use crate::sys::externals::function::{DynamicFunction, VMDynamicFunction};
use crate::sys::{FromToNativeWasmType, Function, RuntimeError, Store, WasmTypeList};
use std::panic::{catch_unwind, AssertUnwindSafe};
use wasmer_engine::ExportFunction;
use wasmer_types::NativeWasmType;
@@ -223,14 +223,14 @@ macro_rules! impl_native_traits {
}
#[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
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
{
fn get_self_from_extern_with_generics(_extern: &crate::externals::Extern) -> Result<Self, crate::exports::ExportError> {
use crate::exports::Exportable;
crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::exports::ExportError::IncompatibleType)
fn get_self_from_extern_with_generics(_extern: &crate::sys::externals::Extern) -> Result<Self, crate::sys::exports::ExportError> {
use crate::sys::exports::Exportable;
crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::sys::exports::ExportError::IncompatibleType)
}
fn into_weak_instance_ref(&mut self) {

View File

@@ -6,8 +6,8 @@
//! Therefore, you should use this abstraction whenever possible to avoid memory
//! related bugs when implementing an ABI.
use crate::cell::WasmCell;
use crate::{externals::Memory, FromToNativeWasmType};
use crate::sys::cell::WasmCell;
use crate::sys::{externals::Memory, FromToNativeWasmType};
use std::{cell::Cell, fmt, marker::PhantomData, mem};
use wasmer_types::ValueType;
@@ -294,7 +294,7 @@ impl<T: Copy, Ty> fmt::Debug for WasmPtr<T, Ty> {
#[cfg(test)]
mod test {
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
/// bounds errors are caught with `deref`

View File

@@ -1,4 +1,4 @@
use crate::tunables::BaseTunables;
use crate::sys::tunables::BaseTunables;
use loupe::MemoryUsage;
use std::any::Any;
use std::fmt;

View File

@@ -1,4 +1,4 @@
use crate::{MemoryType, Pages, TableType};
use crate::sys::{MemoryType, Pages, TableType};
use loupe::MemoryUsage;
use std::cmp::min;
use std::ptr::NonNull;

View File

@@ -1,6 +1,6 @@
use crate::externals::Function;
use crate::store::{Store, StoreObject};
use crate::RuntimeError;
use crate::sys::externals::Function;
use crate::sys::store::{Store, StoreObject};
use crate::sys::RuntimeError;
use wasmer_types::Value;
pub use wasmer_types::{
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,

View File

@@ -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(())
}

View File

@@ -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(())
}

View File

@@ -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(())
}

View 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);
}
}

View 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
View 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();
// }
}

View File

@@ -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(())
}

View File

@@ -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
View 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(())
}
}

View 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(())
}
}

View 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
View 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(())
}
}

View 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(())
}
}

View File

@@ -11,7 +11,7 @@ readme = "README.md"
edition = "2018"
[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"
thiserror = "1"
blake3 = "0.3"

View File

@@ -10,10 +10,6 @@ edition = "2018"
[lib]
proc-macro = true
[features]
# It will make imports from `wasmer_js::` instead of `wasmer::`
js = []
[dependencies]
syn = { version = "1.0.72", features = ["full", "extra-traits"] }
quote = "1"
@@ -22,4 +18,4 @@ proc-macro-error = "1.0.0"
[dev-dependencies]
wasmer = { path = "../api", version = "2.0.0" }
compiletest_rs = "0.6"
compiletest_rs = "0.6"

View File

@@ -13,26 +13,21 @@ use crate::parse::WasmerAttr;
#[proc_macro_derive(WasmerEnv, attributes(wasmer))]
pub fn derive_wasmer_env(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input: DeriveInput = syn::parse(input).unwrap();
#[cfg(feature = "js")]
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);
let gen = impl_wasmer_env(&input);
gen.into()
}
fn impl_wasmer_env_for_struct(
root: &Ident,
name: &Ident,
data: &DataStruct,
generics: &Generics,
_attrs: &[Attribute],
) -> 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 where_clause = generics.where_clause.clone();
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
}
@@ -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;
set_dummy(quote! {
impl ::#root::WasmerEnv for #struct_name {
fn init_with_instance(&mut self, instance: &::#root::Instance) -> Result<(), ::#root::HostEnvInitError> {
impl ::wasmer::WasmerEnv for #struct_name {
fn init_with_instance(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> {
Ok(())
}
}
@@ -56,7 +51,7 @@ fn impl_wasmer_env(root: &Ident, input: &DeriveInput) -> TokenStream {
match &input.data {
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!(),
}
@@ -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 helpers = vec![];
//let mut assign_tokens = vec![];
@@ -210,7 +205,7 @@ fn derive_struct_fields(root: &Ident, data: &DataStruct) -> (TokenStream, TokenS
}
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)*
Ok(())
}

View File

@@ -16,7 +16,7 @@ lazy_static = "1.4"
libc = "^0.2"
log = "0.4"
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]
getrandom = "0.2"

View File

@@ -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"]

View File

@@ -1,78 +0,0 @@
# `wasmer-js` [![Build Status](https://github.com/wasmerio/wasmer/workflows/build/badge.svg?style=flat-square)](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [![Join Wasmer Slack](https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square)](https://slack.wasmer.io) [![MIT License](https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square)](https://github.com/wasmerio/wasmer/blob/master/LICENSE) [![crates.io](https://img.shields.io/crates/v/wasmer-js.svg)](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

View File

@@ -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");

View File

@@ -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);
}

View File

@@ -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"))
}

View File

@@ -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();
// }

View File

@@ -20,7 +20,7 @@ getrandom = "0.2"
typetag = "0.1"
serde = { version = "1.0", features = ["derive"] }
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]
winapi = "0.3"