๐Ÿš€ The fastest WebAssembly interpreter, and the most universal runtime

Overview

Wasm3

WAPM GitHub issues Tests status Fuzzing Status GitHub license

The fastest WebAssembly interpreter, and the most universal runtime.
Based on CoreMark 1.0 and independent benchmarks. Your mileage may vary.

Twitter Discord Telegram

Getting Started

Here's a small getting started guide. Click here to start:

LIVE DEMO

Installation

Please follow the installation instructions.

Wasm3 can also be used as a library for:

Python3 โ”‚ Rust โ”‚ C/C++ โ”‚ GoLang โ”‚ Zig
Swift โ”‚ .Net โ”‚ Arduino, PlatformIO, Particle โ”‚ QuickJS

Status

wasm3 passes the WebAssembly spec testsuite and is able to run many WASI apps.

Minimum useful system requirements: ~64Kb for code and ~10Kb RAM

wasm3 runs on a wide range of architectures (x86, x86_64, ARM, RISC-V, PowerPC, MIPS, Xtensa, ARC32, ...) and platforms:

  • Linux, Windows, OS X, FreeBSD, Android, iOS
  • OpenWrt, Yocto, Buildroot (routers, modems, etc.)
  • Raspberry Pi, Orange Pi and other SBCs
  • MCUs: Arduino, ESP8266, ESP32, Particle, ... see full list
  • Browsers. Yes, using WebAssembly itself!
  • wasm3 can execute wasm3 (self-hosting)

Features

Webassembly Core Proposals Extra
โ˜‘ Import/Export of Mutable Globals โ˜‘ Structured execution tracing
โ˜‘ Non-trapping float-to-int conversions โ˜‘ Big-Endian systems support
โ˜‘ Sign-extension operators โ˜‘ Wasm and WASI self-hosting
โ˜‘ Multi-value โ˜‘ Gas metering
โ˜‘ Bulk memory operations (partial support) โ˜‘ Linear memory limit (< 64KiB)
โ˜ Multiple memories
โ˜ Reference types
โ˜ Tail call optimization
โ˜ Fixed-width SIMD
โ˜ Exception handling

Motivation

Why use a "slow interpreter" versus a "fast JIT"?

In many situations, speed is not the main concern. Runtime executable size, memory usage, startup latency can be improved with the interpreter approach. Portability and security are much easier to achieve and maintain. Additionally, development impedance is much lower. A simple library like Wasm3 is easy to compile and integrate into an existing project. (Wasm3 builds in a just few seconds). Finally, on some platforms (i.e. iOS and WebAssembly itself) you can't generate executable code pages in runtime, so JIT is unavailable.

Why would you want to run WASM on embedded devices?

Wasm3 started as a research project and remains so by many means. Evaluating the engine in different environments is part of the research. Given that we have Lua, JS, Python, Lisp, ... running on MCUs, WebAssembly is actually a promising alternative. It provides toolchain decoupling as well as a completely sandboxed, well-defined, predictable environment. Among practical use cases we can list edge computing, scripting, plugin systems, running IoT rules, smart contracts, etc.

Used by

ใ€€ ใ€€ ใ€€ ใ€€ ใ€€ ใ€€ ใ€€ ใ€€

Further Resources

Demos
Installation instructions
Cookbook
Troubleshooting
Build and Development instructions
Supported Hardware
Testing & Fuzzing
Performance
Interpreter Architecture
Logging
Awesome WebAssembly Tools

License

This project is released under The MIT License (MIT)

