WebAssembly implementation from scratch in Safe Rust with zero dependencies

Overview

wain

crates.io CI

wain is a WebAssembly INterpreter written in Rust from scratch with zero dependencies. An implementation of WebAssembly.

screencast

Features:

  • No unsafe code. Memory safety and no undefined behavior are guaranteed
  • No external runtime dependency. It means no unsafe dependency and less binary size
  • Efficiency. Avoid unnecessary allocations and run instructions as fast as possible without unsafe code
  • Modular implementation. Binary format parser, text format parser, validator, executor are developed as separate libraries

Note that this project is in progress. Before v1.0.0 means experimental. Not all of the features are implemented yet. Current status is that all the MVP implementations have been done and many tasks are remaining.

Roadmap to v1.0.0 (priority order):

  • Add sufficient tests to all libraries and fuzz tests for parsers
  • Pass all spec tests
  • Add benchmarks to track performance
  • Introduce an intermediate representation to execute instructions more efficiently
  • Add documentation for every public APIs

Please see the task board for current progress.

This project started for fun and understanding Wasm deeply.

Installation

wain crate is not published yet. Please clone this repository and build the project by cargo build.

Minimum supported Rust version is 1.45.0.

$ cargo install wain
$ wain --help

If you don't want to run text format code, it can be omitted:

# Only run binary format files
$ cargo install wain --no-default-features --features binary

Usage

wain command

Run a binary format Wasm source file:

$ wain examples/hello/hello.wasm
Hello, world

Run a text format Wasm source file:

$ wain examples/hello/hello.wat
Hello, world

Without argument, wain command detects both binary format and text format from stdin and runs the input.

$ wain < examples/hello/hello.wasm
Hello, world
$ wain < examples/hello/hello.wat
Hello, world

Please see examples directory for more examples.

Current restrictions are as follows:

  • Only int putchar(int) and int getchar() are implemented as external functions by default
  • wain can run only one module at once. It means that importing things from other modules does not work yet
  • Many extensions like threads, WASI support, SIMD support, ... are not implemented yet

As libraries

wain consists of multiple crates.

  • wain: Command line tool to execute given Wasm sources
  • wain-ast: Abstract syntax tree definition. Implementation of Wasm structure spec. This syntax tree is common for both binary format and text format
  • wain-syntax-binary: Parser for Wasm binary format (.wasm files). Implementation for Wasm binary format spec. It parses &[u8] value into wain_ast::Root abstract syntax tree
  • wain-syntax-text: Parser for Wasm text format (.wat files). Implementation for Wasm text format spec. It parses &str value into wain_ast::Root abstract syntax tree
  • wain-validate: Validator of a Wasm abstract syntax tree. Implementation of Wasm validation spec
  • wain-exec: Executor which interprets a Wasm abstract syntax tree. Implementation of Wasm execution spec. It directly interprets a syntax tree for now, but in the it would translate the tree into an intermediate representation to execute it efficiently

wain-* crates are libraries as modular implementation of WebAssembly. They can parse, validate, execute WebAssembly code.

Here is an example code to run the interpreter from Rust.

extern crate wain_syntax_binary;
extern crate wain_validate;
extern crate wain_exec;

use std::fs;
use std::process::exit;
use wain_syntax_binary::parse;
use wain_validate::validate;
use wain_exec::execute;

// Read wasm binary
let source = fs::read("foo.wasm").unwrap();

// Parse binary into syntax tree
let tree = match parse(&source) {
    Ok(tree) => tree,
    Err(err) => {
        eprintln!("Could not parse: {}", err);
        exit(1);
    }
};

// Validate module
if let Err(err) = validate(&tree) {
    eprintln!("This .wasm file is invalid!: {}", err);
    exit(1);
}

// Execute module
if let Err(trap) = execute(&tree.module) {
    eprintln!("Execution was trapped: {}", trap);
    exit(1);
}

Or invoke specific exported function with arguments

// ...(snip)

use wain_exec::{Runtime, DefaultImporter, Value};
use std::io;

// Create default importer to call external function supported by default
let stdin = io::stdin();
let stdout = io::stdout();
let importer = DefaultImporter::with_stdio(stdin.lock(), stdout.lock());

