Skip to content

Layer 1 campaign: migrate perry-codegen's lowerings onto the rooting-by-construction API (88 modules, 262 hazard sites) #7615

Description

@proggeramlug

Layer 1 of the GC-correctness plan (docs/engine-plan.md, docs/src/internals/rfc-rooting-by-construction.md) is the only track that was never started. This issue is its campaign map: the ordered inventory of perry-codegen modules to migrate onto the crate::rooting combinators, one slice per PR.

Routing: linked from #7294. Design: #7459 (the RFC's own constructor was E0499, corrected). First lowering: #7461. Template slice: the PR that opens this issue.


What "migrated" means

Two properties, both checked by cargo test -p perry-codegen --lib rooting:::

  1. The module names no expr::temp_root symbol. That module is the raw, order-sensitive API — push / get / set / truncate, plus guards the caller must remember to release — and every bug in the gc(layer 3): from-space quarantine catches 55 stale dereferences across the gap suite — the instrument is in CI but aimed at one synthetic fixture #7341 family was an ordering mistake against it. It is the escape hatch the RFC's step 3 says to #[deny] per module. Rust has no attribute that denies calling a pub(crate) function from one module, so the deny is a test over the module's own source, inlined by include_str!.
  2. No raw heap pointer exists as a value the lowering can hold across a collection point. rooting::call_rooted returns a slot, never a register; rooting::call_with_roots re-reads each slot as part of emitting the consuming call; rooting::with_operands_rooted owns the release on every path out, including ?.

A slice finishes by adding its modules to MIGRATED_MODULES in crates/perry-codegen/src/rooting.rs. Removing a line is a regression, not a cleanup.

Acceptance per slice

  • Emitted IR byte-identical (normalised for register/label renumbering) on a program set that exercises the module's lowerings, or every difference itemised and justified — a difference is normally a real rooting bug the migration found, which is the point.
  • gc-root-dominance corpus green in both gated modes, including --seeded-violations 40.
  • cargo test -p perry-codegen --lib, -p perry-runtime --no-fail-fast.
  • The gap-test families that touch the module's lowerings, identical failure set on both arms.

Honest statement of what this buys

Measured on the template slice by sabotaging the migrated module four ways:

