diff --git a/Cargo.lock b/Cargo.lock index fdd024b2a4e..5ee06814296 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index ecb161315cf..7dbac4d1496 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,6 @@ members = [ "lib/engine-universal", "lib/engine-dylib", "lib/engine-staticlib", - "lib/js-api", "lib/object", "lib/vm", "lib/wasi", diff --git a/Makefile b/Makefile index 3cd96fb15a6..f0d1a1fb813 100644 --- a/Makefile +++ b/Makefile @@ -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 ##### diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index 4868f5ccd6d..57eb0d8b6c1 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -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"] +# +##### \ No newline at end of file diff --git a/lib/api/README.md b/lib/api/README.md index 7ef67360b74..c0145bc881d 100644 --- a/lib/api/README.md +++ b/lib/api/README.md @@ -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 - -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**). - -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. - -> 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. + +* **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. + +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 diff --git a/lib/js-api/src/cell.rs b/lib/api/src/js/cell.rs similarity index 96% rename from lib/js-api/src/cell.rs rename to lib/api/src/js/cell.rs index fdcd62709c1..b8c41507928 100644 --- a/lib/js-api/src/cell.rs +++ b/lib/api/src/js/cell.rs @@ -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 WasmCell<'_, T> { /// /// ``` /// use std::cell::Cell; - /// use wasmer_js::WasmCell; + /// use wasmer::WasmCell; /// /// let cell = Cell::new(5); /// let wasm_cell = WasmCell::new(&cell); diff --git a/lib/js-api/src/env.rs b/lib/api/src/js/env.rs similarity index 97% rename from lib/js-api/src/env.rs rename to lib/api/src/js/env.rs index 2d4809e206d..30db0fb3c83 100644 --- a/lib/js-api/src/env.rs +++ b/lib/api/src/js/env.rs @@ -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 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 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, diff --git a/lib/js-api/src/error.rs b/lib/api/src/js/error.rs similarity index 98% rename from lib/js-api/src/error.rs rename to lib/api/src/js/error.rs index ddbef50137c..205cf2de946 100644 --- a/lib/js-api/src/error.rs +++ b/lib/api/src/js/error.rs @@ -1,4 +1,4 @@ -use crate::lib::std::string::String; +use crate::js::lib::std::string::String; #[cfg(feature = "std")] use thiserror::Error; diff --git a/lib/js-api/src/export.rs b/lib/api/src/js/export.rs similarity index 96% rename from lib/js-api/src/export.rs rename to lib/api/src/js/export.rs index 7daa9dab73d..06f72ed3e84 100644 --- a/lib/js-api/src/export.rs +++ b/lib/api/src/js/export.rs @@ -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; diff --git a/lib/js-api/src/exports.rs b/lib/api/src/js/exports.rs similarity index 94% rename from lib/js-api/src/exports.rs rename to lib/api/src/js/exports.rs index 195e94545bd..98cca5f9d62 100644 --- a/lib/js-api/src/exports.rs +++ b/lib/api/src/js/exports.rs @@ -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>; } diff --git a/lib/js-api/src/externals/function.rs b/lib/api/src/js/externals/function.rs similarity index 97% rename from lib/js-api/src/externals/function.rs rename to lib/api/src/js/externals/function.rs index 41479055c16..d9ccea88be4 100644 --- a/lib/js-api/src/externals/function.rs +++ b/lib/api/src/js/externals/function.rs @@ -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. diff --git a/lib/js-api/src/externals/global.rs b/lib/api/src/js/externals/global.rs similarity index 89% rename from lib/js-api/src/externals/global.rs rename to lib/api/src/js/externals/global.rs index 73e48cf732b..431547129a2 100644 --- a/lib/js-api/src/externals/global.rs +++ b/lib/api/src/js/externals/global.rs @@ -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)); diff --git a/lib/js-api/src/externals/memory.rs b/lib/api/src/js/externals/memory.rs similarity index 93% rename from lib/js-api/src/externals/memory.rs rename to lib/api/src/js/externals/memory.rs index badc4c1bf2c..4dc868d1fbf 100644 --- a/lib/js-api/src/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -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(); diff --git a/lib/js-api/src/externals/mod.rs b/lib/api/src/js/externals/mod.rs similarity index 95% rename from lib/js-api/src/externals/mod.rs rename to lib/api/src/js/externals/mod.rs index 57645e1bc0f..ebcb2b9e049 100644 --- a/lib/js-api/src/externals/mod.rs +++ b/lib/api/src/js/externals/mod.rs @@ -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 diff --git a/lib/js-api/src/externals/table.rs b/lib/api/src/js/externals/table.rs similarity index 93% rename from lib/js-api/src/externals/table.rs rename to lib/api/src/js/externals/table.rs index a7f7ee7fc53..cc7608fee9b 100644 --- a/lib/js-api/src/externals/table.rs +++ b/lib/api/src/js/externals/table.rs @@ -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 { let descriptor = js_sys::Object::new(); js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into())?; diff --git a/lib/js-api/src/import_object.rs b/lib/api/src/js/import_object.rs similarity index 96% rename from lib/js-api/src/import_object.rs rename to lib/api/src/js/import_object.rs index c5def4176ba..63bb41d50f6 100644 --- a/lib/js-api/src/import_object.rs +++ b/lib/api/src/js/import_object.rs @@ -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(); diff --git a/lib/js-api/src/instance.rs b/lib/api/src/js/instance.rs similarity index 91% rename from lib/js-api/src/instance.rs rename to lib/api/src/js/instance.rs index 2942f3c20fb..c7e155adc33 100644 --- a/lib/js-api/src/instance.rs +++ b/lib/api/src/js/instance.rs @@ -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)")?; diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs new file mode 100644 index 00000000000..b27d2756c3c --- /dev/null +++ b/lib/api/src/js/mod.rs @@ -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"); diff --git a/lib/js-api/src/module.rs b/lib/api/src/js/module.rs similarity index 97% rename from lib/js-api/src/module.rs rename to lib/api/src/js/module.rs index fddf94f1ed8..fb02c27b9a2 100644 --- a/lib/js-api/src/module.rs +++ b/lib/api/src/js/module.rs @@ -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 diff --git a/lib/js-api/src/module_info_polyfill.rs b/lib/api/src/js/module_info_polyfill.rs similarity index 100% rename from lib/js-api/src/module_info_polyfill.rs rename to lib/api/src/js/module_info_polyfill.rs diff --git a/lib/js-api/src/native.rs b/lib/api/src/js/native.rs similarity index 89% rename from lib/js-api/src/native.rs rename to lib/api/src/js/native.rs index b30fac36fe9..6cbd4c53894 100644 --- a/lib/js-api/src/native.rs +++ b/lib/api/src/js/native.rs @@ -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 { - 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 { + use crate::js::exports::Exportable; + crate::js::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::js::exports::ExportError::IncompatibleType) } } }; diff --git a/lib/js-api/src/ptr.rs b/lib/api/src/js/ptr.rs similarity index 97% rename from lib/js-api/src/ptr.rs rename to lib/api/src/js/ptr.rs index 3e353e35122..e5c0c471b90 100644 --- a/lib/js-api/src/ptr.rs +++ b/lib/api/src/js/ptr.rs @@ -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) { /// 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 fmt::Debug for WasmPtr { #[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 diff --git a/lib/js-api/src/resolver.rs b/lib/api/src/js/resolver.rs similarity index 99% rename from lib/js-api/src/resolver.rs rename to lib/api/src/js/resolver.rs index cc3bc9337c1..6f373eac145 100644 --- a/lib/js-api/src/resolver.rs +++ b/lib/api/src/js/resolver.rs @@ -1,4 +1,4 @@ -use crate::export::Export; +use crate::js::export::Export; /// Import resolver connects imports with available exported values. pub trait Resolver { diff --git a/lib/js-api/src/store.rs b/lib/api/src/js/store.rs similarity index 100% rename from lib/js-api/src/store.rs rename to lib/api/src/js/store.rs diff --git a/lib/js-api/src/trap.rs b/lib/api/src/js/trap.rs similarity index 100% rename from lib/js-api/src/trap.rs rename to lib/api/src/js/trap.rs diff --git a/lib/js-api/src/types.rs b/lib/api/src/js/types.rs similarity index 93% rename from lib/js-api/src/types.rs rename to lib/api/src/js/types.rs index 80507ae2403..8b9723987f8 100644 --- a/lib/js-api/src/types.rs +++ b/lib/api/src/js/types.rs @@ -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::{ diff --git a/lib/api/src/utils.rs b/lib/api/src/js/utils.rs similarity index 100% rename from lib/api/src/utils.rs rename to lib/api/src/js/utils.rs diff --git a/lib/js-api/src/wasm_bindgen_polyfill.rs b/lib/api/src/js/wasm_bindgen_polyfill.rs similarity index 100% rename from lib/js-api/src/wasm_bindgen_polyfill.rs rename to lib/api/src/js/wasm_bindgen_polyfill.rs diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index b92cdc77563..49d535beb03 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -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) +//! //! +//! # WebAssembly Primitives //! -//! # Wasm 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. //! +//! 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)" +)] //! -//! -------- +//! 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)); //! -//! By default the `wat`, `default-cranelift`, and `default-universal` features -//! are enabled. +//! 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(feature = "cranelift")] -pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel}; +#[cfg(all(feature = "sys", target_arch = "wasm32"))] +compile_error!("The `sys` feature must be enabled only for non-`wasm32` target."); -#[cfg(feature = "llvm")] -pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM}; - -#[cfg(feature = "universal")] -pub use wasmer_engine_universal::{Universal, UniversalArtifact, UniversalEngine}; +#[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 = "dylib")] -pub use wasmer_engine_dylib::{Dylib, DylibArtifact, DylibEngine}; +#[cfg(feature = "sys")] +mod sys; -/// Version number of this crate. -pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +#[cfg(feature = "sys")] +pub use sys::*; -/// 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; +#[cfg(feature = "js")] +mod js; -/// 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::*; diff --git a/lib/api/src/cell.rs b/lib/api/src/sys/cell.rs similarity index 100% rename from lib/api/src/cell.rs rename to lib/api/src/sys/cell.rs diff --git a/lib/api/src/env.rs b/lib/api/src/sys/env.rs similarity index 99% rename from lib/api/src/env.rs rename to lib/api/src/sys/env.rs index d8078414579..4a5491d7235 100644 --- a/lib/api/src/env.rs +++ b/lib/api/src/sys/env.rs @@ -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. diff --git a/lib/api/src/exports.rs b/lib/api/src/sys/exports.rs similarity index 98% rename from lib/api/src/exports.rs rename to lib/api/src/sys/exports.rs index 899f494a33e..6978a60428f 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/sys/exports.rs @@ -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; diff --git a/lib/api/src/externals/function.rs b/lib/api/src/sys/externals/function.rs similarity index 99% rename from lib/api/src/externals/function.rs rename to lib/api/src/sys/externals/function.rs index 26061482f33..babb2311a37 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/sys/externals/function.rs @@ -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; diff --git a/lib/api/src/externals/global.rs b/lib/api/src/sys/externals/global.rs similarity index 96% rename from lib/api/src/externals/global.rs rename to lib/api/src/sys/externals/global.rs index 788c649bf48..776153af5c0 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/sys/externals/global.rs @@ -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; diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/sys/externals/memory.rs similarity index 97% rename from lib/api/src/externals/memory.rs rename to lib/api/src/sys/externals/memory.rs index 0f02f8ccec3..b5b6ba5cc7e 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/sys/externals/memory.rs @@ -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 /// diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/sys/externals/mod.rs similarity index 96% rename from lib/api/src/externals/mod.rs rename to lib/api/src/sys/externals/mod.rs index 79859c92d9e..029e4e4206b 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/sys/externals/mod.rs @@ -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; diff --git a/lib/api/src/externals/table.rs b/lib/api/src/sys/externals/table.rs similarity index 95% rename from lib/api/src/externals/table.rs rename to lib/api/src/sys/externals/table.rs index b006927b1f6..fd981ac4be4 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/sys/externals/table.rs @@ -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 { let item = init.into_table_reference(store)?; let tunables = store.tunables(); diff --git a/lib/api/src/import_object.rs b/lib/api/src/sys/import_object.rs similarity index 99% rename from lib/api/src/import_object.rs rename to lib/api/src/sys/import_object.rs index ab4b61d36fd..e8491c684ce 100644 --- a/lib/api/src/import_object.rs +++ b/lib/api/src/sys/import_object.rs @@ -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(); diff --git a/lib/api/src/instance.rs b/lib/api/src/sys/instance.rs similarity index 96% rename from lib/api/src/instance.rs rename to lib/api/src/sys/instance.rs index 592fd2eeca9..86fe1f64738 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -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}; diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs new file mode 100644 index 00000000000..157a26a4a64 --- /dev/null +++ b/lib/api/src/sys/mod.rs @@ -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; diff --git a/lib/api/src/module.rs b/lib/api/src/sys/module.rs similarity index 99% rename from lib/api/src/module.rs rename to lib/api/src/sys/module.rs index f72ae74e61a..27df4fd6f31 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/sys/module.rs @@ -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; diff --git a/lib/api/src/native.rs b/lib/api/src/sys/native.rs similarity index 95% rename from lib/api/src/native.rs rename to lib/api/src/sys/native.rs index a350c6f090b..7c3f8705be9 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/sys/native.rs @@ -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 { - 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 { + 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) { diff --git a/lib/api/src/ptr.rs b/lib/api/src/sys/ptr.rs similarity index 99% rename from lib/api/src/ptr.rs rename to lib/api/src/sys/ptr.rs index e6a4a9be64e..33be4844f9c 100644 --- a/lib/api/src/ptr.rs +++ b/lib/api/src/sys/ptr.rs @@ -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 fmt::Debug for WasmPtr { #[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` diff --git a/lib/api/src/store.rs b/lib/api/src/sys/store.rs similarity index 99% rename from lib/api/src/store.rs rename to lib/api/src/sys/store.rs index d78f63e1381..8709ee9cc83 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/sys/store.rs @@ -1,4 +1,4 @@ -use crate::tunables::BaseTunables; +use crate::sys::tunables::BaseTunables; use loupe::MemoryUsage; use std::any::Any; use std::fmt; diff --git a/lib/api/src/tunables.rs b/lib/api/src/sys/tunables.rs similarity index 99% rename from lib/api/src/tunables.rs rename to lib/api/src/sys/tunables.rs index d714ffd602b..39a86ef6fd1 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/sys/tunables.rs @@ -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; diff --git a/lib/api/src/types.rs b/lib/api/src/sys/types.rs similarity index 97% rename from lib/api/src/types.rs rename to lib/api/src/sys/types.rs index 70c7a196173..ef291e9889b 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/sys/types.rs @@ -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, diff --git a/lib/js-api/src/utils.rs b/lib/api/src/sys/utils.rs similarity index 100% rename from lib/js-api/src/utils.rs rename to lib/api/src/sys/utils.rs diff --git a/lib/api/tests/export.rs b/lib/api/tests/export.rs deleted file mode 100644 index b65d2487bb2..00000000000 --- a/lib/api/tests/export.rs +++ /dev/null @@ -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 { - // 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 { - // 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 { - // 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 { - // 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(f: &NativeFunc) -> Option -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, - } - - 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, - } - - 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, - } - - 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, - } - - 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>, - } - - 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(()) -} diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs deleted file mode 100644 index dff570d2ef2..00000000000 --- a/lib/api/tests/externals.rs +++ /dev/null @@ -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 = 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 = 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, - } - - 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(()) -} diff --git a/lib/api/tests/instance.rs b/lib/api/tests/instance.rs deleted file mode 100644 index 69733877424..00000000000 --- a/lib/api/tests/instance.rs +++ /dev/null @@ -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(()) -} diff --git a/lib/api/tests/js_externals.rs b/lib/api/tests/js_externals.rs new file mode 100644 index 00000000000..5be196078e6 --- /dev/null +++ b/lib/api/tests/js_externals.rs @@ -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 = 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 = 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, + } + + 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); + } +} diff --git a/lib/api/tests/js_instance.rs b/lib/api/tests/js_instance.rs new file mode 100644 index 00000000000..374f0094140 --- /dev/null +++ b/lib/api/tests/js_instance.rs @@ -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, + } + + 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, + } + + fn imported_fn(env: &Env, args: &[Val]) -> Result, 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 = + 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(result: Result) { + match result { + Ok(result) => { + assert!( + false, + "Expected early termination with `ExitCode`, found: {:?}", + result + ); + } + Err(e) => { + match e.downcast::() { + // 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")) + } +} diff --git a/lib/api/tests/js_module.rs b/lib/api/tests/js_module.rs new file mode 100644 index 00000000000..f245e222806 --- /dev/null +++ b/lib/api/tests/js_module.rs @@ -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![ + 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![ImportType::new( + "host", + "func", + FunctionType::new(vec![], vec![]) + ),] + ); + assert_eq!( + module.imports().memories().collect::>(), + vec![ImportType::new( + "host", + "memory", + MemoryType::new(Pages(1), None, false) + ),] + ); + assert_eq!( + module.imports().tables().collect::>(), + vec![ImportType::new( + "host", + "table", + TableType::new(Type::FuncRef, 1, None) + ),] + ); + assert_eq!( + module.imports().globals().collect::>(), + 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![ + 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![ExportType::new("func", FunctionType::new(vec![], vec![])),] + ); + assert_eq!( + module.exports().memories().collect::>(), + vec![ExportType::new( + "memory", + MemoryType::new(Pages(2), None, false) + ),] + ); + assert_eq!( + module.exports().tables().collect::>(), + vec![ExportType::new( + "table", + TableType::new(Type::FuncRef, 2, None) + ),] + ); + assert_eq!( + module.exports().globals().collect::>(), + 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(); + // } +} diff --git a/lib/api/tests/module.rs b/lib/api/tests/module.rs deleted file mode 100644 index 64708d2ae54..00000000000 --- a/lib/api/tests/module.rs +++ /dev/null @@ -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![ - 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![ImportType::new( - "host", - "func", - FunctionType::new(vec![], vec![]) - ),] - ); - assert_eq!( - module.imports().memories().collect::>(), - vec![ImportType::new( - "host", - "memory", - MemoryType::new(Pages(1), None, false) - ),] - ); - assert_eq!( - module.imports().tables().collect::>(), - vec![ImportType::new( - "host", - "table", - TableType::new(Type::FuncRef, 1, None) - ),] - ); - assert_eq!( - module.imports().globals().collect::>(), - 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![ - 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![ExportType::new("func", FunctionType::new(vec![], vec![])),] - ); - assert_eq!( - module.exports().memories().collect::>(), - vec![ExportType::new( - "memory", - MemoryType::new(Pages(1), None, false) - ),] - ); - assert_eq!( - module.exports().tables().collect::>(), - vec![ExportType::new( - "table", - TableType::new(Type::FuncRef, 1, None) - ),] - ); - assert_eq!( - module.exports().globals().collect::>(), - 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(()) -} diff --git a/lib/api/tests/reference_types.rs b/lib/api/tests/reference_types.rs deleted file mode 100644 index 8a1aaa6e033..00000000000 --- a/lib/api/tests/reference_types.rs +++ /dev/null @@ -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, _> { - 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); - 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, 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 { - 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, _> { - 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, _> { - let inner = - [("hello".to_string(), "world".to_string()), - ("color".to_string(), "orange".to_string())] - .iter() - .cloned() - .collect::>(); - 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::>(); - 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 = 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 = 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 = instance.exports.get_native_function("drop")?; - - let er = ExternRef::new(3u32); - f.call(er.clone())?; - - assert_eq!(er.downcast::().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::().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 = - 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::().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::().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(()) -} diff --git a/lib/api/tests/sys/export.rs b/lib/api/tests/sys/export.rs new file mode 100644 index 00000000000..9975a8580ee --- /dev/null +++ b/lib/api/tests/sys/export.rs @@ -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 { + // 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 { + // 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 { + // 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 { + // 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( + f: &NativeFunc, + ) -> Option + 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, + } + + 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, + } + + 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
, + } + + 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, + } + + 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>, + } + + 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(()) + } +} diff --git a/lib/api/tests/sys/externals.rs b/lib/api/tests/sys/externals.rs new file mode 100644 index 00000000000..56002390403 --- /dev/null +++ b/lib/api/tests/sys/externals.rs @@ -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 = 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 = 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, + } + + 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(()) + } +} diff --git a/lib/api/tests/sys/instance.rs b/lib/api/tests/sys/instance.rs new file mode 100644 index 00000000000..4afbba187e2 --- /dev/null +++ b/lib/api/tests/sys/instance.rs @@ -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(()) + } +} diff --git a/lib/api/tests/sys/module.rs b/lib/api/tests/sys/module.rs new file mode 100644 index 00000000000..2214b289ece --- /dev/null +++ b/lib/api/tests/sys/module.rs @@ -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![ + 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![ImportType::new( + "host", + "func", + FunctionType::new(vec![], vec![]) + ),] + ); + assert_eq!( + module.imports().memories().collect::>(), + vec![ImportType::new( + "host", + "memory", + MemoryType::new(Pages(1), None, false) + ),] + ); + assert_eq!( + module.imports().tables().collect::>(), + vec![ImportType::new( + "host", + "table", + TableType::new(Type::FuncRef, 1, None) + ),] + ); + assert_eq!( + module.imports().globals().collect::>(), + 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![ + 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![ExportType::new("func", FunctionType::new(vec![], vec![])),] + ); + assert_eq!( + module.exports().memories().collect::>(), + vec![ExportType::new( + "memory", + MemoryType::new(Pages(1), None, false) + ),] + ); + assert_eq!( + module.exports().tables().collect::>(), + vec![ExportType::new( + "table", + TableType::new(Type::FuncRef, 1, None) + ),] + ); + assert_eq!( + module.exports().globals().collect::>(), + 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(()) + } +} diff --git a/lib/api/tests/sys/reference_types.rs b/lib/api/tests/sys/reference_types.rs new file mode 100644 index 00000000000..989f60fcbea --- /dev/null +++ b/lib/api/tests/sys/reference_types.rs @@ -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, _> { + 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); + 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, 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 { + 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, _> { + 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, _> { + let inner = + [("hello".to_string(), "world".to_string()), + ("color".to_string(), "orange".to_string())] + .iter() + .cloned() + .collect::>(); + 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::>(); + 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 = 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 = 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 = instance.exports.get_native_function("drop")?; + + let er = ExternRef::new(3u32); + f.call(er.clone())?; + + assert_eq!(er.downcast::().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::().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 = + 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::().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::().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(()) + } +} diff --git a/lib/cache/Cargo.toml b/lib/cache/Cargo.toml index 396ff756ea1..c729a736daa 100644 --- a/lib/cache/Cargo.toml +++ b/lib/cache/Cargo.toml @@ -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" diff --git a/lib/derive/Cargo.toml b/lib/derive/Cargo.toml index 53aefdbacd3..52a4154d430 100644 --- a/lib/derive/Cargo.toml +++ b/lib/derive/Cargo.toml @@ -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" \ No newline at end of file diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index 449453771b4..00c34634951 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -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(()) } diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index a4cdf7add1d..2b9cb4cad97 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -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" diff --git a/lib/js-api/Cargo.toml b/lib/js-api/Cargo.toml deleted file mode 100644 index 945d1012bcc..00000000000 --- a/lib/js-api/Cargo.toml +++ /dev/null @@ -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 "] -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"] diff --git a/lib/js-api/README.md b/lib/js-api/README.md deleted file mode 100644 index 297f103afc1..00000000000 --- a/lib/js-api/README.md +++ /dev/null @@ -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 diff --git a/lib/js-api/src/lib.rs b/lib/js-api/src/lib.rs deleted file mode 100644 index e9c160b5fa4..00000000000 --- a/lib/js-api/src/lib.rs +++ /dev/null @@ -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"); diff --git a/lib/js-api/tests/externals.rs b/lib/js-api/tests/externals.rs deleted file mode 100644 index ae43d1bf18c..00000000000 --- a/lib/js-api/tests/externals.rs +++ /dev/null @@ -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 = 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 = 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, - } - - 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); -} diff --git a/lib/js-api/tests/instance.rs b/lib/js-api/tests/instance.rs deleted file mode 100644 index 58d96588f88..00000000000 --- a/lib/js-api/tests/instance.rs +++ /dev/null @@ -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, - } - - 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, - } - - fn imported_fn(env: &Env, args: &[Val]) -> Result, 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 = 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(result: Result) { - match result { - Ok(result) => { - assert!( - false, - "Expected early termination with `ExitCode`, found: {:?}", - result - ); - } - Err(e) => { - match e.downcast::() { - // 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")) -} diff --git a/lib/js-api/tests/module.rs b/lib/js-api/tests/module.rs deleted file mode 100644 index 9f57d71cf09..00000000000 --- a/lib/js-api/tests/module.rs +++ /dev/null @@ -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![ - 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![ImportType::new( - "host", - "func", - FunctionType::new(vec![], vec![]) - ),] - ); - assert_eq!( - module.imports().memories().collect::>(), - vec![ImportType::new( - "host", - "memory", - MemoryType::new(Pages(1), None, false) - ),] - ); - assert_eq!( - module.imports().tables().collect::>(), - vec![ImportType::new( - "host", - "table", - TableType::new(Type::FuncRef, 1, None) - ),] - ); - assert_eq!( - module.imports().globals().collect::>(), - 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![ - 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![ExportType::new("func", FunctionType::new(vec![], vec![])),] - ); - assert_eq!( - module.exports().memories().collect::>(), - vec![ExportType::new( - "memory", - MemoryType::new(Pages(2), None, false) - ),] - ); - assert_eq!( - module.exports().tables().collect::>(), - vec![ExportType::new( - "table", - TableType::new(Type::FuncRef, 2, None) - ),] - ); - assert_eq!( - module.exports().globals().collect::>(), - 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(); -// } diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 7e9313402aa..be2dac2c867 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -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"