You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Answer "why not Rust, Go, or C" with the measured numbers
The old answer conceded the ground ("excellent when a rewrite makes sense"),
argued from preference ("the hot path you want to keep"), and undersold the
result as "comparable". The bench corpus says otherwise: wasm from rustc,
clang and zig runs about 2× behind JZ by geomean and Go's over 4×, and their
native binaries still trail, with native C level. Say that, on the site and
in the README's comparison bullet.
Copy file name to clipboardExpand all lines: README.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -253,8 +253,10 @@ JavaScript's bounds checks.
253
253
to Porffor's native artifact on speed or size per case or by geomean.
254
254
-**[scriptc](https://github.com/vercel-labs/scriptc)** also AOT-compiles typed JS/TS without an engine (TS annotations → LLVM), embedding QuickJS only as an opt-in fallback for dynamic code. It is native-first with WASI as a target; JZ is WASM-first, infers types from idiomatic untyped JS, and keeps dynamic fallbacks inside the WASM module.
255
255
-**[AssemblyScript](https://github.com/AssemblyScript/assemblyscript)** produces lean WASM, but is not directly executable JavaScript.
256
-
-**Rust, C, Zig, Go, and MoonBit** offer explicit static types and mature native
257
-
toolchains, but require a second implementation when the source of truth is JS.
256
+
-**Rust, C, Zig, Go, and MoonBit** compiled to wasm run behind JZ by geomean on
257
+
the corpus: rustc, clang and zig about 2×, Go and MoonBit over 4×. As native
258
+
binaries Rust, Zig and Go still trail and C is level, so a rewrite buys a
259
+
second toolchain and test suite for slower wasm.
258
260
-**[Javy](https://github.com/bytecodealliance/javy)** and
Copy file name to clipboardExpand all lines: index.html
+13-12Lines changed: 13 additions & 12 deletions
Original file line number
Diff line number
Diff line change
@@ -1349,8 +1349,8 @@ <h1>JS as it is<br class="hb">to native speed</h1>
1349
1349
<pathd="M6 9l6 6 6-6" />
1350
1350
</svg></summary>
1351
1351
<divclass="ans prose">
1352
-
<p>JZ compiles a distilled JavaScript subset, Crockford’s “good parts” – into native-grade WASM.</p>
1353
-
<p><b>Valid JZ is valid JS</b>. Same source runs as plain JS or compiles without rewrite to <code>.wasm</code> – sandboxed, portable, memory-safe. No runtime, no GC, no type annotations, auto-SIMD, deterministic output.</p>
1352
+
<p>JZ compiles a JavaScript subset into native-grade WASM.</p>
1353
+
<p><em>Valid JZ is valid JS</em>: same source runs as plain JS or compiles to <code>.wasm</code> – sandboxed, portable, memory-safe. No runtime, no GC, no type annotations, auto-SIMD, deterministic output.</p>
1354
1354
<table>
1355
1355
<thead>
1356
1356
<tr>
@@ -1361,23 +1361,23 @@ <h1>JS as it is<br class="hb">to native speed</h1>
1361
1361
<tbody>
1362
1362
<tr>
1363
1363
<td>DSP, audio, synthesis</td>
1364
-
<td>UI, DOM, frontend state</td>
1364
+
<td>UI, DOM, frontend</td>
1365
1365
</tr>
1366
1366
<tr>
1367
1367
<td>Images, video, pixels</td>
1368
-
<td>Network, hot I/O, serving HTTP</td>
1368
+
<td>Network, hot I/O, serving</td>
1369
1369
</tr>
1370
1370
<tr>
1371
1371
<td>Simulation, physics, games</td>
1372
-
<td>Dynamic object models and monkey-patching</td>
<spanclass="t">eval Function with</span><spanclass="t">Proxy Reflect</span><spanclass="t">descriptors</span><spanclass="t">prototype chains</span><spanclass="t">top-level await</span><spanclass="t">import()</span><spanclass="t">DOM</span><spanclass="t">Node Intl Temporal</span>
1401
1400
</div>
1402
1401
</div>
1403
-
<p>And what differs: no GC (call <code>memory.reset()</code>), 64-bit BigInt, compile-time regexes, ASCII case and UTC dates. <ahref="https://github.com/dy/jz#faq" target="_blank" rel="noopener">Details →</a></p>
<p>What differs: no GC (call <code>memory.reset()</code>), 64-bit BigInt, compile-time regexes, ASCII case and UTC dates. <ahref="https://github.com/dy/jz#faq" target="_blank" rel="noopener">Details →</a></p>
<divclass="ans prose">Ordinary code already carries useful type evidence: <code>let x = 0.5</code>, <code>Float32Array</code>, an array index, a loop counter. JZ infers it instead of turning the file into another language. Ambiguous values take a slower, always-correct dynamic path.</div>
1411
+
<divclass="ans prose">JS code already carries useful type evidence: <code>let x = 0.5</code>, <code>Float32Array</code>, an array index, a loop counter. JZ infers it instead of turning the file into another language. Ambiguous values take a slower, always-correct dynamic path.</div>
1412
1412
</details>
1413
1413
1414
1414
@@ -1417,7 +1417,7 @@ <h1>JS as it is<br class="hb">to native speed</h1>
1417
1417
<pathd="M6 9l6 6 6-6" />
1418
1418
</svg></summary>
1419
1419
<divclass="ans prose">
1420
-
<p>Porffor aims to cover the full JS spec but emits no WASM (its 2026 rewrite compiles through C to native) and runs slower than V8 on the <ahref="bench/">cases</a> it completes; scriptc makes native CLI binaries from TypeScript, no WASM target; AssemblyScript compiles a typed TypeScript dialect to WASM.</p>
1420
+
<p>Porffor aims to cover the full JS spec but emits no WASM and runs slower than V8 on the <ahref="bench/">cases</a> it completes; scriptc makes native CLI binaries from TypeScript, no WASM target; AssemblyScript compiles a typed TypeScript dialect to WASM.</p>
1421
1421
<p>JZ compiles plain JS that still runs and tests as JS, and the release gate keeps its WASM fastest per case; the price is the overdynamic constructs it refuses.</p>
1422
1422
</div>
1423
1423
</details>
@@ -1427,7 +1427,8 @@ <h1>JS as it is<br class="hb">to native speed</h1>
1427
1427
<pathd="M6 9l6 6 6-6" />
1428
1428
</svg></summary>
1429
1429
<divclass="ans prose">
1430
-
<p>Rust, Go, and C are excellent when a rewrite and second toolchain make sense. JZ is for the hot path you want to keep in JavaScript: one source, one test suite, a JS fallback, and comparable WASM or <ahref="#native">native</a> performance.</p>
1430
+
<p>If it is already Rust, keep it in Rust. If it is JavaScript, a rewrite buys a second language, toolchain and test suite, a marshalling boundary on every call, and slower wasm: on the <ahref="bench/">corpus</a>, rustc, clang and zig output runs about 2× behind JZ by geomean, and Go's over 4×.</p>
1431
+
<p>Their native binaries do not change the picture: Rust, Zig and Go still trail JZ's wasm by geomean, and C is level.</p>
0 commit comments