Skip to content

size: NmNamespaceOps armed dispatch for namespace-object behaviors + armed reactor pump slots (devirt foundation, −50 KB) - #6928

Merged
proggeramlug merged 9 commits into
mainfrom
size/nm-constants-devirt
Jul 28, 2026
Merged

size: NmNamespaceOps armed dispatch for namespace-object behaviors + armed reactor pump slots (devirt foundation, −50 KB)#6928
proggeramlug merged 9 commits into
mainfrom
size/nm-constants-devirt

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Foundation for the native-module namespace devirt (−50 KB now on a hello world: 4,709,904 → 4,659,792 bytes; unlocks the per-module callable_exports/constants registry split where the bulk lands).

Changes

NmNamespaceOps armed function table (object/nm_namespace_hooks.rs): the always-linked generic object paths reach native-module namespace behavior through an armed table instead of static calls —

  • Object.getOwnPropertyDescriptor's namespace branch (fs accessor special cases, process.permission) — descriptors.rs
  • dynamic namespace stores (CommonJS monkey-patching, Buffer.poolSize) — field_set_by_name.rs
  • Reflect existing-own-key probe (repeated Object.defineProperty(console, …)) — reflect_support.rs
  • namespace own-key enumeration — descriptors.rs
  • dynamic-get bound methods (const fn = fs.lstatSync) — value/dynamic_object.rs
  • EventEmitter.prototype methods (emit/on/…) are undefined — breaks the setPrototypeOf mixin pattern (pino) #5477 EventEmitter-export prototype install — class_registry/prototype_objects.rs
  • dynamic-super() EventEmitter subclass init — closure/dispatch/value_call.rs

The table is armed by install_native_module_vtable(), which every path that mints a NATIVE_MODULE_CLASS_ID object calls first (all five mint sites verified adjacent). Extracted implementations stay in their original files; the ONLY reference to each is the ops static on the native-module side, so the reference direction does the dead-stripping. Unarmed + matching class-id is unreachable, so behavior is bit-identical (the hook bodies provably never execute in a program without namespaces — traced).

Armed runtime-pump slots (lib.rs): the child_process and node-pty reactors self-register (at first live handle, black_box-guarded like NM_INSTALL_ALL_HOOK) instead of being statically drained by js_run_stdlib_pump — this cut the pump → cp emitter → cluster → namespace-creation retainer chain and is where the −50 KB comes from.

One hook was attempted and reverted in-branch (Buffer-subclass static dispatch): a differential probe showed class X extends Buffer registers its parent before the lazy callable-exports closure would arm. The probe suite is the enforcement mechanism for every arming invariant here.

Verification

Follow-up (mapped, not in this PR)

-why_live now terminates at two structures: the eager populate_global_this_builtins (multi-rooted) and the universal bound_native_callable_export_value (module, prop) dispatcher. Splitting the latter into per-module registries + lazy globalThis installs is the ~300-400 KB unlock; this PR is deliberately limited to the reference-direction foundation.

Summary by CodeRabbit

  • Performance
    • Reduced binary size by approximately 50 KB for programs that do not use native-module namespaces.
  • Bug Fixes
    • Preserved native-module namespace behavior for property access, enumeration, method binding, and EventEmitter inheritance.
    • Improved asynchronous child-process and pseudo-terminal processing when live handles are created.
  • Refactor
    • Runtime processing is now activated only when relevant features are in use.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Native-module namespace operations now use a lazily armed NmNamespaceOps table, and reactor pumps use runtime-registered callback slots. Namespace behavior is extracted into helpers, while child-process and PTY reactors arm their pumps when live entries are created.

Changes

Namespace hooks and reactor dispatch

