# WASM module examples ### Rust WASI app Create a new project: ```sh $ cargo new --bin hello $ cd hello $ rustup target add wasm32-wasi ``` Build and run: ```sh $ cargo build --release --target wasm32-wasi $ wasm3 ./target/wasm32-wasi/release/hello.wasm Hello, world! ``` ### AssemblyScript WASI app Create `hello.ts`: ```ts import "wasi" import {Console} from "as-wasi" Console.log('Hello World!'); ``` Create `package.json`: ```json { "scripts": { "asbuild:debug": "asc hello.ts -b hello.wasm --debug", "asbuild:optimized": "asc hello.ts -b hello.wasm -O3s --noAssert", "asbuild:tiny": "asc hello.ts -b hello.wasm -O3z --noAssert --runtime stub --use abort=", "build": "npm run asbuild:optimized" }, "devDependencies": { "assemblyscript": "*", "as-wasi": "*" } } ``` Build and run: ```sh $ npm install $ npm run build $ wasm3 hello.wasm Hello World! ``` ### TinyGo WASI app Create `hello.go`: ```go package main import "fmt" func main() { fmt.Printf("Hello, %s!\n", "world") } ``` Build and run: ```sh $ tinygo build -o hello.wasm -target wasi -no-debug hello.go $ wasm3 hello.wasm Hello, world! ``` ### Zig WASI app Create `hello.zig`: ```zig const std = @import("std"); pub fn main() !void { const stdout = std.io.getStdOut().writer(); try stdout.print("Hello, {s}!\n", .{"world"}); } ``` Build and run: ```sh $ zig build-exe -O ReleaseSmall -target wasm32-wasi hello.zig $ wasm3 hello.wasm Hello, world! ``` ## Zig library Create `add.zig`: ```zig export fn add(a: i32, b: i32) i64 { return a + b; } ``` Build and run: ```sh $ zig build-lib add.zig -O ReleaseSmall -target wasm32-freestanding $ wasm3 --repl add.wasm wasm3> add 1 2 Result: 3 ``` ### C/C++ WASI app The easiest way to start is to use [Wasienv](https://github.com/wasienv/wasienv). Create `hello.cpp`: ```cpp #include int main() { std::cout << "Hello, world!" << std::endl; return 0; } ``` Or `hello.c`: ```c #include int main() { printf("Hello, %s!\n", "world"); return 0; } ``` Build and run: ```sh $ wasic++ -O3 hello.cpp -o hello.wasm $ wasicc -O3 hello.c -o hello.wasm $ wasm3 hello.wasm Hello World! ``` Limitations: - `setjmp/longjmp` and `C++ exceptions` are not available - no support for `threads` and `atomics` - no support for `dynamic libraries` ### Grain WASI app Create `hello.gr`: ``` print("Hello, world!") ``` Build and run: ```sh $ grain compile hello.gr -o hello.wasm $ wasm3 hello.wasm Hello, world! ``` ### WAT WASI app Create `hello.wat`: ```wat (module ;; wasi_snapshot_preview1!fd_write(file_descriptor, *iovs, iovs_len, nwritten) -> status_code (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32))) (memory 1) (export "memory" (memory 0)) ;; Put a message to linear memory at offset 32 (data (i32.const 32) "Hello, world!\n") (func $main (export "_start") ;; Create a new io vector at address 0x4 (i32.store (i32.const 4) (i32.const 32)) ;; iov.iov_base - pointer to the start of the message (i32.store (i32.const 8) (i32.const 14)) ;; iov.iov_len - length of the message (call $fd_write (i32.const 1) ;; file_descriptor - 1 for stdout (i32.const 4) ;; *iovs - pointer to the io vector (i32.const 1) ;; iovs_len - count of items in io vector (i32.const 20) ;; nwritten - where to store the number of bytes written ) drop ;; discard the WASI status code ) ) ``` Build and run: ```sh $ wat2wasm hello.wat -o hello.wasm $ wasm3 hello.wasm Hello, world! ``` ### WAT library Create `swap.wat`: ```wat (module (func (export "swap") (param i32 i32) (result i32 i32) (get_local 1) (get_local 0) ) ) ``` Build and run: ```sh $ wat2wasm swap.wat -o swap.wasm $ wasm3 --repl swap.wasm wasm3> :invoke swap 123 456 Result: 456:i32, 123:i32 ``` # Tracing Drag'n'drop any of the WASI apps to [`WebAssembly.sh`](https://webassembly.sh/) and run: ```sh $ wasm3-strace /tmp/hello.wasm ``` The execution trace will be produced: ```js _start () { __wasilibc_init_preopen () { malloc (i32: 16) { dlmalloc (i32: 16) { sbrk (i32: 0) { } = 131072 sbrk (i32: 65536) { ```
Click to expand! ```js } = 131072 } = 131088 } = 131088 calloc (i32: 24, i32: 0) { dlmalloc (i32: 96) { } = 131120 memset (i32: 131120, i32: 65504, i32: 0) { } = 131120 } = 131120 po_map_assertvalid (i32: 131088) { } po_map_assertvalid (i32: 131088) { } } wasi_unstable!fd_prestat_get(3, 65528) { } = 0 malloc (i32: 2) { dlmalloc (i32: 2) { } = 131232 } = 131232 wasi_unstable!fd_prestat_dir_name(3, 131232, 1) { } = 0 __wasilibc_register_preopened_fd (i32: 3, i32: 131120) { po_map_assertvalid (i32: 131088) { } po_map_assertvalid (i32: 131088) { } strdup (i32: 131232) { strlen (i32: 131232) { } = 1 malloc (i32: 2) { dlmalloc (i32: 2) { } = 131248 } = 131248 memcpy (i32: 131248, i32: 131233, i32: 131232) { } = 131248 } = 131248 wasi_unstable!fd_fdstat_get(3, 65496) { } = 0 po_map_assertvalid (i32: 131088) { } po_map_assertvalid (i32: 131088) { } } = 0 free (i32: 131232) { dlfree (i32: 131232) { } } wasi_unstable!fd_prestat_get(4, 65528) { } = 0 malloc (i32: 2) { dlmalloc (i32: 2) { } = 131232 } = 131232 wasi_unstable!fd_prestat_dir_name(4, 131232, 1) { } = 0 __wasilibc_register_preopened_fd (i32: 4, i32: 131120) { po_map_assertvalid (i32: 131088) { } po_map_assertvalid (i32: 131088) { } strdup (i32: 131232) { strlen (i32: 131232) { } = 1 malloc (i32: 2) { dlmalloc (i32: 2) { } = 131264 } = 131264 memcpy (i32: 131264, i32: 131233, i32: 131232) { } = 131264 } = 131264 wasi_unstable!fd_fdstat_get(4, 65496) { } = 0 po_map_assertvalid (i32: 131088) { } po_map_assertvalid (i32: 131088) { } } = 0 free (i32: 131232) { dlfree (i32: 131232) { } } wasi_unstable!fd_prestat_get(5, 65528) { } = 8 __wasm_call_ctors () { } __original_main () { printf (i32: 65536, i32: 0) { vfprintf (i32: 69512, i32: 0, i32: 65536) { printf_core (i32: 0, i32: -1, i32: 65536, i32: -16, i32: 65480) { } = 0 __towrite (i32: 69512) { } = 0 printf_core (i32: 69512, i32: 8, i32: 65536, i32: -1, i32: 65480) { __fwritex (i32: 65536, i32: 0, i32: 7) { memcpy (i32: 68472, i32: 0, i32: 65536) { } = 68472 } = 7 __fwritex (i32: 65543, i32: 0, i32: 0) { memcpy (i32: 68479, i32: 0, i32: 65543) { } = 68479 } = 0 pop_arg (i32: 64456, i32: 0, i32: 9) { } strnlen (i32: 65548, i32: 0) { memchr (i32: 65548, i32: 4, i32: 0) { } = 65553 } = 5 __fwritex (i32: 67222, i32: 65553, i32: 0) { memcpy (i32: 68479, i32: 0, i32: 67222) { } = 68479 } = 0 __fwritex (i32: 65548, i32: 65553, i32: 5) { memcpy (i32: 68479, i32: 0, i32: 65548) { } = 68479 } = 5 __fwritex (i32: 65545, i32: 0, i32: 2) { __stdout_write (i32: 69512, i32: 0, i32: 65545) { __isatty (i32: 1) { wasi_unstable!fd_fdstat_get(1, 64376) { } = 0 } = 1 __stdio_write (i32: 69512, i32: 64368, i32: 65545) { writev (i32: 1, i32: -16, i32: 64384) { Hello, world! wasi_unstable!fd_write(1, 64384, 2, 64380) { } = 0 } = 14 } = 2 } = 2 memcpy (i32: 68472, i32: -1, i32: 65547) { } = 68472 } = 2 } = 14 } = 14 } = 14 } = 0 __prepare_for_exit () { dummy () { } __stdio_exit () { __ofl_lock () { } = 69504 } } } ```
# Gas Metering ```sh $ npm install -g wasm-metering $ wasm-meter hello.wasm hello-metered.wasm $ wasm3 hello-metered.wasm Warning: Gas is limited to 500000000.0000 Hello, world! Gas used: 20.8950 $ wasm3 --gas-limit 10 hello-metered.wasm Warning: Gas is limited to 10.0000 Gas used: 10.0309 Error: [trap] Out of gas ``` # Other resources - [WebAssembly by examples](https://wasmbyexample.dev/home.en-us.html) by Aaron Turner - [Writing WebAssembly](https://docs.wasmtime.dev/wasm.html) in Wasmtime docs