One garbage collector per process: TypeScriptRuntime.dll on gc.dll (Windows) - #309
Merged
Merged
Conversation
The gc default-library DLL links the static gc.lib, so it runs a collector of its own beside TypeScriptRuntime.dll (JIT) and beside gc.dll (exe + user DLL). Measured: 2000/2000 and 1984/2000 held strings read freed memory, 0 with collection suppressed. The proposal takes Boehm from gc.dll in every binary that can share a process, and keeps the static gc.lib for a lone exe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
….dll TypeScriptRuntime.dll linked Boehm statically, so a JIT run that loads a gc shared library - a user's, or the default library's DLL - had two collectors, and one freed strings only the other's memory referenced (2000/2000 under the JIT). On Windows the runtime now takes Boehm from gc.dll: the top-level CMake defines an imported tslang_gc_shared target from 3rdParty/gcdll (TSLANG_GC_SHARED_PREFIX, GC_DLL), fails to configure without it, and copies gc.dll into bin/. prepare_3rdParty.bat builds it; the release zip ships it and passes GC_SHARED_LIB_PATH to the default-library build, whose DLL now links gc.dll too (TypeScriptCompilerDefaultLib, same branch). New test pair gc_single_collector: the library builds the held strings AND churns, so its collector is the one that must run. Fails with the old runtime, passes with the new one; JIT + default-lib DLL and exe + user DLL + default-lib DLL repros go from 2000/2000 and 1984/2000 bad to 0. Linux unchanged. Suite: 2,704 of 2,704. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merged
6 tasks
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
Under
-mm=gc, every binary that links Boehm statically runs its own collector. When two of them share a process, a collection frees objects that only the other binary's memory still references. Nothing crashes; the program reads wrong data.TypeScriptRuntime.dlland the default library'sTypeScriptDefaultLib.dllboth linked Boehm statically. So a JIT run that loads the default library, or any gc DLL, had two collectors. An exe that loads a user DLL also had two, because the default-library DLL brought its own. This PR is step 1, 5 and part of 6 oftslang/docs/single-gc-collector-design.md, included here as a proposal.gc.dll(Windows only).tslang_gc_sharedtarget from3rdParty/gcdll/x64/<build>.TSLANG_GC_SHARED_PREFIXoverrides the path, andGC_DLLmakes the Boehm headers declare its functions as imported.TypeScriptRuntimelinks the new target and copiesgc.dllintobin/.gc.cppno longer forces static linking whenGC_DLLis set.prepare_3rdParty.batbuilds the shared Boehm.bin/gc.dllin its root.GC_SHARED_LIB_PATHto the default-library build.import_gc_single_collector.ts/export_gc_single_collector.ts, registered as-jit -sharedand AOT-shared. The library side builds the strings the importer holds, then churns with different content. That makes the library's own collector run, and it must see the importer's array. The existing owned-returns tests churn in the importer, which is why their JIT variant passed with two collectors.docs/memory-models.mdand the design doc.Companion PR:
TypeScriptCompilerDefaultLib, branchfix-single-gc-collector. It links the gcTypeScriptDefaultLib.dllagainstgc.dll.Linux is unchanged; nothing has been measured there yet.
Measured (Windows release)
Every "before" failure also passed with collection suppressed (
GC_INITIAL_HEAP_SIZE=1GB), so the extra collector is the cause.test-jit-shared-export-import-gc-single-collectortest-compile-shared-export-import-gc-single-collectorThe new JIT test was also rerun with the old static-Boehm runtime to confirm it still fails there.
Test plan
ctest, Windows release: 2,704 of 2,704TypeScriptRuntime.dllandTypeScriptDefaultLib.dllboth importgc.dll(llvm-readobj --coff-imports)gc.dll)gc.dllin the root andgcdll/Not in this PR
tslangchoosing the shared GC for--emit=dlland for exes that import a DLLconstdeclared in aforbody in a namespace function gives "can't resolve name". The new test useslet.🤖 Generated with Claude Code