From 6a73c9373c92a4a0376c28e19debc9a123d389af Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Sun, 5 Jul 2026 22:30:45 +0100 Subject: [PATCH 1/6] not needed code --- tslang/tslang/jit.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tslang/tslang/jit.cpp b/tslang/tslang/jit.cpp index c0d07ff5..668d4e9b 100644 --- a/tslang/tslang/jit.cpp +++ b/tslang/tslang/jit.cpp @@ -349,18 +349,18 @@ int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compile // bound to (ucrtbase buffers its streams separately from our static CRT). fflush(stdout); fflush(stderr); -#ifdef _WIN32 - for (auto crtName : {"ucrtbase.dll", "ucrtbased.dll"}) - { - if (HMODULE crt = GetModuleHandleA(crtName)) - { - if (auto crtFflush = (int(__cdecl *)(FILE *))GetProcAddress(crt, "fflush")) - { - crtFflush(nullptr); // fflush(NULL) flushes all of that CRT's output streams - } - } - } - TerminateProcess(GetCurrentProcess(), 0); -#endif +// #ifdef _WIN32 +// for (auto crtName : {"ucrtbase.dll", "ucrtbased.dll"}) +// { +// if (HMODULE crt = GetModuleHandleA(crtName)) +// { +// if (auto crtFflush = (int(__cdecl *)(FILE *))GetProcAddress(crt, "fflush")) +// { +// crtFflush(nullptr); // fflush(NULL) flushes all of that CRT's output streams +// } +// } +// } +// TerminateProcess(GetCurrentProcess(), 0); +// #endif return 0; } From d9326c9fe077e7371d23b62b1e4ff50ab27fc972 Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Sun, 5 Jul 2026 23:05:11 +0100 Subject: [PATCH 2/6] Enable debug-specific flushing of CRT output streams on Windows --- tslang/tslang/jit.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tslang/tslang/jit.cpp b/tslang/tslang/jit.cpp index 668d4e9b..71d0e5d5 100644 --- a/tslang/tslang/jit.cpp +++ b/tslang/tslang/jit.cpp @@ -349,18 +349,20 @@ int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compile // bound to (ucrtbase buffers its streams separately from our static CRT). fflush(stdout); fflush(stderr); -// #ifdef _WIN32 -// for (auto crtName : {"ucrtbase.dll", "ucrtbased.dll"}) -// { -// if (HMODULE crt = GetModuleHandleA(crtName)) -// { -// if (auto crtFflush = (int(__cdecl *)(FILE *))GetProcAddress(crt, "fflush")) -// { -// crtFflush(nullptr); // fflush(NULL) flushes all of that CRT's output streams -// } -// } -// } -// TerminateProcess(GetCurrentProcess(), 0); -// #endif +#ifdef _WIN32 + #if _DEBUG + for (auto crtName : {"ucrtbase.dll", "ucrtbased.dll"}) + { + if (HMODULE crt = GetModuleHandleA(crtName)) + { + if (auto crtFflush = (int(__cdecl *)(FILE *))GetProcAddress(crt, "fflush")) + { + crtFflush(nullptr); // fflush(NULL) flushes all of that CRT's output streams + } + } + } + TerminateProcess(GetCurrentProcess(), 0); + #endif +#endif return 0; } From d5702b26f87e588102b9301531f3cd070e20b9ad Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Sun, 5 Jul 2026 23:56:09 +0100 Subject: [PATCH 3/6] Add symbol options to visualizer configurations in launch.json --- tslang/tslang/.vscode/launch.json | 396 ++++++++++++++++++++++++++---- tslang/tslang/jit.cpp | 1 + 2 files changed, 356 insertions(+), 41 deletions(-) diff --git a/tslang/tslang/.vscode/launch.json b/tslang/tslang/.vscode/launch.json index 94e4d6b1..305fcc2e 100644 --- a/tslang/tslang/.vscode/launch.json +++ b/tslang/tslang/.vscode/launch.json @@ -17,7 +17,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - MLIR", @@ -34,7 +46,19 @@ "cwd": "C:/temp/", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Linux) ./tslang - MLIR", @@ -53,7 +77,7 @@ "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { "name": "(Windows) tslang.exe - MLIR-AFFINE", @@ -71,7 +95,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Linux) ./tslang - MLIR-AFFINE", @@ -88,8 +124,7 @@ "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], - "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { "name": "(Windows) tslang.exe - MLIR-LLVM", @@ -106,7 +141,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Linux) ./tslang - MLIR-LLVM", @@ -120,8 +167,7 @@ "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], - "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { "name": "(Windows) tslang.exe - LLVM", @@ -142,7 +188,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Linux) ./tslang - LLVM", @@ -156,8 +214,7 @@ "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], - "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { "name": "(Windows) tslang.exe - BC", @@ -174,7 +231,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - OBJ", @@ -192,7 +261,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - ASM", @@ -211,7 +292,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - EXE", @@ -247,7 +340,19 @@ }, ], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) (ClangCL) tslang.exe - EXE", @@ -283,10 +388,21 @@ "value": "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/lib" }, ], - "console": "externalTerminal", "visualizerFile": "${workspaceFolder}/../tslang.natvis", "MIMode": "gdb", "MIDebuggerPath": "lldb.exe", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - EXE(DI) - NO DEFAULT", @@ -321,7 +437,19 @@ }, ], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - EXE(OPT) - NO DEFAULT", @@ -356,7 +484,19 @@ }, ], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - EXE(OPT) (Release EXE) - NO DEFAULT", @@ -390,7 +530,19 @@ }, ], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - LLVM - NO DEFAULT", @@ -424,7 +576,19 @@ }, ], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - DLL", @@ -457,7 +621,19 @@ }, ], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - WASM", @@ -476,7 +652,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - WASM - emscripten", @@ -497,7 +685,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - JIT", @@ -517,7 +717,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - JIT (no default)", @@ -527,7 +739,7 @@ "args": [ "-emit=jit", "I:/Playground/1.ts", - "-debug-only=mlir,llvm,pass", + //"-debug-only=mlir,llvm,pass", "-mlir-disable-threading", "-di", "--no-default-lib", @@ -537,7 +749,19 @@ "cwd": "I:/Playground", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - JIT-OBJ", @@ -555,7 +779,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Linux) tslang - JIT", @@ -572,7 +808,6 @@ "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], - "console": "externalTerminal", "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { @@ -603,7 +838,6 @@ "value": "${workspaceFolder}/../../__build/tslang/linux-ninja-gcc-debug/lib" } ], - "console": "externalTerminal", "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { @@ -637,7 +871,6 @@ "value": "${workspaceFolder}/../../../TypeScriptCompilerDefaultLib/__build/release" }, ], - "console": "externalTerminal", "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { @@ -668,7 +901,6 @@ "value": "${workspaceFolder}/../../__build/tslang/linux-ninja-gcc-debug/lib" } ], - "console": "externalTerminal", "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { @@ -698,7 +930,6 @@ "value": "${workspaceFolder}/../../__build/tslang/linux-ninja-gcc-debug/lib" } ], - "console": "externalTerminal", "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { @@ -718,7 +949,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - DefaultLib Compile (MLIR)", @@ -737,7 +980,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - DefaultLib Compile (DI) (OBJ)", @@ -757,7 +1012,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - DefaultLib Compile (opt) (OBJ)", @@ -780,7 +1047,19 @@ "cwd": "${workspaceFolder}", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Linux) tslang - DefaultLib Compile (OBJ)", @@ -800,7 +1079,6 @@ "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], - "console": "externalTerminal", "visualizerFile": "${workspaceFolder}/../tslang.natvis" }, { @@ -816,6 +1094,18 @@ "moduleLoad": true, "trace": true }, + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - new VSCode project", @@ -830,7 +1120,19 @@ "cwd": "I:/Playground", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Windows) tslang.exe - Install Default lib", @@ -844,7 +1146,19 @@ "cwd": "I:/Playground", "environment": [], "console": "externalTerminal", - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis", + "symbolOptions": { + "searchPaths": [ + "C:/symbols", + "${workspaceFolder}/../../__build/tslang/windows-msbuild-2026-debug/bin" + ], + "searchMicrosoftSymbolServer": true, + "cachePath": "C:/symbols", + "moduleFilter": { + "mode": "loadAllButExcluded", + "excludedModules": [ "DoNotLookForThisOne*.dll" ] + } + } }, { "name": "(Linux) tslang - Install Default lib", @@ -857,7 +1171,7 @@ "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], - "visualizerFile": "${workspaceFolder}/../tslang.natvis" + "visualizerFile": "${workspaceFolder}/../tslang.natvis" } ] } \ No newline at end of file diff --git a/tslang/tslang/jit.cpp b/tslang/tslang/jit.cpp index 71d0e5d5..4d2359aa 100644 --- a/tslang/tslang/jit.cpp +++ b/tslang/tslang/jit.cpp @@ -361,6 +361,7 @@ int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compile } } } + TerminateProcess(GetCurrentProcess(), 0); #endif #endif From 364f11158319f8612b65f700e6db567dbf98a3d6 Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Mon, 6 Jul 2026 00:02:38 +0100 Subject: [PATCH 4/6] Document JIT GC static-roots crash and resolution (test-jit-Raytrace) Co-Authored-By: Claude Fable 5 --- docs/jit-gc-static-roots.md | 151 ++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 docs/jit-gc-static-roots.md diff --git a/docs/jit-gc-static-roots.md b/docs/jit-gc-static-roots.md new file mode 100644 index 00000000..6503aade --- /dev/null +++ b/docs/jit-gc-static-roots.md @@ -0,0 +1,151 @@ +# JIT crash: GC collects objects referenced only by globals (test-jit-Raytrace) + +Status: **fixed** (PR #184, 2026-07-05). Files: `tslang/jit.cpp`, +`lib/TypeScriptRuntime/gc.cpp`, `include/TypeScript/gcwrapper.h`, +`lib/TypeScriptRuntime/TypeScriptRuntime.def`. + +## Symptom + +`test-jit-Raytrace` (raytrace.ts) crashed with `0xC0000005` when run under +`--emit=jit`, most reliably at `--opt_level=0` (the debug tester configuration). +The test had been disabled since 2023 with the comment +`# TODO: find out why it is crashing`. + +Characteristic behaviour that pointed at the garbage collector: + +| Configuration | Result | +|--------------------------------|---------| +| AOT (`--emit=exe`) at O0 | passes | +| JIT at O0, 1x1 or 16x16 render | passes | +| JIT at O0, 48x48 and larger | crashes | +| JIT at O0 with `--nogc` | passes | + +The crash appears exactly when the Boehm heap grows enough to trigger the +first collection cycle. + +## Root cause 1: JIT data sections are not GC roots + +The Boehm GC discovers static roots automatically only for *loader-mapped +modules*: on Windows it walks the address space and registers writable +`MEM_IMAGE` regions (the `.data`/`.bss` of the exe and every DLL). That is why +AOT binaries work out of the box. + +JIT'd code is different. The MLIR `ExecutionEngine` links objects with +RTDyld, whose `SectionMemoryManager` obtains section memory from plain +`VirtualAlloc`/`mmap` (`MEM_PRIVATE`). The globals of the JIT'd module — +including every static class member — live in those sections, and **the GC +never scans them**. + +Consequence: an object whose only reference is a global (`Color.background`, +`Surfaces.shiny`, … in raytrace.ts) is unreachable from the GC's point of +view. On the first collection it is freed, its block is recycled by a later +allocation, and the next access through the stale pointer reads garbage or +faults (in raytrace the fault came from calling `thing.surface.reflect()` +through a recycled object). + +### Minimal reproduction + +```ts +class Vec { + constructor(public x: number, public y: number, public z: number) {} +} + +class Statics { + static background = new Vec(11, 22, 33); +} + +function main() { + for (let i = 0; i < 3000000; i++) { + let v = new Vec(i, i, i); // force GC cycles + } + print(Statics.background.x); // expected 11 +} +``` + +Before the fix this printed `2.9751e+006` — i.e. the static's memory had been +recycled as `Vec(i, i, i)` with `i ≈ 2975100`, an allocation from the last +collection cycle. With `--nogc` it printed `11`. + +### Fix + +`tslang/jit.cpp` installs a custom `llvm::SectionMemoryManager::MemoryMapper` +(`GCRootsSectionMemoryMapper`) through +`mlir::ExecutionEngineOptions::sectionMemoryMapper`. Every **RWData** section +allocation is registered with the collector: + +``` +GC_add_roots(base, base + size); // on allocate (RWData only) +GC_remove_roots(base, base + size); // on release +``` + +`GC_add_roots`/`GC_remove_roots` are resolved at run time with +`llvm::sys::DynamicLibrary::SearchForAddressOfSymbol` from the already-loaded +`TypeScriptRuntime` library, so the mapper is inert under `--nogc` or when no +GC runtime is present. The exports were added as thin wrappers +(`_mlir__GC_add_roots`, `_mlir__GC_remove_roots`) in +`lib/TypeScriptRuntime/gc.cpp` and re-exported under the plain names in +`TypeScriptRuntime.def`, following the existing pattern for `GC_malloc` etc. + +Notes: + +- `GC_add_roots` auto-initializes the collector (bdwgc 8.2), so registering + sections *before* the JIT'd `__mlir_gctors` calls `GC_init()` is safe. +- `SectionMemoryManager` sub-allocates several object sections from one mapped + page, so registering the whole mapped block covers `.data`, `.bss` and any + later RW sections placed in it. +- The number of RW blocks per module is tiny compared to bdwgc's + `MAX_ROOT_SETS` (~8192). + +## Root cause 2: two TypeScriptRuntime copies = two GC instances + +The first fix initially appeared not to work, which exposed a second bug. + +`runJit()` unconditionally appended a fallback `TypeScriptRuntime` path +(resolved through `TSLANG_LIB_PATH` / the tslang lib directory) to the shared +library list — *even when the caller had already passed one via +`--shared-libs`*. When the two paths point at different files, Windows loads +**two copies of TypeScriptRuntime.dll**, each with its own statically linked +Boehm GC: two heaps, two root sets, two sets of collector state. + +The host registered roots in the copy found first by +`SearchForAddressOfSymbol`, while the JIT'd code allocated from the other +copy — so the registration had no effect. Beyond this bug, the double load is +a general hazard: any pointer that crosses the two heaps (realloc/free of a +block owned by the other instance) corrupts memory. + +This is easy to hit locally: the test runner passes +`--shared-libs=/bin/TypeScriptRuntime.dll` while `TSLANG_LIB_PATH` +points at an installed copy (e.g. `I:\tslang`). + +### Fix + +`runJit()` now skips the fallback lookup when the `--shared-libs` list already +names a `TypeScriptRuntime` library (case-insensitive stem match). Exactly one +copy of the runtime — and therefore one GC — is loaded per JIT process. + +## How to diagnose this class of bug + +1. `--nogc` passing while the normal run crashes ⇒ collector involvement. +2. Crash threshold scaling with allocation volume ⇒ first collection cycle. +3. AOT passing while JIT fails ⇒ suspect JIT-only differences: static roots, + symbol resolution, unwind info. +4. Print a static's fields after an allocation-heavy loop (repro above): a + value tracking the loop counter proves the block was recycled. +5. Check for duplicate runtime copies: + `Get-Process tslang | % Modules | ? ModuleName -match TypeScriptRuntime` — + more than one entry (or one from an unexpected path) means two GC + instances. +6. `tslang --emit=jit --dump-object-file --object-filename=out.obj …` dumps + the JIT'd object; `llvm-nm`/`llvm-readobj` show which section a global + lives in (`B`/`D` symbols ⇒ `.bss`/`.data` ⇒ must be a GC root range). + +## Related + +- The same PR fixed `00for_await_yield` at `-O3`: `print()`'s string-concat + lowering emitted a variable-size stack `alloca` inside `async_execute_fn` + coroutines, which LLVM's CoroSplit rejects ("Coroutines cannot handle non + static allocas yet"); `StringConcatOpLowering` now heap-allocates when the + enclosing function carries the `presplitcoroutine` attribute. +- Known, still open: a tight multi-million-iteration `new` loop at + `--opt --opt_level=3` under JIT dies with `0xC00000FD` (stack overflow); + reproduces on pre-fix binaries, unrelated to the GC roots work. From 1f4da18f597b2fe36d10af0aafe9ddb33d333941 Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Mon, 6 Jul 2026 00:30:39 +0100 Subject: [PATCH 5/6] Refactor JIT memory management to register GC roots and handle Win64 unwind info --- tslang/test/tester/CMakeLists.txt | 4 - tslang/tslang/jit.cpp | 402 +++++++++++++++++++++++++----- 2 files changed, 336 insertions(+), 70 deletions(-) diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index 716dee32..080b4979 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -628,7 +628,6 @@ add_test(NAME test-jit-00-for-await COMMAND test-runner -jit "${PROJECT_SOURCE_D # TODO: async generator / for-await-of hangs at runtime under JIT # error: EXEC : LLVM error : Coroutines cannot handle non static allocas yet add_test(NAME test-jit-00-for-await-yield COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00for_await_yield.ts") -if (NOT(WIN32)) add_test(NAME test-jit-00-try-catch COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00try_catch.ts") add_test(NAME test-jit-01-try-catch COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/01try_catch.ts") add_test(NAME test-jit-00-try-catch-return COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00try_catch_return.ts") @@ -638,7 +637,6 @@ add_test(NAME test-jit-00-try-finally-return COMMAND test-runner -jit "${PROJECT add_test(NAME test-jit-00-try-catch-rethrow COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00try_catch_rethrow.ts") add_test(NAME test-jit-00-try-catch-return-dispose COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00try_catch_return_dispose.ts") add_test(NAME test-jit-01-try-catch-return-dispose COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/01try_catch_return_dispose.ts") -endif() add_test(NAME test-jit-00-types COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00types.ts") add_test(NAME test-jit-00-property-access-conditional COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00property_access_cond.ts") add_test(NAME test-jit-00-method-access-conditional COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00method_access_cond.ts") @@ -727,9 +725,7 @@ add_test(NAME test-jit-43-nestednamespace COMMAND test-runner -jit "${PROJECT_SO add_test(NAME test-jit-44-toplevelcode COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/44toplevelcode.ts") add_test(NAME test-jit-45-enumtostring COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/45enumtostring.ts") add_test(NAME test-jit-48-instanceof COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/48instanceof.ts") -if (NOT(WIN32)) add_test(NAME test-jit-51-exceptions COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/51exceptions.ts") -endif() add_test(NAME test-jit-241-arrayforeach COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/241arrayforeach.ts") add_test(NAME test-jit-243-arrayevery COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/243arrayevery.ts") add_test(NAME test-jit-244-arraysome COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/244arraysome.ts") diff --git a/tslang/tslang/jit.cpp b/tslang/tslang/jit.cpp index 4d2359aa..9921a462 100644 --- a/tslang/tslang/jit.cpp +++ b/tslang/tslang/jit.cpp @@ -2,9 +2,17 @@ #include "mlir/ExecutionEngine/ExecutionEngine.h" #include "mlir/IR/BuiltinOps.h" +#include "mlir/Target/LLVMIR/Export.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" +#include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Memory.h" #include "llvm/Support/Path.h" @@ -96,63 +104,169 @@ int loadLibrary(mlir::SmallString<256> &libPath, llvm::StringMap &export return 0; } -// JIT'd globals live in RTDyld-allocated RW data sections (plain VirtualAlloc/mmap -// memory), which the Boehm GC does not scan: for AOT binaries the loader-mapped -// data segment is registered as a root set automatically, but in the JIT an object -// reachable only from a global (e.g. a static class member) is collected on the -// first GC cycle and its memory recycled, corrupting later accesses. Register every -// RW data section with the GC as a root range. GC_add_roots/GC_remove_roots are -// resolved dynamically from the already-loaded TypeScriptRuntime library, so this -// stays inert when the GC is disabled or not present. -class GCRootsSectionMemoryMapper : public llvm::SectionMemoryManager::MemoryMapper +#ifdef _WIN64 +// Image base of the JIT'd module (tslang JITs a single module per run), needed by +// the _CxxThrowException shim below. Filled in by JitSectionMemoryManager. +static uint64_t jitImageBase = 0; +#endif + +// A SectionMemoryManager that makes JIT'd code behave like AOT'd code: +// +// 1. GC roots. JIT'd globals live in RTDyld-allocated data sections (plain +// VirtualAlloc/mmap memory), which the Boehm GC does not scan: for AOT binaries +// the loader-mapped data segment is registered as a root set automatically, but +// in the JIT an object reachable only from a global (e.g. a static class member) +// is collected on the first GC cycle and its memory recycled. Register every RW +// data section via GC_add_roots, resolved dynamically from the already-loaded +// TypeScriptRuntime library so this stays inert under --nogc. +// +// 2. Win64 unwind info. LLVM's RTDyld never registers .pdata with the OS +// (RTDyldMemoryManager::registerEHFramesInProcess only speaks the Itanium +// __register_frame protocol), so a C++ exception thrown from JIT'd code aborts: +// RtlUnwindEx finds no RUNTIME_FUNCTION for JIT PCs and never reaches the catch +// funclet. Register every .pdata section RTDyld hands us with +// RtlAddFunctionTable, using the same "image base" RTDyld resolves +// IMAGE_REL_AMD64_ADDR32NB relocations against: the lowest section load address +// (see RuntimeDyldCOFFX86_64::getImageBase). +// +// 3. Executable read-only data (Win64). For external ADDR32NB targets — e.g. the +// __CxxFrameHandler3 personality referenced from .xdata — RTDyld materializes a +// jump thunk in the *referencing* section's stub area, and the OS exception +// dispatcher calls through it. Read-only sections therefore must be mapped +// executable; route them through the code allocator. +class JitSectionMemoryManager : public llvm::SectionMemoryManager { - // AllocationPurpose lives in the enclosing SectionMemoryManager, not in the - // MemoryMapper base class, so it is not found by unqualified lookup here - using AllocationPurpose = llvm::SectionMemoryManager::AllocationPurpose; using GCRootsFn = void (*)(void *, void *); public: - llvm::sys::MemoryBlock allocateMappedMemory(AllocationPurpose purpose, size_t numBytes, - const llvm::sys::MemoryBlock *const nearBlock, unsigned flags, - std::error_code &errCode) override + uint8_t *allocateCodeSection(uintptr_t size, unsigned alignment, unsigned sectionID, + llvm::StringRef sectionName) override + { + auto *addr = llvm::SectionMemoryManager::allocateCodeSection(size, alignment, sectionID, sectionName); + noteSectionAddress(addr); + return addr; + } + + uint8_t *allocateDataSection(uintptr_t size, unsigned alignment, unsigned sectionID, + llvm::StringRef sectionName, bool isReadOnly) override { - auto block = llvm::sys::Memory::allocateMappedMemory(numBytes, nearBlock, flags, errCode); - if (purpose == AllocationPurpose::RWData && block.base() != nullptr) +#ifdef _WIN64 + if (isReadOnly) + { + // see (3): unwind personality thunks live in read-only sections + return allocateCodeSection(size, alignment, sectionID, sectionName); + } +#endif + + auto *addr = llvm::SectionMemoryManager::allocateDataSection(size, alignment, sectionID, sectionName, isReadOnly); + noteSectionAddress(addr); + if (!isReadOnly && addr != nullptr) { if (auto addRoots = reinterpret_cast( llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("GC_add_roots"))) { - addRoots(block.base(), static_cast(block.base()) + block.allocatedSize()); - gcRootBlocks.push_back(block.base()); + addRoots(addr, addr + size); + gcRootSections.push_back({addr, size}); } } - return block; + return addr; + } + +#ifdef _WIN64 + void registerEHFrames(uint8_t *addr, uint64_t loadAddr, size_t size) override + { + auto entryCount = size / sizeof(RUNTIME_FUNCTION); + if (entryCount == 0 || imageBase == 0) + { + return; + } + + if (RtlAddFunctionTable(reinterpret_cast(addr), static_cast(entryCount), imageBase)) + { + functionTables.push_back(reinterpret_cast(addr)); + } } - std::error_code protectMappedMemory(const llvm::sys::MemoryBlock &block, unsigned flags) override + void deregisterEHFrames() override { - return llvm::sys::Memory::protectMappedMemory(block, flags); + for (auto *table : functionTables) + { + RtlDeleteFunctionTable(table); + } + + functionTables.clear(); } +#endif - std::error_code releaseMappedMemory(llvm::sys::MemoryBlock &block) override + ~JitSectionMemoryManager() override { - if (llvm::is_contained(gcRootBlocks, block.base())) + if (auto removeRoots = reinterpret_cast( + llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("GC_remove_roots"))) { - if (auto removeRoots = reinterpret_cast( - llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("GC_remove_roots"))) + for (auto §ion : gcRootSections) { - removeRoots(block.base(), static_cast(block.base()) + block.allocatedSize()); + removeRoots(section.first, section.first + section.second); } } - - return llvm::sys::Memory::releaseMappedMemory(block); } private: - mlir::SmallVector gcRootBlocks; + void noteSectionAddress(uint8_t *addr) + { + if (addr == nullptr) + { + return; + } + + if (imageBase == 0 || reinterpret_cast(addr) < imageBase) + { + imageBase = reinterpret_cast(addr); +#ifdef _WIN64 + jitImageBase = imageBase; +#endif + } + } + + uint64_t imageBase = 0; + mlir::SmallVector> gcRootSections; +#ifdef _WIN64 + mlir::SmallVector functionTables; +#endif }; +#ifdef _WIN64 +// MSVC x64 C++ EH encodes throw-site type information as image-relative offsets. +// vcruntime's _CxxThrowException recovers the base with RtlPcToFileHeader on the +// ThrowInfo pointer, which fails for JIT'd memory (it is not a loader-mapped +// image), so __CxxFrameHandler3 would resolve the throw-side RVAs against a null +// base and never match a catch clause. Raise the exception ourselves, substituting +// the image base RTDyld resolved those RVAs against. +static void jitCxxThrowException(void *exceptionObject, void *throwInfo) +{ + constexpr DWORD cxxExceptionCode = 0xE06D7363; // 'msc' | 0xE0000000 + constexpr ULONG_PTR cxxMagicNumber = 0x19930520; // EH_MAGIC_NUMBER1 + + // ThrowInfo from an AOT module (e.g. a runtime DLL) still resolves normally + void *moduleBase = nullptr; + if (throwInfo != nullptr) + { + RtlPcToFileHeader(throwInfo, &moduleBase); + } + + ULONG_PTR args[] = {cxxMagicNumber, reinterpret_cast(exceptionObject), + reinterpret_cast(throwInfo), + moduleBase != nullptr ? reinterpret_cast(moduleBase) + : static_cast(jitImageBase)}; + RaiseException(cxxExceptionCode, EXCEPTION_NONCONTINUABLE, 4, args); +} + +// from the statically linked vcruntime; bound into the JIT'd module as its +// exception personality so throw and catch sides use the same CRT +extern "C" EXCEPTION_DISPOSITION __CxxFrameHandler3(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, + struct _DISPATCHER_CONTEXT *); +#endif + int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compileOptions) { // to avoid false positive memory leak reports in release builds @@ -240,25 +354,6 @@ int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compile } } - // Create an MLIR execution engine. The execution engine eagerly JIT-compiles - // the module. - mlir::SmallVector sharedLibPaths; - sharedLibPaths.append(begin(clSharedLibs), end(clSharedLibs)); - - // must outlive the engine: sections are released from the engine's destructor - GCRootsSectionMemoryMapper gcRootsMemoryMapper; - - mlir::ExecutionEngineOptions engineOptions; - engineOptions.sectionMemoryMapper = &gcRootsMemoryMapper; - engineOptions.transformer = optPipeline; - engineOptions.enableObjectDump = dumpObjectFile; - engineOptions.enableGDBNotificationListener = !enableOpt; - engineOptions.sharedLibPaths = sharedLibPaths; - if (enableOpt.getValue()) - { - engineOptions.jitCodeGenOptLevel = (llvm::CodeGenOptLevel) optLevel.getValue(); - } - #ifdef _WIN32 // tslang.exe links the CRT statically (/MT[d]), so its libc symbols are not in // any DLL export table. The JIT's process-symbol resolver would otherwise bind @@ -284,19 +379,40 @@ int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compile addSym("calloc", (void*)&calloc); addSym("memset", (void*)&memset); addSym("memcpy", (void*)&memcpy); - } +#ifdef _WIN64 + // C++ EH: bind the JIT'd module's personality to our static CRT and route + // throws through the shim that fixes up the throw-site image base (see + // jitCxxThrowException above). + addSym("__CxxFrameHandler3", (void *)&__CxxFrameHandler3); + addSym("_CxxThrowException", (void *)&jitCxxThrowException); #endif - - auto maybeEngine = mlir::ExecutionEngine::create(module, engineOptions); - if (!maybeEngine) - { - llvm::WithColor::error(llvm::errs(), "tslang") << "failed to construct an execution engine, error: " << maybeEngine.takeError() << "\n"; - return -1; } - auto &engine = maybeEngine.get(); +#endif if (dumpObjectFile) { + // Compile-and-dump only, no execution: the stock MLIR engine is enough. + mlir::SmallVector sharedLibPaths; + sharedLibPaths.append(begin(clSharedLibs), end(clSharedLibs)); + + mlir::ExecutionEngineOptions engineOptions; + engineOptions.transformer = optPipeline; + engineOptions.enableObjectDump = true; + engineOptions.enableGDBNotificationListener = !enableOpt; + engineOptions.sharedLibPaths = sharedLibPaths; + if (enableOpt.getValue()) + { + engineOptions.jitCodeGenOptLevel = (llvm::CodeGenOptLevel) optLevel.getValue(); + } + + auto maybeEngine = mlir::ExecutionEngine::create(module, engineOptions); + if (!maybeEngine) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to construct an execution engine, error: " << maybeEngine.takeError() << "\n"; + return -1; + } + auto &engine = maybeEngine.get(); + auto expectedFPtr = engine->lookup(mainFuncName); if (!expectedFPtr) { @@ -310,30 +426,184 @@ int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compile { targetTriple = llvm::Triple::normalize(TargetTriple); } - + TheTriple = llvm::Triple(targetTriple); engine->dumpToObjectFile( - objectFilename.empty() - ? inputFilename + ((TheTriple.getOS() == llvm::Triple::Win32) ? ".obj" : ".o") + objectFilename.empty() + ? inputFilename + ((TheTriple.getOS() == llvm::Triple::Win32) ? ".obj" : ".o") : objectFilename); return 0; } - if (module.lookupSymbol(MLIR_GCTORS)) + // Run path: build our own LLJIT instead of mlir::ExecutionEngine — the stock + // engine hard-codes a plain SectionMemoryManager, which neither registers GC + // roots for JIT'd globals nor Win64 unwind info (see JitSectionMemoryManager). + + // Load the shared libraries into the process; the JIT resolves external + // symbols from their export tables via the current-process generator below. + for (auto &libPathStr : clSharedLibs) + { + std::string errMsg; + llvm::sys::DynamicLibrary::getPermanentLibrary(libPathStr.c_str(), &errMsg); + if (!errMsg.empty()) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "Loading error lib: " << libPathStr << " error: " << errMsg << "\n"; + return -1; + } + } + + auto llvmContext = std::make_unique(); + auto llvmModule = mlir::translateModuleToLLVMIR(module, *llvmContext); + if (!llvmModule) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to emit LLVM IR\n"; + return -1; + } + + auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost(); + if (!tmBuilderOrError) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to create a JITTargetMachineBuilder for the host, error: " << tmBuilderOrError.takeError() << "\n"; + return -1; + } + + if (enableOpt.getValue()) + { + tmBuilderOrError->setCodeGenOptLevel((llvm::CodeGenOptLevel) optLevel.getValue()); + } + + auto tmOrError = tmBuilderOrError->createTargetMachine(); + if (!tmOrError) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to create a TargetMachine for the host, error: " << tmOrError.takeError() << "\n"; + return -1; + } + + llvmModule->setDataLayout((*tmOrError)->createDataLayout()); + llvmModule->setTargetTriple((*tmOrError)->getTargetTriple()); + + if (auto err = optPipeline(llvmModule.get())) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to optimize LLVM IR, error: " << std::move(err) << "\n"; + return -1; + } + + auto maybeJit = + llvm::orc::LLJITBuilder() + .setJITTargetMachineBuilder(std::move(*tmBuilderOrError)) + .setDataLayout(llvmModule->getDataLayout()) + .setObjectLinkingLayerCreator( + [targetTriple = llvmModule->getTargetTriple()](llvm::orc::ExecutionSession &session) + -> llvm::Expected> { + auto objectLayer = std::make_unique( + session, [](const llvm::MemoryBuffer &) { return std::make_unique(); }); + + if (!enableOpt.getValue()) + { + if (auto *gdbListener = llvm::JITEventListener::createGDBRegistrationListener()) + { + objectLayer->registerJITEventListener(*gdbListener); + } + } + + // COFF format binaries (Windows) need special handling to deal + // with exported symbol visibility (cf mlir::ExecutionEngine) + if (targetTriple.isOSBinFormatCOFF()) + { + objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true); + objectLayer->setAutoClaimResponsibilityForObjectSymbols(true); + } + + return objectLayer; + }) + .create(); + if (!maybeJit) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to construct the JIT engine, error: " << maybeJit.takeError() << "\n"; + return -1; + } + + auto &jit = maybeJit.get(); + + // Resolve symbols from the current process, including the loaded shared + // libraries and the AddSymbol overrides above. + auto generator = llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(jit->getDataLayout().getGlobalPrefix()); + if (!generator) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to create a process symbol generator, error: " << generator.takeError() << "\n"; + return -1; + } + + jit->getMainJITDylib().addGenerator(std::move(*generator)); + +#ifdef _WIN32 + // Bind CRT entry points to tslang.exe's static CRT (/MT[d]) explicitly: the + // process generator above resolves from DLL export tables only, so without + // these definitions the JIT'd code would bind to ucrtbase.dll — a different + // CRT instance with its own stdout buffers and heap. JITDylib definitions + // take precedence over generators, making the binding deterministic. + { + llvm::orc::MangleAndInterner interner(jit->getExecutionSession(), jit->getDataLayout()); + llvm::orc::SymbolMap crtOverrides; + auto addOverride = [&](const char *name, void *addr) { + crtOverrides[interner(name)] = {llvm::orc::ExecutorAddr::fromPtr(addr), llvm::JITSymbolFlags::Exported}; + }; + addOverride("puts", (void *)&puts); + addOverride("printf", (void *)&printf); + addOverride("malloc", (void *)&malloc); + addOverride("free", (void *)&free); + addOverride("realloc", (void *)&realloc); + addOverride("calloc", (void *)&calloc); + addOverride("memset", (void *)&memset); + addOverride("memcpy", (void *)&memcpy); +#ifdef _WIN64 + // C++ EH: same-CRT personality, and throws routed through the shim that + // fixes up the throw-site image base (see jitCxxThrowException above) + addOverride("__CxxFrameHandler3", (void *)&__CxxFrameHandler3); + addOverride("_CxxThrowException", (void *)&jitCxxThrowException); +#endif + if (auto err = jit->getMainJITDylib().define(llvm::orc::absoluteSymbols(std::move(crtOverrides)))) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to define CRT overrides, error: " << std::move(err) << "\n"; + return -1; + } + } +#endif + + if (auto err = jit->addIRModule(llvm::orc::ThreadSafeModule(std::move(llvmModule), std::move(llvmContext)))) + { + llvm::WithColor::error(llvm::errs(), "tslang") << "failed to add the module to the JIT engine, error: " << std::move(err) << "\n"; + return -1; + } + + // run platform initializers (llvm.global_ctors etc.) + if (auto err = jit->initialize(jit->getMainJITDylib())) { - if (auto gctorsResult = engine->invokePacked(MLIR_GCTORS)) + llvm::WithColor::error(llvm::errs(), "tslang") << "JIT initialization failed, error: " << std::move(err) << "\n"; + return -1; + } + + auto invoke = [&](llvm::StringRef name) { + auto sym = jit->lookup(name); + if (!sym) { - llvm::WithColor::error(llvm::errs(), "tslang") << "JIT calling global constructors failed, error: " << gctorsResult << "\n"; + llvm::WithColor::error(llvm::errs(), "tslang") << "JIT invocation failed, error: " << sym.takeError() << "\n"; return -1; } + + sym->toPtr()(); + return 0; + }; + + if (module.lookupSymbol(MLIR_GCTORS) && invoke(MLIR_GCTORS) != 0) + { + return -1; } - // Invoke the JIT-compiled function. - if (auto invocationResult = engine->invokePacked(mainFuncName)) + if (invoke(mainFuncName.getValue()) != 0) { - llvm::WithColor::error(llvm::errs(), "tslang") << "JIT invocation failed, error: " << invocationResult << "\n"; return -1; } From 85ee290054d94101bd44e72a1ddcc0b6df4dc4b5 Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Mon, 6 Jul 2026 00:53:23 +0100 Subject: [PATCH 6/6] Fix JIT crash in release builds by ensuring unconditional termination process --- tslang/tslang/jit.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tslang/tslang/jit.cpp b/tslang/tslang/jit.cpp index 9921a462..e4b38526 100644 --- a/tslang/tslang/jit.cpp +++ b/tslang/tslang/jit.cpp @@ -631,9 +631,12 @@ int runJit(int argc, char **argv, mlir::ModuleOp module, CompileOptions &compile } } } - + #endif + + // Must stay unconditional: without it release builds crash (0xC0000005) or + // deadlock in teardown after async tests — the AsyncRuntime static destructor + // waits on thread-pool workers during DLL_PROCESS_DETACH (see above). TerminateProcess(GetCurrentProcess(), 0); - #endif #endif return 0; }