Repository navigation
A shared library reads the default library's data through its DLL - #630
Merged
Merged
Conversation
`tslang --emit=dll` links the default library's DLL, and a DLL exports data only as `__imp_<name>`. The default library's ambient data (core.d.ts's PrimeHelpers.hashCollisionThreshold, `declare namespace Math`'s PI, `declare class Number`'s EPSILON) was a plain external global, so a library using Map failed to link: "unresolved external symbol PrimeHelpers.hashCollisionThreshold referenced in function Map<!ts.string,!ts.number>.tryInsert". Functions were fine: the import library gives each one a thunk. The files loaded for lib.d.ts are now recorded, and an ambient global declared in one of them gets the `import` attribute when the program links the shared default library (isDLL, not Android). ExportFixPass makes it dllimport on Windows and drops it elsewhere. --emit=exe and --emit=jit objects are unchanged. Test: test-compile-shared-defaultlib-data links a DLL reading all three and runs a program importing it; skipped without a built default library. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ASDAlexander77
added a commit
that referenced
this pull request
Oct 20, 2026
#630 made --emit=dll read the default library's data through `__imp_`, but that does not carry over to --jit-native. Its DLL links the JIT cache's objects, which are compiled for the JIT's static large code model, and x86 codegen gives a dllimport global no `__imp_` reference under that model (X86Subtarget::classifyGlobalReference). Checked: with the data marked dllimport for JIT objects too, the in-memory JIT still runs, but the objects keep plain `Math.PI` references and the DLL link fails without the static default library. The comment and the design doc said this was the same bug as --emit=dll; they now give the actual reason. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
tslang --emit=dllfailed to link any program that reads data defined in the default library:A shared library links the default library's DLL (
exe.cpp), and a DLL exports data only as__imp_<name>. The import library has no plainPrimeHelpers.hashCollisionThreshold, only__imp_PrimeHelpers.hashCollisionThreshold. The default library's ambient data incore.d.ts/lib.d.tscarries no@dllimportmarker, so it was emitted as a plainexternal global. Functions were not affected because the import library gives each one a thunk.--emit=exelinks the static default library, and--emit=jitbinds the symbol from the DLL's exports, so neither showed the bug.The same failure hits
Math.PI(a const insidedeclare namespace Math),Number.EPSILON/MAX_SAFE_INTEGER(static fields ofdeclare class Number) andRangeError..rtti(read byinstanceof).Fix
MLIRGenModule.cpp:loadReferencedFilerecords each file loaded forlib.d.ts(the file and everything it references) indefaultLibFiles.MLIRGenImpl.h:createGlobalVariablegives theimportattribute to an ambient (isExternal) global declared in one of those files when the program links the shared default library (isDLL, not Android, default lib on). ExportFixPass turns that intodllimporton Windows MSVC and drops it on other targets, the same path a user library's@dllimportdeclarations take. The global staysVariableType::External, so it is a pureexternal dllimportdeclaration with no initializer.lib.generics.tsis the library's source compiled into the program, so its definitions are not ambient and are unaffected.--emit=exeand--emit=jitobjects are unchanged: the gate isisDLL, so there is no LNK4217 and no__imp_for RTDyld to resolve. I checked that the exe's IR still has a plainexternal globalfor these symbols. Out of scope on purpose: an--emit=objobject that is later linked with-sharedby hand still gets plain externals.Test
test-compile-shared-defaultlib-data(test/tester/defaultlib-data-import.cmake, sources intest/tester/defaultlib/) builds a-mm=rcDLL with the real default library that readsPrimeHelpers.hashCollisionThreshold(through a Map),Math.PIandNumber.EPSILON. It then builds and runs an exe that imports the DLL. Like the default-library collector tests, it is skipped when no default library has been built.--optand with--di.ctest -C Release -R "shared|import|defaultlib": 536/536 passed (1 test was already disabled). That includestest-{jit,compile}-gc-defaultlib-collector, which ran and were not skipped.Error/RangeErrorwithinstanceofin a try/catch,Set,Date,Number.MAX_SAFE_INTEGERandMath.E. The unfixed compiler fails on 4 symbols. The fixed one links, and a host exe calling the DLL prints the expected values.🤖 Generated with Claude Code