Skip to content

WeakRef: the target is cleared once it has gone; weakref_basic asserts it - #17

Merged
ASDAlexander77 merged 1 commit into
mainfrom
weakref-gc-clears
Sep 30, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
weakref-gc-clears

Conversation

@ASDAlexander77

@ASDAlexander77 ASDAlexander77 commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Summary

Under gc, WeakRef never let go of its target. After the last reference was gone and GC_gcollect() had run, deref() still returned the object.

The target sat in a plain pointer field. The collector finds that pointer when it scans the WeakRef, so the target stayed reachable and the weak link was never cleared. gc.h says the link location should hold "a disguised pointer to obj". The field now holds the target's address complemented, which is what GC_HIDE_POINTER does. The collector sets it to 0 when the target goes.

Tests

weakref_basic only printed its results and checked for "ALL DONE", so it passed even though the link was never cleared. It now asserts three things:

  • deref() returns the object before a collection;
  • it returns undefined after the collection;
  • an object that is still held survives.

The deref() of a live object runs in a function of its own, so no pointer to it stays in main's frame for the collector's conservative stack scan to find.

It passed every run under gc: the JIT at -O0 and -O3, and 10 of 10 compiled runs at each level.

gc only

WeakRef and this test are gc-only for now, and both say so in a comment. Under rc, none and own the compiler now rejects the GC_* calls with a clear error (ASDAlexander77/TypeScriptCompiler#420). Real rc weak references remain later work.

Results

gc, compile + JIT 158/158
rc, compile + JIT 157/157, plus weakref_basic skipped as gc-only

🤖 Generated with Claude Code

…s it

WeakRef kept its target in a plain pointer field. The collector finds that
pointer when it scans the WeakRef, so the target stayed reachable and the
disappearing link was never cleared: after the last reference went and
GC_gcollect() ran, deref() still gave the object. gc.h asks for a disguised
pointer in the link location; the field now holds the target's address
complemented (GC_HIDE_POINTER), which the collector sets to 0 when the
target goes.

weakref_basic only printed its results and checked for "ALL DONE", so it
passed with the link never cleared. It now asserts: the object before a
collection, undefined after it, and that a held object survives. The
deref of a live object is in a function of its own, so no pointer to it is
left in main's frame for the conservative stack scan.

WeakRef and this test are gc only - under rc, none and own the compiler now
rejects the GC_* calls (TypeScriptCompiler: "A call to the collector's API
outside -mm=gc is a compile error"). Both say so in a comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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