Skip to content

perf(codegen): full-outline the class-field-GET diamond for oversized modules (#5391 path 2)#5410

Merged
proggeramlug merged 1 commit into
mainfrom
feat/full-outline-ic-get
Jun 18, 2026
Merged

perf(codegen): full-outline the class-field-GET diamond for oversized modules (#5391 path 2)#5410
proggeramlug merged 1 commit into
mainfrom
feat/full-outline-ic-get

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What

Extends the #5334 lever-B full-outline from class-field SET to class-field GET: when full-outline is enabled (size-gated by PERRY_FULL_OUTLINE_IC), the class_field_get diamond (inline precheck + guard call + fast slot load + by-name fallback + phi) collapses to a single js_class_field_get_ic(...) call returning the field value.

Part of #5391 path 2 — shrinking large minified functions at their source so clang -O0 (whose per-function time is superlinear in size) can compile them.

Runtime helper

js_class_field_get_ic runs the same js_typed_feedback_class_field_get_guard; on a PASS reads the field slot as f64 (a plain number is self-boxing in nan-boxing, so raw-f64 and boxed slots read identically — matching the inline class_field_get.fast plain load double); on a MISS records the fallback and reads by name. The outline drops the inline path's static raw-number type hint (result treated as a general JS value), which is value-correct.

Validation

  • New unit test full_outline_ic_collapses_class_field_get_to_single_call (both gate states).
  • E2E: a class with field GET+SET runs to the correct result (5999997) with full-outline ON and OFF.
  • Full perry-codegen suite green. Default off = unchanged behavior.
  • On the cli.js bundle, this fired at 39,445 GET sites (alongside 115,454 SET), trimming IR 1.10GB → 1.02GB.

Scope note (honest)

This shrinks class-field-heavy functions. The bundle's largest functions, however, are dominated by a different construct — inline object/array literal construction (the 18MB perry_closure...31856 is ~17K js_gc_note_slot_layout + 11K js_inline_arena_slow_alloc + 9K js_write_barrier_slot: a giant data-table builder). Shrinking those needs literal-construction / inline-allocator outlining, a separate follow-up under #5391.

Refs #5391, #5334.

Summary by CodeRabbit

  • Chores
    • Optimized class field property access performance through an enhanced inline cache implementation for specific runtime scenarios.
    • Added supporting infrastructure for fast-path property retrieval operations with verification tests.

… modules (#5391 path 2)

Extends the #5334 lever-B full-outline from field-SET to field-GET. After
codegen-unit splitting (#5407) removed the module memory wall and the
string-init split removed the 68MB generated function, the residual wall is
the bundle's large minified USER functions (7-18MB closures): clang -O0
time is superlinear in single-function size. Full-outlining the IC diamonds
shrinks those functions at their source.

When full-outline is enabled (size-gated), the class-field-GET diamond
(inline precheck + guard call + fast slot load + by-name fallback + phi)
collapses to one `js_class_field_get_ic(...)` call returning the field
value. The runtime helper runs the same guard, reads the field slot as f64
on a pass (a plain number is self-boxing in nan-boxing, so raw-f64 and
boxed slots read identically — matching the inline `load double`), and
records + reads by name on a miss. The outline drops the inline path's
static raw-number type hint (result treated as a general JS value), which
is value-correct.

class-field GET is the largest remaining diamond kind on the bundle (~39K
sites). Gated by the existing PERRY_FULL_OUTLINE_IC; default off = unchanged.
Unit test covers both gate states; full codegen suite green.
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a42f7b36-ddea-4ba1-be22-611dc845dc96

📥 Commits

Reviewing files that changed from the base of the PR and between 7497483 and 47fa131.

📒 Files selected for processing (4)
  • crates/perry-codegen/src/expr/property_get.rs
  • crates/perry-codegen/src/runtime_decls/objects.rs
  • crates/perry-codegen/tests/typed_feedback.rs
  • crates/perry-runtime/src/typed_feedback/guards.rs

📝 Walkthrough

Walkthrough

Adds a fully-outlined inline-cache path for class-field GET operations. A new js_class_field_get_ic extern-C function is introduced in the runtime, its ABI is declared in the codegen runtime declarations, and the PropertyGet class-field fast path conditionally emits a single call to it (bypassing the inline guard/phi diamond) when full_outline_ic_enabled() is true. A new test verifies both IR shapes.

Changes

Full-outline IC for class-field GET

Layer / File(s) Summary
Runtime js_class_field_get_ic entry point and symbol retention
crates/perry-runtime/src/typed_feedback/guards.rs
Adds #[no_mangle] pub extern "C" fn js_class_field_get_ic that runs the typed-feedback guard and either reads the cached f64 slot directly on PASS or falls back to js_object_get_field_by_name_f64 on FAIL. Adds G1E to the keep_guard_symbols retention block to prevent LTO/strip from removing the new symbol.
ABI declaration and PropertyGet codegen emission
crates/perry-codegen/src/runtime_decls/objects.rs, crates/perry-codegen/src/expr/property_get.rs
Declares js_class_field_get_ic with its full DOUBLE-returning ABI signature in declare_phase_b_objects. In property_get.rs, adds a conditional branch in the class-field fast path that, when full_outline_ic_enabled() is true, computes key_raw and expected_keys and emits a single outlined IC call, returning immediately before the inline guard/precheck/phi logic.
IR-level test for outline vs inline GET paths
crates/perry-codegen/tests/typed_feedback.rs
Adds full_outline_ic_collapses_class_field_get_to_single_call, which asserts that with PERRY_FULL_OUTLINE_IC=1 only js_class_field_get_ic appears in IR and the inline class_field_get.fast/fallback/guard are absent, and vice versa with PERRY_FULL_OUTLINE_IC=0.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PerryTS/perry#5198: Modifies the same class-field PropertyGet fast path in property_get.rs, establishing the inline typed-feedback shape-guard logic that this PR replaces under full_outline_ic_enabled.
  • PerryTS/perry#5385: Implements the analogous fully-outlined IC path for class-field SET (js_class_field_set_ic) and introduces the full_outline_ic_enabled gating infrastructure that this PR's GET path depends on.

Poem

🐇 Hoppy news from the warren below,
A diamond of guards collapsed to one call,
js_class_field_get_ic takes the show —
One outlined IC to cover it all!
No more fast/fallback/phi to trace,
Just a single leap through cyberspace. 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main optimization: extending full-outline to class-field GET operations for oversized modules, with specific reference to the scope and related issue.
Description check ✅ Passed The PR description is comprehensive and follows the template structure with What, Runtime helper, Validation, and Scope sections, though test plan checkboxes are incomplete.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/full-outline-ic-get

Comment @coderabbitai help to get the list of available commands and usage tips.

@proggeramlug proggeramlug merged commit 4bbef50 into main Jun 18, 2026
15 checks passed
@proggeramlug proggeramlug deleted the feat/full-outline-ic-get branch June 18, 2026 17:50
nglmercer pushed a commit to nglmercer/perry that referenced this pull request Jun 18, 2026
…lict in compile/link/mod.rs

Brings main's PerryTS#5400 (Windows response-file link) + PerryTS#5406/PerryTS#5408/PerryTS#5410/PerryTS#5412 codegen
split + PerryTS#5402 require Tier 2 + PerryTS#5414 unknown builtin-namespace fix into the
Windows plugin support branch. The conflict in compile/link/mod.rs is
structural: main extracted the orchestrator into link/build_and_run.rs
while the branch kept it inline. Resolved by taking main's refactor and
re-applying the Windows plugin support on top:

- compile/link/mod.rs: add PLUGIN_HOST_SYMBOLS const (the runtime + plugin
  export list — single source of truth for the macOS -u force-keep and
  the Windows .def file) plus use std::io::Write for the .def writer.

- compile/link/build_and_run.rs: convert the if ctx.needs_plugins &&
  !is_windows block to if ctx.needs_plugins with platform branches.
  The Windows branch writes a per-build perry_plugin_host_<pid>.def
  using the NAME directive (not LIBRARY — that one tells link.exe
  the output is a DLL and breaks the host .exe) and passes
  /DEF:<path> to the linker. PLUGIN_HOST_SYMBOLS replaces the inline
  
untime_syms array on macOS too.

- compile.rs: dylib link path on Windows now uses lld-link with
  /FORCE:UNRESOLVED (the .def file lists plugin_activate /
  perry_plugin_abi_version / plugin_deactivate so lld-link's empty
  default export table doesn't break GetProcAddress in the host) and
  writes a per-build .def file with the same three symbols. Lifts the
  pre-existing 'use link.exe' out for the LLVM-friendly linker.

- codegen/entry.rs: re-apply the dylib plugin ABI shim block (emits
  perry_plugin_abi_version, plugin_activate, and the optional
  plugin_deactivate) on top of main's refactor of compile_module_entry.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant