perf(json): recover UTF-16 parser hot paths#1000
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe JSON parser now uses buffered string construction, explicit character comparisons for number parsing, and additional strict-mode tests for unescaped Unicode and control characters. ChangesJSON parser updates
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
Web Tooling Benchmark
18 pinned Web Tooling workloads; 18 workloads produced at least one Goccia sample. Raw results from 1 sample per workload; full stdout/stderr for failures and min/max/CV stay in the |
Benchmark Results439 benchmarks · PR vs same-runner Interpreted: 🟢 40 improved · 🔴 40 regressed · 359 unchanged · avg +0.8% Typical per-run noise (median variance): interpreted ±1.8%, bytecode ±2.1%. Deltas within noise overlap and read as unchanged. arraybuffer.js — Interp: 🟢 1, 13 unch. · avg -0.5% · Bytecode: 🟢 2, 12 unch. · avg +1.7%
arrays.js — Interp: 19 unch. · avg +0.9% · Bytecode: 🔴 1, 18 unch. · avg +1.1%
async-await.js — Interp: 🔴 1, 5 unch. · avg -0.5% · Bytecode: 🟢 1, 5 unch. · avg +0.3%
async-generators.js — Interp: 🟢 1, 1 unch. · avg -0.4% · Bytecode: 2 unch. · avg -2.9%
atomics.js — Interp: 🔴 1, 5 unch. · avg +0.6% · Bytecode: 🔴 2, 4 unch. · avg -2.0%
base64.js — Interp: 🟢 1, 🔴 1, 8 unch. · avg -0.5% · Bytecode: 🔴 1, 9 unch. · avg -0.9%
classes.js — Interp: 🟢 1, 🔴 4, 26 unch. · avg -1.0% · Bytecode: 🟢 2, 🔴 6, 23 unch. · avg -3.0%
closures.js — Interp: 🟢 1, 10 unch. · avg +1.8% · Bytecode: 🟢 1, 10 unch. · avg -1.5%
collections.js — Interp: 12 unch. · avg +1.0% · Bytecode: 🔴 1, 11 unch. · avg +0.0%
csv.js — Interp: 13 unch. · avg +2.3% · Bytecode: 13 unch. · avg +0.2%
destructuring.js — Interp: 🟢 3, 🔴 2, 17 unch. · avg +0.3% · Bytecode: 🟢 1, 🔴 1, 20 unch. · avg -0.2%
fibonacci.js — Interp: 🟢 1, 7 unch. · avg -1.6% · Bytecode: 🔴 4, 4 unch. · avg -2.7%
float16array.js — Interp: 🟢 3, 🔴 3, 26 unch. · avg +0.2% · Bytecode: 🟢 3, 🔴 3, 26 unch. · avg +0.2%
for-in/for-in.js — Interp: 🟢 1, 2 unch. · avg +1.8% · Bytecode: 3 unch. · avg +4.5%
for-of.js — Interp: 🟢 1, 🔴 2, 4 unch. · avg -0.9% · Bytecode: 🟢 1, 6 unch. · avg +2.5%
generators.js — Interp: 4 unch. · avg +1.9% · Bytecode: 🟢 1, 🔴 1, 2 unch. · avg -0.8%
intl.js — Interp: 6 unch. · avg +0.6% · Bytecode: 🔴 1, 5 unch. · avg -3.2%
iterators.js — Interp: 🟢 5, 37 unch. · avg +4.0% · Bytecode: 🔴 15, 27 unch. · avg -3.8%
json.js — Interp: 🟢 11, 12 unch. · avg +9.7% · Bytecode: 🟢 12, 🔴 1, 10 unch. · avg +10.2%
jsx.jsx — Interp: 🔴 4, 17 unch. · avg -2.4% · Bytecode: 🟢 3, 🔴 4, 14 unch. · avg +0.2%
modules.js — Interp: 9 unch. · avg -3.2% · Bytecode: 🟢 1, 8 unch. · avg -1.5%
numbers.js — Interp: 12 unch. · avg +4.1% · Bytecode: 🟢 1, 11 unch. · avg +1.7%
objects.js — Interp: 7 unch. · avg -0.9% · Bytecode: 🔴 1, 6 unch. · avg -0.6%
promises.js — Interp: 🔴 1, 11 unch. · avg -1.1% · Bytecode: 🟢 1, 11 unch. · avg -0.7%
property-access.js — Interp: 🔴 1, 4 unch. · avg -3.0% · Bytecode: 5 unch. · avg +2.3%
regexp.js — Interp: 🟢 2, 11 unch. · avg +2.9% · Bytecode: 🔴 1, 12 unch. · avg -0.8%
strings.js — Interp: 🟢 1, 🔴 2, 16 unch. · avg -1.1% · Bytecode: 🟢 2, 17 unch. · avg +1.9%
temporal.js — Interp: 6 unch. · avg +1.8% · Bytecode: 6 unch. · avg -2.1%
tsv.js — Interp: 9 unch. · avg -0.4% · Bytecode: 🔴 1, 8 unch. · avg +0.1%
typed-arrays.js — Interp: 🟢 4, 🔴 5, 13 unch. · avg +14.5% · Bytecode: 🟢 3, 🔴 6, 13 unch. · avg -4.4%
uint8array-encoding.js — Interp: 🟢 2, 🔴 4, 12 unch. · avg -6.9% · Bytecode: 🔴 7, 11 unch. · avg -13.7%
weak-collections.js — Interp: 🟢 1, 🔴 9, 5 unch. · avg -16.7% · Bytecode: 🟢 6, 9 unch. · avg +19.5%
Deterministic profile diffDeterministic profile diff: no significant changes. Measured on ubuntu-latest x64. Each PR run also builds the |
Suite TimingTest Runner (interpreted: 11,519 passed; bytecode: 11,519 passed)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Test runner worker shutdown frees thread-local heaps in bulk; that shutdown reclamation is not counted as GC collections or collected objects.
Benchmarks (interpreted: 439; bytecode: 439)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Benchmark runner performs explicit between-file collections, so collection and collected-object counts can be much higher than the test runner.
Boot
Empty-script ( Measured on ubuntu-latest x64. |
JetStream 3 Performance Barometer
Geomean reference ratio: QuickJS 26.97×; Node.js 314.83×. 1.00× means aligned; values above 1.00× mean Goccia was proportionally slower after normalizing JetStream’s higher-is-better score. This is a directional barometer across runtimes with different goals, not a product ranking. Raw samples and failure details remain in the |
AWFY Results
Geomean Ratios
14 pinned AWFY benchmarks. Medians from 5 interleaved samples per engine; raw JSON includes min/max/CV and is attached as the |
test262 Conformance
Areas closest to 100%
Per-test deltas (+0 / -0 / timeout +2 / -1)New timeouts (2):
Resolved timeouts (1):
Steady-state failures and timeouts are non-blocking; PASS → non-timeout failure transitions fail the conformance gate. Measured on ubuntu-latest x64, bytecode mode. Areas grouped by the first two test262 path components; minimum 25 attempted tests, areas already at 100% excluded. Δ vs main compares against the most recent cached |
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
TStringBufferfor escaped strings.fpc_uchar_to_charandiconvon x86-64.Testing
./build.pas --clean testrunner,./build/GocciaTestRunner tests, and./build/GocciaTestRunner tests --mode=bytecode(1,442 files, 11,519 tests, 25,742 assertions in each mode).JSONParser.Testsuite on macOS arm64 and Ubuntu x86-64 (54/54 passing on both)../format.pas --check(429 files).Measurements
Current
c477011eversus the string fast path, IQR-filtered medians:The string fix reduces parse-only retired instructions from 1,065,647,274 to 770,802,416 (-27.67%), branches from 145,668,284 to 107,413,247 (-26.26%), and branch mispredicts from 3,285,568 to 2,995,097 (-8.84%).
Same-commit string-patch versus direct-ASCII comparisons, IQR-filtered medians:
Callgrind confirms the second mechanism: the integer-only probe falls from 398,062,860 to 271,508,200 retired instructions (-31.79%). Direct comparison with the pre-regression parent leaves integer parsing +9.34%, while exact decimal conversion remains +349.14% and structure-only parsing +40.64%; those residual gaps are not bundled into this PR.
Fresh CI same-runner
mainversus PR measurements confirm transfer to the repository benchmark suite:benchmarks/json.jsThe pinned AWFY
Jsonrow moves only +0.73%, confirming it is not a substitute for the missing audit kernel. All 49 PR checks pass, including test262 (52,219/52,328 pass, 99.8%, no new non-timeout failures).