-
-
Notifications
You must be signed in to change notification settings - Fork 161
perf: cut executed instructions on parameter guards, per-element array work and key lookups #10378
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
Closed
Closed
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
4457958
perf(runtime): skip re-registering a class parent edge that is unchanged
2ea8c45
perf(runtime): flush store plans on a pop only when it retires a proof
4e79e5a
perf(codegen): prove an all-number class parameter nominally
33f9b2d
perf(codegen): stop letting a loop license a per-element guard walk
9d8f416
perf(codegen): build a rest bundle the way an array literal is built
4464ac4
perf(runtime): resolve the map result's header once per element
212572a
perf(runtime): gate the numeric push guard's observation on feedback …
c9bf05e
perf(codegen): read the packed loop's element base from the hoisted r…
dd12c47
perf(codegen): the packed loop's counter read shades no GC root
8f6ea64
perf(runtime): answer an ASCII string index from the value
75c7908
perf(runtime): resolve the recorded prototype only where it is read
9768145
perf(codegen): let the concat chain format the parts it already formats
6ee4968
perf(codegen): give a constant-key `in` a presence inline cache
84258c0
perf(runtime): latch the instanceof prototype-override escape hatch
c54f34a
docs: changelog fragment for #10378
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| Second wave of the executed-instruction campaign (after #10295), aimed at the | ||
| three areas that audit deferred: parameter guards, per-element array work, and | ||
| key/string lookups. Across a 97-probe set called through a dynamic namespace | ||
| lookup, the summed per-call cost falls 20,308 -> 16,996 (-16.3%) with no probe | ||
| regressing beyond the noise floor. | ||
|
|
||
| A constant-key `in` now caches a presence answer on the receiver's ShapeId: | ||
| 955 -> 30 instructions. Only positive answers about an OWN key are cached, | ||
| because that is the only claim no prototype mutation can falsify -- a negative | ||
| would be a statement about the whole chain, and there is no epoch to key one | ||
| on. Every way of losing the key either moves the ShapeId or raises | ||
| OBJ_FLAG_STABLE_TOMBSTONES, which the guard rejects. | ||
|
|
||
| Parameter guards stop walking descriptors nothing consumes. A clone consumes | ||
| one fact per parameter -- the declared type -- and never the descriptor's | ||
| field nodes, so an all-number class parameter is proved nominally from the | ||
| class id plus the typed-layout-intact bit, and the rule that let a loop in the | ||
| body license an unbounded per-element walk is gone. A 1,600-element `Pt[]` | ||
| parameter costs 1,146,528 instructions per call before and 21,553 after; a | ||
| `string[]` of the same length 213,233 -> 88,468; a class parameter with eight | ||
| number fields 3,194 -> 1,306. One non-`number` field on the chain puts the | ||
| whole chain back on the walk (control: 1,828 -> 1,844), because the intact bit | ||
| is a raw-f64 claim and says nothing about what a pointer slot holds. | ||
|
|
||
| Rest bundles are built the way array literals are -- one inline bump | ||
| allocation and N stores instead of `js_array_alloc` plus a per-element | ||
| `js_array_push_f64` that re-classified the receiver every time: `f(1, 2, 3)` | ||
| 909 -> 85, `f(o, o, o)` 1,655 -> 486, with bundles wider than 16 left on the | ||
| old path. `map` resolves its result header once per element rather than three | ||
| times, keeping the full protocol (canonicalize, retire the numeric claim, | ||
| layout note, remembered-set edge): `a.map(v => v + 1)` over 16 elements | ||
| 6,068 -> 4,028. The packed loop stops re-deriving its element base per element | ||
| and its counter read shades no GC root, restricted to offset 0 because | ||
| `arr[i +/- c]` can leave the array and reach the prototype chain. | ||
|
|
||
| Smaller runtime paths: an ASCII string index answers from the short-string | ||
| value instead of a four-call chain ending in a thread-local table (172 -> 123); | ||
| `[[HasProperty]]` resolves the recorded prototype only where it is read; | ||
| the concat chain formats number parts in place instead of building an | ||
| intermediate heap string; `instanceof`'s `util.inherits` escape hatch becomes | ||
| a process-wide latch instead of two registry probes per miss (miss 1,199 -> | ||
| 1,081, hit unchanged); and a subclass `pop` flushes store plans only when it | ||
| actually retires a proof. | ||
|
|
||
| One change carries no measured win and its commit message says so: skipping | ||
| the re-registration of an unchanged class parent edge removes a process-global | ||
| prop_plan epoch bump and a CLASS_REGISTRY write lock from the outlined | ||
| allocation entry, but every allocation loop that could be built takes the | ||
| inline allocator instead, which never calls register_class. | ||
|
|
||
| Three spec divergences found while measuring are filed, not fixed: #10364 | ||
| (`instanceof` against a Proxy right-hand side segfaults), #10365 (four | ||
| divergences from the spec's prototype walk), #10366 (`in` does not reach | ||
| `Function.prototype`). All reproduce on unmodified main. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
🔎 Supported by static analysis
🏁 Script executed:
Repository: PerryTS/perry
Length of output: 12181
🏁 Script executed:
Repository: PerryTS/perry
Length of output: 16196
Correct the inline allocator description.
object_alloc_class_inline_keys_implcallsregister_class(class_id, parent_class_id)wheneverparent_class_id != 0. The unchanged-edge check returns before the epoch bump and registry write lock. Replace the final clause with:📝 Committable suggestion
🤖 Prompt for AI Agents