// Make abstract machine runtime. It instantiates a module
let mut runtime = match Runtime::instantiate(&tree.module, importer) {
    Ok(m) => m,
    Err(err) => {
        eprintln!("could not instantiate module: {}", err);
        exit(1);
    }
};

// Let's say `int add(int, int)` is exported
match runtime.invoke("add", &[Value::I32(10), Value::I32(32)]) {
    Ok(ret) => {
        // `ret` is type of `Option<Value>` where it contains `Some` value when the invoked
        // function returned a value. Otherwise it's `None` value.
        if let Some(Value::I32(i)) = ret {
            println!("10 + 32 = {}", i);
        } else {
            unreachable!();
        }
    }
    Err(trap) => eprintln!("Execution was trapped: {}", trap),
}

By default, only following C functions are supported in env module as external functions

  • int putchar(int) (in wasm (func (param i32) (result i32)))
  • int getchar(void) (in wasm (func (param) (result i32)))
  • void *memcpy(void *, void *, size_t) (in wasm (func (param i32 i32 i32) (result i32)))
  • void abort(void) (in wasm (func (param) (result)))

But you can implement your own struct which implements wain_exec::Importer for defining external functions from Rust side.

extern crate wain_exec;
extern crate wain_ast;
use wain_exec::{Runtime, Stack, Memory, Importer, ImportInvokeError, ImportInvalidError}
use wain_ast::ValType;

struct YourOwnImporter {
    // ...
}

impl Importer for YourOwnImporter {
    fn validate(&self, name: &str, params: &[ValType], ret: Option<ValType>) -> Option<ImportInvalidError> {
        // `name` is a name of function to validate. `params` and `ret` are the function's signature.
        // Return ImportInvalidError::NotFound when the name is unknown.
        // Return ImportInvalidError::SignatureMismatch when signature does not match.
        // wain_exec::check_func_signature() utility is would be useful for the check.
    }
    fn call(&mut self, name: &str, stack: &mut Stack, memory: &mut Memory) -> Result<(), ImportInvokeError> {
        // Implement your own function call. `name` is a name of function and you have full access
        // to stack and linear memory. Pop values from stack for getting arguments and push value to
        // set return value.
        // Note: Consistency between imported function signature and implementation of this method
        // is your responsibility.
        // On invocation failure, return ImportInvokeError::Fatal. It is trapped by interpreter and it
        // stops execution immediately.
    };
}

let ast = ...; // Parse abstract syntax tree and validate it

let mut runtime = Runtime::instantiate(&ast.module, YourOwnImporter{ /* ... */ }).unwrap();
let result = runtime.invoke("do_something", &[]);

To know the usage of APIs, working examples are available at examples/api/.

Future works

  • WASI support
  • Wasm features after MVP support (threads, SIMD, multiple return values, ...)
  • Compare benchmarks with other Wasm implementations
  • Self-hosting interpreter. Compile wain into Wasm and run it by itself

How it works

Here I note some points on each phase of interpretation.

Parsing

Sequence to parse Wasm

wain-syntax-binary parses .wasm binary file into wain_ast::Root abstract syntax tree following binary format spec. Wasm binary format is designed to be parsed by basic LL(1) parser. So parsing is very straightforward. Parser implementation is smaller than 1000 lines.

In contrast, implementation of parsing text format is more complicated. wain-syntax-text parses .wat text file into wain_ast::Root abstract syntax tree following text format spec.

  1. Lex and parse .wat file into WAT sytnax tree which is dedicated for text format resolving many syntax sugars. Since multiple modules can be put in .wat file, it can be parsed into multiple trees
  2. Translate the WAT syntax trees into common Wasm syntax trees (wain_ast::Root) resolving identifiers. Identifiers may refer things not defined yet (forward references) so .wat file cannot be parsed into common Wasm syntax trees directly
  3. Compose a single module from the multiple Wasm syntax trees following spec

Validation