reintroduced shape compiles? caught by
#7192 in the borrow form (RootingEmitter, the RFC's design) NO — E0499 rustc, via compile_fail doctest
hold the call_with_roots result across a later lowering yes nothing
the verbatim pre-#7453 code, via a bare ctx.block().call yes nothing — see below
reach back into expr::temp_root yes the ledger test
hold the operand guard so it can be released on one arm (#7462) yes the ledger test

So: on the real emitter the API does not make the bug fail to compile. FnCtx has no interior mutability, so the borrow-carrying Raw<'e> cannot be built on it (#7459/#7461 established this). What the migration buys is that the correct form is the only one the API can express, that the release cannot be branch-conditional, and that the escape hatch is denied per module. Getting an actual compile error needs the RefCell'd emitter of the RFC's step 1 — a separate, wider change.

Ordering

Hazard density first, because that is where the bug lives. haz counts sites where a raw-pointer binding is used after an intervening emission — the #7453/#7192 shape, measured on the emitter's own source (heuristic, over-reports; it is a worklist, not a verdict). raw counts .call(I64, "js_*") sites, which by perry's convention return a raw heap pointer (NaN-boxed values come back as DOUBLE). root counts existing rooting references, i.e. how much of the module is already hand-rooted.

Whole campaign: 88 modules, 694 raw sites, 262 hazard sites, ~79k lines.

Slice 0 — DONE (the template)

History: #7453 #7461 #7462 #7463 #7464 #7465

1 modules · 669 lines · 11 raw sites · 7 hazard sites

module lines raw haz root issues named in the file
expr/url_main.rs 669 11 7 4 #7463 #7462 #7461 #7459 #7453 #7341

Slice 1a — array methods (largest hazard population)

1 modules · 1200 lines · 37 raw sites · 40 hazard sites

module lines raw haz root issues named in the file
lower_array_method.rs 1200 37 40 0 #6229 #4091 #3148 #2814 #2808 #2805

Slice 1b — array search/copy methods

2 modules · 1564 lines · 40 raw sites · 26 hazard sites

module lines raw haz root issues named in the file
expr/arrays_finds.rs 1204 28 23 0 #7590 #6996 #6229 #6088 #5067 #4091
expr/array_methods.rs 360 12 3 0 #2838 #2836 #2816 #2013 #1312 #1177

Slice 2 — instance methods + collections

3 modules · 3209 lines · 60 raw sites · 40 hazard sites

module lines raw haz root issues named in the file
expr/instance_misc1.rs 1776 36 17 13 #7210 #7154 #6364 #6301 #6003 #5834
expr/logical_collections.rs 1052 24 14 21 #7200 #7198 #7154 #6951 #5560 #5559
lower_call/property_get/map_set.rs 381 0 9 49 #6970 #2872 #2856 #2830

Slice 3 — literal accumulators (#7211 / #7280 home; NOT IR-identical)

History: #6951 #7211 #7280 #7602

4 modules · 1776 lines · 18 raw sites · 7 hazard sites

module lines raw haz root issues named in the file
expr/objects_arrays_lit.rs 116 5 1 15 #7280 #6971
expr/array_literal.rs 269 3 0 8 #6951 #5391 #1146 #1098
expr/object_literal.rs 437 2 0 21 #6951 #1098
expr/array_push.rs 954 8 6 0 #7590 #7574 #7511 #7469 #6904 #5459

Slice 4 — computed reads/writes (#7206 home)

History: #7206

9 modules · 6189 lines · 10 raw sites · 8 hazard sites

module lines raw haz root issues named in the file
expr/index_get.rs 1404 0 1 8 #7574 #7192 #7154 #6904 #6750 #6132
expr/index_get/guarded_array.rs (no raw-pointer site; listed for completeness)
expr/index_get/inline_dyn_typed_array.rs (no raw-pointer site; listed for completeness)
expr/index_set.rs 1755 7 0 32 #7590 #7341 #7207 #7201 #7154 #6011
expr/index_set_typed_array.rs (no raw-pointer site; listed for completeness)
expr/property_get.rs 1737 3 0 0 #7153 #7128 #6710 #6588 #6003 #5924
expr/property_get/globalget.rs 427 0 6 0 #6674 #4033 #3527 #2904 #1374 #1373
expr/property_get/helpers.rs 866 0 1 0 #7480 #7153 #5093
expr/property_set.rs (no raw-pointer site; listed for completeness)

Slice 5 — call / construct paths (#7192 / #7207 home)

History: #7192 #7207

14 modules · 11138 lines · 70 raw sites · 9 hazard sites

module lines raw haz root issues named in the file
lower_call/new.rs 1989 4 0 17 #7552 #7536 #7535 #7532 #7525 #7512
lower_call/new_ctor_args.rs 400 3 0 0 #6538 #6537 #5437 #740 #672
expr/call_spread.rs 547 27 5 0 #6475 #653
expr/this_super_call.rs 1272 3 1 0 #6710 #6326 #5437 #5137 #5127 #1787
expr/super_method.rs 442 6 1 0 #1126 #774
expr/new_dynamic.rs 758 4 1 0 #5437 #5253 #4699 #3680 #3663 #3142
lower_call/property_get/dynamic_dispatch.rs 1416 4 0 4 #7211 #7143 #7142 #6927 #5437 #5391
lower_call/property_get/static_dispatch.rs 387 5 1 2 #7211 #5703 #1788 #1787 #915 #912
lower_call/property_get/number_string.rs 238 6 0 0 #3146 #2864
lower_call/property_get/promise_chain.rs 172 3 0 0 #1030 #1008 #973
lower_call/func_ref.rs 922 1 0 5 #7240 #7211 #7154 #4785 #3576 #1816
lower_call/early_branches.rs 985 1 0 6 #7211 #6369 #6328 #5030 #3576 #1113
lower_call/scalar_method.rs 1161 2 0 0 #5094
lower_call/mod.rs 449 1 0 32 #7592 #7510 #7240 #7154 #6951 #6326

Slice 6 — strings / regex

2 modules · 2623 lines · 71 raw sites · 6 hazard sites

module lines raw haz root issues named in the file
lower_string_method.rs 1958 37 2 37 #7128 #6971 #6951 #5906 #4871 #3987
expr/string_regex_proc.rs 665 34 4 0 #6666 #4091 #2789 #2788 #2013 #618

Slice 7 — builtins, math, misc

16 modules · 16547 lines · 171 raw sites · 32 hazard sites

module lines raw haz root issues named in the file
lower_call/builtin.rs 1710 41 2 0 #5458 #4915 #4103 #3985 #3657 #2875
expr/misc_methods.rs 1033 25 10 0 #6709 #4091 #2826 #2804 #2770 #1401
expr/math_simple.rs 1255 16 1 14 #6970 #4091
expr/os_uri_dates.rs 512 23 5 0 #2851 #2796 #1187
expr/env_clones.rs 422 19 5 0 #4546 #3917 #2013 #1123 #630 #600
expr/bigint_set.rs 1372 15 5 0 #4091 #2796
expr/compare.rs 629 4 2 0 #3576
expr/literals_vars.rs 865 10 0 0 #7055 #6369 #6003 #1380 #1343 #915
expr/static_field_meta.rs 828 5 2 18 #7211 #7154 #6951 #6654 #6523 #6438
expr/static_method.rs 390 5 0 0 #5924 #5922 #4831 #4656 #2582 #894
expr/helpers.rs 636 3 0 0 #7469 #6921 #6011 #4511 #2905 #2875
expr/binary.rs 730 1 0 13 #6951 #6904 #6884 #5525
expr/pod_record.rs 549 1 0 0
expr/index.rs 643 1 0 0 #7396 #6904 #5094 #1098
expr/i32_fast_path.rs 1906 1 0 0 #7232 #6593 #5466 #1098
expr/mod.rs 3067 1 0 4 #7603 #7590 #7573 #7480 #7469 #7404

Slice 8 — leaves: crypto, native, ext, fetch

27 modules · 14252 lines · 174 raw sites · 82 hazard sites

module lines raw haz root issues named in the file
lower_call/options/fetch.rs 1287 50 1 0 #4915 #2638 #1688 #1649 #1211 #1099
lower_call/options/abort.rs 152 2 1 0 #1099 #1097
lower_call/options/mod.rs 100 2 0 0 #1099 #1097
lower_call/extern_func.rs 1799 15 0 0 #7210 #7154 #6087 #5812 #5626 #5621
lower_call/extern_timers.rs 276 14 0 15 #7210 #2013 #1671 #1213 #665
lower_call/namespace_call.rs 384 8 6 17 #7210 #5924 #680 #678 #636
lower_call/native_module_dispatch.rs 418 5 1 0 #6563 #1852 #927 #915 #605
lower_call/event_target.rs 80 1 3 0
lower_call/console_promise.rs 1583 9 0 45 #7214 #7211 #7206 #7192 #7184 #7154
lower_call/ui_styling.rs 565 0 1 0
lower_call/native/mod.rs 543 3 1 0 #6185 #1074 #1002
lower_call/native/native_tui_layout_branch.rs 534 8 9 0 #679 #634
lower_call/native/native_instance_branch.rs 454 2 3 0
lower_call/native/native_ui_widgets_branch.rs 454 4 2 0 #1867 #1865 #610
lower_call/native/native_ui_appshell_branch.rs 415 3 0 0 #1495 #1280 #658 #635
lower_call/native/jsonwebtoken.rs 291 7 0 0 #1074 #927
expr/calls/crypto_kdf.rs 304 5 23 0 #3146 #2013
expr/calls/crypto_misc.rs 619 7 14 0 #3146 #2550 #2013 #1364
expr/calls/crypto_hash.rs 352 6 3 0 #3146 #2013 #1419 #1354 #1352 #1076
expr/calls/crypto_keys.rs 232 3 1 0
expr/calls/fs.rs 398 1 0 0 #631
expr/child_proc.rs 445 4 7 38 #3079 #1938 #1937 #1933 #1780
expr/dyn_extern_i18n.rs 1187 9 2 8 #7280 #7211 #6951 #6660 #5389 #5230
expr/js_runtime.rs 288 1 1 0
expr/native_memory.rs 370 0 3 0
expr/closure.rs 433 4 0 0 #4831 #1845 #1021
expr/fs_await.rs 289 1 0 12 #7341 #5437 #788

Slice 9 — codegen/ and stmt/ tail

12 modules · 18858 lines · 29 raw sites · 5 hazard sites

module lines raw haz root issues named in the file
codegen/entry.rs 1653 1 4 4 #7128 #7109 #7106 #6991 #6952 #6903
codegen/closure.rs 1488 6 0 2 #7208 #7170 #7128 #7109 #7106 #7055
codegen/method.rs 1732 2 0 4 #7128 #7109 #7106 #6952 #6469 #6369
codegen/helpers.rs 1704 2 0 0 #7493 #7354 #7340 #7332 #7326 #7174
codegen/function.rs 1080 1 0 2 #7302 #7170 #7128 #7109 #7107 #7106
codegen/string_pool.rs 1333 1 0 0 #5957 #5592 #5391 #5042 #4880 #4850
codegen/arguments.rs 112 3 0 0 #7055
stmt/loops.rs 7120 9 0 1 #7480 #7287 #7154 #6812 #6809 #6750
stmt/mod.rs 755 1 0 0 #7590 #7521 #7302 #7154 #7105 #6750
stmt/masked_window_region.rs 1055 1 0 0 #6794 #6750
stmt/unused_expr.rs 194 1 1 0 #4091
native_value/materialize.rs 632 1 0 0 #7128 #854

Unassigned (add to a slice before starting it)

module lines raw haz root
expr/temp_root.rs 1133 3 0 84

Terminal condition

expr/temp_root.rs becomes pub(in crate::rooting) — the raw API unreachable from any lowering, not merely uncounted. That is the same end state Layer 3 states for its raw accessor (#7457/#7458), and it is what makes the ledger permanent rather than a convention.

Related findings from the template slice

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions