feat(runtime): expose gc() as a callable globalThis property - #5712
Merged
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThe runtime adds a callable ChangesGlobalThis gc builtin exposure
Sequence Diagram(s)sequenceDiagram
participant globalThis
participant global_this_gc_thunk
participant js_gc_collect
globalThis->>global_this_gc_thunk: gc([force])
global_this_gc_thunk->>js_gc_collect: collect garbage
js_gc_collect-->>global_this_gc_thunk: done
global_this_gc_thunk-->>globalThis: undefined
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Follow-up to the `typeof gc` capability-guard fix. That change makes the bare-identifier guard `if (typeof gc === "function") gc()` work, but the other idiomatic capability-guard forms read `gc` as a VALUE: if (globalThis.gc) globalThis.gc(); // Node CLI docs' own example global.gc?.(); // Bun's documented form const g = globalThis.gc; g?.(); These all read `globalThis.gc`, which Perry never installed, so they were `undefined` / no-ops even though `gc()` is callable. Install `gc` as a real callable property on the globalThis singleton (a ClosureHeader-backed value, like `setTimeout`/`queueMicrotask`), routed to the same `js_gc_collect` the bare `gc()` intrinsic uses. Non-enumerable; the optional Node `force` argument is accepted but ignored (Perry's gc is a full collection). Now `typeof globalThis.gc === "function"`, `globalThis.gc` is truthy, and `globalThis.gc()` / `globalThis.gc?.()` / `gc?.()` all run a real collection.
machineloop
force-pushed
the
feat/gc-callable-global
branch
from
June 27, 2026 02:10
fb49b05 to
881bab8
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Follow-up to the
typeof gccapability-guard fix (#5711). That change makes the bare-identifier guardif (typeof gc === "function") gc()work, but the other idiomatic capability-guard forms readgcas a value offglobalThis:--expose-gcCLI flag docs: https://nodejs.org/api/cli.html#--expose-gc (which itself shows the capability-guard idiomif (globalThis.gc) globalThis.gc()).--expose-gcexposinggc()on the global object, and theglobal.gc?.()form).These all read
globalThis.gc, which Perry never installed — so they wereundefined/ silent no-ops even thoughgc()is fully callable.This installs
gcas a real callable property on the globalThis singleton,exactly like
setTimeout/queueMicrotask, routed to the samejs_gc_collectthe baregc()intrinsic uses.Changes
crates/perry-runtime/src/object/global_this/builtin_thunks.rs— newglobal_this_gc_thunk: callsjs_gc_collect, returnsundefined. Node'soptional
forceargument is accepted (arity 1) but ignored (Perry'sgcisa full collection).
crates/perry-runtime/src/object/global_this_tables.rs— add"gc"toGLOBAL_THIS_BUILTIN_FUNCTIONS.crates/perry-runtime/src/object/global_this/populate.rs— installgc(non-enumerable; arity 1) as a
ClosureHeader-backed value on the singleton.crates/perry-runtime/src/object/global_this.rs— re-export the thunk.After this,
typeof globalThis.gc === "function",globalThis.gcis truthy,and
globalThis.gc()/globalThis.gc?.()/gc?.()/const g = globalThis.gc; g()all run a real collection.Related issue
n/a — completes the
--expose-gc-family capability-guard idioms for Perry'salways-available
gc. Builds on thetypeof gcfix (#5711).Test plan
No regression:
setTimeout/parseInt/fetchremain installed callableglobals; timers still fire.
(Known minor gap, out of scope: the bare-identifier rebind
const f = gc; f()still reports
typeof f === "boolean"—gclowers to anExternFuncRefvaluelike
setTimeoutdoes, but unlikesetTimeoutdoesn't materialize to a closurein that position. It is not one of the documented guard idioms and is left as a
separate follow-up.)
cargo build --releaseclean — built-p perry-runtime(and-p perry); the full-workspace build needs the GTK/gdk-pixbuflibs forperry-ui-*, which CI provides.cargo test --workspace --exclude perry-ui-ios --exclude perry-ui-tvos --exclude perry-ui-watchos --exclude perry-ui-gtk4 --exclude perry-ui-android --exclude perry-ui-windowspasses — rancargo test -p perry-runtime --lib global_this(18/18) plus the end-to-end guard-forms check; full workspace deferred to CI (perry-uineedsgdk-pixbuf).test-files/or a#[test]—global_thisbuiltin install covered byperry-runtimetests; the guard forms verified end to end above.docs/src/— n/a, an internal global-builtin install, no new public API surface.-p perry-ui-<backend>— n/a.Screenshots / output
n/a — see the bounded-RSS guard-forms output in the test plan.
Checklist
feat:/fix:/docs:/chore:prefix convention —feat(runtime): …Summary by CodeRabbit
Summary by CodeRabbit
globalThis.gc()function to the runtime.globalThis.gc()triggers garbage collection and returnsundefined.globalThis.gc(force)), which is accepted but ignored.globalThis.gcsafely.