Skip to content

Unify blueprint bridge on ConvertBlueprintToClassValue#100

Merged
frostney merged 2 commits into
mainfrom
fix/split-blueprint-bridge-caches
Mar 17, 2026
Merged

Unify blueprint bridge on ConvertBlueprintToClassValue#100
frostney merged 2 commits into
mainfrom
fix/split-blueprint-bridge-caches

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Mar 17, 2026

Fixes #99.

Summary

  • Unify both blueprint-to-class bridge paths (UnwrapToGocciaValue and Construct) on ConvertBlueprintToClassValue, eliminating the cache cross-contamination where a simpler bridge from the value path could be reused by the construct path
  • Remove the now-unused BlueprintToClassValue function (the simpler converter that omitted getters/setters, static fields, private members, and field initializers)
  • Add targeted tests for bridge consistency covering static methods, getters/setters, private fields, and instanceof identity

Approach

Option C from the issue: unify on the richer converter everywhere. Options A (split caches) and B (keyed cache) were explored but split caches caused instanceof failures because construction and value unwrapping produced different TGocciaClassValue instances with different prototypes, so instanceof could not match them. Unifying on the richer converter ensures one class value per blueprint with consistent prototype identity.

Test plan

  • Interpreter: 3502 passed, 0 failed, 41 skipped
  • Bytecode: 3502 passed, 0 failed, 0 skipped
  • New bridge consistency tests pass in both modes
  • CI benchmarks for performance comparison

Made with Cursor

Summary by CodeRabbit

  • Tests

    • Added validation for class reference behavior with instanceof checks.
    • Extended test coverage for property accessors with private field support.
  • Refactor

    • Internal runtime code clarity improved through function naming updates.

Fixes #99. The UnwrapToGocciaValue path previously used the simpler
BlueprintToClassValue which omitted getters/setters, static fields,
private members, and field initializers. If a blueprint was first seen
via value unwrapping, the cached simpler bridge could be reused by
Construct, dropping richer semantics.

Unify both paths on ConvertBlueprintToClassValue so the cache always
holds the full-fidelity class value. Remove the now-unused
BlueprintToClassValue function. Add targeted tests for bridge
consistency covering static methods, getters/setters, private fields,
and instanceof identity across value-unwrap and construction paths.

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5502e9d6-db49-4e57-aa75-4e1d0ef37b63

📥 Commits

Reviewing files that changed from the base of the PR and between 750905e and caebb7a.

📒 Files selected for processing (2)
  • tests/language/classes/basic-class-declaration.js
  • tests/language/classes/getters-setters.js

📝 Walkthrough

Walkthrough

The change removes the public BlueprintToClassValue function declaration and replaces all usages with ConvertBlueprintToClassValue in runtime operations, standardizing on the richer blueprint-to-class conversion method. Two new test cases verify class reference behavior and private field backing with getters/setters.

Changes

Cohort / File(s) Summary
Runtime Operations Refactoring
units/Goccia.Runtime.Operations.pas
Removed public forward declaration of BlueprintToClassValue and introduced ConvertBlueprintToClassValue as the standard conversion function. All call sites updated to use the new function name, eliminating the old simpler conversion path in favor of the richer bridge semantics.
Class Reference Test
tests/language/classes/basic-class-declaration.js
Added test case "class reference preserves instanceof" verifying that class reference aliases correctly support instanceof checks and instantiation without losing type identity.
Getters/Setters with Private Fields Test
tests/language/classes/getters-setters.js
Added test case validating getters and setters using private backing fields, including constructor initialization, accessor functionality, and instance type verification.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 The bridges are unified, clear and bright,
ConvertBlueprintToClassValue shines with might!
Private fields dance with getters so fine,
Class references checked, all in a line.
Runtime ops harmonized—a hop toward the light! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: renaming and unifying the blueprint bridge function to ConvertBlueprintToClassValue, which is the primary objective of the PR.
Linked Issues check ✅ Passed The PR successfully implements option C from issue #99: unifying on ConvertBlueprintToClassValue everywhere, removing BlueprintToClassValue, and adding targeted tests for bridge consistency covering getters/setters and instanceof checks.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the PR objectives: the blueprint bridge function rename/removal, function call updates, and new test coverage for class declarations and accessor behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/split-blueprint-bridge-caches
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Remove implementation-detail test file (blueprint-bridge-consistency.js).
Merge the two uncovered scenarios into existing language-level tests:
- Class reference preserving instanceof → basic-class-declaration.js
- Getters/setters with private backing field → getters-setters.js

