Skip to content

0.2a0

Pre-release
Pre-release

Choose a tag to compare

@simonw simonw released this 01 Oct 17:10
3398e81

pwasm can now run real programs compiled from C. This release bundles WebAssembly builds of MicroPython, QuickJS and Micro QuickJS, so you can run untrusted Python or JavaScript in a sandbox with memory, CPU and time limits, using nothing but Python. #12

from pwasm.guests import MicroPython, QuickJS

mp = MicroPython(timeout=2.0)
print(mp.exec("print([x * x for x in range(5)])"))  # [0, 1, 4, 9, 16]

js = QuickJS(max_memory=32 * 1024 * 1024)
print(js.eval("[1, 2, 3].map(x => x * 2)"))  # [2, 4, 6]

Running untrusted code

  • New pwasm.guests module with MicroPython, QuickJS and MQuickJS classes. Guests can call Python functions you register, return results decoded from JSON, and raise PythonError or JSError for guest exceptions.
  • New pwasm.sandbox.Sandbox class for running your own modules. It handles import resolution, WASI and resource limits, and provides alloc(), free() and call() helpers for moving data in and out.
  • Resource limits: pass limits=Limits(fuel=..., max_memory=...) to instantiate() and call limits.set_deadline() for wall-clock timeouts. Two new exceptions, OutOfFuel and Timeout, are both subclasses of TrapError. Instances without limits pay no overhead for these checks.
  • pwasm.wasi.WasiLite is a small WASI preview1 implementation. It covers captured stdout/stderr, stdin, clocks, randomness, arguments and environment variables. It has no filesystem or network access.
  • pwasm.emscripten.EmscriptenSjLj implements the invoke_* trampolines needed by C code compiled with emscripten-style setjmp/longjmp.

WebAssembly support

  • pwasm now implements the full WebAssembly 2.0 core instruction set except SIMD. That includes i64, f32 and f64 arithmetic, conversions, sign extension, saturating truncation, multi-value, bulk memory, tables, call_indirect and reference types.
  • The non-SIMD WebAssembly 2.0 core spec test suite is now vendored and runs in CI.
  • Modules can import Python functions, memories, globals and tables, including ones exported by other instances. Function references can be called from Python.
  • decode_module() now accepts bytearray and memoryview as well as bytes.

Performance

  • New compile-to-Python tier: hot functions are translated into Python source code, which typically runs 8 to 14 times faster than the interpreter. instantiate() has a new mode= argument that takes "auto" (the default), "compile" or "interpret".
  • Compiled code is cached on disk in ~/.cache/pwasm, so later processes start much faster. For example, QuickJS start-up drops from about 1.3s to 0.1s. Set PWASM_CACHE_DIR to change the location, or set it to an empty string to disable the cache.
  • The interpreter now compiles each function to flat code with branches resolved ahead of time. This builds on the parallel-array and super-instruction optimizations from #11.

Other changes

  • pwasm now runs on PyPy. CI tests PyPy 3.11 as well as CPython 3.10 through 3.14.
  • The executor has been rewritten. Internal helpers such as pwasm.executor.execute_function() and to_i32() have been removed. MemoryInstance and GlobalInstance now live in pwasm.runtime.
  • The wheel is now about 650KB because it includes the three guest .wasm files.

Release notes by Claude Opus 5.5