Merge branch 'master' into feat-deprecated-runtime-core

This commit is contained in:
Ivan Enderlin
2020-07-16 13:27:59 +02:00
61 changed files with 1511 additions and 138 deletions

View File

@@ -92,10 +92,12 @@ jobs:
if: matrix.os == 'macos-latest'
run: |
curl https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-apple-darwin.tar.xz -L -o llvm.tar.xz
mkdir -p /opt/llvm-10
tar xf llvm.tar.xz --strip-components=1 -C /opt/llvm-10
echo ::add-path::/opt/llvm-10/bin
echo ::set-env name=LLVM_SYS_100_PREFIX::/opt/llvm-10
mkdir -p ${{ env.LLVM_DIR }}
tar xf llvm.tar.xz --strip-components=1 -C ${{ env.LLVM_DIR }}
echo "::add-path::${{ env.LLVM_DIR }}/bin"
echo "::set-env name=LLVM_SYS_100_PREFIX::${{ env.LLVM_DIR }}"
env:
LLVM_DIR: ${{ github.workspace }}/llvm-10
- name: Install LLVM (Linux)
if: matrix.os == 'ubuntu-latest'
run: |

1
Cargo.lock generated
View File

@@ -2149,6 +2149,7 @@ dependencies = [
"lazy_static",
"rustc_version",
"structopt",
"tempfile",
"test-generator",
"wasm-common",
"wasmer",

View File

@@ -70,6 +70,7 @@ blake3 = "0.3"
criterion = "0.3"
lazy_static = "1.4"
wasmer-engine-dummy = { path = "tests/lib/engine-dummy" }
tempfile = "3.1"
[features]
# Don't add the compiler features in default, please add them on the Makefile
@@ -98,6 +99,7 @@ wasi = ["wasmer-wasi"]
emscripten = ["wasmer-emscripten"]
wat = ["wasmer/wat"]
compiler = [
"wasmer-compiler/translator",
"wasmer-engine-jit/compiler",
"wasmer-engine-native/compiler"
]
@@ -135,3 +137,48 @@ test-llvm = [
[[bench]]
name = "static_and_dynamic_functions"
harness = false
[[example]]
name = "engine-jit"
path = "examples/engine_jit.rs"
required-features = ["cranelift"]
[[example]]
name = "engine-native"
path = "examples/engine_native.rs"
required-features = ["cranelift"]
[[example]]
name = "engine-headless"
path = "examples/engine_headless.rs"
required-features = ["cranelift"]
[[example]]
name = "cross-compilation"
path = "examples/engine_cross_compilation.rs"
required-features = ["cranelift"]
[[example]]
name = "compiler-singlepass"
path = "examples/compiler_singlepass.rs"
required-features = ["singlepass"]
[[example]]
name = "compiler-cranelift"
path = "examples/compiler_cranelift.rs"
required-features = ["cranelift"]
[[example]]
name = "compiler-llvm"
path = "examples/compiler_llvm.rs"
required-features = ["llvm"]
[[example]]
name = "exported-function"
path = "examples/exports_function.rs"
required-features = ["cranelift"]
[[example]]
name = "wasi"
path = "examples/wasi.rs"
required-features = ["cranelift", "wasi"]

View File

@@ -96,7 +96,7 @@ build-capi-llvm:
# Testing #
###########
test: $(foreach compiler,$(compilers),test-$(compiler)) test-packages
test: $(foreach compiler,$(compilers),test-$(compiler)) test-packages test-examples
test-singlepass:
cargo test --release $(compiler_features) --features "test-singlepass"
@@ -112,6 +112,8 @@ test-packages:
cargo test -p wasmer-vm --release
cargo test -p wasm-common --release
cargo test -p wasmer-wasi --release
cargo test -p wasmer-object --release
cargo test -p wasmer-engine-native --release --no-default-features
test-capi-singlepass: build-capi-singlepass
cargo test --manifest-path lib/c-api/Cargo.toml --release \
@@ -130,6 +132,9 @@ test-capi: test-capi-singlepass test-capi-cranelift test-capi-llvm
test-wasi-unit:
cargo test --manifest-path lib/wasi/Cargo.toml --release
test-examples:
cargo test --release $(compiler_features) --features wasi --examples
#############
# Packaging #
#############

View File

@@ -28,7 +28,7 @@
<br />
[Wasmer](https://wasmer.io/) is the fastest and most popular [WebAssembly](https://webassembly.org/) runtime:
[Wasmer](https://wasmer.io/) is a standalone [WebAssembly](https://webassembly.org/) runtime:
* **Universal**: Wasmer is available in *Linux, macOS and Windows* (for both Desktop and [ARM](https://medium.com/wasmer/running-webassembly-on-arm-7d365ed0e50c))
* **Fast**: Wasmer aims to run WebAssembly at near-native speed
* **Pluggable**: Wasmer can be used from almost **any programming language**
@@ -52,19 +52,20 @@ Get started with Wasmer:
```sh
curl https://get.wasmer.io -sSfL | sh
```
> Note: *Wasmer is also [available on Windows](https://github.com/wasmerio/wasmer/releases)*
<details>
<summary><b>Alternative</b>: Install with Homebrew</summary>
<summary>With PowerShell</summary>
<p>
```sh
brew install wasmer
```powershell
iwr https://win.wasmer.io -useb | iex
```
</p>
</details>
> *Check all available installation methods here: https://github.com/wasmerio/wasmer-install*
#### 2. Use Wasmer
Download a WASM file, and use it universally! You can start with QuickJS: [qjs.wasm](https://registry-cdn.wapm.io/contents/_/quickjs/0.0.3/build/qjs.wasm)
@@ -88,14 +89,15 @@ Wasmer runtime can be used as a library embedded in different languages, so you
| &nbsp; | Language | Docs | Author(s) | Maintenance | Release | Stars |
|-|-|-|-|-|-|-|
| ![Rust logo](./assets/languages/rust.svg) | [**Rust**](https://github.com/wasmerio/wasmer-rust-example) | [Docs](https://wasmerio.github.io/wasmer/crates/wasmer_vm/) | Wasmer | actively developed | <a href="https://crates.io/crates/wasmer-vm/" target="_blank">![last release](https://img.shields.io/crates/v/wasmer-vm?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer?style=flat-square) |
| ![Rust logo](./assets/languages/rust.svg) | [**Rust**](https://github.com/wasmerio/wasmer-rust-example) | [Docs](https://wasmerio.github.io/wasmer/crates/wasmer_runtime/) | Wasmer | actively developed | <a href="https://crates.io/crates/wasmer/" target="_blank">![last release](https://img.shields.io/crates/v/wasmer-runtime?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer?style=flat-square) |
| ![C logo](./assets/languages/c.svg) | [**C/C++**](https://github.com/wasmerio/wasmer-c-api) | [Docs](https://wasmerio.github.io/wasmer/c/runtime-c-api/) | Wasmer | actively developed | <a href="https://github.com/wasmerio/wasmer-c-api/" target="_blank">![last release](https://img.shields.io/github/v/release/wasmerio/wasmer?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer?style=flat-square) |
| ![Python logo](./assets/languages/python.svg) | [**Python**](https://github.com/wasmerio/python-ext-wasm) | [Docs](https://github.com/wasmerio/python-ext-wasm#api-of-the-wasmer-extensionmodule) | Wasmer | actively developed | <a href="https://pypi.org/project/wasmer/" target="_blank">![last release](https://img.shields.io/pypi/v/wasmer?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/python-ext-wasm?style=flat-square) |
| ![Go logo](./assets/languages/go.svg) | [**Go**](https://github.com/wasmerio/go-ext-wasm) | [Docs](https://github.com/wasmerio/go-ext-wasm#basic-example-exported-function) | Wasmer | actively developed | <a href="https://github.com/wasmerio/go-ext-wasm" target="_blank">![last release](https://img.shields.io/github/v/release/wasmerio/go-ext-wasm?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/go-ext-wasm?style=flat-square) |
| ![PHP logo](./assets/languages/php.svg) | [**PHP**](https://github.com/wasmerio/php-ext-wasm) | [Docs](https://wasmerio.github.io/php-ext-wasm/wasm/) | Wasmer | actively developed | <a href="https://pecl.php.net/package/wasm" target="_blank">![last release](https://img.shields.io/github/v/release/wasmerio/php-ext-wasm?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/php-ext-wasm?style=flat-square) |
| ![Ruby logo](./assets/languages/ruby.svg) | [**Ruby**](https://github.com/wasmerio/ruby-ext-wasm) | [Docs](https://www.rubydoc.info/gems/wasmer/) | Wasmer | actively developed | <a href="https://rubygems.org/gems/wasmer" target="_blank">![last release](https://img.shields.io/gem/v/wasmer?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/ruby-ext-wasm?style=flat-square) |
| ![Postgres logo](./assets/languages/postgres.svg) | [**Postgres**](https://github.com/wasmerio/postgres-ext-wasm) | | Wasmer | actively developed | <a href="https://github.com/wasmerio/postgres-ext-wasm" target="_blank">![last release](https://img.shields.io/github/v/release/wasmerio/postgres-ext-wasm?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/postgres-ext-wasm?style=flat-square) |
| ![JS Logo](./assets/languages/js.svg) | [**JavaScript**](https://github.com/wasmerio/wasmer-js) | [Docs](https://docs.wasmer.io/wasmer-js/wasmer-js) | Wasmer | actively developed | <a href="https://www.npmjs.com/package/@wasmer/wasi" target="_blank">![last release](https://img.shields.io/npm/v/@wasmer/wasi?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer-js?style=flat-square) |
| ![JS logo](./assets/languages/js.svg) | [**JavaScript**](https://github.com/wasmerio/wasmer-js) | [Docs](https://docs.wasmer.io/wasmer-js/wasmer-js) | Wasmer | actively developed | <a href="https://www.npmjs.com/package/@wasmer/wasi" target="_blank">![last release](https://img.shields.io/npm/v/@wasmer/wasi?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer-js?style=flat-square) |
| ![Java logo](./assets/languages/java.svg) | [**Java**](https://github.com/wasmerio/java-ext-wasm) | [Docs](https://github.com/wasmerio/java-ext-wasm/#api-of-the-wasmer-library) | Wasmer | actively developed | <a href="https://bintray.com/wasmer/wasmer-jni/wasmer-jni" target="_blank">![last release](https://img.shields.io/bintray/v/wasmer/wasmer-jni/wasmer-jni?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/java-ext-wasm?style=flat-square) |
| ![C# logo](./assets/languages/csharp.svg) | [**C#/.Net**](https://github.com/migueldeicaza/WasmerSharp) | [Docs](https://migueldeicaza.github.io/WasmerSharp/) |[Miguel de Icaza](https://github.com/migueldeicaza) | actively developed | <a href="https://www.nuget.org/packages/WasmerSharp/" target="_blank">![last release](https://img.shields.io/nuget/v/WasmerSharp?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/migueldeicaza/WasmerSharp?style=flat-square) |
| ![R logo](./assets/languages/r.svg) | [**R**](https://github.com/dirkschumacher/wasmr) | [Docs](https://github.com/dirkschumacher/wasmr#example) | [Dirk Schumacher](https://github.com/dirkschumacher) | actively developed | | ![number of Github stars](https://img.shields.io/github/stars/dirkschumacher/wasmr?style=flat-square) |
| ![Elixir logo](./assets/languages/elixir.png) | [**Elixir**](https://github.com/tessi/wasmex) | [Docs](https://hexdocs.pm/wasmex/api-reference.html) | [Philipp Tessenow](https://github.com/tessi) | actively developed | <a href="https://hex.pm/packages/wasmex" target="_blank">![last release](https://img.shields.io/hexpm/v/wasmex?style=flat-square)</a> | ![number of Github stars](https://img.shields.io/github/stars/tessi/wasmex?style=flat-square) |

167
examples/README.md Normal file
View File

@@ -0,0 +1,167 @@
# Wasmer Examples
This directory contains a collection of examples. This isn't an
exhaustive collection though, if one example is missing, please ask,
we will be happy to fulfill your needs!
## Examples
The examples are written in a difficulty/discovery order. Concepts that
are explained in an example is not necessarily re-explained in a next
example.
### Engines
1. [**JIT engine**][engine-jit], explains what an engine is, what the
JIT engine is, and how to set it up. The example completes itself
with the compilation of the Wasm module, its instantiation, and
finally, by calling an exported function.
_Keywords_: JIT, engine, in-memory, executable code.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example engine-jit --release --features "cranelift"
```
</details>
2. [**Native engine**][engine-native], explains what a native engine
is, and how to set it up. The example completes itself with the
compilation of the Wasm module, its instantiation, and finally, by
calling an exported function.
_Keywords_: native, engine, shared library, dynamic library,
executable code.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example engine-native --release --features "cranelift"
```
</details>
3. [**Headless engines**][engine-headless], explains what a headless
engine is, what problem it does solve, and what are the benefits of
it. The example completes itself with the instantiation of a
pre-compiled Wasm module, and finally, by calling an exported
function.
_Keywords_: native, engine, constrained environment, ahead-of-time
compilation, cross-compilation, executable code, serialization.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example engine-headless --release --features "cranelift"
```
</details>
4. [**Cross-compilation**][cross-compilation], illustrates the power
of the abstraction over the engines and the compilers, such as it
is possible to cross-compile a Wasm module for a custom target.
_Keywords_: engine, compiler, cross-compilation.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example cross-compilation --release --features "cranelift"
```
</details>
### Compilers
5. [**Singlepass Compiler**][compiler-singlepass], explains how to use
the [Singlepass compiler](https://github.com/wasmerio/wasmer-reborn/tree/master/lib/compiler-singlepass).
_Keywords_: engine, compiler, singlepass.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example compiler-singlepass --release --features "singlepass"
```
</details>
6. [**Cranelift Compiler**][compiler-cranelift], explains how to use
the [Cranelift compiler](https://github.com/wasmerio/wasmer-reborn/tree/master/lib/compiler-cranelift).
_Keywords_: engine, compiler, cranelift.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example compiler-cranelift --release --features "cranelift"
```
</details>
7. [**LLVM Compiler**][compiler-llvm], explains how to use
the [LLVM compiler](https://github.com/wasmerio/wasmer-reborn/tree/master/lib/compiler-llvm).
_Keywords_: engine, compiler, llvm.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example compiler-llvm --release --features "llvm"
```
</details>
### Exports
8. [**Exported function**][exported-function], explains how to get and
how to call an exported function. They come in 2 flavors: dynamic,
and “static”/native. The pros and cons are discussed briefly.
_Keywords_: export, function, dynamic, static, native.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example exported-function --release --features "cranelift"
```
</details>
### Integrations
9. [**WASI integration**][integration-wasi], explains how to get and
how to call an exported function. They come in 2 flavors: dynamic,
and “static”/native. The pros and cons are discussed briefly.
_Keywords_: export, function, dynamic, static, native.
<details>
<summary><em>Execute the example</em></summary>
```shell
$ cargo run --example wasi --release --features "cranelift,wasi"
```
</details>
[engine-jit]: ./engine_jit.rs
[engine-native]: ./engine_native.rs
[engine-headless]: ./engine_headless.rs
[compiler-singlepass]: ./compiler_singlepass.rs
[compiler-cranelift]: ./compiler_cranelift.rs
[compiler-llvm]: ./compiler_llvm.rs
[cross-compilation]: ./engine_cross_compilation.rs
[exported-function]: ./exports_function.rs
[integration-wasi]: ./wasi.rs

View File

@@ -0,0 +1,66 @@
//! A Wasm module can be compiled with multiple compilers.
//!
//! This example illustrates how to use the Cranelift compiler.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example compiler-cranelift --release --features "cranelift"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
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)))
"#
.as_bytes(),
)?;
// Use Cranelift compiler with the default settings
let compiler = Cranelift::default();
// Create the store
let store = Store::new(&JIT::new(&compiler).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
// Create an empty import object.
let import_object = imports! {};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
let sum = instance.exports.get_function("sum")?;
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
Ok(())
}
#[test]
#[cfg(feature = "cranelift")]
fn test_compiler_cranelift() -> Result<(), Box<dyn std::error::Error>> {
main()
}

66
examples/compiler_llvm.rs Normal file
View File

@@ -0,0 +1,66 @@
//! A Wasm module can be compiled with multiple compilers.
//!
//! This example illustrates how to use the LLVM compiler.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example compiler-llvm --release --features "llvm"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler_llvm::LLVM;
use wasmer_engine_jit::JIT;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
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)))
"#
.as_bytes(),
)?;
// Use LLVM compiler with the default settings
let compiler = LLVM::default();
// Create the store
let store = Store::new(&JIT::new(&compiler).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
// Create an empty import object.
let import_object = imports! {};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
let sum = instance.exports.get_function("sum")?;
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
Ok(())
}
#[test]
#[cfg(feature = "llvm")]
fn test_compiler_llvm() -> Result<(), Box<dyn std::error::Error>> {
main()
}

View File

@@ -0,0 +1,66 @@
//! A Wasm module can be compiled with multiple compilers.
//!
//! This example illustrates how to use the Singlepass compiler.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example compiler-singlepass --release --features "singlepass"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler_singlepass::Singlepass;
use wasmer_engine_jit::JIT;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
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)))
"#
.as_bytes(),
)?;
// Use Singlepass compiler with the default settings
let compiler = Singlepass::default();
// Create the store
let store = Store::new(&JIT::new(&compiler).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
// Create an empty import object.
let import_object = imports! {};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
let sum = instance.exports.get_function("sum")?;
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
Ok(())
}
#[test]
#[cfg(feature = "singlepass")]
fn test_compiler_singlepass() -> Result<(), Box<dyn std::error::Error>> {
main()
}

View File

@@ -0,0 +1,106 @@
//! Defining an engine in Wasmer is one of the fundamental steps.
//!
//! As a reminder, an engine applies roughly 2 steps:
//!
//! 1. It compiles the Wasm module bytes to executable code, through
//! the intervention of a compiler,
//! 2. It stores the executable code somewhere.
//!
//! This example focuses on the first step: the compiler. It
//! illustrates how the abstraction over the compiler is so powerful
//! that it is possible to cross-compile a Wasm module.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example cross-compilation --release --features "cranelift"
//! ```
//!
//! Ready?
use std::str::FromStr;
use wasmer::{wat2wasm, Module, RuntimeError, Store};
use wasmer_compiler::{CpuFeature, Target, Triple};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_native::Native;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
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)))
"#
.as_bytes(),
)?;
// Define a compiler configuration.
//
// In this situation, the compiler is
// `wasmer_compiler_cranelift`. The compiler is responsible to
// compile the Wasm module into executable code.
let mut compiler_config = Cranelift::default();
// Here we go.
//
// Let's define the target “triple”. Historically, such things had
// three fields, though additional fields have been added over
// time.
let triple = Triple::from_str("x86_64-linux-musl")
.map_err(|error| RuntimeError::new(error.to_string()))?;
// Here we go again.
//
// Let's define a CPU feature.
let mut cpu_feature = CpuFeature::set();
cpu_feature.insert(CpuFeature::from_str("sse2")?);
// Here we go finally.
//
// Let's build the target.
let target = Target::new(triple, cpu_feature);
println!("Chosen target: {:?}", target);
// Define the engine that will drive everything.
//
// In this case, the engine is `wasmer_engine_native` which means
// that a native object is going to be generated.
//
// That's where we specify the target for the compiler.
// Use the native engine.
let engine = Native::new(&mut compiler_config)
// Here we go.
// Pass the target to the engine! The engine will share
// this information with the compiler.
.target(target)
// Get the engine.
.engine();
// Create a store, that holds the engine.
let store = Store::new(&engine);
println!("Compiling module...");
// Let's compile the Wasm module.
let _module = Module::new(&store, wasm_bytes)?;
println!("Module compiled successfully.");
// Congrats, the Wasm module is cross-compiled!
//
// What to do with that? It is possible to use an engine (probably
// a headless engine) to execute the cross-compiled Wasm module an
// the targeted platform.
Ok(())
}
#[test]
#[cfg(not(windows))]
fn test_cross_compilation() -> Result<(), Box<dyn std::error::Error>> {
main()
}

153
examples/engine_headless.rs Normal file
View File

@@ -0,0 +1,153 @@
//! Defining an engine in Wasmer is one of the fundamental steps.
//!
//! This example illustrates a neat feature of engines: their ability
//! to run in a headless mode. At the time of writing, all engines
//! have a headless mode, but it's not a requirement of the `Engine`
//! trait (defined in the `wasmer_engine` crate).
//!
//! What problem does it solve, and what does it mean?
//!
//! Once a Wasm module is compiled into executable code and stored
//! somewhere (e.g. in memory with the JIT engine, or in a native
//! object with the native engine), the module can be instantiated and
//! executed. But imagine for a second the following scenario:
//!
//! * Modules are compiled ahead of time, to be instantiated later
//! on.
//! * Modules are cross-compiled on a machine ahead of time
//! to be run on another machine later one.
//!
//! In both scenarios, the environment where the compiled Wasm module
//! will be executed can be very constrained. For such particular
//! contexts, Wasmer can be compiled _without_ the compilers, so that
//! the `wasmer` binary is as small as possible. Indeed, there is no
//! need for a compiler since the Wasm module is already compiled. All
//! we need is an engine that _only_ drives the instantiation and
//! execution of the Wasm module.
//!
//! And that, that's a headless engine.
//!
//! To achieve such a scenario, a Wasm module must be compiled, then
//! serialized —for example into a file—, then later, potentially on
//! another machine, deserialized. The next steps are classical: The
//! Wasm module is instantiated and executed.
//!
//! This example uses a `compiler` because it illustrates the entire
//! workflow, but keep in mind the compiler isn't required after the
//! compilation step.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example engine-headless --release --features "cranelift"
//! ```
//!
//! Ready?
use tempfile::NamedTempFile;
use wasmer::imports;
use wasmer::wat2wasm;
use wasmer::Instance;
use wasmer::Module;
use wasmer::Store;
use wasmer::Value;
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_native::Native;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// First step, let's compile the Wasm module and serialize it.
// Note: we need a compiler here.
let serialized_module_file = {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
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)))
"#
.as_bytes(),
)?;
// Define a compiler configuration.
//
// In this situation, the compiler is
// `wasmer_compiler_cranelift`. The compiler is responsible to
// compile the Wasm module into executable code.
let mut compiler_config = Cranelift::default();
println!("Creating Native engine...");
// Define the engine that will drive everything.
//
// In this case, the engine is `wasmer_engine_native` which
// means that a native object is going to be generated. So
// when we are going to serialize the compiled Wasm module, we
// are going to store it in a file with the `.so` extension
// for example (or `.dylib`, or `.dll` depending of the
// platform).
let engine = Native::new(&mut compiler_config).engine();
// Create a store, that holds the engine.
let store = Store::new(&engine);
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
println!("Serializing module...");
// Here we go. Let's serialize the compiled Wasm module in a
// file.
let serialized_module_file = NamedTempFile::new()?;
module.serialize_to_file(&serialized_module_file)?;
serialized_module_file
};
// Second step, deserialize the compiled Wasm module, and execute
// it, for example with Wasmer without a compiler.
{
println!("Creating headless Native engine...");
// We create a headless Native engine.
let engine = Native::headless().engine();
let store = Store::new(&engine);
println!("Deserializing module...");
// Here we go.
//
// Deserialize the compiled Wasm module. This code is unsafe
// because Wasmer can't assert the bytes are valid (see the
// `wasmer::Module::deserialize`'s documentation to learn
// more).
let module = unsafe { Module::deserialize_from_file(&store, serialized_module_file) }?;
// Congrats, the Wasm module has been deserialized! Now let's
// execute it for the sake of having a complete example.
// Create an import object. Since our Wasm module didn't declare
// any imports, it's an empty object.
let import_object = imports! {};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
println!("Calling `sum` function...");
// The Wasm module exports a function called `sum`.
let sum = instance.exports.get_function("sum")?;
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
}
Ok(())
}
#[test]
#[cfg(not(windows))]
fn test_engine_headless() -> Result<(), Box<dyn std::error::Error>> {
main()
}