Validation is done by traversing a given Wasm syntax tree in wain-validate crate. Conforming spec, following things are validated:

  • In Wasm, every reference is an index. It validates all indices are not out of bounds
  • Wasm is designed to check stack operations statically. It validates instructions sequences with emulating stack state
  • Type check is best-effort due to polymorphic instruction select. Since almost all instructions are not polymorphic, almost all type checks can be done in validation

Conforming the spec, wain validates instructions after unreachable instruction. For example,

(unreachable) (i64.const 0) (i32.add)

i32.add is invalid because it should take two i32 values from stack but at least one i64 value is in the stack.

Execution

wain-exec crate interprets a Wasm syntax tree conforming spec. Thanks to validation, checks at runtime are minimal (e.g. function signature on indirect call).

  1. Allocate memory, table, global variables. Initialize stack
  2. Interpret syntax tree nodes pushing/popping values to/from stack

Currently wain interprets a Wasm syntax tree directly. I'm planning to define intermediate representation which can be interpreted faster.

Entrypoint is 'start function' which is defined either

  1. Function set in start section
  2. Exported function named _start in export section

The 1. is a standard entrypoint but Clang does not emit start section. Instead it handles _start function as entrypoint. wain implements both entrypoints (1. is prioritized).

License

the MIT license

Comments
  • Fix import check

    Fix import check

    All imports must occur before any regular definition of a function, table, memory, or global.

    cf. https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A0%E2%91%A2

    Passed new 12 tests.

    before

    End ".../wain/spec-test/wasm-testsuite/imports.wast":
      total: 150, passed: 22, failed: 128, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19393, failed: 235, skipped: 129
    

    before

    End ".../wain/spec-test/wasm-testsuite/imports.wast":
      total: 150, passed: 34, failed: 116, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19405, failed: 223, skipped: 129
    
    opened by kariya-mitsuru 22
  • Refactor validate

    Refactor validate

    バリデーションをちょっとリファクタリングしました。

    FuncBodyContext::op_stackVec<Type> 型だったのですが、スタックに Type::Unknown が置かれるのは unreachable な時の現在のフレームのスタックの一番下にたかだか1つだけなので、op_stack の型を Vec<ValType> に変更して、CtrlFrame::has_unknown というフィールドを作りました。

    opened by kariya-mitsuru 13
  • [crash] unwrap panic while parsing invalid wasm module

    [crash] unwrap panic while parsing invalid wasm module

    Hey,

    Found this bug while doing some testing. The module is invalid because the version is missing from the wasm header.

    thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: TryFromSliceError(())', /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wain-syntax-binary-0.1.2/src/parser.rs:241:61
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    

    Download: unwrap_panic_wain.zip

    $ hexdump -C unwrap_panic_wain.wasm
    00000000  00 61 73 6d                                       |.asm|
    00000004
    
    bug 
    opened by pventuzelo 9
  • Fix instantiate

    Fix instantiate

    Move invoking start function from execute method to instantiate method. Change assert_trap to match the above changes.

    Passed new 6 tests.

    before

    End ".../wain/spec-test/wasm-testsuite/start.wast":
      total: 21, passed: 12, failed: 9, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19426, failed: 202, skipped: 129
    

    after

    End ".../wain/spec-test/wasm-testsuite/start.wast":
      total: 21, passed: 18, failed: 3, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19432, failed: 196, skipped: 129
    
    opened by kariya-mitsuru 9
  • [crash] memory allocation failed error during parsing

    [crash] memory allocation failed error during parsing

    Hey,

    Just triggered this memory allocation bug. Don't know if your cargo-fuzz was able to catch it so I prefer to open an issue anyway ;)

    $ ./target/debug/wain alloc_failed_wain.wasm
    memory allocation of 23477014352 bytes failed[1]    10077 abort (core dumped)  ./target/debug/wain alloc_failed_wain.wasm
    
    

    Download: alloc_failed_wain.zip

    backtrace from gdb

    #0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
    #1  0x00007ffff71e1801 in __GI_abort () at abort.c:79
    #2  0x0000555555711a37 in std::sys::unix::abort_internal () at src/libstd/sys/unix/mod.rs:167
    #3  0x000055555570f62d in rust_oom () at src/libstd/alloc.rs:282
    #4  0x000055555572a9a7 in alloc::alloc::handle_alloc_error () at src/liballoc/alloc.rs:307
    #5  0x00005555556a273c in alloc::raw_vec::RawVec<T,A>::reserve (self=0x7fffffffac38, used_capacity=0, 
        needed_extra_capacity=266784254)
        at /rustc/49cae55760da0a43428eba73abcb659bb70cf2e4/src/liballoc/raw_vec.rs:345
    #6  0x00005555556b19a9 in alloc::vec::Vec<T>::reserve (self=0x7fffffffac38, additional=266784254)
        at /rustc/49cae55760da0a43428eba73abcb659bb70cf2e4/src/liballoc/vec.rs:500
    #7  0x00005555556a52cd in <wain_ast::Module as wain_syntax_binary::parser::Parse>::parse (
        parser=0x7fffffffd650) at wain-syntax-binary/src/parser.rs:325
    #8  0x0000555555683827 in wain_syntax_binary::parser::Parser::parse (self=0x7fffffffd650)
        at wain-syntax-binary/src/parser.rs:126
    #9  0x00005555556a2be2 in <wain_ast::Root<wain_syntax_binary::source::BinarySource> as wain_syntax_binary::parser::Parse>::parse (parser=0x7fffffffd650) at wain-syntax-binary/src/parser.rs:218
    #10 0x0000555555683707 in wain_syntax_binary::parser::Parser::parse (self=0x7fffffffd650)
        at wain-syntax-binary/src/parser.rs:126
    #11 0x00005555556806c8 in wain_syntax_binary::parse (input=...) at wain-syntax-binary/src/lib.rs:16
    #12 0x00005555555930cb in wain::run_binary (bin=...) at src/main.rs:150
    #13 0x00005555555933f1 in wain::main () at src/main.rs:179
    
    opened by pventuzelo 6
  • Fix constant expression

    Fix constant expression

    A constant expression should contain exactly one instruction. Moreover, global.get of a constant expression cannot refer any mutable global variables.

    before

    End ".../wain/spec-test/wasm-testsuite/globals.wast":
      total: 79, passed: 75, failed: 4, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/global.wast":
      total: 82, passed: 78, failed: 4, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19393, failed: 235, skipped: 129
    

    after

    End ".../wain/spec-test/wasm-testsuite/globals.wast":
      total: 79, passed: 76, failed: 3, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/global.wast":
      total: 82, passed: 79, failed: 3, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19395, failed: 233, skipped: 129
    
    opened by kariya-mitsuru 4
  • Fix hex-float parse

    Fix hex-float parse

    Passed new 52 tests.

    before

    End ".../wain/spec-test/wasm-testsuite/const.wast":
      total: 767, passed: 707, failed: 60, skipped: 0
    
    Results of 76 files:
      total: 19740, passed: 18662, failed: 882, skipped: 196
    

    after

    End ".../wain/spec-test/wasm-testsuite/const.wast":
      total: 767, passed: 759, failed: 8, skipped: 0
    
    Results of 76 files:
      total: 19740, passed: 18714, failed: 830, skipped: 196
    
    opened by kariya-mitsuru 4
  • Fix constant expression

    Fix constant expression

    Only imported global variables should be used in a constant expression.

    Passed new 4 tests.

    before

    End ".../wain/spec-test/wasm-testsuite/globals.wast":
      total: 79, passed: 76, failed: 3, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/global.wast":
      total: 82, passed: 79, failed: 3, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19426, failed: 202, skipped: 129
    

    after

    End ".../wain/spec-test/wasm-testsuite/globals.wast":
      total: 79, passed: 78, failed: 1, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/global.wast":
      total: 82, passed: 81, failed: 1, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19430, failed: 198, skipped: 129
    
    opened by kariya-mitsuru 3
  • Fix TypeUse

    Fix TypeUse

    Inline parameter and result declaration without typeidx should insert type definition at the last of module.

    Inline parameter and result declaration with typeidx should check consistency.

    Passed new 10 tests.

    before

    End ".../wain/spec-test/wasm-testsuite/func.wast":
      total: 130, passed: 124, failed: 6, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/call_indirect.wast":
      total: 153, passed: 149, failed: 4, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19416, failed: 212, skipped: 129
    

    after

    End ".../wain/spec-test/wasm-testsuite/func.wast":
      total: 130, passed: 130, failed: 0, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/call_indirect.wast":
      total: 153, passed: 153, failed: 0, skipped: 0
    
    Results of 76 files:
      total: 19757, passed: 19426, failed: 202, skipped: 129
    
    opened by kariya-mitsuru 3
  • Fix trunc instruction

    Fix trunc instruction

    The instruction inn.trunc_fmm_sx should cause trap if source value cannot be represented by target type.

    Note: The old implementations of cast functions are renamed and preserved for future use. (Wasm 1.1 has the instruction inn.trunc_sat_fmm_sx that should use these functions.)

    Passed new 75 tests.

    before

    End ".../wain/spec-test/wasm-testsuite/conversions.wast":
      total: 436, passed: 369, failed: 67, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/traps.wast":
      total: 37, passed: 29, failed: 8, skipped: 0
    
    Results of 76 files:
      total: 19740, passed: 19046, failed: 498, skipped: 196
    

    after

    End ".../wain/spec-test/wasm-testsuite/conversions.wast":
      total: 436, passed: 436, failed: 0, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/traps.wast":
      total: 37, passed: 37, failed: 0, skipped: 0
    
    Results of 76 files:
      total: 19740, passed: 19121, failed: 423, skipped: 196
    
    opened by kariya-mitsuru 3
  • Fix string handling

    Fix string handling

    1. string cannot contain control characters.
    2. hex escape like "\80" represents a byte, not a unicode character.

    Passed new 250 tests.

    before

    End ".../wain/spec-test/wasm-testsuite/names.wast":
      total: 487, passed: 411, failed: 76, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/utf8-invalid-encoding.wast":
      total: 177, passed: 1, failed: 176, skipped: 0
    
    Results of 76 files:
      total: 19740, passed: 18796, failed: 748, skipped: 196
    

    after

    End ".../wain/spec-test/wasm-testsuite/names.wast":
      total: 487, passed: 485, failed: 2, skipped: 0
    
    End ".../wain/spec-test/wasm-testsuite/utf8-invalid-encoding.wast":
      total: 177, passed: 177, failed: 0, skipped: 0
    
    Results of 76 files:
      total: 19740, passed: 19046, failed: 498, skipped: 196
    
    opened by kariya-mitsuru 3
  • Resource limits

    Resource limits

    Once an execution is started, as a caller I have no control over the amount of memory and CPU time that is being used. Do you think it would be reasonable to

    • allow setting hard limits that will make additional allocations fail
    • stop the execution after a certain number of instructions?

    The execution limit could potentially be made possible without any such limit existing in the engine by exposing more internal api so instead of just invoking invoke and waiting for the result, some API for driving each step could be exposed.

    enhancement 
    opened by oli-cosmian 3
