Measure Wado's performance or the size of the Wasm it generates, and refresh the benchmark/ and wasm-size/ README files. Use for any benchmarking or size-measurement request, whichever benchmark it names.
日本語の概要は準備中です。原文の説明を表示しています。
Transpile Wado Wasm components to JS with jco, then run, debug, and benchmark them on Node. Use for anything that involves jco, Node, or a browser as the host.
日本語の概要は準備中です。原文の説明を表示しています。
実行スコア 未検証
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
jco (bytecodealliance) transpiles a Wasm component into JS + core Wasm so it runs on a plain Wasm engine (V8/Node, browsers) instead of a Component Model runtime. Wado targets WASI P3; this doc covers what the released jco does for Wado today and what is still blocked.
scripts/jco, mise run jco-*).-f no-wide-arithmetic — V8 has no wide-arithmetic
proposal, and float formatting / i128 emit it._setPreopens (see below).mise run jco-hello-released. Benchmark:
mise run jco-bench <program.wado>.WebAssembly.Suspending), so no flag is needed; the repo pins node = "26"
in mise.toml. Node 24 needs --experimental-wasm-jspi; Node 22's older JSPI
fails (WebAssembly.Suspending is not a constructor)./tmp pitfall: outside the repo, node may resolve to a system Node 22
(mise activation is path-scoped). Run inside the repo, or use the pinned
binary's absolute path.-f no-wide-arithmetic (see below).scripts/jco)Released @bytecodealliance/jco as a library. transpile-released.mjs is a
plain transpile() — jco's own preview3-shim serves every import a Wado
program makes, and the output links to it through a node_modules symlink the
script writes beside the files.
The shim writes stdout from a worker that is torn down once the event loop
empties, so lines still queued when run() resolves are lost, and a runner that
calls process.exit on that promise loses more. Hold the loop open for a
second after run() resolves. The lines of one run can also arrive out of
order.
A program that reads files needs a preopen. Set it before importing the
transpiled module, mapping the guest's . to a host directory as
wado run --dir <dir>::. does:
import { _setPreopens } from "@bytecodealliance/preview3-shim/filesystem";
_setPreopens({ ".": "/abs/host/dir" });
const m = await import("./out/prog.js");
await m.run.run();
await new Promise((r) => setTimeout(r, 1000));
Import the shim the output links to through its node_modules symlink. A
second copy of the shim holds its own preopen table, which the program never
reads.
mise tasks:
mise run jco-deps # npm install released jco under scripts/jco
mise run jco-transpile-released foo.wasm [out-dir]
mise run jco-hello-released # compile + transpile + run hello on Node
mise run jco-bench <program.wado> [runs] # compile -f no-wide-arithmetic, transpile, self-time
| Capability | Status |
|---|---|
| Transpile (GC component) | ✅ works, wasi:http/service included |
| JSPI | ✅ native (Node 26 no flag; Node 24 needs the flag) |
| Wide-arithmetic component | ❌ transpile rejects it (wide arithmetic support is not enabled); even if forced, V8 rejects the opcode at runtime → use -f no-wide-arithmetic |
| Stdout via stream | ✅ jco's own shim delivers it, if the runner holds the event loop open after run() resolves |
| Filesystem read stream | ✅ reads through a preopen set with _setPreopens (zlib benchmark verified) |
-f no-wide-arithmetic)Wado emits the Wasm wide-arithmetic proposal (i64.mul_wide_u/s, i64.add128,
i64.sub128) for float formatting (core:prelude/fpfmt.wado) and i128. No
V8 implements it (checked through Node 26; no flag, --wasm-staging no help),
so any component containing those opcodes fails WebAssembly.compile with
invalid numeric opcode: 0xfc16.
-f no-wide-arithmetic rewrites each such builtin call, before NIR, to a
32-bit-limb software form in core:rt (i64_mul_wide_u_soft and so on;
wado-compiler/src/lower/wide_arith.rs). NIR and WIR then show ordinary calls,
which the optimizer inlines. Compile every Node-bound Wado program with this
flag — a bare println of a float needs it.
BA ships a preview3-shim implementing P3 cli / clocks / filesystem /
http, with a browser build beside the Node one. A plain jco transpile wires
it, and stdout, float formatting, wasi:random, MonotonicClock and an HTTP
handle all run through it unaided. Its browser cli is unimplemented
(throw new Todo()), which is why the playground keeps a hand-written one.
A hand-written clock is where precision goes missing: system-clock.now is an
instant carrying sub-second nanoseconds, and get-resolution a bare duration.
mise run jco-bench <program.wado> [runs] compiles with -f no-wide-arithmetic,
transpiles via the released pipeline, and runs the program self-timed runs
times (default 3; keep the best). The benchmark programs already self-time via
core:benchmark + MonotonicClock and print their own
throughput line, so no host timing is needed.
JCO_PREOPEN names the host directory granted as the program's . (default:
the repository root). The benchmarks read their data relative to benchmark/:
mise run jco-bench benchmark/mandelbrot/mandelbrot.wado
JCO_PREOPEN=benchmark mise run jco-bench benchmark/zlib/zlib_bench.wado
| Benchmark | Wado on Node (jco) | Wado on wasmtime |
|---|---|---|
| mandelbrot | ~4.0 M px/s | ~4.2 M |
| sieve | ~150 M numbers/s | ~64 M (V8 ~2.3× faster) |
| fts | ~12 M conv/s | — |
| zlib compress | ~65 MB/s | — |
| zlib decompress | ~220 MB/s | — |
The Node column is mise run jco-bench <program.wado> as above; the wasmtime
column is wado run -O2 <program.wado> from benchmark/, as
benchmark/mise.toml runs it.
Compute throughput on V8 lands within ~5–10% of wasmtime (sieve is much faster on V8). Numbers are indicative on a noisy cloud VM; keep best-of-3.
The other filesystem benchmarks (json-{twitter,canada,catalog}, sqlite-parse, syntax-highlight, cbor) load their data the same way, outside the timed loop, but have not been run on Node yet.
Not jco. Handled by -f no-wide-arithmetic.
An instance serves a couple of calls, then the next suspends on a stream read
whose host injection is never driven (JCO_DEBUG=1 ends at
[StreamEnd#copy()] blocked). cloudflare-worker/ builds one per request.
Transpiled output is one large JS file. Useful canonical-builtin → JS mappings:
| Wasm builtin | jco JS function | Notes |
|---|---|---|
stream.write | streamWrite() | JSPI Suspending |
stream.read | streamRead() | JSPI Suspending |
canon lower (async) | _lowerImportBackwardsCompat() | JSPI Suspending |
task.return | taskReturn() | |
future.new (lift) | _genStreamHostInjectFn / createReadableStreamEnd | host→guest wiring |
Catch swallowed errors — jco's async machinery loses errors as unhandled rejections:
process.on('unhandledRejection', e => { console.error('UNHANDLED:', e); process.exit(1); });
JCO_DEBUG=1 node run.mjs — verbose trace of every instruction/trampoline.
A trailing [ComponentAsyncState#suspendTask()] with no progress = a
rendezvous deadlock.
Inject logging by string-replacing a function header in the transpiled JS
(e.g. add console.error(...) to streamRead/generatedStreamHostInject).
Timeout hangs: timeout 12 node run.mjs so a deadlock doesn't wedge.
| Error | Likely cause |
|---|---|
invalid numeric opcode: 0xfc16 | Wide-arithmetic — recompile with -f no-wide-arithmetic |
WebAssembly.Suspending is not a constructor | Node < 24, or Node 22 picked up outside the repo (use Node 26) |
FutureReadableEnd is not defined | Future-end classes not injected (run via transpile-released.mjs) |
| stdout empty or missing lines | The runner exits or empties the event loop before the shim's worker flushes (wait after run()) |
Bare unreachable from a program that reads files | No preopen set (_setPreopens), or a path outside it; the panic message is lost with the exit |
wide arithmetic support is not enabled (transpile) | Compile with -f no-wide-arithmetic; V8 cannot run the opcodes either |
| Hang / timeout | JSPI Suspending missing on a trampoline, or a stream rendezvous deadlock |
まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
Measure Wado's performance or the size of the Wasm it generates, and refresh the benchmark/ and wasm-size/ README files. Use for any benchmarking or size-measurement request, whichever benchmark it names.
日本語の概要は準備中です。原文の説明を表示しています。
Measure how long GitHub Actions jobs and steps took across past runs, and find the pull request that made CI slower. Use for any question about CI duration, a slow job, or when CI got slow.
日本語の概要は準備中です。原文の説明を表示しています。
How to answer code review feedback — a human reviewer, CodeRabbit, or any review bot. Verify the findings, report the classes they are instances of to the user before fixing, then fix the class rather than the sites named. Put design decisions to the user, then run /distill. Invoke when responding to review comments on a pull request, or to the findings of a /code-review run.
日本語の概要は準備中です。原文の説明を表示しています。
Investigate and improve code coverage for the wado-compiler crate. Use for any question about what the tests do and do not reach, dead code included.
日本語の概要は準備中です。原文の説明を表示しています。
Review the branch with /code-review at high, then answer the findings with /code-review-response.
日本語の概要は準備中です。原文の説明を表示しています。
Use rust-gdb to inspect variables and step through code without modifying it. Prefer it over print debugging for any investigation into what the compiler is actually doing (lldb is unavailable on Claude Code Web).
日本語の概要は準備中です。原文の説明を表示しています。