Comments
  • GUI support

    GUI support

    Hi,

    I've just discovered this project and I really like that it can run on MCUs too.

    I'm from LVGL and I wonder if you are interested in integrating a UI engine into wasm3.

    help wanted backlog discussion 
    opened by kisvegabor 37
  • Question: memory allocation inside wasm module

    Question: memory allocation inside wasm module

    Every time I trying to use something complex in wasm sources I got "WASM3 error: restricted opcode".

    For example std:string in cpp:

    #include <string>
    extern "C" {
        #define WASM_EXPORT __attribute__((used)) __attribute__((visibility ("default")))
       
        extern void exPrint(const char* str);
        
        WASM_EXPORT
        void printHello() {
            std::string helloString {"Hello From Wasm!"};
            exPrint(helloString.c_str());
        }
    }
    

    compiled with emcc src.cpp -o src.wasm -s STANDALONE_WASM -s ERROR_ON_UNDEFINED_SYMBOLS=0 -O0 --no-entry

    Or Array<> in typescript:

    declare function exSendInt8Array(len : i32) : void;
    
    export function getInt8Array() : void {
      let arr = new Array<i8>(100)
      for (let i:i8 = 0; i < arr.length; i++) {
        arr[i] = i;
      }
      exSendInt8Array(arr.length)
    }
    

    compiled with asc src.ts --binaryFile src.wasm --optimize

    Is it a problem of compiling WASM? Or I have to attach every single libraries by hand?

    I've seen m3_api_lib.c where is m3_LinkLibC function. But do I have to create the similar for all libraries that is used in my WASM sourcec?

    Looks like this problem connected whith allocating on a heap commands / instructions, cause I also have the same problem with malloc...

    I will be grateful for any help

    opened by skrphv 25
  • Memory issues on ESP32 (Arduino)?

    Memory issues on ESP32 (Arduino)?

    By simply invoking String.UTF8.encode(someStr) from the sample I'm receiving a panic on my ESP32 developer board. Any suggestions?

    Guru Meditation Error: Core  1 panic'ed (IllegalInstruction). Exception was unhandled.
    Core 1 register dump:
    PC      : 0x746e656d  PS      : 0x00060d30  A0      : 0x800d25a3  A1      : 0x3ffb1bf0  
    A2      : 0x3ffb2068  A3      : 0x000000fb  A4      : 0x3f4010dc  A5      : 0x3ffb1c30  
    A6      : 0x05010007  A7      : 0x00000000  A8      : 0x800d24c5  A9      : 0x400d1a60  
    A10     : 0x3ffb2068  A11     : 0x000000fb  A12     : 0x3f401b74  A13     : 0xffffffff  
    A14     : 0x3f401b74  A15     : 0x000000e2  SAR     : 0x00000020  EXCCAUSE: 0x00000000  
    EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000  
    
    opened by onionhammer 25
  • NodeMCU examples throw errors

    NodeMCU examples throw errors

    About two weeks ago, we were able to run several WebAssembly modules on NodeMCU ESP microcontrollers following the esp32-pio and esp8266 platform examples.

    In the meanwhile, work on wasm3 has clearly continued - we are particularly happy with the WASI support!

    I am, however, now unable to run our WASM modules using the latest code base. For instance, on adapting the esp8266 example as follows:

    #include <stdio.h>
    
    #include "Arduino.h"
    
    #define FATAL(msg, ...) { printf("Fatal: " msg "\n", ##__VA_ARGS__); return; }
    
    #include "m3/m3.h" 
    #include "m3/m3_env.h"
    
    #include "m3/extra/fib32.wasm.h"
    
    void run_wasm()
    {
        M3Result result = c_m3Err_none;
    
        uint8_t* wasm = (uint8_t*)fib32_wasm;
        size_t fsize = fib32_wasm_len-1;
    
        IM3Environment env = m3_NewEnvironment ();
        if (!env) FATAL("m3_NewEnvironment failed");
    
        IM3Runtime runtime = m3_NewRuntime (env, 64*1024, NULL);
        if (!runtime) FATAL("m3_NewRuntime failed");
    
        IM3Module module;
        result = m3_ParseModule (env, &module, wasm, fsize);
        if (result) FATAL("m3_ParseModule: %s", result);
    
        result = m3_LoadModule (runtime, module);
        if (result) FATAL("m3_LoadModule: %s", result);
        
        /*result = m3_LinkWASI (runtime->modules);
        if (result) FATAL("m3_LinkWASI: %s", result); 
        
        result = m3_LinkLibC (runtime->modules);
        if (result) FATAL("m3_LinkLibC: %s", result);*/
        
        IM3Function f;
        result = m3_FindFunction (&f, runtime, "fib");
        if (result) FATAL("m3_FindFunction: %s", result);
    
        const char* i_argv[2] = { "3", NULL };
        result = m3_CallWithArgs (f, 1, i_argv);
    
        if (result) FATAL("Call: %s", result);
    
        long value = *(long*)(runtime->stack);
    
        Serial.println(value);
    
    }
    
    void setup()
    {
      Serial.begin(115200);
      delay(10);
    
      Serial.print("\nwasm3 on ESP8266, build " __DATE__ " " __TIME__ "\n");
    
      u32 start = millis();
      run_wasm();
      u32 end = millis();
    
      Serial.print(String("Elapsed: ") +  (end - start) + " ms\n");
    }
    
    void loop()
    {
      delay(100);
    }
    

    ... one of our ESP8266's throws the following error:

    wasm3 on ESP8266, build Dec 27 2019 18:59:05
    Fatal: m3_NewRuntime failed
    Elapsed: 6 ms
    

    Also, updating the code of the esp32-pio example along the same lines throws a Guru Meditation error, followed by a boot loop.

    Might it be possible to provide a minimal working example that runs, for instance, fib32_wasm on ESP8266 and ESP32 using the latest version of wasm3?

    (Separately, linking WASI gives rise to the following error on the ESP8266: /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/time/clock.c:62: undefined reference to _times_r ... but that is of course a different issue)

    opened by robinvanemden 24
  • Self-hosting

    Self-hosting

    Bring wasm3 to a level where it can run itself. JFF ;)

    Actions list:

    • [x] Improve interpreter so it can execute itself
    • [x] Build in 32-bit mode (normal native x86 build) and fix spec tests
    • [x] Build wasm3.wasm
    • [x] Improve test script so we can run spec tests on wasm3.wasm
    • [x] Fix spec tests for wasm3.wasm
    • [x] Fix imported (native) function calls
    • [x] Implement MetaWASI (redirect WASI calls to the host WASI environment)
    • [x] Run WASI apps in self-hosted mode
    • [x] Run spec tests in self-hosted mode
    research 
    opened by vshymanskyy 17
  • Example interacting with hardware peripherals

    Example interacting with hardware peripherals

    All the platforms use the same fib32.wasm.h but I haven't found an example that interacts with the hardware peripherals like GPIO. Is that possible, even if with a bit of wasm<>C++ glue code? I could imagine something like wasm-bindgen be helpful here, or Interface Types when that's ready. But for now blinking an LED would be great :)

    opened by beriberikix 16
  • Backtraces in Wasm3

    Backtraces in Wasm3

    This PR adds the ability to print and also to obtain via the API backtraces when a trap is encountered during WASM execution, for this issue: https://github.com/wasm3/wasm3/issues/190

    $ ./wasm3 panic_test.wasm
    thread '<unnamed>' panicked at 'Argh!', src/lib.rs:14:9
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    Error: [Fatal] repl_call: [trap] unreachable executed
    wasm backtrace:
      0: 0x45c2 - .unnamed!__rust_start_panic
      1: 0x43e3 - .unnamed!rust_panic
      2: 0x4059 - .unnamed!_ZN3std9panicking20rust_panic_with_hook17h072472ae3822b936E
      3: 0x342 - .unnamed!_ZN3std9panicking11begin_panic28_$u7b$$u7b$closure$u7d$$u7d$17h071e97ff39f73a93E
      4: 0x309 - .unnamed!_ZN3std10sys_common9backtrace26__rust_end_short_backtrace17hef704c5aa373cc3aE
      5: 0x38d - .unnamed!_ZN3std9panicking11begin_panic17hec272784e336dab5E
      6: 0x2d0 - .unnamed!_ZN10panic_test3bar3baz17h1cc59b36f6073eaaE
      7: 0x2b9 - .unnamed!_ZN10panic_test3foo17hfc394019100935fbE
      8: 0x2b0 - .unnamed!_start
    Error: [trap] unreachable executed ()
    

    There are two main parts to this PR:

    1. Reporting function frames when a trap is encountered to the runtime
    2. Creating a mapping back from VM code to WASM bytecode offset

    Reporting function frames is done by the addition of a new field on the M3Runtime struct for holding backtrace information. This seems like the simplest and least-invasive method since within an instruction we don't have access to too much context, but we do have a pointer back to the runtime. The basic idea is that when a trap occurs, the stack will look like this:

    +-----------+
    | trap site |
    +-----------+
    |  op_Entry |
    +-----------+
    |  op_Call  |
    +-----------+
    |  op_Entry |
    +-----------+
    |  op_Call  |
    +-----------+
    |  op_Entry |
    +-----------+
    |    ...    |
    

    The trap site and all the op_Calls have the relevant program counter that we actually want to report to the backtrace frame, and the op_Entrys have the relevant M3Function that the trap site/op_Call is in. So when a trap is encountered, we push a new backtrace frame onto the runtime before returning the trap, and when unwinding through op_Call we check to see if we actually have a trap, and push a backtrace frame if so. When we unwind through an op_Entry, we check to see if we actually have a trap, and then fill in the function information on the last backtrace frame if so.

    Since this only happens when a trap is encountered and we have to check the return value anyway in op_Call and op_Entry instructions the effect on performance should hopefully be minimal.

    The second part is mapping the program counter back into WASM byte offsets. I've done kind of the most naive thing I can think of here, which is to allocate some space for this along with every code page and then store the mapping there. The current implementation wastes far too much memory unnecessarily so I'm very open to ideas for how to do this in a better way.

    Otherwise, the method for generating the mapping entries is fairly simple - I store the byte offset just before every single opcode on the M3Compilation struct, and when an opcode is emitted I use that byte offset to emit an entry. This also generates the correct mapping for bridge instructions.

    opened by t-veor 14
  • Implement stack access API

    Implement stack access API

    We need to come up with some stack access API, as currently we can only get function results by tampering with the stack directly. I.e. this has to be revised: https://github.com/wasm3/wasm3/blob/99bdcabdcd06c278d3ffd290348effb2f7b8fbbd/platforms/arduino/src/main.cpp#L48-L55

    Please comment if you have any suggestions on the API.

    feature API 
    opened by vshymanskyy 13
  • platforms/esp32-idf: make the code compile, add build test, cleanup

    platforms/esp32-idf: make the code compile, add build test, cleanup

    • esp32-idf: Remove unneeded files
    • Simplify main.c, remove leftovers from IDF hello-world example
    • Sync ESP32 examples for IDF and PIO, check in CI that the source is kept the same
    • Add a build job for esp32-idf
    • Run the test in QEMU for esp32
    opened by igrr 13
  • Invalid execution of optimized smallpt binary

    Invalid execution of optimized smallpt binary

    ./wasm3 smallpt-ex.wasm 4 32 | sha1sum Produces (correctly) ea05d85998b2f453b588ef76a1256215bf9b851c

    However if smallpt-ex.wasm is build with -O3 or -Os flags, it produces wrong output. With -O2 or -Oz, it works as expected. They all execute fine in wasmer.

    Pre-built binaries: smallpt.zip

    bug 
    opened by vshymanskyy 12
  • WIP: PoC: an alternative to tail calls (for Xtensa)

    WIP: PoC: an alternative to tail calls (for Xtensa)

    As pointed out in https://github.com/wasm3/wasm3/issues/28#issuecomment-569831125, Xtensa port suffers from lack of tail call optimization in the compiler. Tail calls are possible on the ESP8266 (but not implemented in GCC) and aren't possible on the ESP32, due to the ABI limitation.

    This PR aims to provide an alternative to tail calls as means of chaining primitive operations.

    The idea is to modify the operation function signature as follows:

    m3_ret_struct_t OP(pc_t _pc, u64 * _sp, m3reg_t _r0, f64 _fp0);
    

    where return structure m3_ret_struct_t has the same layout (in registers) as the input arguments:

    typedef struct {
        union {
            pc_t pc;
            m3ret_t err;
        };
        m3stack_t sp;
        m3reg_t r0;
        f64 fp0;
    } m3_ret_struct_t;
    

    No tail calls are performed, instead all the operations are called from the following loop:

        while (true) {
            m3_ret_struct_t rs = ((IM3Operation) *_pc)(_pc+1, _sp, _r0, _fp0);
            _pc = rs.pc;
            _sp = rs.sp;
            _r0 = rs.r0;
            _fp0 = rs.fp0;
            if (_sp == NULL) {
                return rs.err;
            }
        }
    

    Zero/non-zero _sp is used to indicate whether execution should be continued (operation wants a tail call) or the loop should return (operation wants to return).

    The theory (which I haven't tested yet) is that the C loop above can be implemented in a few assembly instructions. This is because the return values after function call are already in the right registers. So we only need to check if _sp is zero, increment the PC, and jump to the PC again.

    At the moment this modification seems to pass the spec tests.

    Another change is converting _mem into a global value. This is needed to make the operation arguments fit into the registers, as on Xtensa only 6 32-bit registers are used for argument passing. The rest of the arguments would have to be spilled onto the stack. If necessary, _mem can be made thread-local instead of global.

    opened by igrr 12
  • Giving control of memory allocation/resize to user code

    Giving control of memory allocation/resize to user code

    Would it be possible to pass a MemoryResize callback to M3Runtime, so that the memory allocation strategy can be controlled from user side?

    E.g. my current use case is reserving 4gb of virtual memory upfront with mmap, and committing new pages only when memory needs to grow.

    This both avoids an unnecessary copy and guarantees that memory addresses are stable, so I can actually provide a native memory allocator on the embedder side and expose it to wasm code (instead of compiling the allocator to wasm).

    For now I just hacked in my own callback and user pointer in M3Runtime, but it would be nice to have an 'official' API. I can clean it up and submit a PR if you think this is useful.

    opened by martinfouilleul 0
  • Contributing `wasm-c-api`

    Contributing `wasm-c-api`

    I wanted to check if wasm3 would be open to accepting wasm-c-api patches if Google were to contribute the implementation?

    I am not making any promises though. Our project is very interested in adopting wasm3 as the runtime of choice but we prefer to standardize on wasm-c-api for VM management.

    If you have reservations about wasm-c-api, please share them with us. Perhaps we can address whatever issues there are.

    feature API 
    opened by bald-man 1
  • Update to wasm spec: data/element segments cannot access internal globals

    Update to wasm spec: data/element segments cannot access internal globals

    See https://github.com/WebAssembly/spec/issues/1522. It seems that there wasn't an explicit test for this case, and wasm3's current behavior will be incorrect.

    e.g.

    (memory 1)
    (global i32 (i32.const 0)
    (data (global.get 0) "")
    

    should be invalid, because a data segment initializer can't reference a non-imported global.

    bug 
    opened by binji 0
  • `wasm3` app: validate input parameters format

    `wasm3` app: validate input parameters format

    Steps to reproduce

    It is related to https://github.com/wasmerio/wasmer/issues/857. The demo.wasm is uploaded as demo-wasm.txt. demo-wasm.txt

    wasm3 --func fib demo.wasm abc

    Environment

    wasm3 0.5.0 macOS10.15 and ubuntu20.04

    Expected result

    outputs an error message of requiring digit parameter but give string.

    Actual result

    Result: 0

    improvement app 
    opened by Zhangyx24 0
  • Clone a parsed module that has not been loaded to a runtime

    Clone a parsed module that has not been loaded to a runtime

    When running very short workloads, the time spent in the m3_ParseModule can be significant, or even most of the execution time. This can be mitigated by being able to save a parsed module, and then only call m3_LoadModule on deep copies of it.

    Reusing the runtime is not an option because I have many modules with the same interfaces, and state can not be allowed to "leak" between runs of modules, even if the same module is run twice.

    feature 
    opened by reuvenpo 0
Releases(v0.5.0)
Owner
Wasm3 Labs
Wasm3 Labs
C++ WebAssembly assembler

wasmblr A single header file WebAssembly assembler. This library makes it easier to generate web assembly binaries directly from C++. Useful for JIT c

Bram Wasti 142 Sep 9, 2022
๐ŸŒฑLight and powerful C++ web framework for highly scalable and resource-efficient web application. It's zero-dependency and easy-portable.

Oat++ News Hey, meet the new oatpp version 1.2.5! See the changelog for details. Check out the new oatpp ORM - read more here. Oat++ is a modern Web F

Oat++ 5.7k Sep 22, 2022
C++ application development framework, to help developers create and deploy applications quickly and simply

ULib - C++ library Travis CI: Coverity Scan: ULib is a highly optimized class framework for writing C++ applications. I wrote this framework as my too

stefano casazza 948 Sep 17, 2022
Pistache is a modern and elegant HTTP and REST framework for C++

Pistache is a modern and elegant HTTP and REST framework for C++. It is entirely written in pure-C++17* and provides a clear and pleasant API.

null 2.8k Sep 21, 2022
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.

Welcome! The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design

Microsoft 7k Sep 20, 2022
Crow is very fast and easy to use C++ micro web framework (inspired by Python Flask)

Crow is C++ microframework for web. (inspired by Python Flask) #include "crow.h" int main() { crow::SimpleApp app; CROW_ROUTE(app, "/")([]()

Jaeseung Ha 7k Sep 24, 2022
C library to create simple HTTP servers and Web Applications.

Onion http server library Travis status Coverity status Onion is a C library to create simple HTTP servers and Web Applications. master the developmen

David Moreno Montero 1.9k Sep 21, 2022
C++ Parallel Computing and Asynchronous Networking Engine

ไธญๆ–‡็‰ˆๅ…ฅๅฃ Sogou C++ Workflow As Sogou`s C++ server engine, Sogou C++ Workflow supports almost all back-end C++ online services of Sogou, including all sea

Sogou-inc 9.2k Sep 21, 2022
a very based, minimal, and flexible static site generator written in pure C89 with no external deps.

based-ssg is a very based, minimal, and flexible static site generator written in pure C89 with no external deps.

null 14 Aug 15, 2022
cserv is an event-driven and non-blocking web server

cserv is an event-driven and non-blocking web server. It ideally has one worker process per cpu or processor core, and each one is capable of handling thousands of incoming network connections per worker. There is no need to create new threads or processes for each connection.

null 42 Sep 14, 2022
This is a proof-of-concept of a modern C web-framework that compiles to WASM and is used for building user interfaces.

DanCing Web ?? ?? (DCW) Getting Started Dancing Web is now distributed with the Tarantella Package Manager โ€” a tool I've made to simplify setup of pro

Danilo Chiarlone 3 Sep 11, 2021
wwasm (Wgmlgz wasm) - is a c++ & reactjs liblary for connecting c++ backend and reactjs frontend.

WWASM (Wgmlgz wasm) - is a c++ & reactjs liblary for connecting c++ backend and reactjs frontend.

null 1 Nov 23, 2021
Python bindings for Wasm3, the fastest WebAssembly interpreter

pywasm3 Python bindings for Wasm3, the fastest WebAssembly interpreter Main repository: Wasm3 project Install # Latest release: pip3 install pywasm3

Wasm3 Labs 47 Aug 8, 2022
โœ”๏ธThe smallest header-only GUI library(4 KLOC) for all platforms

Welcome to GUI-lite The smallest header-only GUI library (4 KLOC) for all platforms. ไธญๆ–‡ Lightweight โœ‚๏ธ Small: 4,000+ lines of C++ code, zero dependenc

null 6.4k Sep 21, 2022
hashcat is the world's fastest and most advanced password recovery utility

hashcat is the world's fastest and most advanced password recovery utility, supporting five unique modes of attack for over 300 highly-optimized hashing algorithms. hashcat currently supports CPUs, GPUs, and other hardware accelerators on Linux, Windows, and macOS, and has facilities to help enable distributed password cracking.

null 15.4k Sep 25, 2022
LAppS - Lua Application Server for micro-services with default communication over WebSockets. The fastest and most vertically scalable WebSockets server implementation ever. Low latency C++ <-> Lua stack roundtrip.

LAppS - Lua Application Server This is an attempt to provide very easy to use Lua Application Server working over WebSockets protocol (RFC 6455). LApp

null 47 Apr 25, 2022
FastFormat - The fastest, most robust C++ formatting library

FastFormat The fastest, most robust C++ formatting library Git access to the FastFormat formatting library (C++) FastFormat is an extremely fast, 100%

null 51 Jul 12, 2022
A WebAssembly interpreter written in C for demonstration.

wasmc ไธญๆ–‡ๆ–‡ๆกฃ A WebAssembly interpreter written in C for demonstration. This repository implements a WebAssembly interpreter. It is written to clarify ho

ๆนฎ่ฟœ 54 Jul 25, 2022