Skip to content

Expand JSON.stringify error coverage#145

Merged
frostney merged 1 commit into
mainfrom
feature/json-stringify-error-tests
Mar 31, 2026
Merged

Expand JSON.stringify error coverage#145
frostney merged 1 commit into
mainfrom
feature/json-stringify-error-tests

Conversation

@frostney
Copy link
Copy Markdown
Owner

Summary

  • expand JSON.stringify coverage for circular references, toJSON, thrown errors, invalid replacers/space, symbols, functions, deep nesting, and sparse arrays
  • align the runtime JSON serializer with the new edge-case expectations, including cycle detection and toJSON() handling
  • document the supported JSON.stringify special cases in docs/built-ins.md

Testing

  • ./build.pas clean loader
  • ./build.pas testrunner
  • ./build/TestRunner tests/built-ins/JSON/stringify.js --no-progress
  • ./build/TestRunner tests --no-progress

Closes #122.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 30, 2026

Warning

Rate limit exceeded

@frostney has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 15 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 4 minutes and 15 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fff62131-0d60-407b-be27-8c46267f9469

📥 Commits

Reviewing files that changed from the base of the PR and between 0f48261 and 8e56ed4.

📒 Files selected for processing (4)
  • docs/built-ins.md
  • tests/built-ins/JSON/stringify.js
  • units/Goccia.Builtins.JSON.pas
  • units/Goccia.JSON.pas
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/json-stringify-error-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

Benchmark Results

263 benchmarks

Interpreted: 🔴 19 regressed · 244 unchanged · avg -2.5%
Bytecode: 🟢 1 improved · 🔴 149 regressed · 113 unchanged · avg -7.7%

