Experiment 230: Reject AArch64 NEON JSON safe-prefix scan + copy

Date: 2026-07-15

Status: Rejected

Category: Moonshot

Direction:result-transfer-shape

Benchmark Run: none — focused

benchmark/experiments/select_bytes_text_string_reserve.dart;

two final order-flipped paired passes plus prototype-development rounds are

recorded in

benchmark/results/2026-07-15T10-41-42Z-exp230-neon-json-scan-copy.md.

No release-suite run because no release lane isolates long safe TEXT JSON

encoding wall time; the focused harness is the durable gate established by

exp 202 / 219.

Archive:archive/exp-230

Problem

json_write_string scans safe TEXT with the portable 8-byte SWAR loop from

exp 043, then copies the complete safe span

through buf_write. Exp 202

showed that reservation alone does not matter; exp 219

won by removing snprintf only for control escapes. Exp 229

then introduced the codebase's first AArch64/NEON kernel and named SIMD JSON

escape scan as the next TEXT-side mechanism.

Safe long strings still pay two traversals: classify, then copy. The plausible

moonshot was to fuse them, storing each vector only after proving it contains

no control byte, quote, or backslash.

Hypothesis

Assumption challenged: safe JSON TEXT needs a portable scan followed by a

separate copy. AArch64 NEON can classify and copy 16 bytes per iteration,

turning two scalar/SWAR traversals into one vector traversal without changing

the public API or output bytes.

Accept only if 256-byte and 1 KiB safe ASCII both reproduce at least 15%

candidate-faster across an order flip, with the CJK lane in the same direction.

Short, mixed, control, and unsafe-at-start/end lanes must remain inside the 3%

effect floor. Reject a win confined to 1 KiB or a 256-byte result that misses

the gate in either ordering.

Approach

The archived final prototype used an AArch64-only long-TEXT path:

the scalar encoder on every other target.

and backslash, vmaxvq_u8 to reduce the escape mask, and vst1q_u8 to copy

a proven-safe vector. These are documented A64 Advanced SIMD intrinsics in

the Arm ACLE reference.

encoding and shorter values retained the canonical scalar function.

and remained scalar. The prototype did not restart SIMD after escapes, so it

did not revive the wider post-escape scan shape from closed exp 221 / PR 236.

dart:convert around 16/32/48/64/80/96/128/256/1024-byte boundaries, with

escapes at vector edges and multibyte UTF-8.

The focused harness now includes safe 64 B, 96 B, 256 B, 1 KiB, and CJK lanes,

plus early- and late-escape guards at 96 B and 256 B.

Results

Decision rows from the two final order-flipped pairs:

LanePair 1Pair 2Read
safe ASCII 256 B-17.7%-12.6%second pass misses 15% gate
safe ASCII 1 KiB-33.6%-34.1%large-span mechanism reproduced
CJK 1K code units-25.2%-25.5%high UTF-8 bytes remain safe
early escape 256 B+2.7%-0.9%neutral/mixed
late escape 256 B-16.0%-5.8%no rollback penalty
early escape 96 B-0.3%+1.1%scalar cutoff, neutral
late escape 96 B-1.3%-3.2%scalar cutoff, neutral-to-faster
escaped text 24 B+2.8%+0.1%inside effect floor
control text 24 B-0.3%+1.4%inside effect floor

The full raw tables document short-lane drift as well. One candidate-first

pass put the unchanged 20-column short lane at +26.1%; the order flip collapsed

it to +1.4%. A one-microsecond narrow-lane movement similarly reports as 10.4%.

Neither is treated as code-path evidence because values below 256 bytes never

enter the prototype.

Prototype development findings

The bounded iterations were informative even though the final result failed:

  1. Putting NEON state into the scalar function changed its register allocation

and regressed short escaped text, repeating exp 229's code-generation lesson.

  1. A clean out-of-line SIMD attempt that rolled back on an unsafe vector kept

scalar assembly byte-identical, but late-escape 96-byte text regressed

15-26% because it paid almost a full speculative pass and then the full

scalar pass.

  1. Continuing scalar from the first unsafe vector removed that double pass.

Moving dispatch to the TEXT caller with a 256-byte cutoff made unsafe guards

neutral, while splitting the escaped tail out of the all-safe kernel reduced

the safe fast path's register frame.

  1. Even after those refinements, the load-bearing 256-byte win did not reproduce

above the preset floor.

Decision

Rejected. Keep the portable SWAR scan + copy encoder.

The 1 KiB result proves fused vector classification-and-copy is a real

mechanism, but it is not enough to ship a new ISA-specific TEXT encoder when

the 256-byte break-even row is 17.7% in one ordering and 12.6% in the other.

The exact runtime prototype is preserved at archive/exp-230 and removed from

the publication branch.

The harness and boundary oracle remain. Reopen only if a production/AOT profile

shows escape-free TEXT at 1 KiB or larger materially dominates result transfer,

or a different mechanism removes the per-cell dispatch/setup floor at 256

bytes. Do not retry another threshold or speculative rollback variant.

Validation

and after runtime revert.

isolate scalar code-generation and unsafe-tail costs.

and scalar-path isolation.