Layer / File(s) Summary
Namespace hook contract and arming
crates/perry-runtime/src/object/{nm_namespace_hooks.rs,mod.rs,native_module.rs}, crates/perry-runtime/src/object/class_registry.rs
Defines and exposes NmNamespaceOps, wires native-module namespace implementations into the table, and arms it during native-module vtable installation.
Namespace operation routing and extracted behavior
crates/perry-runtime/src/object/{descriptors.rs,field_set_by_name.rs,reflect_support.rs}, crates/perry-runtime/src/object/class_registry/*, crates/perry-runtime/src/{closure/dispatch/value_call.rs,value/dynamic_object.rs}
Routes namespace descriptors, keys, writes, reflection, method binding, EventEmitter prototype setup, dynamic super(), and Buffer static dispatch through namespace hooks.
Runtime-registered reactor pumps
crates/perry-runtime/src/lib.rs, crates/perry-runtime/src/{child_process/ reactor.rs,pty/reactor.rs}, changelog.d/6928-nm-namespace-hooks.md
Adds runtime pump slots and dispatch, registers child-process and PTY callbacks when live handles are created, and documents the architecture change.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant NamespaceObject as Native-module namespace object
  participant ObjectRuntime as Object runtime
  participant NamespaceOps as NmNamespaceOps
  participant NativeModule as Native-module implementation
  NamespaceObject->>ObjectRuntime: request descriptor, key, field, or method operation
  ObjectRuntime->>NamespaceOps: query armed operation table
  NamespaceOps->>NativeModule: invoke routed namespace helper
  NativeModule-->>ObjectRuntime: return operation result
Loading
sequenceDiagram
  participant ChildProcess as child_process reactor
  participant PTY as node-pty reactor
  participant RuntimePump as stdlib_pump
  participant StdlibPump as js_run_stdlib_pump
  ChildProcess->>RuntimePump: register slot 0 callback
  PTY->>RuntimePump: register slot 1 callback
  StdlibPump->>RuntimePump: run_runtime_pumps()
  RuntimePump->>ChildProcess: invoke child-process pump
  RuntimePump->>PTY: invoke PTY pump
Loading

Suggested reviewers: andrewtdiz, thehypnoo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the main changes: armed NmNamespaceOps dispatch and armed reactor pump slots for the devirt foundation.
Description check ✅ Passed The description includes a summary, concrete changes, and verification, but it omits the required Related issue, Screenshots, and Checklist sections.
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.
✨ 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 size/nm-constants-devirt

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/perry-runtime/src/object/native_module.rs (1)

336-337: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: drop the pass-through wrappers if signatures already match.

nm_own_keys_array_opt and nm_bind_method_ops just forward to vt_own_keys_array and js_native_module_bind_method with identical signatures — if those functions are unsafe fn with exactly the same argument/return types as the NmNamespaceOps fields, you could assign them directly and drop the two wrapper functions.

Also applies to: 357-365

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-runtime/src/object/native_module.rs` around lines 336 - 337, In
the native module initialization around the NmNamespaceOps fields own_keys_array
and bind_method, verify whether vt_own_keys_array and
js_native_module_bind_method already have matching unsafe function signatures;
if so, assign those functions directly and remove the redundant pass-through
wrappers nm_own_keys_array_opt and nm_bind_method_ops.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/perry-runtime/src/object/native_module.rs`:
- Around line 336-337: In the native module initialization around the
NmNamespaceOps fields own_keys_array and bind_method, verify whether
vt_own_keys_array and js_native_module_bind_method already have matching unsafe
function signatures; if so, assign those functions directly and remove the
redundant pass-through wrappers nm_own_keys_array_opt and nm_bind_method_ops.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 04b21c87-24f3-48b2-85d7-1d36900e879e

📥 Commits

Reviewing files that changed from the base of the PR and between fb2ca94 and eb17c84.

📒 Files selected for processing (15)
  • changelog.d/6928-nm-namespace-hooks.md
  • crates/perry-runtime/src/child_process/reactor.rs
  • crates/perry-runtime/src/closure/dispatch/value_call.rs
  • crates/perry-runtime/src/lib.rs
  • crates/perry-runtime/src/object/class_registry.rs
  • crates/perry-runtime/src/object/class_registry/parent_static.rs
  • crates/perry-runtime/src/object/class_registry/prototype_objects.rs
  • crates/perry-runtime/src/object/descriptors.rs
  • crates/perry-runtime/src/object/field_set_by_name.rs
  • crates/perry-runtime/src/object/mod.rs
  • crates/perry-runtime/src/object/native_module.rs
  • crates/perry-runtime/src/object/nm_namespace_hooks.rs
  • crates/perry-runtime/src/object/reflect_support.rs
  • crates/perry-runtime/src/pty/reactor.rs
  • crates/perry-runtime/src/value/dynamic_object.rs

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