Owner
Linda_pp
int main() { return (U'ω'); } // A dog enjoying software development (with bug)
Linda_pp
Zero-cost high-level lua 5.3 wrapper for Rust

td_rlua This library is a high-level binding for Lua 5.3. You don't have access to the Lua stack, all you can do is read/write variables (including ca

null 47 May 4, 2022
Lunatic based webserver embedding WASM. Supports scaling down to zero and up to infinity.

Frenezulo A WASM-embedding webserver build on top of submillisecond and lunatic. Build to serve as an entry point for microservices compiled to WASM.

Kai Jellinghaus 13 Oct 23, 2022
zzhack-cli is a Command Tool to help you quickly generate a WASM WebApp with simple configuration and zero code

English | 中文文档 zzhack-cli is a Command Tool that can help you quickly generate a WASM WebApp with simple configuration and zero code. It's worth menti

null 17 Feb 9, 2023
A notebook app integrated with todo lists utility. Developed with Rust, WebAssembly, Yew and Trunk.

Flow.er A notebook app integrated with todo-list utility. Project flow.er is a Rust WASM app running in browser. Taking advantage of Yew and Trunk, it

null 45 Dec 31, 2022
witgen is a library to generate .wit files for WebAssembly in Rust

witgen witgen is a library to help you generate wit definitions in a wit file for WebAssembly. Using this lib in addition to wit-bindgen will help you

