Skip to content

Commit

Permalink
Merge branch 'master' into new-footer
Browse files Browse the repository at this point in the history
  • Loading branch information
syrusakbary committed Nov 26, 2019
2 parents 22a63fc + 222ba4f commit 05c3a91
Show file tree
Hide file tree
Showing 18 changed files with 1,586 additions and 0 deletions.
23 changes: 23 additions & 0 deletions docs/runtime/cli/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
id: runtime-cli-getting-started
title: Runtime Command Line Interface Getting Started
sidebar_label: Getting Started
---

If you haven't already, Install the Wasmer CLI.

```
curl https://get.wasmer.io -sSfL | sh
```

Once you have the Wasmer CLI installed, you can run wasm modules from the command line!

To do this, you want to find a Wasm Module compiled down to an ABI that the Wasmer runtime supports, such as WASI or Emscripten. For instance, we can search for a module on WAPM, and go to the module page, and then click on the "Browse modules" tab.

In this example, we will be using the [WASI Compiled QuickJS](https://wapm.io/package/quickjs). To do this we would download the module, and then run:

`wasmer quickjs.wasm`

Which should bring up the QuickJS prompt which you can then interact with.

Next, we can take a look at the command line flags and arguments for the CLI, for more advanced usage.
97 changes: 97 additions & 0 deletions docs/runtime/cli/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
id: runtime-cli-usage
title: Runtime Command Line Interface Usage
sidebar_label: Usage
---

This is the help output from the Wasmer CLI:

```
USAGE:
wasmer <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
cache Wasmer cache
help Prints this message or the help of the given subcommand(s)
run Run a WebAssembly file. Formats accepted: wasm, wast
self-update Update wasmer to the latest version
validate Validate a Web Assembly binary
```

## `wasmer cache`

```
USAGE:
wasmer cache <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
clean Clear the cache
dir Display the location of the cache
help Prints this message or the help of the given subcommand(s)
```

## `wasmer run`

It runs a WebAssembly file. Formats accepted: wasm, wat

```
USAGE:
wasmer run [FLAGS] [OPTIONS] <path> [--] []...
FLAGS:
--enable-all Enable support for all pre-standard proposals.
--disable-cache Disable the cache
-h, --help Prints help information
--enable-simd Enable support for the SIMD proposal.
--enable-threads Enable support for the threads proposal.
--track-state Whether or not state tracking should be disabled during compilation. State tracking is
necessary for tier switching and backtracing.
-V, --version Prints version information
OPTIONS:
--backend <backend> [default: cranelift] [possible values: cranelift, singlepass, llvm]
--em-entrypoint <em-entrypoint> Begin execution at the specified symbol
--em-symbol-map <em-symbol-map> Emscripten symbol map
--env <env-vars>... Pass custom environment variables
--loader <loader> Custom code loader [possible values: local, kernel]
--mapdir <mapped-dirs>... Map a host directory to a different location for the wasm module
--llvm-object-file <obj-file> Emit LLVM generated native code object file.
--llvm-post-opt-ir <post-opt-ir> Emit LLVM IR after optimization pipeline.
--dir <pre-opened-directories>... WASI pre-opened directory
--llvm-pre-opt-ir <pre-opt-ir> Emit LLVM IR before optimization pipeline.
ARGS:
<path> Input file
<>... Application arguments
```

## `wasmer self-update`

It auto-updates the current used wasmer

## `wasmer validate <path>`

It validates that the provided Wasm file is valid.

```
USAGE:
wasmer validate [FLAGS] <path>
FLAGS:
--enable-all Enable support for all pre-standard proposals.
-h, --help Prints help information
--enable-simd Enable support for the SIMD proposal.
--enable-threads Enable support for the threads proposal.
-V, --version Prints version information
ARGS:
<path> Input file
```
96 changes: 96 additions & 0 deletions docs/runtime/rust-integration/examples/early-exit/early-exit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
id: runtime-rust-integration-examples-exit-early
title: Runtime Rust Integration: Interrupting Execution
sidebar_label: Interrupting Execution
---

WebAssembly in its current state is currently run synchronously. Thus, once WebAssembly starts executing, you have to wait for the execution to complete to continue running code on the host (your rust application). However, there are cases where you may want to interrupt this synchronous execution while the guest WebAssembly module is calling a host function. This can be useful for saving resources, and not returning back to the guest WebAssembly for execution, when you already know the Wasm execution will fail, or no longer be needed.

In this example, we will run a Wasm module that calls the imported host function, "interrupt_execution". This host function will immediately stop executing the WebAssembly module:

```rust
// Import the Filesystem so we can read our .wasm file
use std::fs::File;
use std::io::prelude::*;

// Import the wasmer runtime so we can use it
use wasmer_runtime::{
error,
// Include the function macro
func,
imports,
instantiate,
// Include the Context for our Wasm Instance for passing imported host functions
Ctx,
Func,
};

const WASM_FILE_PATH: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/example-rust-wasm-crate/early-exit-import/pkg/early_exit_import_bg.wasm"
);

// Our entry point to our application
fn main() -> error::Result<()> {
// Let's read in our .wasm file as bytes

// Let's open the file.
let mut file = File::open(WASM_FILE_PATH).expect(&format!("wasm file at {}", WASM_FILE_PATH));

// Let's read the file into a Vec
let mut wasm_vec = Vec::new();
file.read_to_end(&mut wasm_vec)
.expect("Error reading the wasm file");

// Now that we have the wasm file as bytes, let's run it with the wasmer runtime

// Let's define the import object used to import our function
// into our webassembly sample application.
//
// Make sure to check your function signature (parameter and return types) carefully!
let import_object = imports! {
// Define the "env" namespace that was implicitly used
// by our example rust wasm crate.
"env" => {
// Key should be the name of the imported function
// Value should be the func! macro, with the function passed in.
"interrupt_execution" => func!(interrupt_execution),
},
};

// Let's create an instance of wasm module running in the wasmer-runtime
let instance = instantiate(&wasm_vec, &import_object)?;

// Let's call the exported "exit_early" function on the wasm module.
let exit_early_func: Func<(), i32> = instance
.func("exit_early")
.expect("exit_early function not found");
let response = exit_early_func.call();

match response {
Ok(value) => {
// This should have thrown an error, return an error
panic!("exit_early did not error. Returned the value: {}", value);
}
Err(e) => {
// Log the error
println!("Error from exit_early: {}", e);
}
}

// Log a success message.
println!("Success!");

// Return OK since everything executed successfully!
Ok(())
}

// Function that is imported into the guest wasm module, that will immediately stop execution
fn interrupt_execution(_ctx: &mut Ctx) -> Result<(), ()> {
// Log that we were called
println!("interrupt_execution called!");

// Return an error, which will immediately stop execution of the wasm module
Err(())
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
id: runtime-rust-integration-examples-handling-errors
title: Runtime Rust Integration: Handling Errors
sidebar_label: Handling Errors
---

There will come a time where running a WebAssembly module will not work, and trying to figure out why it does not work can be a difficult task! In the current MVP of WebAssembly, debugging is quite vauge, in runtimes for both the browser and the server. But errors can still be handled and debugged gracefully.

In this example, we will load a WebAssembly module that purposely `panic!()`'s on its exported function call. The host (our rust application) will pattern match for the error and output the error message returned from Wasmer:

```rust
// Import the Filesystem so we can read our .wasm file
use std::io::prelude::*;
use std::fs::File;

// Import the wasmer runtime so we can use it
use wasmer_runtime::{
instantiate,
Func,
imports,
error,
};

// Our entry point to our application
fn main() -> error::Result<()> {

// Let's read in our .wasm file as bytes

// Let's open the file.
// The file path may be different depending where you run `cargo run`, and where you place the file.
let mut file = File::open("./example-rust-wasm-crate/throw-wasm-error/pkg/throw_wasm_error_bg.wasm").expect("Incorrect file path to wasm module.");

// Let's read the file into a Vec
let mut wasm_vec = Vec::new();
file.read_to_end(&mut wasm_vec).expect("Error reading the wasm file");

// Let's get our byte slice ( [u8] ) from ouw wasm_vec.
let wasm_bytes = wasm_vec.as_slice();

// Now that we have the wasm file as bytes, let's run it with the wasmer runtime

// Our import object, that allows exposing functions to our wasm module.
// We're not importing anything, so make an empty import object.
let import_object = imports!{};

// Let's create an instance of wasm module running in the wasmer-runtime
let instance = instantiate(wasm_bytes, &import_object)?;

// Let's call the exported "throw_error" function ont the wasm module.
let throw_error_func: Func<(), ()> = instance
.func("throw_wasm_error")
.expect("throw_wasm_error function was not found");

let response = throw_error_func.call();

match response {
Ok(_) => {
// The wasm modules should have thrown an error.
panic!("throw_wasm_error did not error");
},
Err(e) => {
// Log the error
println!("Error from throw_wasm_error: {}", e);
},
}

// Log a success message.
println!("Success!");

// Return OK since everything executed successfully!
Ok(())
}
```

If we run the following code with `cargo run`, we would see a result like:

[](https://www.notion.so/5d431ea429a24e6bacead8c003c33920#08e329b5e9864744b8f7d1d362589114)

However, let's make this a little more interesting. Let's unwrap the error, as you would during the development process and not in production. This will cause the program to error at the WebAssembly module function call, and will give a different output to our console:

```rust
// Import the Filesystem so we can read our .wasm file
use std::io::prelude::*;
use std::fs::File;

// Import the wasmer runtime so we can use it
use wasmer_runtime::{
instantiate,
Func,
imports,
error,
};

// Our entry point to our application
fn main() -> error::Result<()> {

// Let's read in our .wasm file as bytes

// Let's open the file.
// The file path may be different depending where you run `cargo run`, and where you place the file.
let mut file = File::open("./example-rust-wasm-crate/throw-wasm-error/pkg/throw_wasm_error_bg.wasm").expect("Incorrect file path to wasm module.");

// Let's read the file into a Vec
let mut wasm_vec = Vec::new();
file.read_to_end(&mut wasm_vec).expect("Error reading the wasm file");

// Let's get our byte slice ( [u8] ) from ouw wasm_vec.
let wasm_bytes = wasm_vec.as_slice();

// Now that we have the wasm file as bytes, let's run it with the wasmer runtime

// Our import object, that allows exposing functions to our wasm module.
// We're not importing anything, so make an empty import object.
let import_object = imports!{};

// Let's create an instance of wasm module running in the wasmer-runtime
let instance = instantiate(wasm_bytes, &import_object)?;

// Let's call the exported "throw_error" function ont the wasm module.
let throw_error_func: Func<(), ()> = instance
.func("throw_wasm_error")
.expect("throw_wasm_error function was not found");

// Unwrapping here, so that the error is thrown here
let _response = throw_error_func.call().unwrap();

/*
Commenting the pattern matching, to show the unwrapped error above.
match response {
Ok(_) => {
// This should have thrown an error, return an error
panic!("throw_wasm_error did not error");
},
Err(e) => {
// Log the error
println!("Error from throw_wasm_error: {}", e);
},
}
*/

// Log a success message.
println!("Success!");

// Return OK since everything executed successfully!
Ok(())
}
```

If we run the code with `cargo run`, we would see a result like:

[](https://www.notion.so/5d431ea429a24e6bacead8c003c33920#27c029496f2b492e813885e6cc88ebf1)

As you can tell, this error doesn't give us much insight into why this had an error. Such as the line number in the host application. This can be extremely fustrating, especially if you are making multiple calls to a wasm module in a complex rust application. What we can do to get some more insight is use what the error itself suggests, which is the `RUST_BACKTRACE=1` environment variable. **It is HIGHLY RECCOMENDED that you use the `RUST_BACKTRACE=1` environment variable for debugging you rust application that embeds the Wasmer runtime.**

So let's run the code with **`RUST_BACKTRACE=1 cargo run`** instead, we would see a result like:

[](https://www.notion.so/5d431ea429a24e6bacead8c003c33920#2b64e7adb22e42b4a49b9086afe70a8b)

If we look our for our file name (`src/main.rs`), we will see at step 10, there was an error on line 44. Which is the line number for where we call and unwrap the `throw_wasm_error` function. This is great, as now we can start to investigate the particular function call, and why it may be returning and error.

Next, let's take a look at how we can interrupt an executing Wasm module.
Loading

0 comments on commit 05c3a91

Please sign in to comment.