91
examples/engine_jit.rs Normal file
View File

@@ -0,0 +1,91 @@
//! Defining an engine in Wasmer is one of the fundamental steps.
//!
//! This example illustrates how to use the `wasmer_engine_jit`, aka
//! the JIT engine. An engine applies roughly 2 steps:
//!
//! 1. It compiles the Wasm module bytes to executable code, through
//! the intervention of a compiler,
//! 2. It stores the executable code somewhere.
//!
//! In the particular context of the JIT engine, the executable code
//! is stored in memory.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example engine-jit --release --features "cranelift"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
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)))
"#
.as_bytes(),
)?;
// Define a compiler configuration.
//
// In this situation, the compiler is
// `wasmer_compiler_cranelift`. The compiler is responsible to
// compile the Wasm module into executable code.
let mut compiler_config = Cranelift::default();
println!("Creating JIT engine...");
// Define the engine that will drive everything.
//
// In this case, the engine is `wasmer_engine_jit` which roughly
// means that the executable code will live in memory.
let engine = JIT::new(&mut compiler_config).engine();
// Create a store, that holds the engine.
let store = Store::new(&engine);
println!("Compiling module...");
// Here we go.
//
// Let's compile the Wasm module. It is at this step that the Wasm
// text is transformed into Wasm bytes (if necessary), and then
// compiled to executable code by the compiler, which is then
// stored in memory by the engine.
let module = Module::new(&store, wasm_bytes)?;
// Congrats, the Wasm module is compiled! Now let's execute it for
// the sake of having a complete example.
// Create an import object. Since our Wasm module didn't declare
// any imports, it's an empty object.
let import_object = imports! {};
println!("Instantiating module...");
// And here we go again. Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
println!("Calling `sum` function...");
// The Wasm module exports a function called `sum`.
let sum = instance.exports.get_function("sum")?;
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
Ok(())
}
#[test]
fn test_engine_jit() -> Result<(), Box<dyn std::error::Error>> {
main()
}

