Merge train 204: dependency group, store-plan cache, builder fold, GC shape borrow, ambient declare (v0.5.1582) - #10393
Conversation
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.87.3 to 2.87.8. - [Release notes](https://github.com/taiki-e/install-action/releases) - [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md) - [Commits](taiki-e/install-action@0758d23...d438492) --- updated-dependencies: - dependency-name: taiki-e/install-action dependency-version: 2.87.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…ith 12 updates Bumps the cargo-minor-and-patch group with 12 updates in the / directory: | Package | From | To | | --- | --- | --- | | [aho-corasick](https://github.com/BurntSushi/aho-corasick) | `1.1.4` | `1.1.5` | | [toml](https://github.com/toml-rs/toml) | `1.1.4+spec-1.1.0` | `1.1.5+spec-1.1.0` | | [tokio-rustls](https://github.com/rustls/tokio-rustls) | `0.26.4` | `0.26.5` | | [rustls](https://github.com/rustls/rustls) | `0.23.43` | `0.23.44` | | [hickory-proto](https://github.com/hickory-dns/hickory-dns) | `0.26.1` | `0.26.2` | | [cc](https://github.com/rust-lang/cc-rs) | `1.4.4` | `1.4.5` | | [encoding_rs](https://github.com/hsivonen/encoding_rs) | `0.8.35` | `0.8.41` | | [lru](https://github.com/jeromefroe/lru-rs) | `0.18.3` | `0.18.4` | | [redis](https://github.com/redis-rs/redis-rs) | `1.6.0` | `1.7.0` | | [mongodb](https://github.com/mongodb/mongo-rust-driver) | `3.8.2` | `3.9.0` | | [der](https://github.com/RustCrypto/formats) | `0.8.1` | `0.8.2` | | [indexmap](https://github.com/indexmap-rs/indexmap) | `2.14.1` | `2.14.2` | Updates `aho-corasick` from 1.1.4 to 1.1.5 - [Commits](BurntSushi/aho-corasick@1.1.4...1.1.5) Updates `toml` from 1.1.4+spec-1.1.0 to 1.1.5+spec-1.1.0 - [Commits](toml-rs/toml@toml-v1.1.4...toml-v1.1.5) Updates `tokio-rustls` from 0.26.4 to 0.26.5 - [Release notes](https://github.com/rustls/tokio-rustls/releases) - [Commits](rustls/tokio-rustls@v/0.26.4...v/0.26.5) Updates `rustls` from 0.23.43 to 0.23.44 - [Release notes](https://github.com/rustls/rustls/releases) - [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md) - [Commits](rustls/rustls@v/0.23.43...v/0.23.44) Updates `hickory-proto` from 0.26.1 to 0.26.2 - [Release notes](https://github.com/hickory-dns/hickory-dns/releases) - [Changelog](https://github.com/hickory-dns/hickory-dns/blob/main/CHANGELOG.md) - [Commits](hickory-dns/hickory-dns@v0.26.1...v0.26.2) Updates `cc` from 1.4.4 to 1.4.5 - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md) - [Commits](rust-lang/cc-rs@cc-v1.4.4...cc-v1.4.5) Updates `encoding_rs` from 0.8.35 to 0.8.41 - [Commits](hsivonen/encoding_rs@v0.8.35...v0.8.41) Updates `lru` from 0.18.3 to 0.18.4 - [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md) - [Commits](jeromefroe/lru-rs@0.18.3...0.18.4) Updates `redis` from 1.6.0 to 1.7.0 - [Release notes](https://github.com/redis-rs/redis-rs/releases) - [Commits](redis-rs/redis-rs@redis-1.6.0...redis-1.7.0) Updates `mongodb` from 3.8.2 to 3.9.0 - [Release notes](https://github.com/mongodb/mongo-rust-driver/releases) - [Commits](mongodb/mongo-rust-driver@v3.8.2...v3.9.0) Updates `der` from 0.8.1 to 0.8.2 - [Commits](RustCrypto/formats@der/v0.8.1...der/v0.8.2) Updates `indexmap` from 2.14.1 to 2.14.2 - [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md) - [Commits](indexmap-rs/indexmap@2.14.1...2.14.2) --- updated-dependencies: - dependency-name: aho-corasick dependency-version: 1.1.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: cc dependency-version: 1.4.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: der dependency-version: 0.8.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: encoding_rs dependency-version: 0.8.40 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: hickory-proto dependency-version: 0.26.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: indexmap dependency-version: 2.14.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: lru dependency-version: 0.18.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: mongodb dependency-version: 3.9.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-minor-and-patch - dependency-name: redis dependency-version: 1.7.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-minor-and-patch - dependency-name: rustls dependency-version: 0.23.44 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: tokio-rustls dependency-version: 0.26.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch - dependency-name: toml dependency-version: 1.1.5+spec-1.1.0 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-minor-and-patch ... Signed-off-by: dependabot[bot] <support@github.com>
The store-plan cache refused any receiver carrying OBJ_FLAG_HAS_DESCRIPTORS. Every zod schema object carries `_zod`, so none ever held a plan and each of its stores re-ran the whole interception vet. The flag was there for a real reason - a plan hit skips the own-accessor short-circuit - but that is a per-KEY fact, and `desc_gate_ok` on the same path already proves the key uncovered. Vetting per key is worth -7.3% on a 300-schema zod workload and -19.7% on the 2,000-receiver fixture. The new native test warms the plan for a class across 300 receivers, then proves an own accessor on a different key still dispatches its setter and a non-writable data descriptor is still respected; it fails if a plan hit ever skips that dispatch.
…0353) `fold_builder_sequences` (#6812) only matched when the `o.k = v` assignments followed the `const o = {}` binding immediately, so a single ordinary declaration in between — the usual way initialisation code names its constants — dropped the whole sequence. The unfolded `{}` lowers to a 0-field `__AnonShape_…`, which denies `Ptr<Shape>` containment (every key really is undeclared on a shape that declares nothing) and sends every store down `js_put_value_set`, re-interning and re-coercing the key per execution: 108,444,840 instructions against 1,400,471 for the same program with the constants written inline. The scan now skips up to 64 statements between an EMPTY literal and its first assignment, sinking the allocation below them. A statement qualifies only when moving the allocation past it is unobservable, which is the pair of conditions the value side already carries: it must not name the binding, and it must not be able to execute user code (a call can reach a hoisted `function peek() { return o; }` that names the binding without naming it in the statement, turning a successful read into a TDZ ReferenceError). Destructuring patterns, `enum`/`namespace` and populated literals are excluded; `type`/`interface` are erased and are skipped. Skipped statements keep their relative order and still run before every folded value.
…e iterator (#10362) Base: 33690c5 (main, includes the #10348 fix from #10352). gc_child_slots built a 152-byte HeapChildSlotIterator for every traced object, 40 bytes of it a lifted ShapeDescriptor (#8122). Two by-value moves of that iterator compiled to out-of-line 152-byte memcpy calls inside visit_gc_layout_slot_descriptors: * the Array and Closure arms' `Option::map(..).unwrap_or_else(..)` temporary, copied into the caller's slot (62% of the calls); * `for .. in child_slots` in the Masked arm, which moved the iterator into the loop (35%). On the #10362 retained-graph fixture that was 6,181,945 memcpy calls of exactly 152 bytes (counted with an LD_PRELOAD shim). After this change: 6. * object/shapes.rs: ShapeRecordRef, a Copy handle to one live slab record (live bound, keys word, keys slot). shape_record_by_id and object_shape_record make the same slab probe as the descriptor lookups, without lifting a copy. note_old_generation_carrier and note_full_trace_carrier take the handle. ShapeDescriptor::record_ref() adapts the one caller that holds a descriptor. keys_slot() is now used only by tests, so it is cfg(test). * object/gc_slots.rs: gc_shape_keys_edge_slot and gc_field_slot_range take the handle. * gc/layout.rs: the iterator carries Option<ShapeRecordRef> (8 bytes; the iterator is now 120). The `_from` mask helpers take the handle. gc_child_slots' Array and Closure arms build the iterator directly in the return slot with let-else, as the ObjectFields arm already did. * gc/layout_slot_visit.rs: the Masked arm iterates `&mut child_slots`. Still one shape-table probe per receiver (#8122). The handle is read at the same points the lifted copy was: the carrier notes and the keys edge, before any visit. It relies on the same record-address validity the carrier notes already write through (#9706). The #8112 old_carrier/ephemeron gate and the #9726 full-trace note are unchanged. instructions:u, min of 5, same host, base (main 33690c5) vs this: gc3 12,572,092,967 -> 12,275,653,370 -2.36% w1000 1,090,107,336 -> 1,081,645,123 -0.78% w5000 2,049,860,743 -> 2,018,013,960 -1.55% w20000 5,094,775,666 -> 4,994,573,033 -1.97% oldyoung 1,525,484,973 -> 1,503,383,712 -1.45% alloc-only 320,266,130 -> 320,266,017 0.00% All outputs match node byte for byte. PERRY_GC_FROMSPACE_SCAN_ABORT=1 is clean on all six fixtures, and it aborts on the same gc3 built at fcd108b. PERRY_GC_VERIFY_EVACUATION=1 on gc3 exits 0.
`declare const x: T` describes a binding the host supplies. TypeScript
erases it, but perry lowered it as a real binding initialized to
`undefined`. That shadowed the global it describes: reads never reached a
globalThis data property or accessor, `typeof` said "undefined", and a
`declare var` was reflected as a non-configurable global property, so a
later `Object.defineProperty(globalThis, "x", ...)` threw.
Every pass that models bindings now asks one predicate,
`lower::ambient::declarator_binds_nothing`: source-position lowering
(module, namespace, function body), `export declare const` (erased like
`export declare function`), the module forward pre-registration and
Script-var reflection, function/closure `var` hoisting and forward-capture
boxing, block TDZ names, the Annex B forbidden set, and the `new Function`
constant-argument scan (which recorded `declare var src` as a never-written
`var` and folded `new Function(src)` to `new Function("undefined")`).
Ambient names also suppress the unknown-identifier warning, like platform
globals.
`declare const __platform__` / `__plugins__` keep their binding: they are
the documented compile-time constants the backends fold from a
`Stmt::Let` with no initializer. #6871 gave every uninitialized lexical
binding an explicit `undefined`, which hid them from that fold, so
`__platform__` read `undefined` on every target. The ambient path restores
the `init: None` shape.
An `export declare const` inside a namespace is left as it was: TypeScript
reads it as `N.x`, not as the global.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (30)
📝 WalkthroughWalkthroughThe pull request changes TypeScript ambient declaration lowering, object builder folding, GC shape handling, and descriptor-aware store plans. It adds focused HIR, runtime, and integration tests, updates changelog entries, bumps the workspace version, and updates the coverage action pin. ChangesAmbient declaration lowering
Builder fold gap handling
GC shape-record handling
Per-key store-plan eligibility
Release metadata
Estimated code review effort: 4 (Complex) | ~60 minutes Change: Other · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant Source
participant HIRLowerer
participant LoweringContext
participant GlobalLookup
Source->>HIRLowerer: declare const/let/var
HIRLowerer->>LoweringContext: record erased ambient name
HIRLowerer-->>Source: emit no runtime binding
Source->>GlobalLookup: reference ambient name
GlobalLookup-->>Source: resolve by global lookup
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
This train lands six PRs as v0.5.1582. They touch no file in common and all six cherry-picked clean.
taiki-e/install-action2.87.3 → 2.87.8 (CI action, SHA-pinned).perf(object): vet the store-plan cache per key, not per receiver.{}(#10353) #10355 —fix(hir): fold a builder whose stores are separated from its{}(codegen: a property store from a constant-valued local loses Ptr<Shape> promotion (75x) #10353).perf(gc): borrow the shape record in the slot visitor, stop moving the iterator (perf(gc): on a retained object graph perry is 8.5× node — 13 minors at ~0.8G instructions each (measured on #10352) #10362).declare const/let/varbinds nothing (#10363) #10374 —fix(hir): an ambientdeclare const/let/varbinds nothing (hir:declare const/let/varis lowered as a real binding initialized to undefined — shadows the global it describes #10363).Eight source commits, each verified to preserve its authorship. No train repairs were needed — all four
crates/-touching PRs shipped their ownchangelog.d/fragment, and every gate passed as assembled.One patch-id differs and the reason is recorded in
train204r-source-proof.json: #10314's commit touches onlyCargo.lock, its added and removed lines are byte-identical to the source, and only the surrounding context moved becausemainadvanced the workspace version line inside the same region.git patch-idhashes context alongside the hunk body, so an unmodified edit replayed onto a moved base yields a different id. No content change.Validation
Validated head
06c5249840, on main99363beb1a. Five-package release build pinned and hash-verified;artifacts_match_pintrue after the suites and again after the gap phase.main.main's known release-onlygc::tests::heap_generation::a_free_or_move_outside_every_scope_is_caught_in_debug_builds.builder_fold_gap,builder_fold_gap_semantics,descriptor_store_fast_paths— all pass.Public benchmark evidence freshness.Gap: filters
object,store,builder,declare,shape,iterator,descriptor. Seven fixtures diverge. Three were newly checked here by compiling and running each under both themainand train compilers, with Node as a third reference; all three behave identically on the two arms:test_issue_3580_arguments_object_semanticstest_issue_4034_object_literal_semanticstest_issue_927_jwt_verify_returns_objectThose three were checked hardest because #10346 changes the store-plan cache and
jwt_verifysits downstream of #10314's crypto bumps — anobjectfixture failing on this train is exactly where a real regression would hide.The A/B asserts build provenance from the binaries themselves: each compiled arm must carry exactly one
git:<sha>stamp and it must be that arm's pin (d0e99ea92bfor main,06c5249840for the train). APERRY_RUNTIME_DIRthat does not resolve falls through to real archives silently, so without this an arm can measure a build that was never made and report a confident, wrong green.The remaining four are previously attributed:
test_gap_iterator_prototype_next_patch(failing onmainsince the commit that added it — see below),test_issue_7981_thread_shape_stamp_parent(perry-only; Node cannot resolveperry/thread),test_three_like_native_class_descriptors(Node exits 1), andtest_issue58_object_string(printsDate.now()elapsed; the same binary varies run to run).A note on
main's long-standing gap failuresThree fixtures the snapshot expects to PASS have been failing on
mainfor over a week and are not caused by this train or any recent one. They were bisected today, per fixture rather than per shard:test_gap_iterator_prototype_next_patch— never passed. Added already failing by8a73d9f80a, the commit that introducedprototype_next_is_canonical. Perry returns raw values where Node returns patched ones, so the fast path misreads a patched prototype. A correctness claim with no passing evidence behind it.test_gap_disposablestack_2875— last passed87dc33492, first failed43200e9d4(34 commits).test_gap_2899_2779_2777_static_helpers— last passed43200e9d4, first failed7651a36c3(107 commits); grouped values come back null.Before merging, the pushed head and unchanged main are checked again. After merging, the rewritten commits are checked for preserved authorship and the main tree must match the validated train exactly.
Summary by CodeRabbit
New Features
declare const,let, andvardeclarations no longer create runtime bindings; references resolve to global values as expected.Bug Fixes
Performance