Sign in

    wasmoon

    A slow and insecure runtime for WebAssembly

    wasm
    webassembly
    runtime
    jit
    Download zip
    Author
    Version
    0.17.1
    License
    Apache-2.0
    Last updated
    yesterday
    Downloads
    196

    #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: Core execution via --no-jit; the unreleased wasmoon_runtime module also supports the MoonBit wasm target under moonrun
    • Async host functions: Suspend interpreter continuations or JIT native fibers without blocking the host thread
    • 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 HTTP 0.3: Streaming HTTP/HTTPS client, service and middleware worlds; wasmoon serve with interpreter or JIT
    • WASI HTTP 0.3: Streaming HTTP/HTTPS client, service and middleware worlds; wasmoon serve with interpreter or JIT
    • WASI Components: Preview 2 and WASI 0.3 hosts with native Component Async JIT on macOS AArch64 and Linux AMD64

    See the portable interpreter guide for wasm embedding and host requirements.

    See the portable interpreter guide for wasm embedding and host requirements.

    #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

    #Async host functions

    Register an async import with Linker::add_async_host_func, then enter Wasm through an async call API. Wasm observes an ordinary blocking import call, while the host future is awaited only after the interpreter continuation or JIT native fiber has been parked.

    linker.add_async_host_func(
    "host",
    "double_later",
    async fn(args) {
    @async.sleep(10)
    match args[0] {
    I32(value) => [I32(value * 2)]
    _ => raise @runtime.TypeMismatch
    }
    },
    func_type={ params: [I32], results: [I32], },
    )

    let values = @executor.call_exported_func_async(
    linker.get_store(), instance, "run", [I32(21)],
    )

    Use JITModuleContext::call_core_func_async for a prepared JIT module. Calling an async import through a synchronous entry point fails explicitly instead of blocking the host thread. Cancelling the surrounding MoonBit task cancels the host future and releases the parked Wasm continuation or native fiber. Async suspension and structured host errors also propagate when JIT-compiled Wasm calls an interpreted imported-Wasm function before reaching the async host. Reference arguments and completed host results remain Store GC roots across every parked or not-yet-consumed boundary.

    If a module's start function can reach an async import, instantiate it with instantiate_with_linker_async or instantiate_module_with_imports_async. The synchronous instantiation APIs reject that path with AsyncHostRequiresAsyncCall.

    MoonBit async functions do not expose a synchronously pollable Future to a synchronous native callback. Wasmoon therefore starts the host operation as a structured child task and parks Wasm once on the first encounter, even when the host function completes without awaiting. Subsequent waiting and resumption do not block the host thread.

    #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

    Use --dir-ro HOST_DIR::GUEST_DIR for a read-only WASIp1 preopen; it can be repeated and combined with --dir. Descendant descriptors cannot acquire filesystem mutation rights. See the rights contract for the permission boundary and embedding APIs.

    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 tests/upstream/core-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 tests/upstream/core-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

    For additional runtime testing, the upstream WASIp1 guest suite runs unchanged Wasmtime P1 programs in interpreter and JIT modes:

    rustup target add wasm32-wasip1 python3 scripts/run_wasmtime_p1.py

    The unchanged upstream profile reports rights/capability contract differences. Regular CI runs the capabilities profile with explicitly recorded adaptations; the agreed Wasmtime-specific hostcall-fuel case remains not applicable.

    The pinned Wasmtime misc_testsuite adds core Wasm and Component Model regression scripts:

    python3 scripts/run_wasmtime_misc.py --check python3 scripts/run_wasmtime_misc.py

    Regular CI runs the full misc suite, including high-memory cases. Assertion-bearing passes and successfully executed scripts without assertions are reported separately. The current reference is Wasmtime 49.0.1; see the reference refresh and acceptance report for exact versions, coverage, remaining contract differences, and the new performance baseline.

    #Library Usage

    #API changes in 0.17.0

    Version 0.17.0 removes the migration-era RuntimeAssembly, RuntimeComponent, CompilerInfrastructureAssembly, and WasmCompilerPipelineError types, plus runtime_assembly, compiler_infrastructure_assembly, and plan_wasm_function_with_compiler_infra. These were exported in earlier 0.x releases; the removal is a source-breaking change in 0.17.0. External callers must migrate before upgrading from 0.16.x.

    Use the architecture documentation and package imports for ownership information. For compilation, create a translation context through wasm_milkir/frontend with wasmoon.wasm_frontend_embedding_environment, then use wasmoon_jit.NativeCompiler::compile_wasm_body_artifact_function, as the production core and component compilers do. This preserves explicit target, context shape, validation, and structured compiler errors rather than routing through a separate probe pipeline. The embedding-environment API is unchanged.

    #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

    wasm_frontend_embedding_environment

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

    Source Files

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io