wazero: the zero dependency WebAssembly runtime for Go developers

wazero: the zero dependency WebAssembly runtime for Go developers

WebAssembly Core Specification Test Go Reference License

WebAssembly is a way to safely run code compiled in other languages. Runtimes execute WebAssembly Modules (Wasm), which are most often binaries with a .wasm extension.

wazero is a WebAssembly 1.0 spec compliant runtime written in Go. It has zero dependencies, and doesn't rely on CGO. This means you can run applications in other languages and still keep cross compilation.

Import wazero and extend your Go application with code written in any language!

Example

The best way to learn wazero is by trying one of our examples.

For the impatient, here's how invoking a factorial function looks in wazero:

func main() {
	// Choose the context to use for function calls.
	ctx := context.Background()

	// Read a WebAssembly binary containing an exported "fac" function.
	// * Ex. (func (export "fac") (param i64) (result i64) ...
	source, err := os.ReadFile("./path/to/fac.wasm")
	if err != nil {
		log.Panicln(err)
	}

	// Create a new WebAssembly Runtime.
	r := wazero.NewRuntime()
	defer r.Close(ctx) // This closes everything this Runtime created.

	// Instantiate the module and return its exported functions
	module, err := r.InstantiateModuleFromCode(ctx, source)
	if err != nil {
		log.Panicln(err)
	}

	// Discover 7! is 5040
	fmt.Println(module.ExportedFunction("fac").Call(ctx, 7))
}

Note: fac.wasm was compiled from fac.wat, in the WebAssembly 1.0 Text Format, it could have been written in another language that compiles to (targets) WebAssembly, such as AssemblyScript, C, C++, Rust, TinyGo or Zig.

Deeper dive

The former example is a pure function. While a good start, you probably are wondering how to do something more realistic, like read a file. WebAssembly Modules (Wasm) are sandboxed similar to containers. They can't read anything on your machine unless you explicitly allow it.

The WebAssembly Core Specification is a standard, governed by W3C process, but it has no scope to specify how system resources like files are accessed. Instead, WebAssembly defines "host functions" and the signatures they can use. In wazero, "host functions" are written in Go, and let you do anything including access files. The main constraint is that WebAssembly only allows numeric types.

For example, you can grant WebAssembly code access to your console by exporting a function written in Go. The below function can be imported into standard WebAssembly as the module "env" and the function name "log_i32".

_, err := r.NewModuleBuilder("env").
	ExportFunction("log_i32", func(v uint32) {
		fmt.Println("log_i32 >>", v)
	}).
	Instantiate(ctx)
if err != nil {
    log.Panicln(err)
}

The WebAssembly community has subgroups which maintain work that may not result in a Web Standard. One such group is the WebAssembly System Interface (WASI), which defines functions similar to Go's x/sys/unix.

The wasi_snapshot_preview1 tag of WASI is widely implemented, so wazero bundles an implementation. That way, you don't have to write these functions.

For example, here's how you can allow WebAssembly modules to read "/work/home/a.txt" as "/a.txt" or "./a.txt":

_, err := wasi.InstantiateSnapshotPreview1(ctx, r)
if err != nil {
    log.Panicln(err)
}

config := wazero.NewModuleConfig().WithFS(os.DirFS("/work/home"))
module, err := r.InstantiateModule(ctx, compiled, config)
...

While we hope this deeper dive was useful, we also provide examples to elaborate each point. Please try these before raising usage questions as they may answer them for you!

Runtime

There are two runtime configurations supported in wazero: Compiler is default:

If you don't choose, ex wazero.NewRuntime(), Compiler is used if supported. You can also force the interpreter like so:

r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfigInterpreter())

Interpreter

Interpreter is a naive interpreter-based implementation of Wasm virtual machine. Its implementation doesn't have any platform (GOARCH, GOOS) specific code, therefore interpreter can be used for any compilation target available for Go (such as riscv64).

Compiler

Compiler compiles WebAssembly modules into machine code ahead of time (AOT), during Runtime.CompileModule. This means your WebAssembly functions execute natively at runtime. Compiler is faster than Interpreter, often by order of magnitude (10x) or more. This is done while still having no host-specific dependencies.

If interested, check out the RATIONALE.md and help us optimize further!

Conformance

Both runtimes pass WebAssembly 1.0 spectests on supported platforms:

Runtime Usage amd64 arm64 others
Interpreter wazero.NewRuntimeConfigInterpreter()
Compiler wazero.NewRuntimeConfigCompiler()

Support Policy

The below support policy focuses on compatability concerns of those embedding wazero into their Go applications.

wazero

wazero is an early project, so APIs are subject to change until version 1.0.

We expect wazero 1.0 to be at or before Q3 2022, so please practice the current APIs to ensure they work for you!

Go

wazero has no dependencies except Go, so the only source of conflict in your project's use of wazero is the Go version.

To simplify our support policy, we adopt Go's Release Policy (two versions).

This means wazero will remain compilable and tested on the version prior to the latest release of Go.

For example, once Go 1.29 is released, wazero may use a Go 1.28 feature.

Platform

wazero has two runtime modes: Interpreter and Compiler. The only supported operating systems are ones we test, but that doesn't necessarily mean other operating system versions won't work.

We currently test Linux (Ubuntu and scratch), MacOS and Windows as packaged by GitHub Actions.

  • Interpreter
    • Linux is tested on amd64 (native) as well arm64 and riscv64 via emulation.
    • MacOS and Windows are only tested on amd64.
  • Compiler
    • Linux is tested on amd64 (native) as well arm64 via emulation.
    • MacOS and Windows are only tested on amd64.

wazero has no dependencies and doesn't require CGO. This means it can also be embedded in an application that doesn't use an operating system. This is a main differentiator between wazero and alternatives.

