-
-
Notifications
You must be signed in to change notification settings - Fork 159
perf: settle eight-shape static write PICs #8026
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| ### perf(objects): settle eight-shape static write caches (#6812) | ||
|
|
||
| Static existing-field writes now retain four inline receiver-shape entries and | ||
| use a compact outlined helper for four more. Once all eight entries are full, | ||
| the cache stays settled instead of continuously evicting its fourth shape; | ||
| ninth and later shapes continue through full `[[Set]]` semantics without | ||
| unbounded code growth. | ||
|
|
||
| On the new 60-million-write eight-shape matrix cell, 15 alternating runs reduce | ||
| Perry's median from 2,359 ms to 768 ms (67.4%, 3.07×) with identical Node/Perry | ||
| checksums. Monomorphic timing is unchanged, four-shape timing stays within 2%, | ||
| and both linked matrix executables have the same file size. |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13707,8 +13707,14 @@ fn static_put_value_uses_write_pic_for_call_free_rhs() { | |||||||||||||
| ir.contains("put.pic.guard2") | ||||||||||||||
| && ir.contains("put.pic.guard3") | ||||||||||||||
| && ir.contains("put.pic.guard4") | ||||||||||||||
| && ir.contains("put.pic.miss4"), | ||||||||||||||
| "the write PIC should retain four bounded shape entries" | ||||||||||||||
| && ir.contains("put.pic.miss4") | ||||||||||||||
| && ir.contains("put.pic.tail") | ||||||||||||||
| && ir.contains("call double @js_put_value_set_ic_poly_tail"), | ||||||||||||||
| "the write PIC should retain four inline entries plus a bounded outlined tail" | ||||||||||||||
| ); | ||||||||||||||
| assert!( | ||||||||||||||
| ir.contains("@perry_ic_0_poly_tail = private global"), | ||||||||||||||
| "the outlined ways must use a distinct zero-initialized cache:\n{ir}" | ||||||||||||||
|
Comment on lines
+13715
to
+13717
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Assert the complete outlined-cache initializer. Line 13716 only checks that a global with this name exists. The assertion also passes if the cache has a non-zero initializer or the wrong element layout. Match the Proposed test update- ir.contains("`@perry_ic_0_poly_tail` = private global"),
+ ir.contains("`@perry_ic_0_poly_tail` = private global [8 x i64] zeroinitializer"),📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| ); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,6 +85,58 @@ for (let r = 0; r < 5; r++) { | |
| } | ||
| console.log("mixed", fieldSum(mixed, ["x"])); | ||
|
|
||
| // The static write PIC settles four inline and four outlined shape entries. | ||
| const mixedEight: any[] = [ | ||
| { x: 0, a: 1 }, | ||
| { x: 0, b: 2 }, | ||
| { x: 0, c: 3 }, | ||
| { x: 0, d: 4 }, | ||
| { x: 0, e: 5 }, | ||
| { x: 0, f: 6 }, | ||
| { x: 0, g: 7 }, | ||
| { x: 0, h: 8 }, | ||
| ]; | ||
| for (let r = 0; r < 5; r++) { | ||
| for (let i = 0; i < mixedEight.length; i++) { | ||
| const object: any = mixedEight[i]; | ||
| object.x = r + i; | ||
| } | ||
| } | ||
| console.log("mixed-eight", fieldSum(mixedEight, ["x"])); | ||
|
|
||
| let tailFrozenThrew = false; | ||
| Object.freeze(mixedEight[7]); | ||
| try { | ||
| for (let i = 0; i < mixedEight.length; i++) { | ||
| const object: any = mixedEight[i]; | ||
| object.x = 100 + i; | ||
| } | ||
| } catch (error) { | ||
| tailFrozenThrew = error instanceof TypeError; | ||
| } | ||
| console.log("tail-frozen", tailFrozenThrew, mixedEight[7].x); | ||
|
Comment on lines
+107
to
+117
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Verify whether the fixture runner injects strict mode or executes this file as a script.
rg -n -C 3 'test_gap_6812_object_write_loop_generalization|experimental-strip-types|alwaysStrict|use strict' .Repository: PerryTS/perry Length of output: 50370 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- fixture ---'
cat -n test-files/test_gap_6812_object_write_loop_generalization.ts
printf '%s\n' '--- exact references and runner logic ---'
rg -n -C 5 \
'test_gap_6812_object_write_loop_generalization|run_gap|test-files/.*\.ts|strip-types|PERRY.*strict|strict mode' \
--glob '!target/**' \
--glob '!node_modules/**' \
--glob '!*.min.js' \
--glob '!*.map' \
. \
| head -n 400Repository: PerryTS/perry Length of output: 44710 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- gap-test runner files ---'
git ls-files '*parity*' '*gap*' '*.sh' | rg '(^|/)(run_parity_tests|run_gap_tests|.*parity.*|.*gap.*)\.(sh|py|mjs)$' | head -n 120
printf '%s\n' '--- runner references ---'
rg -n -C 4 \
'run_gap_tests|run_parity_tests|node --experimental-strip-types|expected.*stdout|stdout.*expected|diff.*stdout' \
scripts run_parity_tests.sh run_gap_tests.sh CLAUDE.md 2>/dev/null | head -n 300
printf '%s\n' '--- standalone JavaScript semantics for the frozen-tail block ---'
node - <<'JS'
"use strict";
function fieldSum(objects, fields) {
let sum = 0;
for (let i = 0; i < objects.length; i++) {
const object = objects[i];
if (object === undefined) continue;
for (let k = 0; k < fields.length; k++) {
const value = object[fields[k]];
if (typeof value === "number") sum += value;
}
}
return sum;
}
const mixedEight = [
{ x: 0, a: 1 }, { x: 0, b: 2 }, { x: 0, c: 3 }, { x: 0, d: 4 },
{ x: 0, e: 5 }, { x: 0, f: 6 }, { x: 0, g: 7 }, { x: 0, h: 8 },
];
for (let r = 0; r < 5; r++) {
for (let i = 0; i < mixedEight.length; i++) mixedEight[i].x = r + i;
}
Object.freeze(mixedEight[7]);
let threw = false;
try {
for (let i = 0; i < mixedEight.length; i++) mixedEight[i].x = 100 + i;
} catch (error) {
threw = error instanceof TypeError;
}
console.log(JSON.stringify({
threw,
tail: mixedEight[7].x,
firstSeven: fieldSum(mixedEight.slice(0, 7), ["x"]),
}));
JSRepository: PerryTS/perry Length of output: 25947 Add an oracle for the seven writes before the frozen tail. The file already uses strict mode. The 🤖 Prompt for AI AgentsSource: Learnings |
||
|
|
||
| // A ninth shape takes the bounded semantic fallback without evicting the | ||
| // settled eight ways. | ||
| const mixedNine: any[] = [ | ||
| { x: 0, a: 1 }, | ||
| { x: 0, b: 2 }, | ||
| { x: 0, c: 3 }, | ||
| { x: 0, d: 4 }, | ||
| { x: 0, e: 5 }, | ||
| { x: 0, f: 6 }, | ||
| { x: 0, g: 7 }, | ||
| { x: 0, h: 8 }, | ||
| { x: 0, i: 9 }, | ||
| ]; | ||
| for (let r = 0; r < 5; r++) { | ||
| for (let i = 0; i < mixedNine.length; i++) { | ||
| const object: any = mixedNine[i]; | ||
| object.x = r + i; | ||
| } | ||
| } | ||
| console.log("mixed-nine", fieldSum(mixedNine, ["x"])); | ||
|
|
||
| let holeThrew = false; | ||
| const hole: any[] = [{ x: 0 }, , { x: 0 }]; | ||
| try { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Update the matrix-size statement.
Adding
shape_eightmakesCASEScontain 26 entries.benchmarks/object-write-6812/results.mdstill says “final 25-cell matrix” and “All 25 write-count/checksum pairs matched” at Lines 69-70. Change both counts to 26, or state explicitly that the follow-up case is excluded from that sweep.🤖 Prompt for AI Agents