Sign in

    wasmoon

    A slow and insecure runtime for WebAssembly

    wasm
    webassembly
    runtime
    jit
    Download zip
    Author
    Version
    0.13.0
    License
    Apache-2.0
    Last updated
    last month
    Downloads
    254

    #Wasmoon

    A WebAssembly runtime written in MoonBit with JIT compilation support.

    Warning: This project is primarily developed with AI assistance and has not been thoroughly audited. Do not use in production or security-sensitive environments.

    Note: JIT optimization is actively improving. Performance depends on workload and platform; benchmark your target programs for an accurate comparison.

    #Features

    • JIT Compiler: AArch64 and amd64 native code generation with SSA-based IR
    • Interpreter: Full WebAssembly 1.0 execution engine, available via --no-jit
    • WAT/WASM Parser: Parse both text and binary formats
    • WASI Preview 1 Support: File I/O, environment variables, command-line arguments
    • GC Proposal Support: i31/struct/array/ref operations in interpreter and JIT
    • Component Model: Component parser, validator, runtime, and stable WIT-shaped facade
    • WASI Components: Preview 2 and WASI 0.3 hosts with native Component Async JIT on macOS AArch64 and Linux AMD64

    #Requirements

    • Required:
      • moon
      • python3
    • Optional:
      • wasmtime (useful for differential/performance comparison workflows)

    #Installation

    moon install Milky2018/wasmoon/cmd/wasmoon moon install Milky2018/wasmoon/cmd/wasmoon-tools

    To use unreleased changes directly from the Git repository:

    moon install https://github.com/Milky2018/wasmoon.git cmd/wasmoon moon install https://github.com/Milky2018/wasmoon.git cmd/wasmoon-tools

    Verify binaries are on PATH:

    wasmoon --help wasmoon-tools --help

    By default these commands install binaries to ~/.moon/bin/ as:

    • wasmoon (runtime CLI)
    • wasmoon-tools (utility CLI)

    #Path B: Repo-local build (development)

    git clone https://github.com/Milky2018/wasmoon.git cd wasmoon ./install.sh

    ./install.sh uses moon build --target native --release to build local binaries into target/moon-install-build/, copies them to target/moon-install-bin/, and then refreshes two repo-root executables:

    • ./wasmoon
    • ./wasmoon-tools

    After code changes, re-run ./install.sh to refresh both executables.

    #As Library

    moon add Milky2018/wasmoon

    #Quick Start (60 seconds)

    # 1) Run with default _start wasmoon run examples/add.wat # 2) Invoke an export with arguments wasmoon run examples/add.wat --invoke add --arg 5 --arg 3 # 3) Interpreter mode wasmoon run examples/add.wat --invoke add --arg 5 --arg 3 --no-jit # 4) WASI dirs/env/options wasmoon run examples/hello_wasi.wat \ --dir . \ --env FOO=bar \ -S inherit-env

    For detailed flags, run:

    wasmoon run --help

    #CLI Commands (concise)

    # run wasmoon run examples/add.wat --invoke add --arg 1 --arg 2 wasmoon run --help # test wasmoon test spec/i32.wast wasmoon test --help # explore wasmoon explore examples/add.wat \ --stage milkir opt-milkir vcode allocated-vcode code-object mc wasmoon explore --help # component wasmoon component path/to/component.wasm --validate wasmoon component path/to/component.wasm \ --invoke 'math#increment' \ --arg 41 wasmoon component path/to/command.component.wasm --run \ --dir /srv/data::/data \ --network loopback wasmoon component path/to/command.component.wasm --run --no-jit wasmoon component --help # component-test wasmoon component-test path/to/component-tests.json wasmoon component-test path/to/component-tests.json --no-jit wasmoon component-test --help # disasm wasmoon disasm examples/stream.wasm wasmoon disasm examples/add.wat wasmoon disasm --help

    Quick differential testing vs Wasmtime (wasm-smith):

    python3 scripts/smith_diff/run.py run --count 1000

    #JIT Trap Debugging

    Use these options when diagnosing JIT failures:

    • -D: debug logging
    • --dump-on-trap: dump MilkIR/Target VCode/MC for the trapping function
    • -W: generate DWARF debug info for JIT code (better stack traces in LLDB)

    Example:

    wasmoon run examples/core_ed25519.wasm -D --dump-on-trap -W

    LLDB quick recipe:

    lldb -- ./wasmoon run examples/core_ed25519.wasm (lldb) run (lldb) bt

    #wasmoon-tools Usage

    wasmoon-tools provides common validation/conversion/WIT workflows:

    # Validate a core Wasm module (WASM/WAT) wasmoon-tools validate examples/add.wat # Convert between WASM and WAT wasmoon-tools wasm2wat examples/stream.wasm -o examples/stream.wat wasmoon-tools wat2wasm examples/add.wat -o examples/add.wasm # Parse WIT and print normalized text / JSON wasmoon-tools wit path/to/foo.wit wasmoon-tools wit path/to/foo.wit --json # Resolve a directory package (with deps/) and emit graph wasmoon-tools wit path/to/pkgdir wasmoon-tools wit path/to/pkgdir --out-dir out # Encode WIT package as component binary / text wasmoon-tools wit path/to/foo.wit --wasm -o foo.wasm wasmoon-tools wit path/to/foo.wit --wat > foo.wat # Importize world flow wasmoon-tools wit foo.wasm --importize --wat wasmoon-tools wit path/to/pkgdir --importize-world my-world --wat

    wasmoon-tools wit supports parsing and dependency resolution through deps/, JSON output, component encoding and decoding, importize workflows, and tested non-scalar and resource-related cases. Unsupported specification cases return a diagnostic.

    #License

    Wasmoon is licensed under Apache-2.0. Some test suites, benchmark workloads, and generated diagnostic artifacts are imported from third-party projects under their own compatible licenses. See THIRD_PARTY_NOTICES.md.

    #Validation / CI-equivalent Checks

    moon check --target native moon test --target native ./install.sh cargo install wasm-tools --version 1.254.0 --locked python3 scripts/run_all_wast.py --dir spec --rec python3 scripts/check_component_snapshot.py python3 scripts/run_component_wast.py --suite stable-0.2 python3 scripts/run_component_wast.py --suite stable-0.2 --no-jit python3 scripts/run_component_wast.py --suite async-0.3 python3 scripts/run_component_wast.py --suite async-0.3 --no-jit python3 scripts/run_component_wast.py --suite future-gated python3 scripts/run_component_wast.py --suite future-gated --no-jit

    #Library Usage

    #JIT GC Setup

    Call @jit.gc_setup(...) with the VMContext and function-table data used by typed function references:

    • ctx_ptr
    • func_type_indices
    • func_table_ptr
    • num_funcs

    The setup associates GC runtime state with ctx_ptr. Pass the same pointer to @jit.gc_teardown(...) when releasing that state. Incomplete or inconsistent setup data raises GCSetupError.

    #Basic Example

    ///|
    test "basic add" {
    let wat =
    #|(module
    #| (func (export "add") (param i32 i32) (result i32)
    #| local.get 0
    #| local.get 1
    #| i32.add))
    let mod = @wat.parse(wat)
    let (store, instance) = @executor.instantiate_module(mod)
    let result = @executor.call_exported_func(store, instance, "add", [
    I32(5),
    I32(3),
    ])
    debug_inspect(result, content="[I32(8)]")
    }

    #Memory Operations

    ///|
    test "memory" {
    let wat =
    #|(module
    #| (memory (export "mem") 1)
    #| (func (export "store") (param i32 i32)
    #| local.get 0 local.get 1 i32.store)
    #| (func (export "load") (param i32) (result i32)
    #| local.get 0 i32.load))
    let mod = @wat.parse(wat)
    let (store, instance) = @executor.instantiate_module(mod)
    @executor.call_exported_func(store, instance, "store", [I32(0), I32(42)])
    |> ignore
    let result = @executor.call_exported_func(store, instance, "load", [I32(0)])
    debug_inspect(result, content="[I32(42)]")
    }

    #Cross-module Imports

    ///|
    test "cross-module" {
    let linker = @runtime.Linker::Linker()
    let mod_a =
    #|(module (func (export "add") (param i32 i32) (result i32)
    #| local.get 0 local.get 1 i32.add))
    let mod_a = @wat.parse(mod_a)
    let inst_a = @executor.instantiate_with_linker(linker, "math", mod_a)
    linker.register("math", inst_a)
    let mod_b =
    #|(module
    #| (import "math" "add" (func $add (param i32 i32) (result i32)))
    #| (func (export "use_add") (param i32 i32) (result i32)
    #| local.get 0 local.get 1 call $add))
    let mod_b = @wat.parse(mod_b)
    let inst_b = @executor.instantiate_with_linker(linker, "main", mod_b)
    let result = @executor.call_exported_func(
    linker.get_store(),
    inst_b,
    "use_add",
    [I32(3), I32(5)],
    )
    debug_inspect(result, content="[I32(8)]")
    }

    #Host Functions

    ///|
    test "host function" {
    let linker = @runtime.Linker::Linker()
    // Register a host function that doubles an i32
    linker.add_host_func(
    "env",
    "double",
    fn(args) {
    guard args[0] is I32(x) else { return [] }
    [I32(x * 2)]
    },
    func_type={ params: [I32], results: [I32], },
    )
    let wat =
    #|(module
    #| (import "env" "double" (func $double (param i32) (result i32)))
    #| (func (export "quadruple") (param i32) (result i32)
    #| local.get 0 call $double call $double))
    let mod = @wat.parse(wat)
    let instance = @executor.instantiate_with_linker(linker, "main", mod)
    let result = @executor.call_exported_func(
    linker.get_store(),
    instance,
    "quadruple",
    [I32(5)],
    )
    debug_inspect(result, content="[I32(20)]")
    }

    #Project Status

    #Contributor Note

    • Edit README.mbt.md as the source of truth.
    • README.md is a symlink to README.mbt.md.

    #License

    Apache-2.0

    WasmCompilerPipelineError

    pub suberror WasmCompilerPipelineError {
    WasmCompilerPipelineFailure(message~ : String)
    } derive(Eq,
    Debug
    )

    WasmCompilerPipelineError::equal

    WasmCompilerPipelineError::not_equal

    WasmCompilerPipelineError::output

    fn WasmCompilerPipelineError::output(self : WasmCompilerPipelineError, logger : &Logger) -> Unit

    WasmCompilerPipelineError::to_string

    CompilerInfrastructureAssembly

    pub(all) struct CompilerInfrastructureAssembly {
    signature :
    Signature

    milkir_function :
    Function

    code_object :
    JitCodeObject

    }

    RuntimeAssembly

    pub(all) struct RuntimeAssembly {
    product_module : String
    owned_components : Array[RuntimeComponent]
    product_support_modules : Array[String]
    reusable_modules : Array[String]
    } derive(Eq,
    Debug
    )

    RuntimeAssembly::equal

    RuntimeAssembly::not_equal

    fn RuntimeAssembly::not_equal(x : RuntimeAssembly, y : RuntimeAssembly) -> Bool

    RuntimeComponent

    pub(all) enum RuntimeComponent {
    Cli
    RuntimeObjects
    InterpreterExecutor
    WasiPreview1
    JitSelection
    } derive(Eq,
    Debug
    )

    RuntimeComponent::equal

    RuntimeComponent::not_equal

    fn RuntimeComponent::not_equal(x : RuntimeComponent, y : RuntimeComponent) -> Bool

    compiler_infrastructure_assembly

    fn compiler_infrastructure_assembly() -> CompilerInfrastructureAssembly raise WasmCompilerPipelineError

    runtime_assembly

    fn runtime_assembly() -> RuntimeAssembly

    wasm_frontend_embedding_environment

    fn wasm_frontend_embedding_environment(runtime_symbol_prefix? : String, hidden_context_type? :
    Type
    ?, cancellation_safepoints? : Bool) ->
    EmbeddingEnvironment