Skip to content

A call to the collector's API outside -mm=gc is a compile error - #420

Merged
ASDAlexander77 merged 2 commits into
mainfrom
gc-api-outside-gc
Sep 30, 2026
Merged

ASDAlexander77 merged 2 commits into
mainfrom
gc-api-outside-gc

Conversation

@ASDAlexander77

@ASDAlexander77 ASDAlexander77 commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Stacked on #419. This branch also contains #419's commit, so merge #419 first. This PR's own change is the top commit.

Summary

lib.native.d.ts declares GC_gcollect and the weak-link functions that DefaultLib's WeakRef is built on (GC_general_register_disappearing_link, GC_unregister_disappearing_link). Only a gc program links the collector. Under rc, none and own, a call to any of them used to reach the linker as an unresolved symbol. This is how DefaultLib's weakref_basic failed under rc:

error LNK2019: unresolved external symbol GC_general_register_disappearing_link referenced in function makeAndDrop

It's now an error at the call:

lib.generics.ts:1512:9: error: 'GC_general_register_disappearing_link' is part of the garbage collector,
which -mm=rc does not have; it needs -mm=gc, as does WeakRef, which is built on it

WeakRef is gc-only for now. Real weak references under rc (rc document §9.8: a weak count in front of the strong one) remain later work.

Companion DefaultLib PR ASDAlexander77/TypeScriptCompilerDefaultLib#17: WeakRef now clears under gc, and weakref_basic asserts that it does.

Tests

  • test-compile-gc-api-outside-gc-{rc,none,own}: the message.
  • test-compile-gc-api-gc: the same file compiles under gc.

Results

Release ctest 3317/3317
DefaultLib gc (compile + JIT) 158/158
DefaultLib rc (compile + JIT) 157/157, plus weakref_basic skipped as gc-only: no failures

🤖 Generated with Claude Code

ASDAlexander77 and others added 2 commits September 30, 2026 19:57
Every program that awaits anything, built ahead of time under rc, none or
own, failed to link:

  TypeScriptAsyncRuntime.lib(AsyncRuntime.obj) : error LNK2019: unresolved
  external symbol GC_allow_register_threads referenced in function
  GC_enable_threads (and GC_register_my_thread, GC_unregister_my_thread,
  GC_get_stack_base)

The async runtime registers its pool threads with the collector under gc
(AsyncGCThreads.h, from #308). At run time that is inert under the other
models - it only switches on through GC_enable_threads, which only the GC
pass injects - but it sat in the scheduler's own object file, which every
async program links, and only gc programs link gc.lib. `none` linked before
#308.

GC_enable_threads and the collector calls move to an object file of their
own (AsyncGCThreadsCommon.inc, built as AsyncGCThreads.cpp in both
TypeScriptAsyncRuntime and TypeScriptRuntime). The scheduler reaches them
through two hooks that GC_enable_threads installs, so only the call in a
gc program pulls that object in. The scheduler no longer includes gc.h.

test-runner links every model with lld and gc.lib itself, which is why the
rc and none corpus runs of 00async_await.ts passed. New
test-compile-async-without-collector (async-without-collector.cmake) builds
00async_await.ts with `tslang --emit=exe` under rc, none and own, with no
GC_LIB_PATH, and runs it.

DefaultLib's sleep.ts, which failed the same way under rc, links and runs.
00async_gc_threading.ts under gc (the fault the registration fixed, about 6
runs in 10 at -O0 without it): 0 of 20 failures at -O0 and at -O3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib.native.d.ts declares GC_gcollect and the weak-link functions
(GC_general_register_disappearing_link, GC_unregister_disappearing_link)
DefaultLib's WeakRef is built on. Only a gc program links the collector,
so under rc, none and own a call to any of them reached the linker as an
unresolved symbol - DefaultLib's weakref_basic under rc:

  error LNK2019: unresolved external symbol
  GC_general_register_disappearing_link referenced in function makeAndDrop

It is now an error at the call:

  error: 'GC_general_register_disappearing_link' is part of the garbage
  collector, which -mm=rc does not have; it needs -mm=gc, as does WeakRef,
  which is built on it

WeakRef under rc (rc document 9.8: a weak count in front of the strong
one) stays a later piece of work.

Tests test-compile-gc-api-outside-gc-{rc,none,own} (the message) and
test-compile-gc-api-gc (the same file compiles under gc).

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