92
examples/engine_native.rs Normal file
View File

@@ -0,0 +1,92 @@
//! Defining an engine in Wasmer is one of the fundamental steps.
//!
//! This example illustrates how to use the `wasmer_engine_native`,
//! aka the native engine. An engine applies roughly 2 steps:
//!
//! 1. It compiles the Wasm module bytes to executable code, through
//! the intervention of a compiler,
//! 2. It stores the executable code somewhere.
//!
//! In the particular context of the native engine, the executable
//! code is stored in a native object, more precisely in a dynamic
//! library.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example engine-native --release --features "cranelift"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_native::Native;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
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)))
"#
.as_bytes(),
)?;
// Define a compiler configuration.
//
// In this situation, the compiler is
// `wasmer_compiler_cranelift`. The compiler is responsible to
// compile the Wasm module into executable code.
let mut compiler_config = Cranelift::default();
println!("Creating Native engine...");
// Define the engine that will drive everything.
//
// In this case, the engine is `wasmer_engine_native` which means
// that a native object is going to be generated.
let engine = Native::new(&mut compiler_config).engine();
// Create a store, that holds the engine.
let store = Store::new(&engine);
println!("Compiling module...");
// Here we go.
//
// Let's compile the Wasm module. It is at this step that the Wasm
// text is transformed into Wasm bytes (if necessary), and then
// compiled to executable code by the compiler, which is then
// stored into a native object by the engine.
let module = Module::new(&store, wasm_bytes)?;
// Congrats, the Wasm module is compiled! Now let's execute it for
// the sake of having a complete example.
// Create an import object. Since our Wasm module didn't declare
// any imports, it's an empty object.
let import_object = imports! {};
println!("Instantiating module...");
// And here we go again. Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
println!("Calling `sum` function...");
// The Wasm module exports a function called `sum`.
let sum = instance.exports.get_function("sum")?;
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
Ok(())
}
#[test]
fn test_engine_native() -> Result<(), Box<dyn std::error::Error>> {
main()
}

View File

@@ -0,0 +1,111 @@
//! A Wasm module can export entities, like functions, memories,
//! globals and tables.
//!
//! This example illustrates how to use exported functions. They come
//! in 2 flavors:
//!
//! 1. Dynamic functions, where parameters and results are of a
//! slice of `Value`,
//! 2. Native function, where parameters and results are statically
//! typed Rust values.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example exported-function --release --features "cranelift"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Instance, Module, Store, Value};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
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)))
"#
.as_bytes(),
)?;
// Create a Store.
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
// Create an empty import object.
let import_object = imports! {};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
// Here we go.
//
// The Wasm module exports a function called `sum`. Let's get
// it. Note that
//
// ```
// get_function(name)
// ```
//
// is just an alias to
//
// ```
// get::<Function>(name)`.
// ```
let sum = instance.exports.get_function("sum")?;
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
println!("Results: {:?}", results);
assert_eq!(results.to_vec(), vec![Value::I32(3)]);
// That was fun. But what if we can get rid of the `Value`s? Well,
// that's possible with the `NativeFunction` API. The function
// will use native Rust values.
//
// Note that `native` takes 2 generic parameters: `Args` and
// `Rets`, respectively for the parameters and the results. If
// those values don't match the exported function signature, an
// error will be raised.
let sum = sum.native::<(i32, i32), i32>()?;
println!("Calling `sum` function (natively)...");
// Let's call the `sum` exported function. The parameters are
// statically typed Rust values of type `i32` and `i32`. The
// result, in this case particular case, in a unit of type `i32`.
let result = sum.call(1, 2)?;
println!("Results: {:?}", result);
assert_eq!(result, 3);
// Much nicer, isn't it?
//
// Those two API exist because they addres different needs. The
// former has a more dynamic approach, while the second has a more
// static approach.
Ok(())
}
#[test]
fn test_exported_function() -> Result<(), Box<dyn std::error::Error>> {
main()
}

