Skip to content

v1.0.0

Choose a tag to compare

@dy dy released this 02 Nov 15:08
· 264 commits to main since this release

1.0 is a contract: jz, compile, instantiate, jz/interop, the options and the CLI flags change only in a major version, and an accepted program keeps JavaScript's values, exceptions and evaluation order at every optimization level, outside the listed differences.

Breaking

  • JS semantics where 0.9 diverged: strings are UTF-16 ('中'.length is 1, was 3), integers no longer wrap at 2³¹, null.x throws, a[1.5] is undefined, catch (e) gets the thrown Error.
  • The root exports jz (with jz.memory), compile and instantiate only; compileModule, transform, jz.pool, jz/wasi and jz/transform are gone.
  • Options are a closed set: an unknown key throws a TypeError naming it. optimize takes true, false, 'size', 'speed' or { level, simd, tailCall, exceptions, alloc, compact, rationalConst } (no 0–3); memory settings live in memory: { initial, maximum, shared, import, fixed }.
  • instantiate(wasm, { imports, memory, wasi }) links what the module declares and refuses the rest by name.
  • exports holds the program's exports alone; jz's own are named __jz_* on instance.exports.
  • An exported class is a class (new mod.C()); an exported value is its live binding (exports.K, not .value).
  • A thrown value reaches the host as thrown: throw 5 arrives as 5, an Error as the host's Error of its class. Early errors are SyntaxError.
  • A memory has the constructors, read, write, reset and used, nothing else; allocTyped is gone.
  • warnings is a callback of { code, message, file, line, column, fn }; why replaces whyNotSimd.
  • CLI: -O0, -O2, -O3, -Os or -O '{…}'; --why replaces --why-not-simd; a dozen 0.9 flags are gone (jz --help lists what stays).
  • .wasm built by 0.9 needs a rebuild: load a prebuilt module with the jz/interop of the jz that built it.

New

  • Memory comes back: a call frees on return what it allocated and did not keep, a loop each iteration, and replaced state is compacted. 20,000 calls that each build and drop 200 strings hold 1.1 MB, where 0.9.2 grew to 512 MB.
  • try/catch/finally across await and yield, getters and setters, await using, resizable ArrayBuffer.
  • Under the JS host, undeclared names are the host's globals (new Response(s), typeof WebSocket), and console.log prints as the host's console does.
  • memory: { fixed: ['process'] } proves the named exports allocation-free, or fails the compile with the call path.
  • Source maps: sourceMap: true, --source-map.
  • A --host wasi module is a WASI command (_start runs the program, then its own _start, then its timers) or a reactor when it exports _initialize; instantiate runs it in a JS host through wasi: { write, read }.
  • node scripts/native/compile.mjs app.js -o app (repo checkout) builds a native executable through wasm2c; --no-simd output needs no SIMD library.
  • Newly compiling: three.js's math layer (unmodified), web-audio-api (120 modules), @stdlib's math and distribution functions, guest271314's WebSocket server.

Faster, smaller

  • Reference run at the release commit (run 41439115302, AMD EPYC 9V45, 91 cases, 52 in 0.9.2), geomean of rival time over jz time: V8 2.44× over 83 cases, JavaScriptCore 1.98× (83); against each case's nearest wasm rivals, clang→wasm 1.86× (33), rustc→wasm 1.86× (30), AssemblyScript 2.00× (19). -Os output is 0.79× AssemblyScript's bytes over the 51 cases both compile.
  • Not ahead on that run: watr and jz compiling itself (every JS engine), vm (JSC 0.94×, clang→wasm 0.96×, bun 0.98×), threecull (Deno 0.96×), strbuild (zig→wasm 0.985×), hashjoin (bun 0.994×), webaudio (JSC 0.997×). fabrik, polytri and stdlib-exp carry no claim yet.

Fixed

  • Wrong answers 0.9.2 gave without an error: an array lost === and Map-key identity once it grew, an inherited static read undefined, x instanceof pick(k) read false, for-of over a host Set ran zero times, flat(2) flattened one level, 'hello'.substr(-3, 2) was empty.
  • new Array(3e9) throws a RangeError where its length read 2147483647; try catches what o.m?.() throws.
  • A void export returns undefined on bun and Safari, not NaN; a Symbol reaches the host as a Symbol, not NaN.
  • Warnings name the program's own identifiers and positions, not compiler-minted names.

Full Changelog: v0.9.2...v1.0.0