Made-with: Cursor
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/language/classes/blueprint-bridge-consistency.js`:
- Around line 21-101: Add a deterministic regression test that first captures a
class as a value and only afterwards constructs it to reproduce the “value path
first, construct path second” failure: create a class (e.g., RichClass) with a
static method/property, a private field and an accessor, then assign it to a
variable (e.g., RichClassRef = RichClass) to simulate the value-bridge path,
construct an instance via new RichClassRef(), and assert that instance
instanceof RichClass, instance.__proto__.constructor === RichClass, static
members (RichClass.increment or a static getter) behave correctly, and private
field accessors (instance.reveal or getter) return expected values; add this as
a new test case alongside the existing class tests (use a descriptive test name
like "value-then-construct preserves prototype, statics and privates") so it
runs deterministically.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4af3664d-79e6-4215-9780-21defe1bc21a

📥 Commits

Reviewing files that changed from the base of the PR and between 78b24cd and 750905e.

📒 Files selected for processing (2)
  • tests/language/classes/blueprint-bridge-consistency.js
  • units/Goccia.Runtime.Operations.pas

Comment thread tests/language/classes/blueprint-bridge-consistency.js Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 17, 2026

Benchmark Results

254 benchmarks

Interpreted: 🔴 1 regressed · 253 unchanged · avg +0.6%
Bytecode: 🟢 11 improved · 🔴 3 regressed · 240 unchanged · avg +0.9%

arraybuffer.js — Interp: 14 unch. · avg +0.4% · Bytecode: 14 unch. · avg +0.5%
Benchmark Interpreted Δ Bytecode Δ
create ArrayBuffer(0) 425,509 → 438,585 +3.1% 145,039 → 147,658 +1.8%
create ArrayBuffer(64) 418,439 → 428,884 +2.5% 143,011 → 143,772 +0.5%
create ArrayBuffer(1024) 322,779 → 326,770 +1.2% 129,237 → 129,558 +0.2%
create ArrayBuffer(8192) 140,110 → 139,081 -0.7% 80,847 → 81,018 +0.2%
slice full buffer (64 bytes) 510,996 → 510,913 -0.0% 404,474 → 406,374 +0.5%
slice half buffer (512 of 1024 bytes) 429,569 → 433,025 +0.8% 351,867 → 354,252 +0.7%
slice with negative indices 439,706 → 445,562 +1.3% 381,997 → 381,878 -0.0%
slice empty range 498,861 → 503,561 +0.9% 397,945 → 402,699 +1.2%
byteLength access 1,561,536 → 1,573,434 +0.8% 1,316,716 → 1,283,910 -2.5%
Symbol.toStringTag access 1,168,176 → 1,180,332 +1.0% 627,981 → 622,214 -0.9%
ArrayBuffer.isView 771,206 → 727,123 -5.7% 515,608 → 513,099 -0.5%
clone ArrayBuffer(64) 379,921 → 382,550 +0.7% 331,799 → 340,105 +2.5%
clone ArrayBuffer(1024) 296,096 → 296,023 -0.0% 256,945 → 260,333 +1.3%
clone ArrayBuffer inside object 261,972 → 260,441 -0.6% 157,831 → 161,832 +2.5%
arrays.js — Interp: 19 unch. · avg +1.0% · Bytecode: 19 unch. · avg +0.1%
Benchmark Interpreted Δ Bytecode Δ
Array.from length 100 13,897 → 14,224 +2.4% 15,583 → 15,471 -0.7%
Array.from 10 elements 230,283 → 225,010 -2.3% 171,422 → 170,986 -0.3%
Array.of 10 elements 309,297 → 308,767 -0.2% 236,803 → 237,562 +0.3%
spread into new array 334,512 → 332,383 -0.6% 914,482 → 905,143 -1.0%
map over 50 elements 27,525 → 28,051 +1.9% 26,345 → 25,907 -1.7%
filter over 50 elements 23,591 → 23,892 +1.3% 25,264 → 25,507 +1.0%
reduce sum 50 elements 26,574 → 27,146 +2.2% 22,348 → 21,510 -3.8%
forEach over 50 elements 23,497 → 23,240 -1.1% 27,590 → 28,255 +2.4%
find in 50 elements 35,496 → 36,586 +3.1% 32,993 → 32,669 -1.0%
sort 20 elements 12,082 → 12,178 +0.8% 13,350 → 13,061 -2.2%
flat nested array 114,124 → 117,243 +2.7% 485,515 → 494,383 +1.8%
flatMap 71,892 → 72,422 +0.7% 322,026 → 326,038 +1.2%
map inside map (5x5) 21,299 → 21,398 +0.5% 105,643 → 105,455 -0.2%
filter inside map (5x10) 15,834 → 15,910 +0.5% 15,200 → 15,189 -0.1%
reduce inside map (5x10) 19,110 → 19,503 +2.1% 15,507 → 15,646 +0.9%
forEach inside forEach (5x10) 16,816 → 16,978 +1.0% 17,214 → 18,006 +4.6%
find inside some (10x10) 13,838 → 14,080 +1.7% 12,115 → 12,297 +1.5%
map+filter chain nested (5x20) 5,403 → 5,481 +1.4% 5,148 → 5,036 -2.2%
reduce flatten (10x5) 38,165 → 38,617 +1.2% 6,441 → 6,549 +1.7%
async-await.js — Interp: 6 unch. · avg +1.9% · Bytecode: 6 unch. · avg +0.1%
Benchmark Interpreted Δ Bytecode Δ
single await 359,898 → 369,536 +2.7% 292,848 → 292,247 -0.2%
multiple awaits 161,527 → 162,667 +0.7% 124,086 → 123,211 -0.7%
await non-Promise value 823,956 → 844,865 +2.5% 1,057,623 → 1,092,540 +3.3%
await with try/catch 353,176 → 360,410 +2.0% 286,580 → 281,345 -1.8%
await Promise.all 51,185 → 51,446 +0.5% 44,896 → 44,317 -1.3%
nested async function call 183,178 → 188,080 +2.7% 222,074 → 225,464 +1.5%
classes.js — Interp: 31 unch. · avg +1.6% · Bytecode: 🟢 1, 30 unch. · avg +1.2%
Benchmark Interpreted Δ Bytecode Δ
simple class new 115,124 → 118,675 +3.1% 416,994 → 415,919 -0.3%
class with defaults 93,018 → 93,516 +0.5% 295,146 → 297,421 +0.8%
50 instances via Array.from 5,546 → 5,492 -1.0% 7,148 → 7,123 -0.4%
instance method call 59,274 → 59,231 -0.1% 199,087 → 194,448 -2.3%
static method call 91,596 → 92,104 +0.6% 430,534 → 444,284 +3.2%
single-level inheritance 46,156 → 46,169 +0.0% 192,760 → 190,134 -1.4%
two-level inheritance 38,740 → 39,309 +1.5% 160,509 → 159,975 -0.3%
private field access 57,789 → 58,308 +0.9% 214,659 → 212,098 -1.2%
private methods 63,330 → 63,225 -0.2% 274,791 → 279,363 +1.7%
getter/setter access 65,884 → 66,653 +1.2% 204,835 → 203,029 -0.9%
class decorator (identity) 80,217 → 83,527 +4.1% 54,434 → 55,126 +1.3%
class decorator (wrapping) 46,977 → 48,027 +2.2% 38,342 → 39,461 +2.9%
identity method decorator 57,858 → 59,093 +2.1% 44,328 → 47,007 +6.0%
wrapping method decorator 47,594 → 48,567 +2.0% 38,894 → 42,506 🟢 +9.3%
stacked method decorators (x3) 33,758 → 34,771 +3.0% 28,524 → 27,637 -3.1%
identity field decorator 65,945 → 67,232 +2.0% 46,947 → 47,642 +1.5%
field initializer decorator 56,047 → 57,531 +2.6% 42,172 → 43,134 +2.3%
getter decorator (identity) 56,329 → 57,390 +1.9% 42,338 → 42,233 -0.2%
setter decorator (identity) 47,784 → 48,702 +1.9% 36,305 → 36,780 +1.3%
static method decorator 61,721 → 63,126 +2.3% 66,059 → 66,892 +1.3%
static field decorator 71,397 → 72,932 +2.1% 68,767 → 69,639 +1.3%
private method decorator 47,181 → 48,073 +1.9% 38,833 → 39,557 +1.9%
private field decorator 53,057 → 53,390 +0.6% 40,360 → 40,310 -0.1%
plain auto-accessor (no decorator) 88,236 → 91,814 +4.1% 55,562 → 56,290 +1.3%
auto-accessor with decorator 52,057 → 53,735 +3.2% 38,327 → 38,974 +1.7%
decorator writing metadata 43,354 → 43,711 +0.8% 44,248 → 44,875 +1.4%
static getter read 105,007 → 106,815 +1.7% 449,541 → 456,851 +1.6%
static getter/setter pair 80,316 → 80,619 +0.4% 238,472 → 244,597 +2.6%
inherited static getter 59,333 → 59,842 +0.9% 305,435 → 311,103 +1.9%
inherited static setter 63,548 → 65,295 +2.7% 237,925 → 238,858 +0.4%
inherited static getter with this binding 53,844 → 54,277 +0.8% 182,565 → 183,455 +0.5%
closures.js — Interp: 11 unch. · avg +0.2% · Bytecode: 🟢 5, 6 unch. · avg +6.7%
Benchmark Interpreted Δ Bytecode Δ
closure over single variable 131,138 → 135,190 +3.1% 742,858 → 830,102 🟢 +11.7%
closure over multiple variables 118,064 → 119,464 +1.2% 466,900 → 494,140 +5.8%
nested closures 123,359 → 125,645 +1.9% 685,023 → 740,624 🟢 +8.1%
function as argument 94,845 → 93,654 -1.3% 654,947 → 737,869 🟢 +12.7%
function returning function 116,327 → 116,604 +0.2% 730,933 → 811,802 🟢 +11.1%
compose two functions 70,552 → 70,649 +0.1% 443,077 → 489,086 🟢 +10.4%
fn.call 150,433 → 148,211 -1.5% 147,615 → 146,966 -0.4%
fn.apply 110,683 → 111,177 +0.4% 95,507 → 99,890 +4.6%
fn.bind 135,172 → 134,658 -0.4% 149,349 → 150,524 +0.8%
recursive sum to 50 11,576 → 11,586 +0.1% 51,317 → 52,980 +3.2%
recursive tree traversal 19,227 → 18,898 -1.7% 72,184 → 76,064 +5.4%
collections.js — Interp: 12 unch. · avg -0.7% · Bytecode: 12 unch. · avg -1.4%
Benchmark Interpreted Δ Bytecode Δ
add 50 elements 7,273 → 7,080 -2.6% 5,960 → 5,959 -0.0%
has lookup (50 elements) 86,143 → 88,617 +2.9% 92,129 → 88,977 -3.4%
delete elements 48,063 → 47,457 -1.3% 37,382 → 37,418 +0.1%
forEach iteration 16,072 → 15,890 -1.1% 17,843 → 18,386 +3.0%
spread to array 33,332 → 33,662 +1.0% 157,059 → 154,500 -1.6%
deduplicate array 42,145 → 42,282 +0.3% 50,234 → 49,291 -1.9%
set 50 entries 5,317 → 5,248 -1.3% 6,261 → 6,147 -1.8%
get lookup (50 entries) 87,176 → 85,222 -2.2% 101,748 → 98,935 -2.8%
has check 131,538 → 127,151 -3.3% 164,240 → 159,703 -2.8%
delete entries 45,859 → 45,983 +0.3% 36,631 → 35,295 -3.6%
forEach iteration 16,425 → 15,883 -3.3% 17,910 → 18,261 +2.0%
keys/values/entries 8,912 → 9,169 +2.9% 23,166 → 22,226 -4.1%
destructuring.js — Interp: 22 unch. · avg +2.0% · Bytecode: 🟢 1, 21 unch. · avg +3.0%
Benchmark Interpreted Δ Bytecode Δ
simple array destructuring 422,756 → 416,284 -1.5% 1,085,440 → 1,061,298 -2.2%
with rest element 284,178 → 293,891 +3.4% 782,102 → 764,108 -2.3%
with defaults 431,683 → 440,097 +1.9% 1,024,452 → 1,022,395 -0.2%
skip elements 438,735 → 448,794 +2.3% 1,240,880 → 1,230,255 -0.9%
nested array destructuring 179,795 → 185,097 +2.9% 527,372 → 547,552 +3.8%
swap variables 516,270 → 546,824 +5.9% 1,423,388 → 1,499,239 +5.3%
simple object destructuring 299,941 → 301,066 +0.4% 641,987 → 656,185 +2.2%
with defaults 368,633 → 367,844 -0.2% 335,893 → 345,897 +3.0%
with renaming 312,956 → 330,636 +5.6% 745,985 → 760,873 +2.0%
nested object destructuring 148,656 → 153,189 +3.0% 292,480 → 300,519 +2.7%
rest properties 188,706 → 195,958 +3.8% 241,796 → 248,160 +2.6%
object parameter 93,257 → 91,385 -2.0% 207,972 → 219,563 +5.6%
array parameter 122,003 → 124,029 +1.7% 400,369 → 460,033 🟢 +14.9%
mixed destructuring in map 36,047 → 36,443 +1.1% 39,198 → 40,726 +3.9%
forEach with array destructuring 66,770 → 68,177 +2.1% 202,376 → 208,501 +3.0%
map with array destructuring 67,798 → 70,438 +3.9% 253,779 → 262,046 +3.3%
filter with array destructuring 70,213 → 72,613 +3.4% 307,171 → 308,838 +0.5%
reduce with array destructuring 75,432 → 78,795 +4.5% 276,449 → 295,297 +6.8%
map with object destructuring 81,321 → 81,600 +0.3% 82,922 → 83,113 +0.2%
map with nested destructuring 66,725 → 67,089 +0.5% 69,612 → 70,134 +0.8%
map with rest in destructuring 39,322 → 40,338 +2.6% 23,718 → 24,644 +3.9%
map with defaults in destructuring 61,033 → 60,279 -1.2% 38,066 → 40,411 +6.2%
fibonacci.js — Interp: 8 unch. · avg -0.7% · Bytecode: 🟢 1, 7 unch. · avg +1.8%
Benchmark Interpreted Δ Bytecode Δ
recursive fib(15) 319 → 312 -2.1% 1,387 → 1,458 +5.1%
recursive fib(20) 29 → 28 -1.7% 129 → 132 +2.2%
recursive fib(15) typed 320 → 318 -0.8% 1,828 → 1,972 🟢 +7.9%
recursive fib(20) typed 29 → 28 -1.1% 175 → 178 +1.8%
iterative fib(20) via reduce 12,075 → 12,381 +2.5% 9,322 → 9,042 -3.0%
iterator fib(20) 9,463 → 9,491 +0.3% 16,291 → 16,140 -0.9%
iterator fib(20) via Iterator.from + take 14,775 → 14,699 -0.5% 17,853 → 17,836 -0.1%
iterator fib(20) last value via reduce 11,242 → 11,035 -1.8% 13,470 → 13,671 +1.5%
for-of.js — Interp: 7 unch. · avg +3.2% · Bytecode: 🔴 1, 6 unch. · avg +0.5%
Benchmark Interpreted Δ Bytecode Δ
for...of with 10-element array 47,722 → 49,077 +2.8% 166,197 → 169,076 +1.7%
for...of with 100-element array 5,524 → 5,756 +4.2% 24,587 → 24,737 +0.6%
for...of with string (10 chars) 34,111 → 35,279 +3.4% 136,395 → 135,368 -0.8%
for...of with Set (10 elements) 48,617 → 49,262 +1.3% 175,359 → 183,993 +4.9%
for...of with Map entries (10 entries) 30,919 → 32,057 +3.7% 51,582 → 47,745 🔴 -7.4%
for...of with destructuring 41,603 → 42,821 +2.9% 79,602 → 80,757 +1.5%
for-await-of with sync array 45,797 → 47,546 +3.8% 138,384 → 142,966 +3.3%
iterators.js — Interp: 20 unch. · avg +1.5% · Bytecode: 🟢 1, 🔴 1, 18 unch. · avg +0.3%
Benchmark Interpreted Δ Bytecode Δ
Iterator.from({next}).toArray() — 20 elements 14,751 → 14,875 +0.8% 17,764 → 18,568 +4.5%
Iterator.from({next}).toArray() — 50 elements 6,507 → 6,481 -0.4% 8,555 → 8,396 -1.9%
spread pre-wrapped iterator — 20 elements 11,388 → 11,650 +2.3% 16,797 → 17,308 +3.0%
Iterator.from({next}).forEach — 50 elements 4,561 → 4,645 +1.8% 5,906 → 5,876 -0.5%
Iterator.from({next}).reduce — 50 elements 4,564 → 4,618 +1.2% 5,688 → 5,676 -0.2%
wrap array iterator 175,155 → 175,426 +0.2% 111,162 → 112,576 +1.3%
wrap plain {next()} object 10,312 → 10,532 +2.1% 12,637 → 13,635 🟢 +7.9%
map + toArray (50 elements) 4,729 → 4,722 -0.1% 6,000 → 6,065 +1.1%
filter + toArray (50 elements) 4,560 → 4,533 -0.6% 5,540 → 5,743 +3.7%
take(10) + toArray (50 element source) 26,576 → 27,575 +3.8% 28,755 → 28,884 +0.4%
drop(40) + toArray (50 element source) 6,438 → 6,536 +1.5% 8,577 → 8,353 -2.6%
chained map + filter + take (100 element source) 8,488 → 8,661 +2.0% 10,223 → 9,866 -3.5%
some + every (50 elements) 2,655 → 2,696 +1.5% 3,459 → 3,585 +3.6%
find (50 elements) 5,792 → 5,943 +2.6% 7,861 → 7,104 🔴 -9.6%
array.values().map().filter().toArray() 8,896 → 9,197 +3.4% 10,951 → 10,846 -1.0%
array.values().take(5).toArray() 213,661 → 220,785 +3.3% 146,610 → 155,359 +6.0%
array.values().drop(45).toArray() 204,849 → 205,610 +0.4% 148,417 → 147,974 -0.3%
map.entries() chained helpers 10,852 → 11,052 +1.8% 5,634 → 5,651 +0.3%
set.values() chained helpers 18,559 → 18,879 +1.7% 23,617 → 23,019 -2.5%
string iterator map + toArray 14,483 → 14,713 +1.6% 23,747 → 22,778 -4.1%
json.js — Interp: 20 unch. · avg +1.5% · Bytecode: 🟢 1, 19 unch. · avg -0.6%
Benchmark Interpreted Δ Bytecode Δ
parse simple object 169,017 → 179,087 +6.0% 153,903 → 148,627 -3.4%
parse nested object 106,387 → 109,037 +2.5% 94,708 → 90,682 -4.3%
parse array of objects 55,263 → 57,145 +3.4% 53,471 → 51,735 -3.2%
parse large flat object 48,910 → 50,223 +2.7% 46,862 → 46,435 -0.9%
parse mixed types 70,963 → 72,677 +2.4% 65,672 → 63,240 -3.7%
stringify simple object 195,349 → 196,617 +0.6% 171,197 → 163,982 -4.2%
stringify nested object 111,018 → 112,369 +1.2% 93,090 → 91,525 -1.7%
stringify array of objects 63,186 → 63,789 +1.0% 53,770 → 53,621 -0.3%
stringify mixed types 86,030 → 88,385 +2.7% 74,999 → 73,047 -2.6%
reviver doubles numbers 44,767 → 44,373 -0.9% 43,186 → 46,918 🟢 +8.6%
reviver filters properties 38,401 → 37,916 -1.3% 48,660 → 48,279 -0.8%
reviver on nested object 51,267 → 50,997 -0.5% 54,549 → 54,790 +0.4%
reviver on array 29,482 → 29,308 -0.6% 30,900 → 30,732 -0.5%
replacer function doubles numbers 48,497 → 47,738 -1.6% 54,686 → 55,354 +1.2%
replacer function excludes properties 60,566 → 60,421 -0.2% 65,722 → 66,471 +1.1%
array replacer (allowlist) 111,438 → 112,388 +0.9% 100,823 → 101,466 +0.6%
stringify with 2-space indent 96,599 → 100,201 +3.7% 83,471 → 83,887 +0.5%
stringify with tab indent 96,498 → 100,030 +3.7% 83,946 → 83,596 -0.4%
parse then stringify 54,179 → 55,217 +1.9% 51,549 → 51,794 +0.5%
stringify then parse 32,644 → 33,337 +2.1% 31,086 → 31,566 +1.5%
jsx.jsx — Interp: 21 unch. · avg +0.5% · Bytecode: 21 unch. · avg +3.4%
Benchmark Interpreted Δ Bytecode Δ
simple element 197,808 → 203,882 +3.1% 784,947 → 817,449 +4.1%
self-closing element 206,112 → 211,548 +2.6% 794,429 → 837,220 +5.4%
element with string attribute 163,108 → 170,789 +4.7% 553,575 → 579,721 +4.7%
element with multiple attributes 144,431 → 146,055 +1.1% 478,326 → 494,459 +3.4%
element with expression attribute 156,424 → 161,418 +3.2% 553,611 → 564,341 +1.9%
text child 203,614 → 200,297 -1.6% 778,175 → 816,495 +4.9%
expression child 200,455 → 195,486 -2.5% 777,819 → 804,609 +3.4%
mixed text and expression 187,235 → 190,370 +1.7% 719,929 → 727,521 +1.1%
nested elements (3 levels) 73,900 → 76,324 +3.3% 305,790 → 323,481 +5.8%
sibling children 55,783 → 55,938 +0.3% 234,540 → 240,413 +2.5%
component element 142,121 → 143,901 +1.3% 537,581 → 560,760 +4.3%
component with children 87,761 → 88,074 +0.4% 341,771 → 360,658 +5.5%
dotted component 118,951 → 121,532 +2.2% 402,510 → 407,628 +1.3%
empty fragment 210,672 → 206,376 -2.0% 802,040 → 848,056 +5.7%
fragment with children 55,223 → 55,175 -0.1% 233,027 → 236,762 +1.6%
spread attributes 106,333 → 105,505 -0.8% 118,359 → 121,224 +2.4%
spread with overrides 93,162 → 91,575 -1.7% 86,176 → 87,353 +1.4%
shorthand props 154,035 → 151,007 -2.0% 532,627 → 548,264 +2.9%
nav bar structure 26,179 → 25,707 -1.8% 97,644 → 99,376 +1.8%
card component tree 30,416 → 30,027 -1.3% 108,622 → 114,102 +5.0%
10 list items via Array.from 13,809 → 13,920 +0.8% 26,633 → 27,068 +1.6%
numbers.js — Interp: 11 unch. · avg -1.9% · Bytecode: 11 unch. · avg -0.5%
Benchmark Interpreted Δ Bytecode Δ
integer arithmetic 572,831 → 546,241 -4.6% 2,130,297 → 2,178,567 +2.3%
floating point arithmetic 573,602 → 586,603 +2.3% 2,378,200 → 2,430,014 +2.2%
number coercion 180,155 → 171,629 -4.7% 142,031 → 135,242 -4.8%
toFixed 100,080 → 101,291 +1.2% 228,375 → 225,755 -1.1%
toString 153,880 → 157,738 +2.5% 891,968 → 888,865 -0.3%
valueOf 224,625 → 227,970 +1.5% 1,372,894 → 1,319,523 -3.9%
toPrecision 141,235 → 142,115 +0.6% 465,645 → 466,033 +0.1%
Number.isNaN 294,015 → 280,908 -4.5% 177,417 → 177,441 +0.0%
Number.isFinite 291,691 → 273,729 -6.2% 172,511 → 172,104 -0.2%
Number.isInteger 282,288 → 272,302 -3.5% 188,380 → 187,311 -0.6%
Number.parseInt and parseFloat 238,345 → 225,818 -5.3% 154,246 → 155,581 +0.9%
objects.js — Interp: 7 unch. · avg -1.3% · Bytecode: 7 unch. · avg +1.7%
Benchmark Interpreted Δ Bytecode Δ
create simple object 457,924 → 447,198 -2.3% 974,405 → 1,024,675 +5.2%
create nested object 213,633 → 213,202 -0.2% 437,701 → 446,957 +2.1%
create 50 objects via Array.from 8,946 → 8,819 -1.4% 9,373 → 9,262 -1.2%
property read 617,712 → 610,264 -1.2% 917,796 → 906,440 -1.2%
Object.keys 289,403 → 284,159 -1.8% 196,258 → 198,307 +1.0%
Object.entries 106,836 → 107,122 +0.3% 62,971 → 65,794 +4.5%
spread operator 186,360 → 181,772 -2.5% 197,639 → 200,248 +1.3%
promises.js — Interp: 12 unch. · avg +0.6% · Bytecode: 🟢 1, 🔴 1, 10 unch. · avg -0.4%
Benchmark Interpreted Δ Bytecode Δ
Promise.resolve(value) 543,644 → 553,565 +1.8% 366,667 → 366,546 -0.0%
new Promise(resolve => resolve(value)) 196,957 → 192,975 -2.0% 160,931 → 160,410 -0.3%
Promise.reject(reason) 535,761 → 543,463 +1.4% 344,197 → 341,508 -0.8%
resolve + then (1 handler) 164,873 → 167,866 +1.8% 157,952 → 145,377 🔴 -8.0%
resolve + then chain (3 deep) 64,852 → 64,077 -1.2% 67,614 → 67,993 +0.6%
resolve + then chain (10 deep) 21,187 → 20,905 -1.3% 22,513 → 21,060 -6.5%
reject + catch + then 95,126 → 95,447 +0.3% 88,261 → 91,531 +3.7%
resolve + finally + then 83,993 → 84,480 +0.6% 71,542 → 76,811 🟢 +7.4%
Promise.all (5 resolved) 32,199 → 32,891 +2.1% 24,765 → 25,834 +4.3%
Promise.race (5 resolved) 33,707 → 34,748 +3.1% 27,900 → 26,675 -4.4%
Promise.allSettled (5 mixed) 26,959 → 26,891 -0.3% 21,940 → 22,487 +2.5%
Promise.any (5 mixed) 31,526 → 31,940 +1.3% 27,253 → 26,302 -3.5%
strings.js — Interp: 🔴 1, 10 unch. · avg -1.8% · Bytecode: 11 unch. · avg -0.6%
Benchmark Interpreted Δ Bytecode Δ
string concatenation 418,369 → 399,493 -4.5% 395,997 → 391,754 -1.1%
template literal 699,303 → 625,681 🔴 -10.5% 730,632 → 721,509 -1.2%
string repeat 395,786 → 397,049 +0.3% 1,142,956 → 1,129,670 -1.2%
split and join 133,137 → 133,879 +0.6% 342,606 → 336,449 -1.8%
indexOf and includes 164,452 → 163,801 -0.4% 781,423 → 773,878 -1.0%
toUpperCase and toLowerCase 259,347 → 257,115 -0.9% 766,920 → 768,774 +0.2%
slice and substring 157,721 → 157,378 -0.2% 878,109 → 902,552 +2.8%
trim operations 190,274 → 190,735 +0.2% 712,984 → 703,012 -1.4%
replace and replaceAll 206,930 → 201,196 -2.8% 647,430 → 635,664 -1.8%
startsWith and endsWith 132,601 → 131,523 -0.8% 656,121 → 653,081 -0.5%
padStart and padEnd 195,949 → 194,652 -0.7% 710,685 → 710,252 -0.1%
typed-arrays.js — Interp: 22 unch. · avg -1.0% · Bytecode: 22 unch. · avg -1.0%
Benchmark Interpreted Δ Bytecode Δ
new Int32Array(0) 322,729 → 324,705 +0.6% 126,824 → 129,309 +2.0%
new Int32Array(100) 299,111 → 296,223 -1.0% 124,650 → 124,595 -0.0%
new Int32Array(1000) 165,593 → 172,739 +4.3% 74,802 → 72,798 -2.7%
new Float64Array(100) 264,610 → 267,566 +1.1% 111,795 → 109,015 -2.5%
Int32Array.from([...]) 182,612 → 178,139 -2.4% 155,181 → 159,337 +2.7%
Int32Array.of(1, 2, 3, 4, 5) 311,392 → 309,575 -0.6% 256,995 → 255,699 -0.5%
sequential write 100 elements 3,660 → 3,611 -1.3% 15,649 → 15,077 -3.7%
sequential read 100 elements 3,792 → 3,816 +0.6% 11,823 → 11,707 -1.0%
Float64Array write 100 elements 3,448 → 3,421 -0.8% 15,140 → 14,574 -3.7%
fill(42) 47,846 → 45,655 -4.6% 46,452 → 44,285 -4.7%
slice() 209,589 → 204,719 -2.3% 189,956 → 190,041 +0.0%
map(x => x * 2) 8,216 → 8,019 -2.4% 8,593 → 8,428 -1.9%
filter(x => x > 50) 8,445 → 8,100 -4.1% 8,788 → 8,739 -0.6%
reduce (sum) 8,064 → 7,828 -2.9% 7,673 → 7,488 -2.4%
sort() 168,110 → 174,692 +3.9% 158,439 → 154,841 -2.3%
indexOf() 450,339 → 436,816 -3.0% 385,397 → 375,719 -2.5%
reverse() 337,443 → 329,241 -2.4% 283,998 → 281,627 -0.8%
create view over existing buffer 401,551 → 391,409 -2.5% 137,363 → 137,601 +0.2%
subarray() 449,528 → 437,680 -2.6% 374,769 → 373,561 -0.3%
set() from array 582,926 → 568,419 -2.5% 270,466 → 271,506 +0.4%
for-of loop 5,210 → 5,313 +2.0% 20,924 → 21,277 +1.7%
spread into array 18,809 → 18,793 -0.1% 55,901 → 56,543 +1.1%

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 17, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 3499 3499
Tests Passed 3458 ✅ 3499 ✅
Tests Skipped 41 0
Tests Execution 155.5ms 166.8ms
Tests Engine 318.0ms 675.5ms
Benchmarks Total 254 254
Benchmarks Duration 6.71min 11.20min

Measured on ubuntu-latest x64.

@frostney frostney merged commit 874b571 into main Mar 17, 2026
9 checks passed
@frostney frostney deleted the fix/split-blueprint-bridge-caches branch March 17, 2026 17:15
@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.

Split blueprint bridge caches (value bridge vs construct bridge)

1 participant