We verify zero dependencies by running tests in Docker's scratch image. This approach ensures compatibility with any parent image.


wazero is a registered trademark of Tetrate.io, Inc. in the United States and/or other countries

Owner
Tetrate Labs
Open Source projects from Tetrate
Tetrate Labs
Comments
  • JIT: Exception 0xc0000005 0x8 0x0 0x0

    JIT: Exception 0xc0000005 0x8 0x0 0x0

    I'm testing some code with Wazero, and I notice one odd crash, that I'm not sure if it's either my code (which is Zig) or Wazero. That is strange from previous errors, because it's one "Exception 0xc0000005 0x8 0x0 0x0". It's not an panic or something from testing.Error(err).

    I'm using Windows/amd64.


    The log is:

     go test -tags wasi,km,zig -v -bench=. -benchmem -benchtime=5s -cpu 1
    === RUN   TestEncodeObjectAPI
    Exception 0xc0000005 0x8 0x0 0x0                                                                                                                                              
    PC=0x0                                                                                                                                                                        
                                                                                                                                                                                  
    github.com/tetratelabs/wazero/internal/wasm/jit.(*callEngine).execWasmFunction(0xc00074a240, {0x5dd008, 0xc00009e140}, 0xc000952e70, 0xc000952cf0)                            
            Z:/GOPATH/pkg/mod/github.com/tetratelabs/[email protected]/internal/wasm/jit/engine.go:699 +0x185 fp=0xc00095dbb8 sp=0xc00095dae0 pc=0x4d5305 
    github.com/tetratelabs/wazero/internal/wasm/jit.(*moduleEngine).Call(0xc000954030?, {0x5dd008, 0xc00009e140}, 0xc000952e70, 0xc000494dd0, {0xc000954030, 0x1, 0x1})           
            Z:/GOPATH/pkg/mod/github.com/tetratelabs/[email protected]/internal/wasm/jit/engine.go:582 +0x48f fp=0xc00095dcb8 sp=0xc00095dbb8 pc=0x4d4b2f 
    github.com/tetratelabs/wazero/internal/wasm.(*FunctionInstance).Call(0x53bca0?, {0x5dd008?, 0xc00009e140?}, {0xc000954030?, 0xc000022270?, 0x0?})                             
            Z:/GOPATH/pkg/mod/github.com/tetratelabs/[email protected]/internal/wasm/call_context.go:164 +0x63 fp=0xc00095dd08 sp=0xc00095dcb8 pc=0x4901c3
    benchmark%2ekarmem%2eorg.(*Wasm).Run(...)
            X:/karmem/benchmark/main_wasi_test.go:289
    benchmark%2ekarmem%2eorg.TestEncodeObjectAPI(0xc000061040)
            X:/karmem/benchmark/main_wasi_test.go:113 +0x1f6 fp=0xc00095df70 sp=0xc00095dd08 pc=0x50d556
    testing.tRunner(0xc000061040, 0x58dce8)
            C:/Program Files/Go/src/testing/testing.go:1439 +0x102 fp=0xc00095dfc0 sp=0xc00095df70 pc=0x3e3482
    testing.(*T).Run.func1()
            C:/Program Files/Go/src/testing/testing.go:1486 +0x2a fp=0xc00095dfe0 sp=0xc00095dfc0 pc=0x3e432a
    runtime.goexit()
            C:/Program Files/Go/src/runtime/asm_amd64.s:1571 +0x1 fp=0xc00095dfe8 sp=0xc00095dfe0 pc=0x3587a1
    created by testing.(*T).Run
            C:/Program Files/Go/src/testing/testing.go:1486 +0x35f
    
    goroutine 1 [chan receive]:
    testing.(*T).Run(0xc000060ea0, {0x57e4e0?, 0x35af53?}, 0x58dce8)
            C:/Program Files/Go/src/testing/testing.go:1487 +0x37a
    testing.runTests.func1(0xc000020090?)
            C:/Program Files/Go/src/testing/testing.go:1839 +0x6e
    testing.tRunner(0xc000060ea0, 0xc0000c3cd8)
            C:/Program Files/Go/src/testing/testing.go:1439 +0x102
    testing.runTests(0xc000094320?, {0x72cd40, 0x1, 0x1}, {0x26848cc0598?, 0x40?, 0x738f20?})
            C:/Program Files/Go/src/testing/testing.go:1837 +0x457
    testing.(*M).Run(0xc000094320)
            C:/Program Files/Go/src/testing/testing.go:1719 +0x5d9
    main.main()
            _testmain.go:57 +0x1aa
    rax     0x20
    rbx     0x110000
    rcx     0xc000494270
    rdi     0x1100000012
    rsi     0xc0002de820
    rbp     0xc00095dba8
    rsp     0xc00095dad8
    r8      0x23280
    r9      0x8
    r10     0x90
    r11     0x0
    r14     0xc000966600
    r15     0xc004a90000
    rip     0x0
    rflags  0x10202
    cs      0x33
    fs      0x53
    gs      0x2b
    exit status 2
    

    That issue is ONLY affecst JIT, so I think it's an Wazero issue. The biggest issue is that it crashes the entire program and it's not possible to recover.

    Change:

    wazero.NewRuntimeConfigJIT().WithFinishedFeatures()
    

    To:

    wazero.NewRuntimeConfigInterpreter().WithFinishedFeatures()
    

    Runs the tests without issue:

    === RUN   TestEncodeObjectAPI
    --- PASS: TestEncodeObjectAPI (17.07s)
    

    Also, it's ONLY affects WASM compiled with zig build install -Dtarget="wasm32-wasi" -Drelease-safe, so if you compile as debug zig build install -Dtarget="wasm32-wasi" it will run. A lot slower, but runs. The debug have more bounds checks and so on. So, maybe there's something in my code that is actually crashing the runtime, crashing at one unrecoverable point.


    I'll share the source-code soon.

  • gojs: fix memory out of bounds

    gojs: fix memory out of bounds

    When in a loop reading a lot of data, the interpreter passes, but the compiler fails after this change. I'd love a hand from @mathetake to figure out the latter!

  • wasi: adds fd_readdir

    wasi: adds fd_readdir

    This adds an implementation of fd_readdir for WASI, which ensures a very large directory is not kept in host memory until its directory is closed.

    Original implementation and test data are with thanks from @jerbob92

  • wasi: exposes CloseWithExitCode to correct implementation of proc_exit

    wasi: exposes CloseWithExitCode to correct implementation of proc_exit

    Before, when the WASI function "proc_exit" was invoked, not only did the module stay alive, but also only the calling goroutine would receive an error with the exit code.

    panic(wasi.ExitCode(exitCode))
    

    Now, this corrects the implementation to actually shutdown the module, and ensure any callers can see the exit code, not just the caller who invoked exit.

    _ = m.CloseWithExitCode(exitCode)
    

    The changes needed for this were numerous, but allow other implementations, such as AssemblyScript abort handlers, to close the same way:

    • Adds Module.CloseWithExitCode which allows propagating an exit code to any callers of exported functions.
    • Dispatches Module.Close to Module.CloseWithExitCode(0)
    • Replace wasi.ExitCode with sys.ExitError which is returned to any in-flight callers. This formalizes the concept regardless of WASI.
    • Ensures all "close-once" guards are tested on engines.
    • Reuses the numeric field used for the closed flag to store the exit_code atomically.
    • Weave in exit errors into existing test cases to reduce code heft.

    This also folds the partially maintained WASI RATIONALE into the top-level doc.

  • Is it possible to grow api.Memory programmatically?

    Is it possible to grow api.Memory programmatically?

    There are scenarios where we may grow shared memory programmatically:

    module, _ := v.runtime.InstantiateModuleFromCode(ctx, policy)
    module.Memory().Grow(1) // error: unresolved reference 'Grow'
    

    However, the Grow method is not defined on the api.Memory interface. It's only defined on the internal MemoryInstance struct:

    func (m *MemoryInstance) Grow(newPages uint32) (result uint32) {
    	// [...]
    }
    

    Is it intentionally designed like that, or there is another API to grow shared memory?

  • Add emscripten_notify_memory_growth import?

    Add emscripten_notify_memory_growth import?

    Is your feature request related to a problem? Please describe. Compiling using emscripten requires emscripten_notify_memory_growth, defined at https://emscripten.org/docs/api_reference/emscripten.h.html#abi-functions.

    This is one single function and that is useless for Wazero. That is require for malloc.

    Minimal code:

    # include "stdint.h"
    # include "stdlib.h"
    # include "stdio.h"
    
    uint8_t *InputMemory;
    uint8_t *OutputMemory;
    
    int main() {
        OutputMemory = (uint8_t *) malloc(8000000);
        InputMemory = (uint8_t *) malloc(8000000);
    
        if (InputMemory == NULL || OutputMemory == NULL) {
            printf("Erro");
            return 1;
        } else {
            printf("Okay");
            return 0;
        }
    }
    

    Compile with:

    emcc wasm.c -o wasm.wasm -O3 -s ALLOW_MEMORY_GROWTH
    

    Requires emscripten_notify_memory_growth.

    Describe the solution you'd like Maybe Wazero can define such import, so any emscripten compiled wasm will work without declaring additional modules.

    Describe alternatives you've considered It's possible to fix by using:

        env, _ := host.NewModuleBuilder("env").
            ExportFunction("emscripten_notify_memory_growth", func(_ int32) {}).
            Instantiate(ctx)
    

    That is very small footprint, but very annoying to declare it everytime.

    Additional context Maybe we can do something similar of AssemblyScript and create one new Emscripten package? However, it's very small, maybe can be declared on WASI? But, it's not WASI anyway. :\

  • Add tinygo and rust examples that include memory allocation

    Add tinygo and rust examples that include memory allocation

    Hi, thanks for the awesome project! I was taking a look over examples, but I didn't find an example of passing complex values. I'm sorry if I missed something, but do you have something like this? https://wasmedge.org/book/en/embed/go/memory.html#pass-complex-parameters-to-wasm-functions

  • Add support for sign-extension instructions (post MVP feature)

    Add support for sign-extension instructions (post MVP feature)

    Hello,

    I'm opening this issue to report an error I ran into where it appeared wazero was unable to instantiate an AssemblyScript program compiled with asc.

    Here is the error I got:

    functions: invalid function at index 106/280: invalid instruction
    

    Tools like wasm2wat are able to read through the file without issues, so it appears correct tho I do not know whether they perform checks similar to those in wazero.

    I'm attaching the program that triggered the error: test.wasm.gz

    Let me know if you need any other information.

  • Published version v1.0.0-beta1 takes precedence over v1.0.0-beta.2

    Published version v1.0.0-beta1 takes precedence over v1.0.0-beta.2

    I don't know what caused this, since I see no tag v1.0.0-beta1, but according to semver v1.0.0-beta1 (notice the missing dot) will always take precedence over anything after a dot (like v1.0.0-beta.2).

    https://pkg.go.dev/github.com/tetratelabs/wazero?tab=versions

  • Custom data that is passed to host calls via `HostFunctionCallContext`

    Custom data that is passed to host calls via `HostFunctionCallContext`

    Hello! I am excited about wazero as a means to use Wasm without requiring CGO. Looking forward to ARM64 support!

    I was trying to add wazero as an engine to wapc-go and ran into a small snag. I need the ability to attach custom data to the module instance in order to store function invocation state (context, payload, error, etc). This option is available in other Wasm runtimes and should be easy to add to wazero.

    Envisioned usage:

    Instantiation

    	if err := m.store.Instantiate(m.module, moduleName); err != nil {
    		return nil, err
    	}
    
    	ic := invokeContext{
    		ctx: context.Background(),
    		// ctx and request payload is set prior to calling `store.CallFunction`
                    // response payload or error is set after calling the `hostCallHandler` (below)
    	}
    
    	m.store.SetInstanceData(moduleName, &ic)
    

    Invocation

    func (i *Instance) Invoke(ctx context.Context, operation string, payload []byte) ([]byte, error) {
    	*i.ic = invokeContext{
    		ctx:       ctx,
    		operation: operation,
    		guestReq:  payload,
    	}
    
    	results, _, err := i.m.store.CallFunction(i.name, "__guest_call", uint64(len(operation)), uint64(len(payload)))
    
    	// Inspect response payload or error in `invokeContext`
            // results[0] = 1 for success, 0 for failures
    }
    

    Host call

    func (m *Module) my_host_call(ctx *wasm.HostFunctionCallContext, operationPtr, operationLen, payloadPtr, payloadLen int32) int32 {
    	ic := ctx.Data.(*invokeContext)  // <--- Grabs the custom user data
    	data := ctx.Memory.Buffer
    	operation := string(data[operationPtr : operationPtr+operationLen])
    	payload := make([]byte, payloadLen)
    	copy(payload, data[payloadPtr:payloadPtr+payloadLen])
    
    	ic.hostResp, ic.hostErr = m.hostCallHandler(ic.ctx, operation, payload)
    	if ic.hostErr != nil {
    		return 0
    	}
    
    	return 1
    }
    

    Response payload or error are accessed via other host calls: full example here

  • Support WASI poll_oneoff for clock events

    Support WASI poll_oneoff for clock events

    Is your feature request related to a problem? Please describe. Related to https://github.com/tetratelabs/wazero/issues/271. The following code in Rust causes the following panic.

    std::thread::sleep(time::Duration::from_secs(10));
    
    thread '<unnamed>' panicked at 'thread::sleep(): unexpected result of poll_oneoff', library/std/src/sys/wasi/thread.rs:57:22
    

    Describe the solution you'd like Support for the poll_oneoff WASI method.

  • out of bounds memory access on arm64

    out of bounds memory access on arm64

    Describe the bug Starting in version version v1.0.0-pre.6, on an arm64 host I've started to see this error:

    error instantiating wasm binary: module[] function[_start] failed: wasm error: out of bounds memory access
    wasm stack trace:
          .JS_CallInternal(i32,i64,i64,i64,i32,i32,i32) i64
          .js_link_module(i32,i32) i32
          .JS_EvalFunctionInternal(i32,i64,i64,i32,i32) i64
          .JS_EvalFunction(i32,i64) i64
          .js_std_eval_binary(i32,i32,i32,i32)
          .main(i32,i32) i32
                  0xbe2a2: /build/quickjs-2021-03-27/qjs.c:526:13
          .__main_void() i32
          ._start()
          ._start.command_export()
    

    I did not encounter this in the previous wazero version I was running (v1.0.0-pre.5).

    To Reproduce I unfortunately haven't been able to narrow this down to a small example, but do have a more complex Dockerfile that demonstrates the issue.

    This roughly: downloads quickjs (a small js interpreter in c), patches it for wasi, builds with wasi-sdk and tries to open and close the interpreter with wazero to serve as a basic testcase to demonstrate it works on amd64, but not arm64:

    # syntax=docker/dockerfile:1.4
    
    # Must be amd64 for wasi-sdk-16.0, they have no arm releases.
    FROM --platform=linux/amd64 golang:1.19.3-bullseye AS builder
    ADD https://bellard.org/quickjs/quickjs-2021-03-27.tar.xz /quickjs-2021-03-27.tar.xz
    ADD https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-16/wasi-sdk-16.0-linux.tar.gz /wasi-sdk-16.0-linux.tar.gz
    ADD https://gist.githubusercontent.com/robbertvanginkel/5cb999d5b6fb094bd0d286c644617640/raw/quickjs-wasi.patch /quickjs-wasi.patch
    # Support for "ADD --shasum" only in unreleased dockerfile syntax
    RUN echo "a45bface4c3379538dea8533878d694e289330488ea7028b105f72572fe7fe1a  /quickjs-2021-03-27.tar.xz\n" \
    	 "10df3418485e60b9283c1132102f8d3ca34b4fbe8c4649e30282ee84fe42d788  /wasi-sdk-16.0-linux.tar.gz" | sha256sum -c -
    RUN apt-get update \
     && apt-get install -y xz-utils git libxml2 \
     && rm -rf /var/lib/apt/lists/*
    WORKDIR /build
    RUN tar -xf /quickjs-2021-03-27.tar.xz && tar -xf /wasi-sdk-16.0-linux.tar.gz
    RUN --mount=type=cache,target=/go/pkg/mod go install github.com/tetratelabs/wazero/cmd/[email protected]
    RUN <<EOF
    cd quickjs-2021-03-27 
    git apply /quickjs-wasi.patch
    export 
    WASI_SDK_PATH=/build/wasi-sdk-16.0 bash ./build.sh
    EOF
    RUN echo '\q' | wazero run /build/quickjs-2021-03-27/qjs.wasm
    
    # The line above passes, but not on arm64
    FROM --platform=linux/arm64 golang:1.19.3-bullseye
    COPY --from=builder /build/quickjs-2021-03-27/qjs.wasm /qjs.wasm
    RUN <<EOF
    git clone https://github.com/tetratelabs/wazero && cd wazero
    git bisect start v1.0.0-pre.6 v1.0.0-pre.5
    git bisect run bash -c "go build ./cmd/wazero && echo '\q' | ./wazero run /qjs.wasm"
    git bisect log
    exit 1
    EOF
    

    Building the dockerfile above with docker build . will error with the following bisect log:

    bisect run success
    # bad: [94491fef0b85807f5fa309ad2b98fc2fe6791dec] Implements rename in GOOS=js and WASI (#991)
    # good: [5f7467b3e00a01153ac2d51d5efd3fcfb25c4bc3] Enables debug info (a.k.a. DWARF) by default (#924)
    git bisect start 'v1.0.0-pre.6' 'v1.0.0-pre.5'
    # bad: [69688468f8bfbe81d5eb29064c771e2f2f9ddc96] asm(arm64): adds UDF instruction (#961)
    git bisect bad 69688468f8bfbe81d5eb29064c771e2f2f9ddc96
    # bad: [d63c747d53f9b06d9af0355395c949683f06da6c] asm,compiler: reduce allocations during compilation (#936)
    git bisect bad d63c747d53f9b06d9af0355395c949683f06da6c
    # good: [229b4de678a519999fdda9102cc0e4941e65460a] Deletes encode caches (#934)
    git bisect good 229b4de678a519999fdda9102cc0e4941e65460a
    # good: [b90e9f394c638d4c48bbfb95d655b3fd765c3694] leb128: no allocations in decoding (#941)
    git bisect good b90e9f394c638d4c48bbfb95d655b3fd765c3694
    # good: [1f7f20ee2fec9283ea3c4ba9d4a6e37452ff2bc2] Adds gojs.MustInstantiate to avoid conflicts (#940)
    git bisect good 1f7f20ee2fec9283ea3c4ba9d4a6e37452ff2bc2
    # first bad commit: [d63c747d53f9b06d9af0355395c949683f06da6c] asm,compiler: reduce allocations during compilation (#936)
    #25 13.59 # first bad commit: [d63c747d53f9b06d9af0355395c949683f06da6c] asm,compiler: reduce allocations during compilation (#936)
    

    Pointing to d63c747d53f9b06d9af0355395c949683f06da6c as the regression.

    Expected behavior Arm64 does not fail, but runs like amd64 (also verified the file runs under wasmtime on arm64).

    Screenshots N/A

    Environment (please complete the relevant information):

    • Go version: 1.19.3
    • wazero Version: v1.0.0-pre.6
    • Host architecture: arm64
    • Runtime mode: compiler

    Additional context Initially I was thinking this may have been an error in how I patched the quickjs code, as I was observing this when the code was compiled with -O3 but not -O0. However seeing as it ran on older wazero versions and wasmtime I think it may be a regression on the wazero side after all.

  • Suggestion:  enable discussions on this repo

    Suggestion: enable discussions on this repo

    I've noticed that many issues (including some of my own) are not signaling problems with the Wazero codebase, but instead questions for the community to the effect of "how do I do X?" or "is feature Y supported?".

    I think it would be helpful to enable the discussions feature on this repository for such interactions. In addition to keeping code issues and developer support separate, the discussions feature has the benefit of facilitating search.

  • flakey test: gojs Test_stdio_large

    flakey test: gojs Test_stdio_large

    --- FAIL: Test_stdio_large (0.50s)
    [34](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:35)
        require.go:312: expected "stderr 2097152
    [35](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:36)
            ", but was "fatal error: malloc deadlock
    [36](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:37)
            
    [37](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:38)
            runtime stack:
    [38](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:39)
            runtime.throw({0x6b9ce, 0xf})
    [39](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:40)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/panic.go:1198 +0x7
    [40](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:41)
            runtime.mallocgc(0x10, 0x42cc0, 0x1)
    [41](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:42)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/malloc.go:972 +0xcf
    [42](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:43)
            runtime.newobject(0x42cc0)
    [43](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:44)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/malloc.go:1234 +0x4
    [44](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:45)
            runtime.handleEvent()
    [45](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:46)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/lock_js.go:238 +0x2
    [46](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:47)
            runtime.sysReserve(0x0, 0x800000)
    [47](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:48)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/mem_js.go:68 +0xe
    [48](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:49)
            runtime.sysReserveAligned(0x0, 0x400000, 0x400000)
    [49](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:50)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/malloc.go:805 +0x2
    [50](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:51)
            runtime.(*mheap).sysAlloc(0x329700, 0x400000)
    [51](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:52)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/malloc.go:698 +0x4f
    [52](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:53)
            runtime.(*mheap).grow(0x329700, 0x122)
    [53](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:54)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/mheap.go:1347 +0xa
    [54](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:55)
            runtime.(*mheap).allocSpan(0x329700, 0x122, 0x0, 0x1)
    [55](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:56)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/mheap.go:1179 +0x3b
    [56](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:57)
            runtime.(*mheap).alloc.func1()
    [57](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:58)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/mheap.go:913 +0x6
    [58](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:59)
            runtime.systemstack()
    [59](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:60)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/asm_wasm.s:170 +0x2
    [60](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:61)
            runtime.mstart()
    [61](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:62)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/asm_wasm.s:28
    [62](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:63)
            
    [63](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:64)
            goroutine 1 [running]:
    [64](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:65)
            runtime.systemstack_switch()
    [65](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:66)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/asm_wasm.s:181 fp=0x42ace8 sp=0x42ace0 pc=0x13ac0000
    [66](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:67)
            runtime.(*mheap).alloc(0x329700, 0x122, 0x1, 0x0)
    [67](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:68)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/mheap.go:907 +0x2 fp=0x42ad30 sp=0x42ace8 pc=0x11750002
    [68](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:69)
            runtime.(*mcache).allocLarge(0x350108, 0x244000, 0x0, 0x1)
    [69](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:70)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/mcache.go:227 +0x9 fp=0x42ad90 sp=0x42ad30 pc=0x10ed0009
    [70](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:71)
            runtime.mallocgc(0x244000, 0x0, 0x0)
    [71](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:72)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/malloc.go:1088 +0x8f fp=0x42ae18 sp=0x42ad90 pc=0x10a4008f
    [72](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:73)
            runtime.growslice(0x274c0, {0x500000, 0x1d0000, 0x1d0000}, 0x1d0001)
    [73](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:74)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/slice.go:261 +0x83 fp=0x42ae68 sp=0x42ae18 pc=0x12c60083
    [74](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:75)
            io.ReadAll({0xba820, 0x40c018})
    [75](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:76)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/io/io.go:631 +0x7 fp=0x42aee0 sp=0x42ae68 pc=0x15530007
    [76](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:77)
            github.com/tetratelabs/wazero/internal/gojs/testdata/stdio.Main()
    [77](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:78)
            	/home/runner/work/wazero/wazero/internal/gojs/testdata/stdio/main.go:10 +0x2 fp=0x42af28 sp=0x42aee0 pc=0x1f2f0002
    [78](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:79)
            main.main()
    [79](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:80)
            	/home/runner/work/wazero/wazero/internal/gojs/testdata/main.go:40 +0x2a fp=0x42af88 sp=0x42af28 pc=0x1f34002a
    [80](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:81)
            runtime.main()
    [81](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:82)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/proc.go:255 +0x35 fp=0x42afe0 sp=0x42af88 pc=0x121f0035
    [82](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:83)
            runtime.goexit()
    [83](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:84)
            	/opt/hostedtoolcache/go/1.17.13/x64/src/runtime/asm_wasm.s:431 +0x1 fp=0x42afe8 sp=0x42afe0 pc=0x13d50001
    [84](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:85)
            stderr 2097152
    [85](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:86)
            "
    [86](https://github.com/tetratelabs/wazero/actions/runs/3811321496/jobs/6483930063#step:4:87)
            /home/runner/work/wazero/wazero/internal/gojs/misc_test.go:56
    
  • Document best practices around invoking a wasi module multiple times

    Document best practices around invoking a wasi module multiple times

    Is your feature request related to a problem? Please describe. Not a problem per se, just questions around writing production-grade code with Wazero.

    Context: I have a simple Rust program that looks like this:

    use prql_compiler::compile;
    use std::io::{self, Read};
    
    fn main() {
        // example input is "from employees | select [name,age]  ";
    
        let mut prql = String::new();
        let stdin = io::stdin();
        let mut handle = stdin.lock();
        handle.read_to_string(&mut prql).expect("failed to read input"); // read stdin input
        let sql = compile(&prql).expect("failed to compile"); // transform the input into something else
        println!("{}", sql);
    }
    

    It's been compiled with cargo wasi build --release and produced a binary. Validating it works as expected with wasmtime:

    cat input.prql | wasmtime run target/wasm32-wasi/release/prql-wasi.wasm
    SELECT
      name,
      age
    FROM
      employees
    

    I would like to provide a Go library that embeds this wasm binary. Here's what it currently looks like, with non critical sections elided:

    //go:embed prql-wasi.wasm
    var prqlWasm []byte
    
    // Engine holds a reference to the wazero runtime as well as the pre-compiled wasm module
    type Engine struct {
    	code wazero.CompiledModule
    	r    wazero.Runtime
    }
    
    func (e *Engine) Compile(ctx context.Context, inBuf io.Reader, name string) (string, error) {
    	outBuf := new(bytes.Buffer)
    	errBuf := new(bytes.Buffer)
    	config := wazero.NewModuleConfig().
    		WithStdout(outBuf).WithStderr(errBuf).WithStdin(inBuf)
    
    	mod, err := e.r.InstantiateModule(ctx, e.code, config.WithName(name))
    	if err != nil {
    		if exitErr, ok := err.(*sys.ExitError); ok && exitErr.ExitCode() != 0 {
    			return "", err
    		} else if !ok {
    			return "", &ParseError{Input: "who knows", Err: err}
    		}
    	}
    	mod.Close(ctx)
    	errStream := errBuf.String()
    	if errStream != "" {
    		return "", fmt.Errorf(errStream)
    	}
    	return outBuf.String(), nil
    }
    
    func (e *Engine) Close(ctx context.Context) {
    	e.r.Close(ctx)
    }
    
    func New(ctx context.Context) *Engine {
    
    	r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig())
    	wasi_snapshot_preview1.MustInstantiate(ctx, r)
    	code, err := r.CompileModule(ctx, prqlWasm)
    	if err != nil {
    		log.Panicln(err)
    	}
    
    	return &Engine{
    		r:    r,
    		code: code,
    	}
    }
    

    which would be used like this:

    func main() {
    	ctx := context.Background()
    	p := prql.New(ctx)
    	defer p.Close(ctx)
    
    	content, _ := io.ReadAll(os.Stdin)
    	s := string(content)
    	inBuf := strings.NewReader(s)
           // simulate executing a transformation multiple times
    	for i := 0; i < 500; i++ {
                   name := fmt.Sprintf("run-%d", i)
    		_, err := p.Compile(ctx, inBuf,  name)
                    inBuf.Seek(0, 0)
                    // handle err…
           }
    

    Describe the solution you'd like

    It would be greatly beneficial to have documented best practices around how to optimize running a wasi module multiple times.

    Questions that could benefit from being documented

    What are the best practices around invoking a wasi module multiple times? What are the performance implications of using wasi vs a standard wasm module?

    Is it preferable to close the module each time:

    mod, _ := e.r.InstantiateModule(ctx, e.code, config)
    mod.Close()
    

    or invoking it with a different name without closing it:

    _, err := e.r.InstantiateModule(ctx, e.code, config.WithName(name))
    // is mod.Close() necessary if we use a different name for each invocation?
    

    Additional context Wazero has been extremely fun to build prototypes with, and I'm curious about how to start working on production-grade code. A canonical production ready example would be a great starting point for many new projects.

  • cache: crash on tinygo os package tests.

    cache: crash on tinygo os package tests.

    Describe the bug

    tinygo tests don't currently pass, but if you run with a cachedir on the second run, it panics like this

    $ wazero run -cachedir=$HOME/.wazero -mount=.:/ -env=HOME=.  os.wasm -test.v
    panic: runtime error: nil pointer dereference
    error instantiating wasm binary: module[] function[_start] failed: wasm error: unreachable
    wasm stack trace:
    	.runtime.runtimePanic(i32,i32)
    	.runtime.nilPanic()
    	.(*os.File).Write(i32,i32,i32,i32,i32)
    	.(*os.File).WriteString(i32,i32,i32,i32)
    	.os_test.writeFile(i32,i32,i32,i32,i32,i32)
    	.os_test.TestFstat(i32,i32)
    	.testing.tRunner(i32,i32,i32)
    	.testing.runTests$1(i32,i32)
    	.testing.tRunner(i32,i32,i32)
    	.(*testing.M).Run(i32) i32
    	.runtime.run$1()
    	.runtime.run$1$gowrapper(i32)
    	.tinygo_launch(i32)
    	._start()
    

    Note: I tried simpler wasm and it doesn't panic.

    To Reproduce

    either run from os.wasm.gz or build from a tinygo checkout

    ./build/tinygo test -target wasi -c -o os.wasm os
    

    Expected behavior should have same output

    Screenshots

    If I get the stacktrace from above, it looks like this:

    runtime/debug.Stack()
    	/usr/local/go/src/runtime/debug/stack.go:24 +0x65
    runtime/debug.PrintStack()
    	/usr/local/go/src/runtime/debug/stack.go:16 +0x19
    github.com/tetratelabs/wazero/internal/wasmdebug.(*stackTrace).FromRecovered(0xc0001896b8, {0x124dbe0?, 0xc0000b2390?})
    	/Users/adrian/oss/wazero/internal/wasmdebug/debug.go:1
    17 +0x3c
    github.com/tetratelabs/wazero/internal/engine/compiler.(*callEngine).deferredOnCall(0xc000125200, {0x124dbe0, 0xc0000b2390})
    	/Users/adrian/oss/wazero/internal/engine/compiler/engine.go:758 +0x2ed
    github.com/tetratelabs/wazero/internal/engine/compiler.(*callEngine).Call.func1()
    	/Users/adrian/oss/wazero/internal/engine/compiler/engine.go:650 +0x4d
    panic({0x124dbe0, 0xc0000b2390})
    	/usr/local/go/src/runtime/panic.go:884 +0x212
    github.com/tetratelabs/wazero/internal/engine/compiler.nativeCallStatusCode.causePanic(...)
    	/Users/adrian/oss/wazero/internal/engine/compiler/engine.go:427
    github.com/tetratelabs/wazero/internal/engine/compiler.(*callEngine).execWasmFunction(0xc000125200, {0x13026b8?, 0xc0000b7950?}, 0xc00072cc80)
    	/Users/adrian/oss/wazero/internal/engine/compiler/engine.go:944 +0x7a5
    github.com/tetratelabs/wazero/internal/engine/compiler.(*callEngine).Call(0xc000125200, {0x13026b8?, 0xc0000b7950?}, 0xc0000b91e0?, {0x0?, 0x6?, 0x0?})
    	/Users/adrian/oss/wazero/internal/engine/compiler/engine.go:659 +0x22c
    github.com/tetratelabs/wazero/internal/wasm.(*function).Call(0xc00072cc80?, {0x13026b8?, 0xc0000b7950?}, {0x0?, 0xc0000931e0?, 0x0?})
    	/Users/adrian/oss/wazero/internal/wasm/call_context.go:182 +0x48
    github.com/tetratelabs/wazero.(*namespace).InstantiateModule(0xc0000b39b0, {0x13026b8, 0xc0000b7950}, {0x1302aa0?, 0xc000742420}, {0x13042d0?, 0xc0000fe8c0})
    	/Users/adrian/oss/wazero/namespace.go:102 +0x2d9
    github.com/tetratelabs/wazero.(*runtime).InstantiateModule(0x13026b8?, {0x13026b8?, 0xc0000b7950?}, {0x1302aa0?, 0xc000742420?}, {0x13042d0?, 0xc0000fe8c0?})
    	/Users/adrian/oss/wazero/runtime.go:239 +0x3b
    main.doRun({0xc0000cc020, 0x5, 0x5}, {0x13014a0, 0xc0000c6008}, {0x1302030?, 0xc0000c6010?}, 0x12c3390)
    	/Users/adrian/oss/wazero/cmd/wazero/wazero.go:231 +0xe62
    main.doMain({0x13014a0, 0xc0000c6008}, {0x1302030?, 0xc0000c6010?}, 0x12c3390)
    	/Users/adrian/oss/wazero/cmd/wazero/wazero.go:54 +0x28b
    main.main()
    	/Users/adrian/oss/wazero/cmd/wazero/wazero.go:26 +0x3c
    
  • [Feature Request] Support tracking which

    [Feature Request] Support tracking which "memory pages" are dirty

    Is your feature request related to a problem? Please describe. I'm exploring the possibility of "long running" WASM modules running in a distributed environment. To accomplish this, I'd like to be able to ensure durability of arbitrary WASM programs. I can use the existing Memory interface to "snapshot" the entire memory of the module after every invocation, but that's very expensive. I could log all function invocation requests, but that is also potentially very expensive for some workloads.

    Describe the solution you'd like I'd like to be able to track which "memory pages" have been dirtied since the previous invocation. I've created an experimental POC #968 where all store operations modify a bitset in the host memory indicating that a specific "page" of the WASM module memory has been dirtied for ARM architecture. The P.R is kind of a mess right now, but I think it demonstrates the basic idea. Currently it does this by default, but obviously I would make this an "opt in" feature.

    I think what I'm looking for here is the answer to a few questions:

    1. Does this feature interest you at all? If I was able to implement it for ARM and x86 + make it opt-in so it has 0 cost for workloads that don't use it, and also expose it via some reasonable APIs for user who do opt in to it, would you consider merging it?
    2. Does my implementation make any sense? Is there a better way to accomplish what I want?

    Describe alternatives you've considered I don't really have any other ideas except the expensive ways I described in the first paragraph.

    Additional context N/A

🐹🕸️ WebAssembly runtime for Go
🐹🕸️ WebAssembly runtime for Go

Wasmer Go Website • Docs • Slack Channel A complete and mature WebAssembly runtime for Go based on Wasmer. Features Easy to use: The wasmer API mimics

Jan 2, 2023
🐹🕸️ WebAssembly runtime for Go
🐹🕸️ WebAssembly runtime for Go

Wasmer Go Website • Docs • Slack Channel A complete and mature WebAssembly runtime for Go based on Wasmer. Features Easy to use: The wasmer API mimics

Dec 29, 2022
WebAssembly runtime for wasmer-go
WebAssembly runtime for wasmer-go

gowasmer When compiling Go to WebAssembly, the Go compiler assumes the WebAssembly is going to run in a JavaScript environment. Hence a wasm_exec.js f

Dec 28, 2022
Go compiler for small places. Microcontrollers, WebAssembly, and command-line tools. Based on LLVM.

TinyGo - Go compiler for small places TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and comma

Dec 30, 2022
WebAssembly interop between Go and JS values.

vert Package vert provides WebAssembly interop between Go and JS values. Install GOOS=js GOARCH=wasm go get github.com/norunners/vert Examples Hello W

Dec 28, 2022
WebAssembly for Proxies (Golang host implementation)

WebAssembly for Proxies (GoLang host implementation) The GoLang implementation for proxy-wasm, enabling developer to run proxy-wasm extensions in Go.

Dec 29, 2022
A package to build progressive web apps with Go programming language and WebAssembly.
A package to build progressive web apps with Go programming language and WebAssembly.

Go-app is a package for building progressive web apps (PWA) with the Go programming language (Golang) and WebAssembly (Wasm). Shaping a UI is done by

Dec 30, 2022
A package to build progressive web apps with Go programming language and WebAssembly.
A package to build progressive web apps with Go programming language and WebAssembly.

Go-app is a package for building progressive web apps (PWA) with the Go programming language (Golang) and WebAssembly (Wasm). Shaping a UI is done by

Jan 2, 2023
Vugu: A modern UI library for Go+WebAssembly (experimental)

Vugu: A modern UI library for Go+WebAssembly (experimental)

Jan 3, 2023
A template project to demonstrate how to run WebAssembly functions as sidecar microservices in dapr
A template project to demonstrate how to run WebAssembly functions as sidecar microservices in dapr

Live Demo 1. Introduction DAPR is a portable, event-driven runtime that makes it easy for any developer to build resilient, stateless and stateful app

Jan 3, 2023
Tiny, blazing fast WebAssembly compute

Sat, the tiny WebAssembly compute module Sat (as in satellite) is an experiment, and isn't ready for production use. Please try it out and give feedba

Jan 5, 2023
WebAssembly Lightweight Javascript Framework in Go (AngularJS Inspired)

Tango Lightweight WASM HTML / Javascript Framework Intro WebAssembly is nice, Go on the web is nice, so I ported Tangu to Go and WebAssembly. Tangu is

Dec 20, 2022
Running a Command line tool written in Go on browser with WebAssembly

Running a command line tool written in Go on browser with WebAssembly This repo contains code/assets from the article Files: . ├── article.md

Dec 30, 2022
This library provides WebAssembly capability for goja Javascript engine

This module provides WebAssembly functions into goja javascript engine.

Jan 10, 2022
A Brainfuck to WebAssembly compiler written in Go.

brainfuck2wasm A Brainfuck to WebAssembly compiler written in Go. I am writing this compiler for a Medium article. When I complete the compiler, I'll

Jun 6, 2022
Dom - A Go API for different Web APIs for WebAssembly target

Go DOM binding (and more) for WebAssembly This library provides a Go API for dif

Jan 7, 2023
golang-runtime-di is a framework for runtime dependency injection in go

golang-runtime-di description golang-runtime-di is a framework for runtime dependency injection in go. usage quickstart add it to your go.mod: go get

Aug 1, 2022
Golang-WASM provides a simple idiomatic, and comprehensive API and bindings for working with WebAssembly for Go and JavaScript developers
Golang-WASM provides a simple idiomatic, and comprehensive API and bindings for working with WebAssembly for Go and JavaScript developers

A bridge and bindings for JS DOM API with Go WebAssembly. Written by Team Ortix - Hamza Ali and Chan Wen Xu. GOOS=js GOARCH=wasm go get -u github.com/

Dec 22, 2022
🐹🕸️ WebAssembly runtime for Go
🐹🕸️ WebAssembly runtime for Go

Wasmer Go Website • Docs • Slack Channel A complete and mature WebAssembly runtime for Go based on Wasmer. Features Easy to use: The wasmer API mimics

Jan 2, 2023
🐹🕸️ WebAssembly runtime for Go
🐹🕸️ WebAssembly runtime for Go

Wasmer Go Website • Docs • Slack Channel A complete and mature WebAssembly runtime for Go based on Wasmer. Features Easy to use: The wasmer API mimics

Dec 29, 2022