Coenen Benjamin 28 Nov 9, 2022
Build frontend browser apps with Rust + WebAssembly. Supports server side rendering.

Percy Build frontend browser apps with Rust + WebAssembly. Supports server side rendering. The Percy Book This README gives a light introduction to Pe

Chinedu Francis Nwafili 2.1k Jan 1, 2023
Rust bindings for Supabase JavaScript library via WebAssembly.

supabase-js-rs Rust bindings for Supabase JavaScript library via WebAssembly. Usage Add supabase-js-rs to Cargo.toml supabase-js-rs = { version = "0.1

Valery Stepanov 8 Jan 13, 2023
plugy empowers you to construct agnostic dynamic plugin systems using Rust and WebAssembly.

plugy plugy is a plugin system designed to enable the seamless integration of Rust-based plugins into your application. It provides a runtime environm

Geoffrey Mureithi 22 Aug 12, 2023
Let's pretend that life-before-main exists for Rust targeting WebAssembly

Let's pretend that life-before-main exists for Rust targeting WebAssembly. Installation Add a dependency on wasm-init. This crate intentionally provid

Ruan Pearce-Authers 7 Aug 29, 2023
Code for my workshop "Production-ready WebAssembly with Rust" presented at RustLab 2023 in Florence

Workshop: Production-ready WebAssembly with Rust A workshop on Rust for WebAssembly by Alberto Schiabel (@jkomyno). ?? This workshop was first present

Alberto Schiabel 14 Nov 23, 2023
A 3D bin packing library in Rust/WebAssembly.

packme-wasm Demo https://packme.vercel.app This repository hosts an implementation of Dube, E., & Kanavathy L. (2006). Optimizing Three-Dimensional Bi

Ade Yahya Prasetyo 17 Feb 25, 2024
NPM package distributing biscuit in WebAssembly for web components

Biscuit playground This is an example application for Biscuit tokens, where you can manipulate tokens and their verification in your browser. build wi

null 0 Dec 30, 2021
`wasm-snip` replaces a WebAssembly function's body with an `unreachable`

wasm-snip wasm-snip replaces a Wasm function's body with an unreachable instruction. API Docs | Contributing | Chat Built with ?? ?? by The Rust and W

Rust and WebAssembly 177 Dec 28, 2022
WebAssembly (Wasm) interpreter.

Continuous Integration Test Coverage Documentation Crates.io wasmi- WebAssembly (Wasm) Interpreter wasmi was conceived as a component of parity-ethere

Parity Technologies 1k Jan 4, 2023
Dependency solver for Elm, made in WebAssembly

Dependency solver for Elm, made in WebAssembly This repo holds a dependency solver for the elm ecosystem compiled to a WebAssembly module. The wasm mo

Matthieu Pizenberg 3 Jun 16, 2022
A simple code for checking crate 'prost' on WebAssembly (🦀 + 🕸️ = 💖)

rust-wasm-prost This repository is a simple code for checking crate 'prost' on WebAssembly ( ?? + ??️ = ?? ). What is prost? prost is a Protocol Buffe

Chris Ohk 6 Apr 5, 2022
Version of Clue made to be compilable in WebAssembly (WIP)

Clue is a programming language that compiles into Lua code with a syntax similar to languages like C or Rust. Clue tries to be almost as simple as Lua

Clue 2 Jun 16, 2022
Vite + Webassembly starter project

Vite + Typescript+ Webassembly A starter project for you to create a blazingly fast web application Before getting started You need to get these prere

Saugi 9 Aug 18, 2022
Mod_wasm - an extension module for the Apache HTTP Server (httpd) that enables the usage of WebAssembly (Wasm).

mod_wasm is an extension module for the Apache HTTP Server (httpd) that enables the usage of WebAssembly (Wasm). This module will allow to execute certain tasks in the backend in a very efficient and secure way.

VMware  Labs 67 Dec 21, 2022