69
examples/wasi.rs Normal file
View File

@@ -0,0 +1,69 @@
//! Running a WASI compiled WebAssembly module with Wasmer.
//!
//! This example illustrates how to run WASI modules with
//! Wasmer. To run WASI we have to have to do mainly 3 steps:
//!
//! 1. Create a `WasiEnv` instance
//! 2. Attach the imports from the `WasiEnv` to a new instance
//! 3. Run the `WASI` module.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```bash
//! cargo run --example wasi --release --features "cranelift,wasi"
//! ```
//!
//! Ready?
use wasmer::{Instance, Module, Store};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;
use wasmer_wasi::WasiState;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let wasm_path = format!(
"{}/tests/wasi-wast/wasi/unstable/hello.wasm",
std::env::var("CARGO_MANIFEST_DIR").unwrap()
);
// Let's declare the Wasm module with the text representation.
let wasm_bytes = std::fs::read(wasm_path)?;
// Create a Store.
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
println!("Creating `WasiEnv`...");
// First, we create the `WasiEnv`
let mut wasi_env = WasiState::new("hello")
// .args(&["world"])
// .env("KEY", "Value")
.finalize()?;
println!("Instantiating module with WASI imports...");
// Then, we get the import object related to our WASI
// and attach it to the Wasm instance.
let import_object = wasi_env.import_object(&module)?;
let instance = Instance::new(&module, &import_object)?;
// WASI requires to explicitly set the memory for the `WasiEnv`
wasi_env.set_memory(instance.exports.get_memory("memory")?.clone());
println!("Call WASI `_start` function...");
// And we just call the `_start` function!
let start = instance.exports.get_function("_start")?;
start.call(&[])?;
Ok(())
}
#[test]
#[cfg(feature = "wasi")]
fn test_wasi() -> Result<(), Box<dyn std::error::Error>> {
main()
}

View File

@@ -37,7 +37,17 @@ pub enum FunctionDefinition {
Host(HostFunctionDefinition),
}
/// A WebAssembly `function`.
/// A WebAssembly `function` instance.
///
/// A function instance is the runtime representation of a function.
/// It effectively is a closure of the original function (defined in either
/// the host or the WebAssembly module) over the runtime `Instance` of its
/// originating `Module`.
///
/// The module instance is used to resolve references to other definitions
/// during execution of the function.
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#function-instances
#[derive(Clone, PartialEq)]
pub struct Function {
pub(crate) store: Store,
@@ -46,7 +56,7 @@ pub struct Function {
}
impl Function {
/// Creates a new `Function` that is:
/// Creates a new host `Function` that is:
///
/// 1. Static/Monomorphic, i.e. all inputs and outputs have a
/// unique _statically declared type_. The outputs can be
@@ -77,7 +87,7 @@ impl Function {
}
}
/// Creates a new `Function` that is:
/// Creates a new host `Function` that is:
///
/// 1. Static/Monomorphic, i.e. all inputs and outputs have a
/// unique statically declared type. The outputs can be wrapped
@@ -115,7 +125,7 @@ impl Function {
}
}
/// Creates a new `Function` that is:
/// Creates a new host `Function` that is:
///
/// 1. Dynamic/Polymorphic, i.e. all inputs are received in a
/// slice of `Val` (the set of all Wasm values), and all
@@ -150,7 +160,7 @@ impl Function {
}
}
/// Creates a new `Function` that is:
/// Creates a new host `Function` that is:
///
/// 1. Dynamic/Polymorphic, i.e. all inputs are received in a
/// slice of `Val` (the set of all Wasm values), and all
@@ -187,11 +197,12 @@ impl Function {
}
}
/// Returns the underlying type of this function.
/// Returns the [`FunctionType`] of the `Function`.
pub fn ty(&self) -> &FunctionType {
&self.exported.signature
}
/// Returns the [`Store`] where the `Function` belongs.
pub fn store(&self) -> &Store {
&self.store
}

View File

