quickjs-jit 0.12.5

JIT-enabled high level bindings to the QuickJS JavaScript engine
Documentation
# JIT M1 progress report

M1 extends native coverage for strings and JSON and makes call-heavy and
array/typed-array loops profitable in forced Tier 2 and automatic mode. It
preserves exact QuickJS semantics and fail-closed fallback, but does not claim
that the project-wide performance gates or arbitrary JavaScript coverage are
complete.

## Performance

Lower latency is better. The results below are medians from 30 interleaved
fresh processes after five discarded warmup processes. Every mode produced the
same checksum.

| Scenario | QuickJS | QuickJS + forced Tier 1 | QuickJS + forced Tier 2 | Automatic | QuickJS vs automatic |
| --- | ---: | ---: | ---: | ---: | ---: |
| Call-heavy | 1.837 ms | 1.150 ms | 0.243 ms | 0.241 ms | Automatic 7.62x faster |
| Arrays / TypedArrays | 5.791 ms | 18.811 ms | 3.779 ms | 2.710 ms | Automatic 2.14x faster |

At M0, the array workload's best native path was Tier 1 at 13.141 ms, or 2.81x
slower than QuickJS. M1 automatic mode is now 4.85x faster than that M0 native
path and 2.14x faster than QuickJS. Automatic call-heavy is 7.62x faster than
QuickJS and matches the forced Tier 2 steady state within measurement noise.

Across the 30 samples, strict Tier 2 records 66,240 call-heavy entries and 687
array entries. Automatic records 62,367 call-heavy Tier 2 entries and 827 array
Tier 2 entries. All paths have zero fallbacks and zero retries. Every mode
preserves the respective checksums `number:40bb580000000000` and
`string:33983000:8496750.000:2000`.

These are focused measurements, not performance guarantees for arbitrary
JavaScript. Automatic mode uses the production tiering policy and every sample
entered native Tier 2. The profitability-report gate remains inconclusive for
the structural direct-call admission because it is deliberately not reported
as a modeled profitability approval. The project-wide report also remains
FAIL/INCONCLUSIVE for startup/tail regression, the designated 10x
compute-kernel target, and gpui-shell evidence.

The measurement used source commit `b67f381`, five discarded warmups, 30
interleaved fresh-process samples, ten one-second throughput windows, and
10,000 paired bootstrap resamples on x86_64. The source tree was clean and all
samples had identical checksums.

## Implementation progress

Tier 1 now covers atom-backed string constants and the object and element
property-construction paths needed by the string/JSON cases. The versioned JIT
ABI exposes `push_atom_value`, and numeric constant descriptors carry
pointer-free payloads. The append-only ABI minor version is 18, with consistent
bundled bindings for supported targets.

Tier 2 now supports stable heap-reference arguments alongside numeric loop
state and lowers packed Array, Int32Array, and Float64Array length, element
load, and element store operations directly. Stable class, fast-array, data,
count, and detached/resizable-buffer guards are reused only within the
producing block or its unique direct successor for an immutable argument.
Stable in-bounds element stores refresh the guarded data/count fact for an
immediately following load. Local writes, CFG merges, and reentrant effects
invalidate the cached fact. Dynamic bounds checks remain when no range proof
exists.

Tier 2 call lowering now accounts for fixed-call arguments in optimized stack
depths, waits for a monomorphic callee's scalar entry before freezing the
caller artifact, and preserves observed heap-reference entry arguments even
when the caller itself has no arithmetic specialization. The call-heavy outer
loop therefore stays in compiled code instead of re-entering QuickJS once per
callee invocation.

Automatic tiering treats a stable, publishable direct-call edge inside a
verifier-recognized loop as a bounded structural Tier 2 admission because the
preceding generic-call Tier 1 timing cannot model the bridge that Tier 2
removes. It does not label that admission as a modeled profitability approval.
Benchmark warmup waits for Tier 2 execution and pending compilation to settle
instead of treating the first profitability demotion as terminal, and rejects
native automatic samples that time out with compilation still pending.

Wrong classes, Proxy objects, unsupported values, detached or resizable
buffers, out-of-bounds indices, and numeric mismatches deoptimize to exact
interpreter state.

## Correctness

The full runtime test command passes:

```sh
cargo fmt --all -- --check
cargo test -p quickjs-jit-sys --test jit_patch
cargo test -p quickjs-jit-runtime --features compiler,test-support --tests
```

Coverage includes:

- native string/property entry with forced cycle collection and exception
  differential tests;
- native packed and typed-array IR load/store evidence;
- stable packed and typed-array execution with zero deoptimization;
- exact Float64 and Proxy side exits;
- local-reassignment and control-flow guard-cache regressions;
- 50 optimized-code tests, 21 runtime-feedback tests, 11 QuickJS patch tests,
  and bounded Test262 runs in interpreter, automatic, and eligible forced
  tiers;
- a call-heavy production regression proving 16,000 stable direct calls do
  not cause per-call QuickJS re-entry, fallback, or retry.

Independent review found a stale element-guard-cache risk. M1 now scopes cache
reuse by block and immutable argument provenance and invalidates it at every
unsafe boundary; follow-up review confirmed the blocker resolved.

## Known limitations and post-M1 work

1. Automatic profitability model

   Model the compiled-to-compiled bridge benefit directly so structural
   direct-call admissions can eventually use the same measured decision path.

2. Entry and compilation overhead

   Amortize cold compilation and native-entry costs in short-lived runtime and
   reload lifecycle measurements.

3. Range analysis

   Prove loop induction ranges before removing the dynamic bounds checks that
   remain in otherwise guarded element loops.

4. Remaining JavaScript coverage

   Continue with closures and captured variables, collections and BigInt, then
   exception regions, Promise jobs, generators, and async continuations while
   preserving ownership, GC roots, and exact fallback.

## M1 merge gate

M1 is suitable for merge when the PR's required CI checks are green. The
limitations above remain explicit follow-up work and are not represented as
passing project-wide performance gates.