arraybuffer.js — Interp: 14 unch. · avg -0.0% · Bytecode: 🔴 8, 6 unch. · avg -8.2%
Benchmark Interpreted Δ Bytecode Δ
create ArrayBuffer(0) 462,301 → 450,997 -2.4% 561,933 → 498,852 🔴 -11.2%
create ArrayBuffer(64) 440,456 → 434,094 -1.4% 532,568 → 479,761 🔴 -9.9%
create ArrayBuffer(1024) 346,984 → 337,305 -2.8% 422,269 → 372,617 🔴 -11.8%
create ArrayBuffer(8192) 153,321 → 149,248 -2.7% 182,033 → 162,110 🔴 -10.9%
slice full buffer (64 bytes) 505,311 → 518,779 +2.7% 661,856 → 607,240 🔴 -8.3%
slice half buffer (512 of 1024 bytes) 433,786 → 445,944 +2.8% 566,871 → 524,840 🔴 -7.4%
slice with negative indices 428,778 → 419,021 -2.3% 606,673 → 567,151 -6.5%
slice empty range 490,378 → 498,040 +1.6% 648,800 → 604,311 -6.9%
byteLength access 1,341,940 → 1,388,175 +3.4% 1,707,660 → 1,602,486 -6.2%
Symbol.toStringTag access 1,040,240 → 1,045,302 +0.5% 1,127,606 → 1,069,995 -5.1%
ArrayBuffer.isView 748,768 → 765,223 +2.2% 922,309 → 874,509 -5.2%
clone ArrayBuffer(64) 418,819 → 412,728 -1.5% 519,553 → 485,626 -6.5%
clone ArrayBuffer(1024) 326,928 → 324,504 -0.7% 412,596 → 366,905 🔴 -11.1%
clone ArrayBuffer inside object 267,728 → 267,781 +0.0% 321,236 → 297,468 🔴 -7.4%
arrays.js — Interp: 19 unch. · avg +0.2% · Bytecode: 🔴 18, 1 unch. · avg -10.1%
Benchmark Interpreted Δ Bytecode Δ
Array.from length 100 13,211 → 12,991 -1.7% 15,612 → 14,189 🔴 -9.1%
Array.from 10 elements 221,335 → 220,731 -0.3% 266,653 → 238,307 🔴 -10.6%
Array.of 10 elements 278,403 → 280,189 +0.6% 334,835 → 310,173 🔴 -7.4%
spread into new array 325,442 → 323,766 -0.5% 207,924 → 190,647 🔴 -8.3%
map over 50 elements 24,521 → 24,540 +0.1% 29,099 → 26,310 🔴 -9.6%
filter over 50 elements 22,837 → 22,639 -0.9% 26,651 → 23,500 🔴 -11.8%
reduce sum 50 elements 25,133 → 26,058 +3.7% 20,938 → 19,551 -6.6%
forEach over 50 elements 22,344 → 22,938 +2.7% 30,770 → 28,115 🔴 -8.6%
find in 50 elements 32,076 → 31,762 -1.0% 33,071 → 30,608 🔴 -7.4%
sort 20 elements 12,577 → 12,471 -0.8% 14,743 → 10,508 🔴 -28.7%
flat nested array 116,883 → 113,098 -3.2% 139,711 → 127,932 🔴 -8.4%
flatMap 72,575 → 70,622 -2.7% 89,721 → 81,607 🔴 -9.0%
map inside map (5x5) 20,211 → 20,273 +0.3% 24,820 → 22,303 🔴 -10.1%
filter inside map (5x10) 15,637 → 15,643 +0.0% 18,526 → 16,490 🔴 -11.0%
reduce inside map (5x10) 18,592 → 19,025 +2.3% 17,661 → 16,194 🔴 -8.3%
forEach inside forEach (5x10) 16,309 → 16,485 +1.1% 18,508 → 17,093 🔴 -7.6%
find inside some (10x10) 13,157 → 13,276 +0.9% 14,313 → 13,090 🔴 -8.5%
map+filter chain nested (5x20) 5,113 → 5,146 +0.6% 6,030 → 5,393 🔴 -10.5%
reduce flatten (10x5) 37,510 → 38,679 +3.1% 19,216 → 17,361 🔴 -9.7%
async-await.js — Interp: 6 unch. · avg +2.0% · Bytecode: 🔴 5, 1 unch. · avg -8.5%
Benchmark Interpreted Δ Bytecode Δ
single await 376,248 → 385,744 +2.5% 449,506 → 404,864 🔴 -9.9%
multiple awaits 169,125 → 172,041 +1.7% 196,626 → 175,751 🔴 -10.6%
await non-Promise value 839,801 → 860,108 +2.4% 1,170,424 → 1,111,299 -5.1%
await with try/catch 365,461 → 369,191 +1.0% 442,618 → 404,269 🔴 -8.7%
await Promise.all 51,437 → 52,145 +1.4% 56,604 → 51,632 🔴 -8.8%
nested async function call 192,686 → 198,070 +2.8% 251,322 → 231,530 🔴 -7.9%
classes.js — Interp: 31 unch. · avg -0.5% · Bytecode: 🔴 20, 11 unch. · avg -7.7%
Benchmark Interpreted Δ Bytecode Δ
simple class new 139,123 → 140,718 +1.1% 218,718 → 203,820 -6.8%
class with defaults 109,944 → 113,996 +3.7% 152,567 → 142,804 -6.4%
50 instances via Array.from 5,605 → 5,684 +1.4% 8,695 → 7,895 🔴 -9.2%
instance method call 71,250 → 71,319 +0.1% 101,066 → 93,692 🔴 -7.3%
static method call 114,857 → 112,953 -1.7% 204,737 → 187,309 🔴 -8.5%
single-level inheritance 56,323 → 55,659 -1.2% 81,626 → 74,546 🔴 -8.7%
two-level inheritance 48,059 → 47,976 -0.2% 65,083 → 60,414 🔴 -7.2%
private field access 71,986 → 70,907 -1.5% 105,517 → 95,811 🔴 -9.2%
private methods 80,242 → 78,384 -2.3% 112,797 → 101,585 🔴 -9.9%
getter/setter access 75,740 → 75,757 +0.0% 116,010 → 103,100 🔴 -11.1%
class decorator (identity) 92,910 → 92,996 +0.1% 111,923 → 102,520 🔴 -8.4%
class decorator (wrapping) 54,944 → 54,457 -0.9% 64,254 → 58,874 🔴 -8.4%
identity method decorator 65,686 → 64,916 -1.2% 95,462 → 84,530 🔴 -11.5%
wrapping method decorator 52,435 → 52,047 -0.7% 67,466 → 60,663 🔴 -10.1%
stacked method decorators (x3) 35,330 → 35,212 -0.3% 46,096 → 41,747 🔴 -9.4%
identity field decorator 70,749 → 70,558 -0.3% 83,722 → 74,394 🔴 -11.1%
field initializer decorator 60,119 → 59,986 -0.2% 74,897 → 72,023 -3.8%
getter decorator (identity) 64,634 → 66,094 +2.3% 83,188 → 71,868 🔴 -13.6%
setter decorator (identity) 54,490 → 54,816 +0.6% 66,805 → 64,189 -3.9%
static method decorator 70,276 → 70,121 -0.2% 86,064 → 77,326 🔴 -10.2%
static field decorator 82,409 → 81,464 -1.1% 88,736 → 86,285 -2.8%
private method decorator 53,462 → 52,364 -2.1% 86,450 → 70,328 🔴 -18.6%
private field decorator 59,070 → 58,277 -1.3% 61,133 → 62,300 +1.9%
plain auto-accessor (no decorator) 102,344 → 102,670 +0.3% 114,186 → 96,774 🔴 -15.2%
auto-accessor with decorator 54,906 → 54,680 -0.4% 60,890 → 54,278 🔴 -10.9%
decorator writing metadata 44,199 → 43,966 -0.5% 50,362 → 48,823 -3.1%
static getter read 128,456 → 125,900 -2.0% 164,267 → 164,494 +0.1%
static getter/setter pair 97,375 → 94,764 -2.7% 121,548 → 118,803 -2.3%
inherited static getter 76,376 → 74,615 -2.3% 97,881 → 94,489 -3.5%
inherited static setter 82,769 → 81,698 -1.3% 107,026 → 99,387 🔴 -7.1%
inherited static getter with this binding 69,885 → 70,374 +0.7% 88,082 → 87,160 -1.0%
closures.js — Interp: 11 unch. · avg -0.1% · Bytecode: 🔴 4, 7 unch. · avg -6.0%
Benchmark Interpreted Δ Bytecode Δ
closure over single variable 130,471 → 130,676 +0.2% 293,124 → 268,878 🔴 -8.3%
closure over multiple variables 117,723 → 119,483 +1.5% 199,855 → 192,502 -3.7%
nested closures 124,910 → 126,689 +1.4% 231,965 → 221,115 -4.7%
function as argument 93,359 → 93,265 -0.1% 260,549 → 246,752 -5.3%
function returning function 114,251 → 116,815 +2.2% 299,170 → 273,279 🔴 -8.7%
compose two functions 69,647 → 70,862 +1.7% 153,471 → 148,280 -3.4%
fn.call 153,328 → 147,396 -3.9% 227,917 → 227,252 -0.3%
fn.apply 109,258 → 108,421 -0.8% 162,416 → 155,342 -4.4%
fn.bind 143,722 → 141,690 -1.4% 296,462 → 277,286 -6.5%
recursive sum to 50 12,040 → 11,661 -3.1% 27,006 → 24,022 🔴 -11.0%
recursive tree traversal 20,191 → 20,316 +0.6% 38,526 → 34,825 🔴 -9.6%
collections.js — Interp: 12 unch. · avg +0.3% · Bytecode: 🔴 3, 9 unch. · avg -3.3%
Benchmark Interpreted Δ Bytecode Δ
add 50 elements 6,896 → 7,075 +2.6% 7,636 → 7,371 -3.5%
has lookup (50 elements) 88,299 → 90,630 +2.6% 101,197 → 99,717 -1.5%
delete elements 46,722 → 48,306 +3.4% 50,770 → 49,306 -2.9%
forEach iteration 15,813 → 15,387 -2.7% 16,727 → 15,479 🔴 -7.5%
spread to array 27,504 → 27,901 +1.4% 231,607 → 209,808 🔴 -9.4%
deduplicate array 36,425 → 37,639 +3.3% 73,505 → 71,334 -3.0%
set 50 entries 5,141 → 5,164 +0.4% 5,611 → 5,625 +0.3%
get lookup (50 entries) 87,122 → 86,150 -1.1% 92,049 → 91,545 -0.5%
has check 129,001 → 128,558 -0.3% 142,453 → 140,223 -1.6%
delete entries 45,965 → 45,540 -0.9% 46,961 → 47,003 +0.1%
forEach iteration 15,792 → 15,171 -3.9% 17,036 → 15,418 🔴 -9.5%
keys/values/entries 7,727 → 7,640 -1.1% 26,361 → 26,077 -1.1%
destructuring.js — Interp: 22 unch. · avg -1.7% · Bytecode: 🔴 13, 9 unch. · avg -8.4%
Benchmark Interpreted Δ Bytecode Δ
simple array destructuring 368,216 → 370,593 +0.6% 266,346 → 258,426 -3.0%
with rest element 246,548 → 238,519 -3.3% 231,235 → 199,032 🔴 -13.9%
with defaults 375,709 → 384,870 +2.4% 298,282 → 297,547 -0.2%
skip elements 388,488 → 394,191 +1.5% 324,583 → 278,188 🔴 -14.3%
nested array destructuring 168,552 → 166,032 -1.5% 91,714 → 85,954 -6.3%
swap variables 493,046 → 497,464 +0.9% 368,249 → 315,699 🔴 -14.3%
simple object destructuring 302,653 → 295,187 -2.5% 427,919 → 407,030 -4.9%
with defaults 336,230 → 335,977 -0.1% 574,994 → 549,507 -4.4%
with renaming 315,911 → 317,370 +0.5% 467,953 → 442,836 -5.4%
nested object destructuring 152,328 → 150,301 -1.3% 200,891 → 193,376 -3.7%
rest properties 186,114 → 180,948 -2.8% 200,787 → 183,051 🔴 -8.8%
object parameter 93,922 → 92,124 -1.9% 155,889 → 145,262 -6.8%
array parameter 121,364 → 117,365 -3.3% 122,439 → 107,130 🔴 -12.5%
mixed destructuring in map 33,540 → 32,304 -3.7% 37,159 → 35,003 -5.8%
forEach with array destructuring 63,671 → 61,929 -2.7% 47,833 → 41,504 🔴 -13.2%
map with array destructuring 63,324 → 61,817 -2.4% 45,799 → 40,806 🔴 -10.9%
filter with array destructuring 66,034 → 63,679 -3.6% 53,084 → 47,677 🔴 -10.2%
reduce with array destructuring 73,112 → 69,702 -4.7% 50,160 → 45,232 🔴 -9.8%
map with object destructuring 73,629 → 72,648 -1.3% 98,300 → 91,075 🔴 -7.4%
map with nested destructuring 61,497 → 60,525 -1.6% 93,795 → 86,095 🔴 -8.2%
map with rest in destructuring 42,444 → 40,468 -4.7% 27,040 → 23,356 🔴 -13.6%
map with defaults in destructuring 56,808 → 55,722 -1.9% 70,579 → 64,834 🔴 -8.1%
fibonacci.js — Interp: 8 unch. · avg -3.4% · Bytecode: 🔴 7, 1 unch. · avg -10.6%
Benchmark Interpreted Δ Bytecode Δ
recursive fib(15) 325 → 316 -2.7% 958 → 834 🔴 -12.9%
recursive fib(20) 30 → 29 -2.5% 86 → 76 🔴 -12.2%
recursive fib(15) typed 331 → 319 -3.6% 979 → 879 🔴 -10.2%
recursive fib(20) typed 30 → 29 -2.6% 90 → 79 🔴 -11.9%
iterative fib(20) via reduce 12,188 → 11,791 -3.3% 19,259 → 17,234 🔴 -10.5%
iterator fib(20) 9,689 → 9,220 -4.8% 19,523 → 18,215 -6.7%
iterator fib(20) via Iterator.from + take 15,409 → 14,961 -2.9% 22,124 → 20,154 🔴 -8.9%
iterator fib(20) last value via reduce 11,835 → 11,265 -4.8% 16,197 → 14,368 🔴 -11.3%
for-of.js — Interp: 7 unch. · avg -5.4% · Bytecode: 🔴 2, 5 unch. · avg -4.5%
Benchmark Interpreted Δ Bytecode Δ
for...of with 10-element array 46,511 → 43,547 -6.4% 176,714 → 170,113 -3.7%
for...of with 100-element array 5,347 → 4,996 -6.6% 18,532 → 18,478 -0.3%
for...of with string (10 chars) 34,197 → 33,761 -1.3% 91,542 → 87,509 -4.4%
for...of with Set (10 elements) 46,203 → 43,861 -5.1% 164,393 → 154,432 -6.1%
for...of with Map entries (10 entries) 29,939 → 28,188 -5.8% 29,473 → 27,201 🔴 -7.7%
for...of with destructuring 39,607 → 36,938 -6.7% 39,056 → 35,950 🔴 -8.0%
for-await-of with sync array 44,319 → 41,828 -5.6% 131,034 → 129,346 -1.3%
helpers/bench-module.js — Interp: 0 · Bytecode: 0
Benchmark Interpreted Δ Bytecode Δ
iterators.js — Interp: 🔴 5, 15 unch. · avg -5.7% · Bytecode: 🔴 19, 1 unch. · avg -11.4%
Benchmark Interpreted Δ Bytecode Δ
Iterator.from({next}).toArray() — 20 elements 15,559 → 14,664 -5.7% 21,958 → 19,925 🔴 -9.3%
Iterator.from({next}).toArray() — 50 elements 6,650 → 6,382 -4.0% 10,034 → 8,831 🔴 -12.0%
spread pre-wrapped iterator — 20 elements 11,383 → 10,968 -3.6% 21,092 → 19,131 🔴 -9.3%
Iterator.from({next}).forEach — 50 elements 4,615 → 4,376 -5.2% 6,384 → 5,527 🔴 -13.4%
Iterator.from({next}).reduce — 50 elements 4,709 → 4,455 -5.4% 6,363 → 5,412 🔴 -14.9%
wrap array iterator 165,626 → 159,701 -3.6% 205,029 → 175,885 🔴 -14.2%
wrap plain {next()} object 10,756 → 10,242 -4.8% 15,912 → 13,779 🔴 -13.4%
map + toArray (50 elements) 4,671 → 4,463 -4.5% 6,560 → 5,969 🔴 -9.0%
filter + toArray (50 elements) 4,560 → 4,328 -5.1% 6,826 → 5,806 🔴 -14.9%
take(10) + toArray (50 element source) 27,741 → 26,597 -4.1% 37,766 → 35,070 🔴 -7.1%
drop(40) + toArray (50 element source) 6,724 → 6,300 -6.3% 9,955 → 8,698 🔴 -12.6%
chained map + filter + take (100 element source) 8,302 → 7,784 -6.2% 11,954 → 10,210 🔴 -14.6%
some + every (50 elements) 2,699 → 2,466 🔴 -8.6% 3,939 → 3,502 🔴 -11.1%
find (50 elements) 5,856 → 5,381 🔴 -8.1% 7,762 → 7,304 -5.9%
array.values().map().filter().toArray() 8,252 → 7,595 🔴 -8.0% 11,029 → 9,762 🔴 -11.5%
array.values().take(5).toArray() 212,669 → 204,347 -3.9% 255,272 → 233,064 🔴 -8.7%
array.values().drop(45).toArray() 197,773 → 186,740 -5.6% 238,411 → 208,726 🔴 -12.5%
map.entries() chained helpers 10,341 → 9,537 🔴 -7.8% 6,603 → 5,847 🔴 -11.4%
set.values() chained helpers 17,329 → 16,294 -6.0% 22,650 → 19,918 🔴 -12.1%
string iterator map + toArray 13,522 → 12,548 🔴 -7.2% 15,736 → 14,244 🔴 -9.5%
json.js — Interp: 🔴 11, 9 unch. · avg -8.2% · Bytecode: 🔴 17, 3 unch. · avg -11.8%
Benchmark Interpreted Δ Bytecode Δ
parse simple object 174,016 → 164,645 -5.4% 192,978 → 176,788 🔴 -8.4%
parse nested object 107,123 → 100,074 -6.6% 114,076 → 107,605 -5.7%
parse array of objects 62,437 → 58,903 -5.7% 68,270 → 61,729 🔴 -9.6%
parse large flat object 67,978 → 65,381 -3.8% 76,847 → 70,250 🔴 -8.6%
parse mixed types 77,936 → 75,612 -3.0% 88,882 → 78,367 🔴 -11.8%
stringify simple object 196,570 → 174,130 🔴 -11.4% 231,748 → 187,976 🔴 -18.9%
stringify nested object 111,125 → 96,507 🔴 -13.2% 120,927 → 101,922 🔴 -15.7%
stringify array of objects 61,367 → 48,913 🔴 -20.3% 61,101 → 50,913 🔴 -16.7%
stringify mixed types 88,747 → 76,151 🔴 -14.2% 95,636 → 78,450 🔴 -18.0%
reviver doubles numbers 48,827 → 47,405 -2.9% 56,096 → 53,816 -4.1%
reviver filters properties 40,990 → 40,057 -2.3% 48,234 → 43,076 🔴 -10.7%
reviver on nested object 52,120 → 51,689 -0.8% 58,849 → 55,085 -6.4%
reviver on array 32,390 → 31,812 -1.8% 37,050 → 32,905 🔴 -11.2%
replacer function doubles numbers 47,500 → 43,905 🔴 -7.6% 57,149 → 49,438 🔴 -13.5%
replacer function excludes properties 60,535 → 55,509 🔴 -8.3% 67,360 → 59,339 🔴 -11.9%
array replacer (allowlist) 113,086 → 103,524 🔴 -8.5% 129,464 → 112,554 🔴 -13.1%
stringify with 2-space indent 97,136 → 81,412 🔴 -16.2% 105,268 → 92,001 🔴 -12.6%
stringify with tab indent 96,325 → 83,224 🔴 -13.6% 108,214 → 91,203 🔴 -15.7%
parse then stringify 55,610 → 50,621 🔴 -9.0% 62,659 → 55,511 🔴 -11.4%
stringify then parse 34,306 → 31,191 🔴 -9.1% 38,731 → 33,671 🔴 -13.1%
jsx.jsx — Interp: 21 unch. · avg -1.1% · Bytecode: 🔴 1, 20 unch. · avg -3.1%
Benchmark Interpreted Δ Bytecode Δ
simple element 210,383 → 209,744 -0.3% 323,526 → 331,290 +2.4%
self-closing element 219,434 → 218,747 -0.3% 369,840 → 352,561 -4.7%
element with string attribute 177,193 → 175,460 -1.0% 258,109 → 257,231 -0.3%
element with multiple attributes 157,621 → 153,362 -2.7% 208,001 → 201,632 -3.1%
element with expression attribute 167,960 → 163,617 -2.6% 258,894 → 255,411 -1.3%
text child 209,840 → 211,598 +0.8% 342,525 → 324,089 -5.4%
expression child 205,460 → 210,192 +2.3% 331,751 → 325,398 -1.9%
mixed text and expression 195,027 → 193,360 -0.9% 301,727 → 285,931 -5.2%
nested elements (3 levels) 80,402 → 80,064 -0.4% 124,657 → 120,429 -3.4%
sibling children 60,127 → 59,504 -1.0% 93,769 → 89,814 -4.2%
component element 150,384 → 149,302 -0.7% 227,712 → 224,348 -1.5%
component with children 92,565 → 92,167 -0.4% 142,284 → 131,891 🔴 -7.3%
dotted component 126,733 → 124,811 -1.5% 179,645 → 175,389 -2.4%
empty fragment 222,771 → 220,351 -1.1% 390,725 → 366,840 -6.1%
fragment with children 59,597 → 59,773 +0.3% 91,153 → 89,337 -2.0%
spread attributes 111,920 → 108,325 -3.2% 141,113 → 131,557 -6.8%
spread with overrides 97,307 → 94,482 -2.9% 120,500 → 118,701 -1.5%
shorthand props 162,603 → 156,962 -3.5% 240,062 → 233,654 -2.7%
nav bar structure 28,267 → 27,931 -1.2% 41,316 → 41,373 +0.1%
card component tree 32,374 → 32,075 -0.9% 46,404 → 43,623 -6.0%
10 list items via Array.from 14,871 → 14,508 -2.4% 19,942 → 19,428 -2.6%
modules.js — Interp: 9 unch. · avg -3.1% · Bytecode: 🔴 7, 2 unch. · avg -9.2%
Benchmark Interpreted Δ Bytecode Δ
call imported function 480,318 → 461,575 -3.9% 637,419 → 653,432 +2.5%
call two imported functions 269,701 → 259,307 -3.9% 362,256 → 353,148 -2.5%
read imported constant 1,638,335 → 1,579,496 -3.6% 4,108,713 → 3,647,257 🔴 -11.2%
read imported string 1,594,126 → 1,557,318 -2.3% 4,109,933 → 3,487,290 🔴 -15.1%
read JSON string property 1,636,034 → 1,569,907 -4.0% 4,076,285 → 3,654,247 🔴 -10.4%
read JSON number property 1,596,774 → 1,559,759 -2.3% 4,110,576 → 3,649,498 🔴 -11.2%
read JSON boolean property 1,632,399 → 1,573,223 -3.6% 4,111,840 → 3,647,539 🔴 -11.3%
read JSON array property 1,630,359 → 1,565,296 -4.0% 4,114,615 → 3,652,430 🔴 -11.2%
read multiple JSON properties 930,814 → 929,460 -0.1% 3,748,977 → 3,282,923 🔴 -12.4%
numbers.js — Interp: 🔴 1, 10 unch. · avg -3.2% · Bytecode: 🔴 7, 4 unch. · avg -9.9%
Benchmark Interpreted Δ Bytecode Δ
integer arithmetic 518,683 → 479,185 🔴 -7.6% 1,762,920 → 1,508,504 🔴 -14.4%
floating point arithmetic 592,826 → 578,936 -2.3% 1,276,611 → 806,465 🔴 -36.8%
number coercion 191,551 → 189,531 -1.1% 244,368 → 226,636 🔴 -7.3%
toFixed 100,895 → 98,345 -2.5% 122,407 → 111,278 🔴 -9.1%
toString 156,717 → 147,020 -6.2% 199,776 → 183,774 🔴 -8.0%
valueOf 230,266 → 216,834 -5.8% 289,190 → 279,439 -3.4%
toPrecision 145,114 → 138,521 -4.5% 171,868 → 165,771 -3.5%
Number.isNaN 321,359 → 327,182 +1.8% 365,282 → 338,889 🔴 -7.2%
Number.isFinite 325,524 → 317,189 -2.6% 343,024 → 325,133 -5.2%
Number.isInteger 326,493 → 327,483 +0.3% 383,790 → 357,773 -6.8%
Number.parseInt and parseFloat 257,048 → 245,649 -4.4% 290,199 → 268,312 🔴 -7.5%
objects.js — Interp: 🔴 1, 6 unch. · avg -4.6% · Bytecode: 7 unch. · avg -2.9%
Benchmark Interpreted Δ Bytecode Δ
create simple object 491,357 → 477,525 -2.8% 570,807 → 554,729 -2.8%
create nested object 235,544 → 221,790 -5.8% 263,544 → 253,177 -3.9%
create 50 objects via Array.from 9,274 → 8,955 -3.4% 10,168 → 9,819 -3.4%
property read 552,058 → 538,482 -2.5% 442,642 → 438,727 -0.9%
Object.keys 288,900 → 267,776 🔴 -7.3% 333,891 → 319,038 -4.4%
Object.entries 105,518 → 101,639 -3.7% 114,175 → 108,852 -4.7%
spread operator 180,968 → 168,474 -6.9% 210,751 → 210,908 +0.1%
promises.js — Interp: 12 unch. · avg -3.2% · Bytecode: 12 unch. · avg -4.2%
Benchmark Interpreted Δ Bytecode Δ
Promise.resolve(value) 542,388 → 537,836 -0.8% 587,855 → 572,245 -2.7%
new Promise(resolve => resolve(value)) 191,677 → 189,790 -1.0% 236,737 → 232,203 -1.9%
Promise.reject(reason) 549,461 → 539,243 -1.9% 583,421 → 547,010 -6.2%
resolve + then (1 handler) 177,968 → 172,183 -3.3% 209,375 → 200,487 -4.2%
resolve + then chain (3 deep) 70,175 → 67,209 -4.2% 82,910 → 79,357 -4.3%
resolve + then chain (10 deep) 22,169 → 20,641 -6.9% 25,912 → 24,901 -3.9%
reject + catch + then 100,358 → 97,684 -2.7% 118,788 → 112,893 -5.0%
resolve + finally + then 84,697 → 81,897 -3.3% 95,847 → 92,083 -3.9%
Promise.all (5 resolved) 31,491 → 30,834 -2.1% 35,039 → 33,146 -5.4%
Promise.race (5 resolved) 33,498 → 31,844 -4.9% 36,767 → 35,312 -4.0%
Promise.allSettled (5 mixed) 26,537 → 25,681 -3.2% 29,205 → 28,128 -3.7%
Promise.any (5 mixed) 32,101 → 30,600 -4.7% 34,455 → 32,745 -5.0%
strings.js — Interp: 11 unch. · avg -4.1% · Bytecode: 🟢 1, 🔴 4, 6 unch. · avg -3.6%
Benchmark Interpreted Δ Bytecode Δ
string concatenation 408,262 → 385,484 -5.6% 298,311 → 320,633 🟢 +7.5%
template literal 616,385 → 632,591 +2.6% 650,554 → 656,614 +0.9%
string repeat 404,435 → 378,235 -6.5% 492,533 → 455,599 🔴 -7.5%
split and join 139,583 → 131,839 -5.5% 159,056 → 158,677 -0.2%
indexOf and includes 166,953 → 160,415 -3.9% 206,393 → 186,970 🔴 -9.4%
toUpperCase and toLowerCase 252,726 → 243,194 -3.8% 340,275 → 335,024 -1.5%
slice and substring 152,536 → 145,337 -4.7% 206,848 → 192,040 🔴 -7.2%
trim operations 185,839 → 176,194 -5.2% 246,979 → 245,521 -0.6%
replace and replaceAll 210,537 → 201,038 -4.5% 253,316 → 235,954 -6.9%
startsWith and endsWith 132,942 → 127,779 -3.9% 168,876 → 157,432 -6.8%
padStart and padEnd 194,154 → 185,814 -4.3% 244,894 → 225,458 🔴 -7.9%
typed-arrays.js — Interp: 🔴 1, 21 unch. · avg -3.7% · Bytecode: 🔴 14, 8 unch. · avg -9.0%
Benchmark Interpreted Δ Bytecode Δ
new Int32Array(0) 331,890 → 309,757 -6.7% 390,540 → 376,138 -3.7%
new Int32Array(100) 304,689 → 283,698 -6.9% 354,490 → 336,888 -5.0%
new Int32Array(1000) 183,682 → 173,667 -5.5% 225,700 → 201,379 🔴 -10.8%
new Float64Array(100) 276,911 → 261,621 -5.5% 339,187 → 315,154 🔴 -7.1%
Int32Array.from([...]) 183,282 → 171,634 -6.4% 214,568 → 189,229 🔴 -11.8%
Int32Array.of(1, 2, 3, 4, 5) 311,950 → 299,456 -4.0% 352,698 → 364,202 +3.3%
sequential write 100 elements 3,529 → 3,390 -3.9% 17,526 → 15,785 🔴 -9.9%
sequential read 100 elements 3,570 → 3,429 -4.0% 11,561 → 11,172 -3.4%
Float64Array write 100 elements 3,271 → 3,117 -4.7% 12,852 → 8,786 🔴 -31.6%
fill(42) 46,523 → 46,802 +0.6% 59,683 → 47,025 🔴 -21.2%
slice() 197,321 → 197,366 +0.0% 241,384 → 219,909 🔴 -8.9%
map(x => x * 2) 8,022 → 7,656 -4.6% 9,651 → 8,819 🔴 -8.6%
filter(x => x > 50) 8,451 → 7,834 🔴 -7.3% 10,532 → 9,504 🔴 -9.8%
reduce (sum) 7,853 → 7,475 -4.8% 7,923 → 7,487 -5.5%
sort() 171,376 → 164,210 -4.2% 208,059 → 171,972 🔴 -17.3%
indexOf() 422,432 → 414,636 -1.8% 550,352 → 493,375 🔴 -10.4%
reverse() 321,898 → 318,922 -0.9% 393,791 → 351,579 🔴 -10.7%
create view over existing buffer 401,962 → 389,065 -3.2% 473,615 → 455,218 -3.9%
subarray() 420,311 → 419,899 -0.1% 532,944 → 517,966 -2.8%
set() from array 555,995 → 562,120 +1.1% 683,714 → 631,635 🔴 -7.6%
for-of loop 4,986 → 4,703 -5.7% 19,791 → 18,285 🔴 -7.6%
spread into array 17,116 → 16,625 -2.9% 101,733 → 97,870 -3.8%

Measured on ubuntu-latest x64. Changes within ±7% are considered insignificant.

@github-actions
Copy link
Copy Markdown
Contributor

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 3534 3534
Tests Passed 3493 ✅ 3534 ✅
Tests Skipped 41 0
Tests Execution 153.4ms 145.8ms
Tests Engine 306.2ms 531.6ms
Benchmarks Total 263 263
Benchmarks Duration 7.16min 6.01min

Measured on ubuntu-latest x64.

@frostney frostney merged commit 051ff64 into main Mar 31, 2026
9 checks passed
@frostney frostney deleted the feature/json-stringify-error-tests branch March 31, 2026 03:39
@frostney frostney added the internal Refactoring, CI, tooling, cleanup label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal Refactoring, CI, tooling, cleanup

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add error case tests for JSON.stringify

1 participant