@@ -8,6 +8,12 @@ use crate::RuntimeError;
use std::fmt;
use wasmer_vm::{Export, ExportGlobal, VMGlobalDefinition};
/// A WebAssembly `global` instance.
///
/// A global instance is the runtime representation of a global variable.
/// It consists of an individual value and a flag indicating whether it is mutable.
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#global-instances
#[derive(Clone)]
pub struct Global {
store: Store,
@@ -15,12 +21,14 @@ pub struct Global {
}
impl Global {
/// Create a new `Global` with the initial value [`Val`].
pub fn new(store: &Store, val: Val) -> Global {
// Note: we unwrap because the provided type should always match
// the value type, so it's safe to unwrap.
Self::from_type(store, GlobalType::new(val.ty(), Mutability::Const), val).unwrap()
}
/// Create a mutable `Global` with the initial value [`Val`].
pub fn new_mut(store: &Store, val: Val) -> Global {
// Note: we unwrap because the provided type should always match
// the value type, so it's safe to unwrap.
@@ -52,14 +60,17 @@ impl Global {
})
}
/// Returns the [`GlobalType`] of the `Global`.
pub fn ty(&self) -> &GlobalType {
&self.exported.global
}
/// Returns the [`Store`] where the `Global` belongs.
pub fn store(&self) -> &Store {
&self.store
}
/// Retrieves the current value [`Val`] that the Global has.
pub fn get(&self) -> Val {
unsafe {
let definition = &mut *self.exported.definition;
@@ -73,6 +84,13 @@ impl Global {
}
}
/// Sets a custom value [`Val`] to the runtime Global.
///
/// # Errors
///
/// This function will error if:
/// * The global is not mutable
/// * The type of the `Val` doesn't matches the Global type.
pub fn set(&self, val: Val) -> Result<(), RuntimeError> {
if self.ty().mutability != Mutability::Var {
return Err(RuntimeError::new(

View File

@@ -7,6 +7,20 @@ use std::sync::Arc;
use wasm_common::{Pages, ValueType};
use wasmer_vm::{Export, ExportMemory, Memory as RuntimeMemory, MemoryError};
/// A WebAssembly `memory` instance.
///
/// A memory instance is the runtime representation of a linear memory.
/// It consists of a vector of bytes and an optional maximum size.
///
/// The length of the vector always is a multiple of the WebAssembly
/// page size, which is defined to be the constant 65536 abbreviated 64Ki.
/// Like in a memory type, the maximum size in a memory instance is
/// given in units of this page size.
///
/// A memory created by the host or in WebAssembly code will be accessible and
/// mutable from both host and WebAssembly.
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances
#[derive(Clone)]
pub struct Memory {
store: Store,
@@ -14,6 +28,9 @@ pub struct Memory {
}
impl Memory {
/// Creates a new host `Memory` from the provided [`MemoryType`].
///
/// This function will construct the `Memory` using the store [`Tunables`].
pub fn new(store: &Store, ty: MemoryType) -> Result<Memory, MemoryError> {
let tunables = store.tunables();
let style = tunables.memory_style(&ty);
@@ -25,10 +42,12 @@ impl Memory {
})
}
/// Returns the [`MemoryType`] of the `Memory`.
pub fn ty(&self) -> &MemoryType {
self.memory.ty()
}
/// Returns the [`Store`] where the `Memory` belongs.
pub fn store(&self) -> &Store {
&self.store
}
@@ -55,22 +74,31 @@ impl Memory {
slice::from_raw_parts_mut(def.base, def.current_length)
}
/// Returns the pointer to the raw bytes of the `Memory`.
pub fn data_ptr(&self) -> *mut u8 {
let definition = self.memory.vmmemory();
let def = unsafe { definition.as_ref() };
def.base
}
/// Returns the size (in bytes) of the `Memory`.
pub fn data_size(&self) -> usize {
let definition = self.memory.vmmemory();
let def = unsafe { definition.as_ref() };
def.current_length
}
/// Returns the size (in [`Pages`]) of the `Memory`.
pub fn size(&self) -> Pages {
self.memory.size()
}
/// Grow memory by the specified amount of WebAssembly [`Pages`].
///
/// # Errors
///
/// Returns an error if memory can't be grown by the specified amount
/// of pages.
pub fn grow<IntoPages>(&self, delta: IntoPages) -> Result<Pages, MemoryError>
where
IntoPages: Into<Pages>,

View File

@@ -15,15 +15,24 @@ use crate::store::{Store, StoreObject};
use crate::ExternType;
use wasmer_vm::Export;
/// An `Extern` is the runtime representation of an entity that
/// can be imported or exported.
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#external-values
#[derive(Clone)]
pub enum Extern {
/// A external [`Function`].
Function(Function),
/// A external [`Global`].
Global(Global),
/// A external [`Table`].
Table(Table),
/// A external [`Memory`].
Memory(Memory),
}
impl Extern {
/// Return the undelying type of the inner `Extern`.
pub fn ty(&self) -> ExternType {
match self {
Extern::Function(ft) => ExternType::Function(ft.ty().clone()),

View File

@@ -7,11 +7,15 @@ use crate::TableType;
use std::sync::Arc;
use wasmer_vm::{Export, ExportTable, Table as RuntimeTable, VMCallerCheckedAnyfunc};
/// A WebAssembly `table` instance.
///
/// The `Table` struct is an array-like structure representing a WebAssembly Table,
/// which stores function references.
///
/// A table created by the host or in WebAssembly code will be accessible and
/// mutable from both host and WebAssembly.
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#table-instances
#[derive(Clone)]
pub struct Table {
store: Store,
@@ -30,6 +34,8 @@ impl Table {
/// Creates a new `Table` with the provided [`TableType`] definition.
///
/// All the elements in the table will be set to the `init` value.
///
/// This function will construct the `Table` using the store [`Tunables`].
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Table, RuntimeError> {
let item = init.into_checked_anyfunc(store)?;
let tunables = store.tunables();
@@ -49,11 +55,12 @@ impl Table {
})
}
/// Gets the underlying [`TableType`].
/// Returns the [`TableType`] of the `Table`.
pub fn ty(&self) -> &TableType {
self.table.ty()
}
/// Returns the [`Store`] where the `Table` belongs.
pub fn store(&self) -> &Store {
&self.store
}

View File

@@ -12,6 +12,8 @@ use wasmer_vm::InstanceHandle;
/// Instance objects contain all the exported WebAssembly
/// functions, memories, tables and globals that allow
/// interacting with WebAssembly.
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#module-instances
#[derive(Clone)]
pub struct Instance {
handle: InstanceHandle,
@@ -94,6 +96,7 @@ impl Instance {
&self.module
}
/// Returns the [`Store`] where the `Instance` belongs.
pub fn store(&self) -> &Store {
self.module.store()
}

View File

@@ -1,5 +1,25 @@
//! Wasmer API
#![deny(intra_doc_link_resolution_failure)]
#![deny(
missing_docs,
trivial_numeric_casts,
unused_extern_crates,
intra_doc_link_resolution_failure
)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
feature = "cargo-clippy",
warn(
clippy::float_arithmetic,
clippy::mut_mut,
clippy::nonminimal_bool,
clippy::option_map_unwrap_or,
clippy::option_map_unwrap_or_else,
clippy::print_stdout,
clippy::unicode_not_nfc,
clippy::use_self
)
)]
mod exports;
mod externals;

View File

@@ -108,6 +108,7 @@ impl Module {
Module::from_binary(store, bytes.as_ref())
}
/// Creates a new WebAssembly module from a file path.
pub fn from_file(store: &Store, file: impl AsRef<Path>) -> Result<Module, IoCompileError> {
let file_ref = file.as_ref();
let canonical = file_ref.canonicalize()?;
@@ -394,6 +395,7 @@ impl Module {
self.artifact.module_ref().custom_sections(name)
}
/// Returns the [`Store`] where the `Instance` belongs.
pub fn store(&self) -> &Store {
&self.store
}

View File

@@ -20,6 +20,8 @@ use wasmer_vm::{
ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
};
/// A WebAssembly function that can be called natively
/// (using the Native ABI).
pub struct NativeFunc<'a, Args = (), Rets = ()> {
definition: FunctionDefinition,
store: Store,

View File

@@ -6,6 +6,16 @@ use wasmer_engine::Tunables as BaseTunables;
use std::sync::Arc;
use wasmer_engine::Engine;
/// The store represents all global state that can be manipulated by
/// WebAssembly programs. It consists of the runtime representation
/// of all instances of functions, tables, memories, and globals that
/// have been allocated during the lifetime of the abstract machine.
///
/// The `Store` holds the engine (that is —amongst many things— used to compile
/// the Wasm bytes into a valid module artifact), in addition to the
/// [`Tunables`] (that are used to create the memories, tables and globals).
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#store
#[derive(Clone)]
pub struct Store {
engine: Arc<dyn Engine + Send + Sync>,
@@ -13,52 +23,59 @@ pub struct Store {
}
impl Store {
pub fn new<E>(engine: &E) -> Store
/// Creates a new `Store` with a specific [`Engine`].
pub fn new<E>(engine: &E) -> Self
where
E: Engine + ?Sized,
{
Store {
Self {
engine: engine.cloned(),
tunables: Arc::new(Tunables::for_target(engine.target())),
}
}
/// Creates a new `Store` with a specific [`Engine`] and [`Tunables`].
pub fn new_with_tunables<E>(
engine: &E,
tunables: impl BaseTunables + Send + Sync + 'static,
) -> Store
) -> Self
where
E: Engine + ?Sized,
{
Store {
Self {
engine: engine.cloned(),
tunables: Arc::new(tunables),
}
}
/// Returns the [`Tunables`].
pub fn tunables(&self) -> &dyn BaseTunables {
self.tunables.as_ref()
}
/// Returns the [`Engine`].
pub fn engine(&self) -> &Arc<dyn Engine + Send + Sync> {
&self.engine
}
pub fn same(a: &Store, b: &Store) -> bool {
/// Checks whether two stores are identical. A store is considered
/// equal to another store if both have the same engine. The
/// tunables are excluded from the logic.
pub fn same(a: &Self, b: &Self) -> bool {
a.engine.id() == b.engine.id()
}
}
impl PartialEq for Store {
fn eq(&self, other: &Self) -> bool {
Store::same(self, other)
Self::same(self, other)
}
}
// We only implement default if we have assigned a default compiler and engine
#[cfg(all(feature = "default-compiler", feature = "default-engine"))]
impl Default for Store {
fn default() -> Store {
fn default() -> Self {
// We store them on a function that returns to make
// sure this function doesn't emit a compile error even if
// more than one compiler is enabled.
@@ -102,6 +119,8 @@ impl Default for Store {
}
}
/// A trait represinting any object that lives in the `Store`.
pub trait StoreObject {
/// Return true if the object `Store` is the same as the provided `Store`.
fn comes_from_same_store(&self, store: &Store) -> bool;
}

View File

@@ -8,6 +8,12 @@ pub use wasm_common::{
MemoryType, Mutability, TableType, Type as ValType,
};
/// WebAssembly computations manipulate values of basic value types:
/// * Integers (32 or 64 bit width)
/// * Floating-point (32 or 64 bit width)
/// * Vectors (128 bits, with 32 or 64 bit lanes)
///
/// Spec: https://webassembly.github.io/spec/core/exec/runtime.html#values
pub type Val = Value<Function>;
impl StoreObject for Val {

View File

@@ -4,7 +4,6 @@
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "std", deny(unstable_features))]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
feature = "cargo-clippy",

View File

@@ -22,6 +22,8 @@ let compiler = Cranelift::new();
let store = Store::new(&JIT::new(&compiler).engine());
```
*Note: you can find a [full working example using Cranelift compiler here](https://github.com/wasmerio/wasmer-reborn/blob/master/examples/compiler-cranelift.rs).*
## When to use Cranelift
We recommend using this compiler crate **only for development proposes**.

View File

@@ -52,14 +52,6 @@ impl Cranelift {
}
}
/// Should the Cranelift verifier be enabled.
///
/// The verifier assures that the generated Cranelift IR is valid.
pub fn verify_ir(&mut self, enable: bool) -> &mut Self {
self.enable_verifier = enable;
self
}
/// Enable NaN canonicalization.
///
/// NaN canonicalization is useful when trying to run WebAssembly
@@ -197,6 +189,10 @@ impl CompilerConfig for Cranelift {
self.enable_pic = true;
}
fn enable_verifier(&mut self) {
self.enable_verifier = true;
}
/// Transform it into the compiler
fn compiler(&self) -> Box<dyn Compiler + Send> {
Box::new(CraneliftCompiler::new(&self))

View File

@@ -3,10 +3,9 @@
//! Cranelift is a fast IR generator created by Mozilla for usage in
//! Firefox as a next JS compiler generator.
//!
//! Compared to LLVM, Cranelit is a bit faster and made enterely in Rust.
//! Compared to LLVM, Cranelit is a bit faster and made entirely in Rust.
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(
feature = "cargo-clippy",
allow(clippy::new_without_default, clippy::new_without_default)

View File

@@ -22,6 +22,8 @@ let compiler = LLVM::new();
let store = Store::new(&JIT::new(&compiler).engine());
```
*Note: you can find a [full working example using LLVM compiler here](https://github.com/wasmerio/wasmer-reborn/blob/master/examples/compiler-llvm.rs).*
## When to use LLVM
We recommend using LLVM as the default compiler when running WebAssembly

View File

@@ -63,14 +63,6 @@ impl LLVM {
}
}
/// Should the LLVM verifier be enabled.
///
/// The verifier assures that the generated LLVM IR is valid.
pub fn verify_ir(&mut self, enable: bool) -> &mut Self {
self.enable_verifier = enable;
self
}
/// Enable NaN canonicalization.
///
/// NaN canonicalization is useful when trying to run WebAssembly
@@ -184,6 +176,11 @@ impl CompilerConfig for LLVM {
self.is_pic = true;
}
/// Whether to verify compiler IR.
fn enable_verifier(&mut self) {
self.enable_verifier = true;
}
/// Transform it into the compiler.
fn compiler(&self) -> Box<dyn Compiler + Send> {
Box::new(LLVMCompiler::new(&self))

View File

@@ -1630,13 +1630,15 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
let current_block = self.builder.get_insert_block().ok_or_else(|| {
CompileError::Codegen("not currently in a block".to_string())
})?;
self.builder.build_unconditional_branch(*frame.code_after());
for phi in frame.phis().to_vec().iter().rev() {
let (value, info) = self.state.pop1_extra()?;
let value = self.apply_pending_canonicalization(value, info);
phi.add_incoming(&[(&value, current_block)])
}
let frame = self.state.frame_at_depth(0)?;
self.builder.build_unconditional_branch(*frame.code_after());
}
let (if_else_block, if_else_state) = if let ControlFrame::IfElse {
@@ -1721,12 +1723,13 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
.ok_or_else(|| CompileError::Codegen("not currently in a block".to_string()))?;
let frame = self.state.outermost_frame()?;
self.builder.build_unconditional_branch(*frame.br_dest());
for phi in frame.phis().to_vec().iter().rev() {
let (arg, info) = self.state.pop1_extra()?;
let arg = self.apply_pending_canonicalization(arg, info);
phi.add_incoming(&[(&arg, current_block)]);
}
let frame = self.state.outermost_frame()?;
self.builder.build_unconditional_branch(*frame.br_dest());
self.state.reachable = false;
}

View File

@@ -22,6 +22,8 @@ let compiler = Singlepass::new();
let store = Store::new(&JIT::new(&compiler).engine());
```
*Note: you can find a [full working example using Singlepass compiler here](https://github.com/wasmerio/wasmer-reborn/blob/master/examples/compiler-singlepass.rs).*
## When to use Singlepass
Singlepass is designed to emit compiled code at linear time, as such

View File

@@ -26,6 +26,15 @@ pub trait CompilerConfig {
// in case they do something special for emitting PIC code.
}
/// Enable compiler IR verification.
///
/// For compilers capable of doing so, this enables internal consistency
/// checking.
fn enable_verifier(&mut self) {
// By default we do nothing, each backend will need to customize this
// in case they create an IR that they can verify.
}
/// Gets the custom compiler config
fn compiler(&self) -> Box<dyn Compiler + Send>;

View File

@@ -11,7 +11,7 @@ use thiserror::Error;
/// [compiler-error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/CompileError
#[derive(Error, Debug)]
pub enum CompileError {
/// A wasm translation error occured.
/// A Wasm translation error occured.
#[error("WebAssembly translation error: {0}")]
Wasm(#[from] WasmError),

View File

@@ -14,7 +14,6 @@ use crate::trap::TrapInformation;
use crate::{CompiledFunctionUnwindInfo, FunctionAddressMap, JumpTableOffsets, Relocation};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
use wasm_common::entity::PrimaryMap;
use wasm_common::{FunctionIndex, LocalFunctionIndex, SignatureIndex};

View File

@@ -9,7 +9,6 @@
#![warn(unused_import_braces)]
#![cfg_attr(feature = "std", deny(unstable_features))]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
feature = "cargo-clippy",

View File

@@ -15,7 +15,7 @@ lazy_static = "1.4"
libc = "0.2.72"
log = "0.4"
time = "0.1"
wasmer = { path = "../api", version = "1.0.0-alpha.1" }
wasmer = { path = "../api", version = "1.0.0-alpha.1", default-features = false }
[target.'cfg(windows)'.dependencies]
getrandom = "0.1"

View File

@@ -6,6 +6,8 @@ After the compiler process the result, the JIT pushes it into
memory and links it's contents so it can be usable by the
`wasmer` api.
*Note: you can find a [full working example using the JIT engine here](https://github.com/wasmerio/wasmer-reborn/blob/master/examples/engine-jit.rs).*
### Acknowledgments
This project borrowed some of the code of the code memory and unwind tables from the [wasmtime-jit](https://crates.io/crates/wasmtime-jit), the code since then has evolved significantly.

View File

@@ -6,7 +6,6 @@
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(
feature = "cargo-clippy",
allow(clippy::new_without_default, clippy::new_without_default)

View File

@@ -12,7 +12,7 @@ edition = "2018"
[dependencies]
wasm-common = { path = "../wasm-common", version = "1.0.0-alpha.1" }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", default-features = false }
wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha.1", default-features = false, features = ["enable-serde"] }
wasmer-vm = { path = "../vm", version = "1.0.0-alpha.1" }
wasmer-engine = { path = "../engine", version = "1.0.0-alpha.1" }
wasmer-object = { path = "../object", version = "1.0.0-alpha.1" }

View File

@@ -10,6 +10,8 @@ so it can be usable by the `wasmer` API.
This allows Wasmer to achieve *blazing fast* native startup times.
*Note: you can find a [full working example using the JIT engine here](https://github.com/wasmerio/wasmer-reborn/blob/master/examples/engine-jit.rs).*
## Requirements
The `wasmer-engine-native` crate requires a linker available on your

View File

@@ -15,23 +15,23 @@ use tempfile::NamedTempFile;
#[cfg(feature = "compiler")]
use tracing::trace;
use wasm_common::entity::{BoxedSlice, PrimaryMap};
#[cfg(feature = "compiler")]
use wasm_common::DataInitializer;
use wasm_common::{
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer,
SignatureIndex, TableIndex,
FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex,
TableIndex,
};
#[cfg(feature = "compiler")]
use wasmer_compiler::{
Compilation, CompileModuleInfo, Compiler, ModuleEnvironment, OperatingSystem, Target, Triple,
};
use wasmer_compiler::{CompileError, Features};
#[cfg(feature = "compiler")]
use wasmer_engine::Engine;
use wasmer_compiler::{Compilation, CompileModuleInfo, Compiler, ModuleEnvironment, Target};
use wasmer_compiler::{CompileError, Features, OperatingSystem, Triple};
use wasmer_engine::{
Artifact, DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError,
Tunables,
};
#[cfg(feature = "compiler")]
use wasmer_object::{emit_compilation, emit_data, get_object_for_target, CompilationNamer};
use wasmer_engine::{Engine, Tunables};
use wasmer_object::CompilationNamer;
#[cfg(feature = "compiler")]
use wasmer_object::{emit_compilation, emit_data, get_object_for_target};
use wasmer_vm::{MemoryStyle, TableStyle};
use wasmer_vm::{ModuleInfo, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline};
@@ -50,6 +50,8 @@ fn to_compile_error(err: impl Error) -> CompileError {
CompileError::Codegen(format!("{}", err))
}
const WASMER_METADATA_SYMBOL: &[u8] = b"WASMER_METADATA";
impl NativeArtifact {
// Mach-O header in Mac
#[allow(dead_code)]
@@ -91,6 +93,7 @@ impl NativeArtifact {
}
}
#[cfg(feature = "compiler")]
/// Generate a compilation
pub fn generate_compilation<'data>(
data: &'data [u8],
@@ -154,7 +157,7 @@ impl NativeArtifact {
.collect::<Vec<_>>()
.into_boxed_slice();
let target_triple = target.triple().clone();
let target_triple = target.triple();
// We construct the function body lengths
let function_body_lengths = compilation
@@ -179,8 +182,9 @@ impl NativeArtifact {
.expect("Should write number");
metadata_binary.extend(serialized_data);
emit_data(&mut obj, b"WASMER_METADATA", &metadata_binary).map_err(to_compile_error)?;
emit_compilation(&mut obj, compilation, &metadata).map_err(to_compile_error)?;
emit_data(&mut obj, WASMER_METADATA_SYMBOL, &metadata_binary).map_err(to_compile_error)?;
emit_compilation(&mut obj, compilation, &metadata, &target_triple)
.map_err(to_compile_error)?;
let filepath = {
let file = tempfile::Builder::new()
@@ -211,7 +215,7 @@ impl NativeArtifact {
};
let host_target = Triple::host();
let is_cross_compiling = target_triple != host_target;
let is_cross_compiling = target_triple != &host_target;
let cross_compiling_args: Vec<String> = if is_cross_compiling {
vec![
format!("--target={}", target_triple),
@@ -472,7 +476,7 @@ impl NativeArtifact {
// to take the first element of the data to construct the slice from
// it.
let symbol: LibrarySymbol<*mut [u8; 10 + 1]> =
lib.get(b"WASMER_METADATA").map_err(|e| {
lib.get(WASMER_METADATA_SYMBOL).map_err(|e| {
DeserializeError::CorruptedBinary(format!(
"The provided object file doesn't seem to be generated by Wasmer: {}",
e

View File

@@ -9,9 +9,11 @@ pub struct Native<'a> {
}
impl<'a> Native<'a> {
#[cfg(feature = "compiler")]
/// Create a new Native
pub fn new(compiler_config: &'a mut dyn CompilerConfig) -> Self {
compiler_config.enable_pic();
Self {
compiler_config: Some(compiler_config),
target: None,
@@ -42,15 +44,70 @@ impl<'a> Native<'a> {
/// Build the `NativeEngine` for this configuration
pub fn engine(self) -> NativeEngine {
if let Some(_compiler_config) = self.compiler_config {
#[cfg(feature = "compiler")]
{
let compiler_config = _compiler_config;
let target = self.target.unwrap_or_default();
if let Some(compiler_config) = self.compiler_config {
let features = self
.features
.unwrap_or_else(|| compiler_config.default_features_for_target(&target));
let compiler = compiler_config.compiler();
NativeEngine::new(compiler, target, features)
}
#[cfg(not(feature = "compiler"))]
{
unreachable!("Cannot call `NativeEngine::new` without the `compiler` feature")
}
} else {
NativeEngine::headless()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "compiler")]
use std::sync::Arc;
#[cfg(feature = "compiler")]
use wasmer_compiler::{Compiler, FunctionMiddlewareGenerator};
#[cfg(feature = "compiler")]
#[derive(Default)]
pub struct TestCompilerConfig {
pub enabled_pic: bool,
pub middlewares: Vec<Arc<dyn FunctionMiddlewareGenerator>>,
}
#[cfg(feature = "compiler")]
impl CompilerConfig for TestCompilerConfig {
fn enable_pic(&mut self) {
self.enabled_pic = true;
}
fn compiler(&self) -> Box<dyn Compiler + Send> {
unimplemented!("compiler not implemented");
}
fn push_middleware(&mut self, middleware: Arc<dyn FunctionMiddlewareGenerator>) {
self.middlewares.push(middleware);
}
}
#[cfg(feature = "compiler")]
#[test]
#[should_panic(expected = "compiler not implemented")]
fn build_engine() {
let mut compiler_config = TestCompilerConfig::default();
let native = Native::new(&mut compiler_config);
let _engine = native.engine();
}
#[test]
fn build_headless_engine() {
let native = Native::headless();
let _engine = native.engine();
}
}

View File

@@ -5,7 +5,9 @@ use std::collections::HashMap;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use wasm_common::{Features, FunctionType};
#[cfg(feature = "compiler")]
use wasm_common::Features;
use wasm_common::FunctionType;
#[cfg(feature = "compiler")]
use wasmer_compiler::Compiler;
use wasmer_compiler::{CompileError, Target};
@@ -56,10 +58,11 @@ impl NativeEngine {
inner: Arc::new(Mutex::new(NativeEngineInner {
#[cfg(feature = "compiler")]
compiler: None,
#[cfg(feature = "compiler")]
features: Features::default(),
trampolines: HashMap::new(),
signatures: SignatureRegistry::new(),
prefixer: None,
features: Features::default(),
})),
target: Arc::new(Target::default()),
engine_id: EngineId::default(),
@@ -122,6 +125,7 @@ impl Engine for NativeEngine {
}
/// Compile a WebAssembly binary
#[cfg(feature = "compiler")]
fn compile(
&self,
binary: &[u8],
@@ -130,6 +134,19 @@ impl Engine for NativeEngine {
Ok(Arc::new(NativeArtifact::new(&self, binary, tunables)?))
}
/// Compile a WebAssembly binary (it will fail because the `compiler` flag is disabled).
#[cfg(not(feature = "compiler"))]
fn compile(
&self,
_binary: &[u8],
_tunables: &dyn Tunables,
) -> Result<Arc<dyn Artifact>, CompileError> {
Err(CompileError::Codegen(
"The `NativeEngine` is operating in headless mode, so it cannot compile a module."
.to_string(),
))
}
/// Deserializes a WebAssembly module (binary content of a Shared Object file)
unsafe fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
Ok(Arc::new(NativeArtifact::deserialize(&self, &bytes)?))
@@ -161,6 +178,7 @@ pub struct NativeEngineInner {
#[cfg(feature = "compiler")]
compiler: Option<Box<dyn Compiler + Send>>,
/// The WebAssembly features to use
#[cfg(feature = "compiler")]
features: Features,
/// Pointers to trampoline functions used to enter particular signatures
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
@@ -178,7 +196,7 @@ impl NativeEngineInner {
#[cfg(feature = "compiler")]
pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
if self.compiler.is_none() {
return Err(CompileError::Codegen("The NativeEngine is operating in headless mode, so it can only execute already compiled Modules.".to_string()));
return Err(CompileError::Codegen("The `NativeEngine` is operating in headless mode, so it can only execute already compiled Modules.".to_string()));
}
Ok(&**self
.compiler
@@ -186,6 +204,7 @@ impl NativeEngineInner {
.expect("Can't get compiler reference"))
}
#[cfg(feature = "compiler")]
pub(crate) fn get_prefix(&self, bytes: &[u8]) -> String {
if let Some(prefixer) = &self.prefixer {
prefixer(&bytes)
@@ -194,6 +213,7 @@ impl NativeEngineInner {
}
}
#[cfg(feature = "compiler")]
pub(crate) fn features(&self) -> &Features {
&self.features
}
@@ -208,7 +228,7 @@ impl NativeEngineInner {
#[cfg(not(feature = "compiler"))]
pub fn validate<'data>(&self, _data: &'data [u8]) -> Result<(), CompileError> {
Err(CompileError::Validate(
"The NativeEngine is not compiled with compiler support, which is required for validating".to_string(),
"The `NativeEngine` is not compiled with compiler support, which is required for validating".to_string(),
))
}

View File

@@ -4,12 +4,9 @@
//! it generates a shared object file (`.so` or `.dylib` depending on
//! the target), saves it temporarily to disk and uses it natively
//! via `dlopen` and `dlsym` (using the `libloading` library).
//!
//! Note: `.dll` generation for Windows is not yet supported
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
feature = "cargo-clippy",

View File

@@ -1,16 +1,20 @@
# Wasmer Engine
The Wasmer Engine is the general abstraction for Engines in Wasmer.
The `wasmer-engine` crate is the general abstraction for creating Engines in Wasmer.
Wasmer Engines are mainly responsible for two things:
* Transform the compilation code (from any Wasmer Compiler) to **create** an `Artifact`
* **Load** an`Artifact` so it can be used by the user (normally, pushing the code into executable memory and so on)
It currently has two implementations:
* Wasmer JIT
* Wasmer Native
* [JIT](https://github.com/wasmerio/wasmer-reborn/tree/master/lib/engine-jit)
* [Native](https://github.com/wasmerio/wasmer-reborn/tree/master/lib/engine-native)
## Example Implementation
Please check [`wasmer-engine-dummy`](../../tests/lib/engine-dummy/) for an example
implementation for an Engine.
### Acknowledgments
This project borrowed some of the code of the trap implementation from the [wasmtime-api](https://crates.io/crates/wasmtime), the code since then has evolved significantly.

View File

@@ -2,7 +2,6 @@
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(
feature = "cargo-clippy",
allow(clippy::new_without_default, clippy::new_without_default)

View File

@@ -109,10 +109,11 @@ fn get_extern_from_export(_module: &ModuleInfo, export: &Export) -> ExternType {
}
}
/// This function allows to match all imports of a `ModuleInfo` with concrete definitions provided by
/// a `Resolver`.
/// This function allows to match all imports of a `ModuleInfo` with
/// concrete definitions provided by a `Resolver`.
///
/// If all imports are satisfied returns an `Imports` instance required for a module instantiation.
/// If all imports are satisfied, it returns an `Imports` instance
/// required for a module instantiation.
pub fn resolve_imports(
module: &ModuleInfo,
resolver: &dyn Resolver,

View File

@@ -9,7 +9,8 @@ use wasmer_vm::MemoryError;
use wasmer_vm::{Memory, ModuleInfo, Table, VMGlobalDefinition};
use wasmer_vm::{MemoryStyle, TableStyle};
/// Tunables for an engine
/// An engine delegates the creation of memories, tables, and globals
/// to a foreign implementor of this trait.
pub trait Tunables {
/// Construct a `MemoryStyle` for the provided `MemoryType`
fn memory_style(&self, memory: &MemoryType) -> MemoryStyle;

View File

@@ -0,0 +1,11 @@
# Wasmer Native Object
The Wasmer Native Object crate aims at cross-generating native objects
for various platforms.
This crate is the foundation of [the `wasmer-engine-native`
crate](../engine-native/). Given a compilation result, i.e. the result
of `wasmer_compiler::Compiler::compile_module`, this crate exposes
functions to create an `Object` file for a given target. It is a
useful thin layer on top of [the `object`
crate](https://github.com/gimli-rs/object).

View File

@@ -5,7 +5,6 @@
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
feature = "cargo-clippy",

View File

@@ -22,7 +22,21 @@ pub trait CompilationNamer {
fn get_dynamic_function_trampoline_name(&self, index: &FunctionIndex) -> String;
}
/// Create an object for a given target [`Triple`]
/// Create an object for a given target `Triple`.
///
/// # Usage
///
/// ```rust
/// # use wasmer_compiler::Triple;
/// # use wasmer_object::ObjectError;
/// use wasmer_object::get_object_for_target;
///
/// # fn generate_object_for_target(triple: &Triple) -> Result<(), ObjectError> {
/// let mut object = get_object_for_target(&triple)?;
///
/// # Ok(())
/// # }
/// ```
pub fn get_object_for_target(triple: &Triple) -> Result<Object, ObjectError> {
let obj_binary_format = match triple.binary_format {
BinaryFormat::Elf => object::BinaryFormat::Elf,
@@ -45,13 +59,14 @@ pub fn get_object_for_target(triple: &Triple) -> Result<Object, ObjectError> {
)));
}
};
let obj_endianness = match triple.endianness() {
Ok(Endianness::Little) => object::Endianness::Little,
Ok(Endianness::Big) => object::Endianness::Big,
Err(_) => {
return Err(ObjectError::UnknownEndianness);
}
let obj_endianness = match triple
.endianness()
.map_err(|_| ObjectError::UnknownEndianness)?
{
Endianness::Little => object::Endianness::Little,
Endianness::Big => object::Endianness::Big,
};
Ok(Object::new(
obj_binary_format,
obj_architecture,
@@ -59,7 +74,22 @@ pub fn get_object_for_target(triple: &Triple) -> Result<Object, ObjectError> {
))
}
/// Emit data in into an object
/// Write data into an existing object.
///
/// # Usage
///
/// ```rust
/// # use wasmer_compiler::Triple;
/// # use wasmer_object::ObjectError;
/// use wasmer_object::{get_object_for_target, emit_data};
///
/// # fn emit_data_into_object(triple: &Triple) -> Result<(), ObjectError> {
/// let mut object = get_object_for_target(&triple)?;
/// emit_data(&mut object, b"WASMER_METADATA", &b"Hello, World!"[..])?;
///
/// # Ok(())
/// # }
/// ```
pub fn emit_data(obj: &mut Object, name: &[u8], data: &[u8]) -> Result<(), ObjectError> {
let symbol_id = obj.add_symbol(Symbol {
name: name.to_vec(),
@@ -73,14 +103,34 @@ pub fn emit_data(obj: &mut Object, name: &[u8], data: &[u8]) -> Result<(), Objec
});
let section_id = obj.section_id(StandardSection::Data);
obj.add_symbol_data(symbol_id, section_id, &data, 1);
Ok(())
}
/// Emit the compilation into an object
/// Emit the compilation result into an existing object.
///
/// # Usage
///
/// ```rust
/// # use wasmer_compiler::{Compilation, Triple};
/// # use wasmer_object::{CompilationNamer, ObjectError};
/// use wasmer_object::{get_object_for_target, emit_compilation};
///
/// # fn emit_compilation_into_object(
/// # triple: &Triple,
/// # compilation: Compilation,
/// # compilation_namer: impl CompilationNamer,
/// # ) -> Result<(), ObjectError> {
/// let mut object = get_object_for_target(&triple)?;
/// emit_compilation(&mut object, compilation, &compilation_namer, &triple)?;
/// # Ok(())
/// # }
/// ```
pub fn emit_compilation(
obj: &mut Object,
compilation: Compilation,
namer: &impl CompilationNamer,
triple: &Triple,
) -> Result<(), ObjectError> {
let function_bodies = compilation.get_function_bodies();
let function_relocations = compilation.get_relocations();
@@ -166,22 +216,39 @@ pub fn emit_compilation(
}
// Add relocations (function and sections)
let (relocation_size, relocation_kind, relocation_encoding) = match triple.architecture {
Architecture::X86_64 => (
32,
RelocationKind::PltRelative,
RelocationEncoding::X86Branch,
),
architecture => {
return Err(ObjectError::UnsupportedArchitecture(
architecture.to_string(),
))
}
};
let mut all_relocations = Vec::new();
for (function_local_index, relocations) in function_relocations.into_iter() {
let function_name = namer.get_function_name(&function_local_index);
let symbol_id = obj.symbol_id(function_name.as_bytes()).unwrap();
all_relocations.push((symbol_id, relocations))
}
for (section_index, relocations) in custom_section_relocations.into_iter() {
let section_name = namer.get_section_name(&section_index);
let symbol_id = obj.symbol_id(section_name.as_bytes()).unwrap();
all_relocations.push((symbol_id, relocations))
}
for (symbol_id, relocations) in all_relocations.into_iter() {
let (_symbol_id, section_offset) = obj.symbol_section_and_offset(symbol_id).unwrap();
let section_id = obj.section_id(StandardSection::Text);
for r in relocations {
let relocation_address = section_offset + r.offset as u64;
match r.reloc_target {
RelocationTarget::LocalFunc(index) => {
let target_name = namer.get_function_name(&index);
@@ -190,12 +257,9 @@ pub fn emit_compilation(
section_id,
Relocation {
offset: relocation_address,
size: 32, // FIXME for all targets
kind: RelocationKind::PltRelative,
encoding: RelocationEncoding::X86Branch,
// size: 64, // FIXME for all targets
// kind: RelocationKind::Absolute,
// encoding: RelocationEncoding::Generic,
size: relocation_size,
kind: relocation_kind,
encoding: relocation_encoding,
symbol: target_symbol,
addend: r.addend,
},
@@ -221,12 +285,9 @@ pub fn emit_compilation(
section_id,
Relocation {
offset: relocation_address,
size: 32, // FIXME for all targets
kind: RelocationKind::PltRelative,
encoding: RelocationEncoding::X86Branch,
// size: 64, // FIXME for all targets
// kind: RelocationKind::Absolute,
// encoding: RelocationEncoding::Generic,
size: relocation_size,
kind: relocation_kind,
encoding: relocation_encoding,
symbol: target_symbol,
addend: r.addend,
},
@@ -240,12 +301,9 @@ pub fn emit_compilation(
section_id,
Relocation {
offset: relocation_address,
size: 32, // FIXME for all targets
kind: RelocationKind::PltRelative,
encoding: RelocationEncoding::X86Branch,
// size: 64, // FIXME for all targets
// kind: RelocationKind::Absolute,
// encoding: RelocationEncoding::Generic,
size: relocation_size,
kind: relocation_kind,
encoding: relocation_encoding,
symbol: target_symbol,
addend: r.addend,
},
@@ -258,5 +316,6 @@ pub fn emit_compilation(
};
}
}
Ok(())
}

View File

@@ -2,7 +2,6 @@
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(
feature = "cargo-clippy",
allow(clippy::new_without_default, clippy::new_without_default)

View File

@@ -2,3 +2,5 @@
This is the `wasmer-wasi` crate. It provides the necessary
imports to use WASI easily from Wasmer.
*Note: you can find a [full working example using WASI here](https://github.com/wasmerio/wasmer-reborn/blob/master/examples/wasi.rs).*

View File

@@ -6,7 +6,6 @@
#![deny(missing_docs, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
feature = "cargo-clippy",

View File

@@ -16,27 +16,31 @@ use wasmer_compiler::CompilerConfig;
#[derive(Debug, Clone, StructOpt)]
/// The compiler options
pub struct StoreOptions {
/// Use Singlepass compiler
/// Use Singlepass compiler.
#[structopt(long, conflicts_with_all = &["cranelift", "llvm", "backend"])]
singlepass: bool,
/// Use Cranelift compiler
/// Use Cranelift compiler.
#[structopt(long, conflicts_with_all = &["singlepass", "llvm", "backend"])]
cranelift: bool,
/// Use LLVM compiler
/// Use LLVM compiler.
#[structopt(long, conflicts_with_all = &["singlepass", "cranelift", "backend"])]
llvm: bool,
/// Enable compiler internal verification.
#[structopt(long)]
enable_verifier: bool,
/// LLVM debug directory, where IR and object files will be written to.
#[structopt(long, parse(from_os_str))]
llvm_debug_dir: Option<PathBuf>,
/// Use JIT Engine
/// Use JIT Engine.
#[structopt(long, conflicts_with_all = &["native"])]
jit: bool,
/// Use Native Engine
/// Use Native Engine.
#[structopt(long, conflicts_with_all = &["jit"])]
native: bool,
@@ -46,8 +50,6 @@ pub struct StoreOptions {
#[structopt(flatten)]
features: WasmFeatures,
// #[structopt(flatten)]
// llvm_options: LLVMCLIOptions,
}
/// The compiler used for the store
@@ -153,8 +155,7 @@ impl StoreOptions {
}
/// Get the Target architecture
pub fn get_features(&self) -> Result<Features> {
let mut features = Features::default();
pub fn get_features(&self, mut features: Features) -> Result<Features> {
if self.features.threads || self.features.all {
features.threads(true);
}
@@ -181,12 +182,18 @@ impl StoreOptions {
CompilerType::Headless => bail!("The headless engine can't be chosen"),
#[cfg(feature = "singlepass")]
CompilerType::Singlepass => {
let config = wasmer_compiler_singlepass::Singlepass::new();
let mut config = wasmer_compiler_singlepass::Singlepass::new();
if self.enable_verifier {
config.enable_verifier();
}
Box::new(config)
}
#[cfg(feature = "cranelift")]
CompilerType::Cranelift => {
let config = wasmer_compiler_cranelift::Cranelift::new();
let mut config = wasmer_compiler_cranelift::Cranelift::new();
if self.enable_verifier {
config.enable_verifier();
}
Box::new(config)
}
#[cfg(feature = "llvm")]
@@ -276,6 +283,9 @@ impl StoreOptions {
if let Some(ref llvm_debug_dir) = self.llvm_debug_dir {
config.callbacks(Some(Arc::new(Callbacks::new(llvm_debug_dir.clone())?)));
}
if self.enable_verifier {
config.enable_verifier();
}
Box::new(config)
}
#[cfg(not(all(feature = "singlepass", feature = "cranelift", feature = "llvm",)))]
@@ -284,6 +294,8 @@ impl StoreOptions {
compiler.to_string()
),
};
#[allow(unreachable_code)]
Ok((compiler_config, compiler))
}
@@ -310,7 +322,7 @@ impl StoreOptions {
mut compiler_config: Box<dyn CompilerConfig>,
) -> Result<(Box<dyn Engine + Send + Sync>, EngineType)> {
let engine_type = self.get_engine()?;
let features = self.get_features()?;
let features = self.get_features(compiler_config.default_features_for_target(&target))?;
let engine: Box<dyn Engine + Send + Sync> = match engine_type {
#[cfg(feature = "jit")]
EngineType::JIT => Box::new(
@@ -378,7 +390,7 @@ impl StoreOptions {
/// Get the store (headless engine)
pub fn get_store(&self) -> Result<(Store, EngineType, CompilerType)> {
let (engine, engine_type) = self.get_engine_headless()?;
let store = Store::new(&engine);
let store = Store::new(&*engine);
Ok((store, engine_type, CompilerType::Headless))
}

View File

@@ -1,5 +1,6 @@
use std::sync::Arc;
use wasmer::{CompilerConfig, Features, FunctionMiddlewareGenerator, Store, Triple, Tunables};
use wasmer::{Features, FunctionMiddlewareGenerator, Store, Triple, Tunables};
use wasmer_compiler::CompilerConfig;
use wasmer_engine::Engine;
use wasmer_engine_jit::JIT;
@@ -13,14 +14,17 @@ pub fn get_compiler(canonicalize_nans: bool) -> impl CompilerConfig {
} else if #[cfg(feature = "test-cranelift")] {
let mut compiler = wasmer_compiler_cranelift::Cranelift::new();
compiler.canonicalize_nans(canonicalize_nans);
compiler.enable_verifier();
compiler
} else if #[cfg(feature = "test-llvm")] {
let mut compiler = wasmer_compiler_llvm::LLVM::new();
compiler.canonicalize_nans(canonicalize_nans);
compiler.enable_verifier();
compiler
} else if #[cfg(feature = "test-singlepass")] {
let mut compiler = wasmer_compiler_singlepass::Singlepass::new();
compiler.canonicalize_nans(canonicalize_nans);
compiler.enable_verifier();
compiler
} else {
compile_error!("No compiler chosen for the tests")

View File

@@ -3,7 +3,6 @@
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![deny(unstable_features)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
feature = "cargo-clippy",

View File

@@ -192,3 +192,30 @@
(assert_return (invoke "nan-canonicalization-f64-func-call-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-func-call-indirect" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-func-call-indirect-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
;; Test canonicalization is done before branch in `else` operator.
(module
(func (;0;)
(local f64)
i32.const 1
if (result f64)
local.get 0
f64.const 0x1p+0 (;=1;)
f64.add
else
f64.const 0x0p+0 (;=0;)
end
return
)
)
;; Test canonicalization is done before branch in `return` operator.
(module
(func (;0;) (result f64)
(local f64)
f64.const 0x0p+0
local.get 0
f64.mul
return
)
)