From f44aa1ae0fead88b84029660ff36ab46230fb18a Mon Sep 17 00:00:00 2001 From: cs01 Date: Sat, 7 Mar 2026 00:40:45 -0800 Subject: [PATCH 01/12] feat: gate gc_init and -lgc behind usesGC flag --- .../infrastructure/function-generator.ts | 5 +++- .../infrastructure/llvm-declarations.ts | 19 ++++++++------ src/codegen/llvm-generator.ts | 25 +++++++++++++++++++ src/codegen/stdlib/json.ts | 1 + src/compiler.ts | 2 +- src/native-compiler-lib.ts | 4 ++- 6 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/codegen/infrastructure/function-generator.ts b/src/codegen/infrastructure/function-generator.ts index 81a40b07..fa4e53e9 100644 --- a/src/codegen/infrastructure/function-generator.ts +++ b/src/codegen/infrastructure/function-generator.ts @@ -105,6 +105,7 @@ export interface FunctionGeneratorContext { getTargetOS(): string; setRawInterfaceType(name: string, type: string): void; getUsesMathRandom(): boolean; + getUsesGC(): boolean; } export class FunctionGenerator { @@ -1026,7 +1027,9 @@ export class FunctionGenerator { " {\n"; ir += "entry:\n"; - ir += " call void @GC_init()\n"; + if (this.ctx.getUsesGC()) { + ir += " call void @GC_init()\n"; + } if (this.ctx.getUsesMathRandom()) { ir += " %__seed_time = call i64 @time(i8* null)\n"; ir += " call void @srand48(i64 %__seed_time)\n"; diff --git a/src/codegen/infrastructure/llvm-declarations.ts b/src/codegen/infrastructure/llvm-declarations.ts index 3f05b279..7c2e779e 100644 --- a/src/codegen/infrastructure/llvm-declarations.ts +++ b/src/codegen/infrastructure/llvm-declarations.ts @@ -1,4 +1,5 @@ export interface DeclConfig { + gc?: boolean; curl?: boolean; crypto?: boolean; sqlite?: boolean; @@ -25,14 +26,16 @@ export function getLLVMDeclarations(config?: DeclConfig): string { ir += "declare i8* @calloc(i64, i64)\n"; ir += "declare void @free(i8*)\n"; - ir += "; Boehm GC - automatic garbage collection\n"; - ir += "declare void @GC_init()\n"; - ir += "declare noalias i8* @GC_malloc(i64)\n"; - ir += "declare noalias i8* @GC_malloc_atomic(i64)\n"; - ir += "declare noalias i8* @GC_malloc_uncollectable(i64)\n"; - ir += "declare i8* @GC_realloc(i8*, i64)\n"; - ir += "declare void @GC_disable()\n"; - ir += "declare void @GC_enable()\n"; + if (config?.gc) { + ir += "; Boehm GC - automatic garbage collection\n"; + ir += "declare void @GC_init()\n"; + ir += "declare noalias i8* @GC_malloc(i64)\n"; + ir += "declare noalias i8* @GC_malloc_atomic(i64)\n"; + ir += "declare noalias i8* @GC_malloc_uncollectable(i64)\n"; + ir += "declare i8* @GC_realloc(i8*, i64)\n"; + ir += "declare void @GC_disable()\n"; + ir += "declare void @GC_enable()\n"; + } ir += "declare i8* @strcpy(i8*, i8*)\n"; ir += "declare i8* @strncpy(i8*, i8*, i64)\n"; ir += "declare i8* @strcat(i8*, i8*)\n"; diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 276bfb0e..72a8ce67 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -1769,6 +1769,13 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { this.stringBuilderScap.clear(); } + emit(instruction: string): void { + if (!this.usesGC && instruction.includes("@GC_")) { + this.usesGC = 1; + } + super.emit(instruction); + } + getThisPointer(): string | null { return this.thisPointer; } @@ -2551,6 +2558,23 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { } } + if (!this.usesGC) { + for (let i = 0; i < irParts.length; i++) { + if (irParts[i].includes("@GC_")) { + this.usesGC = 1; + break; + } + } + } + if (!this.usesGC) { + for (let i = 0; i < this.globalStrings.length; i++) { + if (this.globalStrings[i].includes("@GC_")) { + this.usesGC = 1; + break; + } + } + } + const mainIr = this.generateMain(); const liftedFunctions = this.exprGen.arrowFunctionGen.getLiftedFunctions(); @@ -2765,6 +2789,7 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { finalParts.push( this.filterDuplicateDeclarations( getLLVMDeclarations({ + gc: this.usesGC !== 0, curl: this.usesCurl !== 0, crypto: this.usesCrypto !== 0, sqlite: this.usesSqlite !== 0, diff --git a/src/codegen/stdlib/json.ts b/src/codegen/stdlib/json.ts index d9ed2b92..1222ce6a 100644 --- a/src/codegen/stdlib/json.ts +++ b/src/codegen/stdlib/json.ts @@ -262,6 +262,7 @@ export class JsonGenerator { return; } + this.ctx.setUsesGC(true); const fieldCount = this.ctx.interfaceStructGenGetFieldCount(typeName); for (let fi = 0; fi < fieldCount; fi++) { diff --git a/src/compiler.ts b/src/compiler.ts index a54ea357..2e683ec0 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -345,7 +345,7 @@ export function compile( const treeSitterPath = sdk ? sdk.vendorPath : TREESITTER_LIB_PATH; const platformLibs = targetIsMac ? "" : " -lm -ldl -lrt -lpthread"; - let linkLibs = `-L${gcPath} -lgc` + platformLibs; + let linkLibs = generator.usesGC ? `-L${gcPath} -lgc` + platformLibs : platformLibs.trimStart(); if (generator.usesJson) { linkLibs += ` -L${yyjsonPath} -lyyjson`; } diff --git a/src/native-compiler-lib.ts b/src/native-compiler-lib.ts index d2a1ed2d..8b23c373 100644 --- a/src/native-compiler-lib.ts +++ b/src/native-compiler-lib.ts @@ -463,7 +463,9 @@ export function compileNative(inputFile: string, outputFile: string): void { : "./vendor/tree-sitter/libtree-sitter.a"; } } - let linkLibs = "-L" + effectiveGcPath + " -lgc" + platformLibs; + let linkLibs = generator.getUsesGC() + ? "-L" + effectiveGcPath + " -lgc" + platformLibs + : platformLibs.trimStart(); if (tsLibPath) { linkLibs = linkLibs + " " + tsLibPath; } From 34cc73e0172ed5471e5a7260efc6725b20a8a8fe Mon Sep 17 00:00:00 2001 From: cs01 Date: Sat, 7 Mar 2026 00:52:23 -0800 Subject: [PATCH 02/12] fix: implement missing setUsesOs on llvmgenerator and igeneratorcontext --- src/codegen/infrastructure/generator-context.ts | 2 ++ src/codegen/llvm-generator.ts | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/codegen/infrastructure/generator-context.ts b/src/codegen/infrastructure/generator-context.ts index 4c77ca34..9126a842 100644 --- a/src/codegen/infrastructure/generator-context.ts +++ b/src/codegen/infrastructure/generator-context.ts @@ -785,6 +785,7 @@ export interface IGeneratorContext { setUsesGC(value: boolean): void; getUsesMathRandom(): boolean; setUsesMathRandom(value: boolean): void; + setUsesOs(value: boolean): void; currentDeclaredInterfaceType: string | undefined; setCurrentDeclaredInterfaceType(type: string | undefined): void; @@ -1250,6 +1251,7 @@ export class MockGeneratorContext implements IGeneratorContext { return false; } setUsesMathRandom(_value: boolean): void {} + setUsesOs(_value: boolean): void {} setCurrentDeclaredInterfaceType(type: string | undefined): void { this.currentDeclaredInterfaceType = type; } diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 72a8ce67..8368116c 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -296,6 +296,7 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { public usesGC: number = 0; public usesMathRandom: number = 0; + public usesOs: number = 0; private dbgAlloc(): number { const id = this.dbgNextId; @@ -1101,6 +1102,12 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { public setUsesMathRandom(value: boolean): void { this.usesMathRandom = value ? 1 : 0; } + public setUsesOs(value: boolean): void { + this.usesOs = value ? 1 : 0; + } + public getUsesOs(): boolean { + return this.usesOs !== 0; + } public setCurrentDeclaredInterfaceType(type: string | undefined): void { this.currentDeclaredInterfaceType = type; } @@ -1498,6 +1505,7 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { this.usesAsyncFs = 0; this.usesGC = 0; this.usesMathRandom = 0; + this.usesOs = 0; this.ast = ast; From 9f6127ac1175a9a38898f83e3dca5ed8ce15fc56 Mon Sep 17 00:00:00 2001 From: cs01 Date: Sat, 7 Mar 2026 07:03:11 -0800 Subject: [PATCH 03/12] gate always-emitted helpers and c_bridges behind feature flags --- src/codegen/llvm-generator.ts | 62 +++++++++++++++++++++++++++++------ src/compiler.ts | 10 +++--- src/native-compiler-lib.ts | 17 ++++++---- 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 8368116c..6187d818 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -297,6 +297,12 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { public usesGC: number = 0; public usesMathRandom: number = 0; public usesOs: number = 0; + public usesDoubleToString: number = 0; + public usesPath: number = 0; + public usesFs: number = 0; + public usesBase64Bridge: number = 0; + public usesUrlBridge: number = 0; + public usesUriBridge: number = 0; private dbgAlloc(): number { const id = this.dbgNextId; @@ -1108,6 +1114,15 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { public getUsesOs(): boolean { return this.usesOs !== 0; } + public getUsesBase64Bridge(): boolean { + return this.usesBase64Bridge !== 0; + } + public getUsesUrlBridge(): boolean { + return this.usesUrlBridge !== 0; + } + public getUsesUriBridge(): boolean { + return this.usesUriBridge !== 0; + } public setCurrentDeclaredInterfaceType(type: string | undefined): void { this.currentDeclaredInterfaceType = type; } @@ -1506,6 +1521,12 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { this.usesGC = 0; this.usesMathRandom = 0; this.usesOs = 0; + this.usesDoubleToString = 0; + this.usesPath = 0; + this.usesFs = 0; + this.usesBase64Bridge = 0; + this.usesUrlBridge = 0; + this.usesUriBridge = 0; this.ast = ast; @@ -1781,6 +1802,24 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { if (!this.usesGC && instruction.includes("@GC_")) { this.usesGC = 1; } + if (!this.usesDoubleToString && instruction.includes("@__double_to_string(")) { + this.usesDoubleToString = 1; + } + if (!this.usesPath && instruction.includes("@__path_")) { + this.usesPath = 1; + } + if (!this.usesFs && instruction.includes("@__fs_")) { + this.usesFs = 1; + } + if (!this.usesBase64Bridge && (instruction.includes("@cs_btoa(") || instruction.includes("@cs_atob(") || instruction.includes("@cs_base64_decode("))) { + this.usesBase64Bridge = 1; + } + if (!this.usesUrlBridge && instruction.includes("@cs_url_")) { + this.usesUrlBridge = 1; + } + if (!this.usesUriBridge && (instruction.includes("@cs_encode_uri_component(") || instruction.includes("@cs_decode_uri_component("))) { + this.usesUriBridge = 1; + } super.emit(instruction); } @@ -2520,21 +2559,11 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { if (safeStr) { irParts.push(safeStr); } - const dblToStr = getDoubleToStringHelper(); - if (dblToStr) { - irParts.push(dblToStr); - } const strHash = getStringHashHelper(); if (strHash) { irParts.push(strHash); } - irParts.push(this.fsGen.generateReaddirSyncHelper()); - irParts.push(this.fsGen.generateStatSyncHelper()); - irParts.push(this.pathGen.generateNormalizeHelper()); - irParts.push(this.pathGen.generateRelativeHelper()); - irParts.push(this.pathGen.generateParseHelper()); - const globalVars = getGlobalVariables(); if (globalVars) { irParts.push(globalVars); @@ -2746,6 +2775,19 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { irParts.push(this.embedGen.generateLengthLookupFunction()); } + if (this.usesDoubleToString) { + irParts.push(getDoubleToStringHelper()); + } + if (this.usesFs) { + irParts.push(this.fsGen.generateReaddirSyncHelper()); + irParts.push(this.fsGen.generateStatSyncHelper()); + } + if (this.usesPath) { + irParts.push(this.pathGen.generateNormalizeHelper()); + irParts.push(this.pathGen.generateRelativeHelper()); + irParts.push(this.pathGen.generateParseHelper()); + } + const needsLibuv = this.usesTimers || this.usesPromises || diff --git a/src/compiler.ts b/src/compiler.ts index 2e683ec0..ff86dd2d 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -345,7 +345,9 @@ export function compile( const treeSitterPath = sdk ? sdk.vendorPath : TREESITTER_LIB_PATH; const platformLibs = targetIsMac ? "" : " -lm -ldl -lrt -lpthread"; - let linkLibs = generator.usesGC ? `-L${gcPath} -lgc` + platformLibs : platformLibs.trimStart(); + const needsGcLib = + generator.usesGC || generator.usesBase64Bridge || generator.usesUrlBridge || generator.usesUriBridge; + let linkLibs = needsGcLib ? `-L${gcPath} -lgc` + platformLibs : platformLibs.trimStart(); if (generator.usesJson) { linkLibs += ` -L${yyjsonPath} -lyyjson`; } @@ -404,9 +406,9 @@ export function compile( const cpBridgeObj = generator.usesChildProcess ? `${bridgePath}/child-process-bridge.o` : ""; const osBridgeObj = `${bridgePath}/os-bridge.o`; const timeBridgeObj = `${bridgePath}/time-bridge.o`; - const base64BridgeObj = `${bridgePath}/base64-bridge.o`; - const urlBridgeObj = `${bridgePath}/url-bridge.o`; - const uriBridgeObj = `${bridgePath}/uri-bridge.o`; + const base64BridgeObj = generator.usesBase64Bridge ? `${bridgePath}/base64-bridge.o` : ""; + const urlBridgeObj = generator.usesUrlBridge ? `${bridgePath}/url-bridge.o` : ""; + const uriBridgeObj = generator.usesUriBridge ? `${bridgePath}/uri-bridge.o` : ""; const dotenvBridgeObj = fs.existsSync(`${bridgePath}/dotenv-bridge.o`) ? `${bridgePath}/dotenv-bridge.o` : ""; diff --git a/src/native-compiler-lib.ts b/src/native-compiler-lib.ts index 8b23c373..24bc75a3 100644 --- a/src/native-compiler-lib.ts +++ b/src/native-compiler-lib.ts @@ -463,9 +463,12 @@ export function compileNative(inputFile: string, outputFile: string): void { : "./vendor/tree-sitter/libtree-sitter.a"; } } - let linkLibs = generator.getUsesGC() - ? "-L" + effectiveGcPath + " -lgc" + platformLibs - : platformLibs.trimStart(); + const needsGcLib = + generator.getUsesGC() || + generator.getUsesBase64Bridge() || + generator.getUsesUrlBridge() || + generator.getUsesUriBridge(); + let linkLibs = needsGcLib ? "-L" + effectiveGcPath + " -lgc" + platformLibs : platformLibs.trimStart(); if (tsLibPath) { linkLibs = linkLibs + " " + tsLibPath; } @@ -509,9 +512,11 @@ export function compileNative(inputFile: string, outputFile: string): void { : ""; const osBridgeObj = effectiveBridgePath + "/os-bridge.o"; const timeBridgeObj = effectiveBridgePath + "/time-bridge.o"; - const base64BridgeObj = effectiveBridgePath + "/base64-bridge.o"; - const urlBridgeObj = effectiveBridgePath + "/url-bridge.o"; - const uriBridgeObj = effectiveBridgePath + "/uri-bridge.o"; + const base64BridgeObj = generator.getUsesBase64Bridge() + ? effectiveBridgePath + "/base64-bridge.o" + : ""; + const urlBridgeObj = generator.getUsesUrlBridge() ? effectiveBridgePath + "/url-bridge.o" : ""; + const uriBridgeObj = generator.getUsesUriBridge() ? effectiveBridgePath + "/uri-bridge.o" : ""; const dotenvBridgePath = effectiveBridgePath + "/dotenv-bridge.o"; const dotenvBridgeObj = fs.existsSync(dotenvBridgePath) ? dotenvBridgePath : ""; const watchBridgeObj = effectiveBridgePath + "/watch-bridge.o"; From 044d20f286701765a0a750c06316951aaf4489a0 Mon Sep 17 00:00:00 2001 From: cs01 Date: Sat, 7 Mar 2026 07:22:09 -0800 Subject: [PATCH 04/12] add comprehensive post-scan fallback for native compiler vtable dispatch --- src/codegen/llvm-generator.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 6187d818..4c140873 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -2775,14 +2775,47 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { irParts.push(this.embedGen.generateLengthLookupFunction()); } + for (let psi = 0; psi < irParts.length; psi++) { + const part = irParts[psi]; + if (!this.usesGC && part.includes("@GC_")) { + this.usesGC = 1; + } + if (!this.usesDoubleToString && part.includes("@__double_to_string(")) { + this.usesDoubleToString = 1; + } + if (!this.usesPath && part.includes("@__path_")) { + this.usesPath = 1; + } + if (!this.usesFs && part.includes("@__fs_")) { + this.usesFs = 1; + } + if (!this.usesBase64Bridge && (part.includes("@cs_btoa(") || part.includes("@cs_atob(") || part.includes("@cs_base64_decode("))) { + this.usesBase64Bridge = 1; + } + if (!this.usesUrlBridge && part.includes("@cs_url_")) { + this.usesUrlBridge = 1; + } + if (!this.usesUriBridge && (part.includes("@cs_encode_uri_component(") || part.includes("@cs_decode_uri_component("))) { + this.usesUriBridge = 1; + } + } + for (let gsi = 0; gsi < this.globalStrings.length; gsi++) { + if (!this.usesGC && this.globalStrings[gsi].includes("@GC_")) { + this.usesGC = 1; + } + } + if (this.usesDoubleToString) { + this.usesGC = 1; irParts.push(getDoubleToStringHelper()); } if (this.usesFs) { + this.usesGC = 1; irParts.push(this.fsGen.generateReaddirSyncHelper()); irParts.push(this.fsGen.generateStatSyncHelper()); } if (this.usesPath) { + this.usesGC = 1; irParts.push(this.pathGen.generateNormalizeHelper()); irParts.push(this.pathGen.generateRelativeHelper()); irParts.push(this.pathGen.generateParseHelper()); From 58582fe4f025ff25e7affdf38667c75545730b7b Mon Sep 17 00:00:00 2001 From: cs01 Date: Sat, 7 Mar 2026 07:28:01 -0800 Subject: [PATCH 05/12] fix prettier formatting --- src/codegen/llvm-generator.ts | 25 +++++++++++++++++++++---- src/compiler.ts | 5 ++++- src/native-compiler-lib.ts | 4 +++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 4c140873..69a0fdb0 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -1811,13 +1811,22 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { if (!this.usesFs && instruction.includes("@__fs_")) { this.usesFs = 1; } - if (!this.usesBase64Bridge && (instruction.includes("@cs_btoa(") || instruction.includes("@cs_atob(") || instruction.includes("@cs_base64_decode("))) { + if ( + !this.usesBase64Bridge && + (instruction.includes("@cs_btoa(") || + instruction.includes("@cs_atob(") || + instruction.includes("@cs_base64_decode(")) + ) { this.usesBase64Bridge = 1; } if (!this.usesUrlBridge && instruction.includes("@cs_url_")) { this.usesUrlBridge = 1; } - if (!this.usesUriBridge && (instruction.includes("@cs_encode_uri_component(") || instruction.includes("@cs_decode_uri_component("))) { + if ( + !this.usesUriBridge && + (instruction.includes("@cs_encode_uri_component(") || + instruction.includes("@cs_decode_uri_component(")) + ) { this.usesUriBridge = 1; } super.emit(instruction); @@ -2789,13 +2798,21 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { if (!this.usesFs && part.includes("@__fs_")) { this.usesFs = 1; } - if (!this.usesBase64Bridge && (part.includes("@cs_btoa(") || part.includes("@cs_atob(") || part.includes("@cs_base64_decode("))) { + if ( + !this.usesBase64Bridge && + (part.includes("@cs_btoa(") || + part.includes("@cs_atob(") || + part.includes("@cs_base64_decode(")) + ) { this.usesBase64Bridge = 1; } if (!this.usesUrlBridge && part.includes("@cs_url_")) { this.usesUrlBridge = 1; } - if (!this.usesUriBridge && (part.includes("@cs_encode_uri_component(") || part.includes("@cs_decode_uri_component("))) { + if ( + !this.usesUriBridge && + (part.includes("@cs_encode_uri_component(") || part.includes("@cs_decode_uri_component(")) + ) { this.usesUriBridge = 1; } } diff --git a/src/compiler.ts b/src/compiler.ts index ff86dd2d..3e2f41b9 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -346,7 +346,10 @@ export function compile( const platformLibs = targetIsMac ? "" : " -lm -ldl -lrt -lpthread"; const needsGcLib = - generator.usesGC || generator.usesBase64Bridge || generator.usesUrlBridge || generator.usesUriBridge; + generator.usesGC || + generator.usesBase64Bridge || + generator.usesUrlBridge || + generator.usesUriBridge; let linkLibs = needsGcLib ? `-L${gcPath} -lgc` + platformLibs : platformLibs.trimStart(); if (generator.usesJson) { linkLibs += ` -L${yyjsonPath} -lyyjson`; diff --git a/src/native-compiler-lib.ts b/src/native-compiler-lib.ts index 24bc75a3..d3245804 100644 --- a/src/native-compiler-lib.ts +++ b/src/native-compiler-lib.ts @@ -468,7 +468,9 @@ export function compileNative(inputFile: string, outputFile: string): void { generator.getUsesBase64Bridge() || generator.getUsesUrlBridge() || generator.getUsesUriBridge(); - let linkLibs = needsGcLib ? "-L" + effectiveGcPath + " -lgc" + platformLibs : platformLibs.trimStart(); + let linkLibs = needsGcLib + ? "-L" + effectiveGcPath + " -lgc" + platformLibs + : platformLibs.trimStart(); if (tsLibPath) { linkLibs = linkLibs + " " + tsLibPath; } From f500a328e926099fb841df5c886ff5715e0ec9a8 Mon Sep 17 00:00:00 2001 From: cs01 Date: Sat, 7 Mar 2026 18:05:28 -0800 Subject: [PATCH 06/12] fix: set usesGC when string builder or curl runtime uses gc internally --- src/codegen/llvm-generator.ts | 4 ++++ src/compiler.ts | 3 ++- src/native-compiler-lib.ts | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 69a0fdb0..c9b775a0 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -2886,6 +2886,10 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { finalParts.push("\n"); } + if (this.usesStringBuilder || this.usesCurl) { + this.usesGC = 1; + } + finalParts.push( this.filterDuplicateDeclarations( getLLVMDeclarations({ diff --git a/src/compiler.ts b/src/compiler.ts index 3e2f41b9..b2f93960 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -349,7 +349,8 @@ export function compile( generator.usesGC || generator.usesBase64Bridge || generator.usesUrlBridge || - generator.usesUriBridge; + generator.usesUriBridge || + generator.usesStringBuilder; let linkLibs = needsGcLib ? `-L${gcPath} -lgc` + platformLibs : platformLibs.trimStart(); if (generator.usesJson) { linkLibs += ` -L${yyjsonPath} -lyyjson`; diff --git a/src/native-compiler-lib.ts b/src/native-compiler-lib.ts index d3245804..930e637a 100644 --- a/src/native-compiler-lib.ts +++ b/src/native-compiler-lib.ts @@ -467,7 +467,8 @@ export function compileNative(inputFile: string, outputFile: string): void { generator.getUsesGC() || generator.getUsesBase64Bridge() || generator.getUsesUrlBridge() || - generator.getUsesUriBridge(); + generator.getUsesUriBridge() || + generator.usesStringBuilder !== 0; let linkLibs = needsGcLib ? "-L" + effectiveGcPath + " -lgc" + platformLibs : platformLibs.trimStart(); From 094f213201eea90c85937ad3c5c65bc100a0a69a Mon Sep 17 00:00:00 2001 From: cs01 Date: Sat, 7 Mar 2026 22:53:34 -0800 Subject: [PATCH 07/12] fix: regex gc linkage, url search params bridge, path parse type ordering --- src/codegen/llvm-generator.ts | 11 +++++++++-- src/codegen/stdlib/path.ts | 2 +- src/compiler.ts | 1 + src/native-compiler-lib.ts | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index c9b775a0..1f0306ac 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -1819,7 +1819,10 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { ) { this.usesBase64Bridge = 1; } - if (!this.usesUrlBridge && instruction.includes("@cs_url_")) { + if ( + !this.usesUrlBridge && + (instruction.includes("@cs_url_") || instruction.includes("@cs_urlsearch_")) + ) { this.usesUrlBridge = 1; } if ( @@ -2806,7 +2809,7 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { ) { this.usesBase64Bridge = 1; } - if (!this.usesUrlBridge && part.includes("@cs_url_")) { + if (!this.usesUrlBridge && (part.includes("@cs_url_") || part.includes("@cs_urlsearch_"))) { this.usesUrlBridge = 1; } if ( @@ -2856,6 +2859,10 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { finalParts.push("\n"); } + if (this.usesPath) { + finalParts.push("%PathParseResult = type { i8*, i8*, i8*, i8*, i8* }\n\n"); + } + finalParts.push("; Tree-sitter type definitions\n"); finalParts.push("%TSParser = type opaque\n"); finalParts.push("%TSTree = type opaque\n"); diff --git a/src/codegen/stdlib/path.ts b/src/codegen/stdlib/path.ts index 7042fcc3..b28459b5 100644 --- a/src/codegen/stdlib/path.ts +++ b/src/codegen/stdlib/path.ts @@ -671,9 +671,9 @@ export class PathGenerator { } // %PathParseResult = { root, dir, base, name, ext } — all i8* + // Type definition emitted separately in llvm-generator.ts finalParts so it precedes all GEPs generateParseHelper(): string { let ir = ""; - ir += "%PathParseResult = type { i8*, i8*, i8*, i8*, i8* }\n\n"; ir += "define i8* @__path_parse(i8* %path) {\n"; ir += "entry:\n"; ir += " %len = call i64 @strlen(i8* %path)\n"; diff --git a/src/compiler.ts b/src/compiler.ts index b2f93960..016304c5 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -347,6 +347,7 @@ export function compile( const platformLibs = targetIsMac ? "" : " -lm -ldl -lrt -lpthread"; const needsGcLib = generator.usesGC || + generator.usesRegex || generator.usesBase64Bridge || generator.usesUrlBridge || generator.usesUriBridge || diff --git a/src/native-compiler-lib.ts b/src/native-compiler-lib.ts index 930e637a..9996d9d1 100644 --- a/src/native-compiler-lib.ts +++ b/src/native-compiler-lib.ts @@ -465,6 +465,7 @@ export function compileNative(inputFile: string, outputFile: string): void { } const needsGcLib = generator.getUsesGC() || + generator.getUsesRegex() || generator.getUsesBase64Bridge() || generator.getUsesUrlBridge() || generator.getUsesUriBridge() || From 5a8724b571b57a1cd3afc7bed171b147b7788c64 Mon Sep 17 00:00:00 2001 From: cs01 Date: Sat, 7 Mar 2026 23:27:29 -0800 Subject: [PATCH 08/12] fix: emit pathparseresult type unconditionally to prevent stage 2 type errors --- src/codegen/llvm-generator.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 1f0306ac..a86d59f8 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -2859,9 +2859,7 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { finalParts.push("\n"); } - if (this.usesPath) { - finalParts.push("%PathParseResult = type { i8*, i8*, i8*, i8*, i8* }\n\n"); - } + finalParts.push("%PathParseResult = type { i8*, i8*, i8*, i8*, i8* }\n\n"); finalParts.push("; Tree-sitter type definitions\n"); finalParts.push("%TSParser = type opaque\n"); From 4db33928a95d5591c57d41e04dcf5c0d5ebd9e32 Mon Sep 17 00:00:00 2001 From: cs01 Date: Sun, 8 Mar 2026 00:13:47 -0800 Subject: [PATCH 09/12] fix: remove duplicate setusesos methods introduced by independent additions to main and gate-gc --- src/codegen/infrastructure/generator-context.ts | 2 -- src/codegen/llvm-generator.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/src/codegen/infrastructure/generator-context.ts b/src/codegen/infrastructure/generator-context.ts index 9126a842..4c77ca34 100644 --- a/src/codegen/infrastructure/generator-context.ts +++ b/src/codegen/infrastructure/generator-context.ts @@ -785,7 +785,6 @@ export interface IGeneratorContext { setUsesGC(value: boolean): void; getUsesMathRandom(): boolean; setUsesMathRandom(value: boolean): void; - setUsesOs(value: boolean): void; currentDeclaredInterfaceType: string | undefined; setCurrentDeclaredInterfaceType(type: string | undefined): void; @@ -1251,7 +1250,6 @@ export class MockGeneratorContext implements IGeneratorContext { return false; } setUsesMathRandom(_value: boolean): void {} - setUsesOs(_value: boolean): void {} setCurrentDeclaredInterfaceType(type: string | undefined): void { this.currentDeclaredInterfaceType = type; } diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index a86d59f8..7bba0ffd 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -1017,7 +1017,6 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { public setUsesCurl(value: boolean): void { this.usesCurl = value ? 1 : 0; } - public setUsesOs(_value: boolean): void {} public getUsesCurl(): boolean { return this.usesCurl !== 0; } From 7f5db515880e0b2bb1de4dace54125b453071a57 Mon Sep 17 00:00:00 2001 From: cs01 Date: Sun, 8 Mar 2026 10:49:16 -0700 Subject: [PATCH 10/12] fix: avoid let x = -1 pattern in transformregexnode to prevent stage 2 type error --- src/parser-native/transformer.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/parser-native/transformer.ts b/src/parser-native/transformer.ts index 93e72a0e..e661fc15 100644 --- a/src/parser-native/transformer.ts +++ b/src/parser-native/transformer.ts @@ -1392,15 +1392,9 @@ function transformAwaitExpression(node: TreeSitterNode): Expression { function transformRegexNode(node: TreeSitterNode): RegexNode { const text = (node as NodeBase).text; - let lastSlash = -1; - for (let i = text.length - 1; i >= 0; i--) { - if (text.charAt(i) === "/") { - lastSlash = i; - break; - } - } - const pattern = text.slice(1, lastSlash); - const flags = text.slice(lastSlash + 1); + const lastSlash = text.lastIndexOf("/"); + const pattern = text.substring(1, lastSlash); + const flags = text.substring(lastSlash + 1, text.length); return { type: "regex", pattern, flags }; } @@ -2645,7 +2639,7 @@ function transformClassDeclaration(node: TreeSitterNode): ClassNode | null { const params = method.params; for (let pi = 0; pi < method.parameterProperties.length; pi++) { const propName = method.parameterProperties[pi]; - let propIdx = -1; + let propIdx: number = -1; for (let k = 0; k < params.length; k++) { if (params[k] === propName) { propIdx = k; From 962a7ec6243d4757ec18e3ce0562953bde758bdf Mon Sep 17 00:00:00 2001 From: cs01 Date: Sun, 8 Mar 2026 11:39:06 -0700 Subject: [PATCH 11/12] fix: replace slice(0, -1) with indexOf-based slice for native compiler compat --- src/codegen/llvm-generator.ts | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 7bba0ffd..3ed1172c 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -331,18 +331,20 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { } private dbgInit(sourceFilePath: string): void { - let lastSlash = -1; - for (let i = 0; i < sourceFilePath.length; i++) { - if (sourceFilePath.charAt(i) === "/") { - lastSlash = i; + let lastSlash: number = 0; + let foundSlash = false; + let pos: number = 0; + let ch = sourceFilePath.charAt(pos); + while (ch !== "") { + if (ch === "/") { + lastSlash = pos; + foundSlash = true; } + pos = pos + 1; + ch = sourceFilePath.charAt(pos); } - let filename = sourceFilePath; - let directory = "."; - if (lastSlash >= 0) { - filename = sourceFilePath.substring(lastSlash + 1); - directory = sourceFilePath.substring(0, lastSlash); - } + const filename = foundSlash ? sourceFilePath.slice(lastSlash + 1) : sourceFilePath; + const directory = foundSlash ? sourceFilePath.slice(0, lastSlash) : "."; this.dbgFileId = this.dbgAlloc(); this.dbgSetNode( @@ -698,7 +700,8 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { name: string, ): { keys: string[]; types: string[]; tsTypes: string[] } | null { if (!this.ast || !this.ast.interfaces) return null; - const baseName = name.endsWith("?") ? name.slice(0, -1) : name; + const qIdx = name.indexOf("?"); + const baseName = qIdx >= 0 ? name.slice(0, qIdx) : name; const cleanName = baseName.indexOf(" | ") !== -1 ? baseName.split(" | ")[0] : baseName; const keys: string[] = []; const types: string[] = []; @@ -713,7 +716,7 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { if (!field) continue; let fieldName = field.name; if (fieldName.endsWith("?")) { - fieldName = fieldName.slice(0, -1); + fieldName = fieldName.slice(0, fieldName.indexOf("?")); } keys.push(fieldName); // field.type is a TS type (e.g. "string", "number") — convert to LLVM for types[] @@ -818,7 +821,7 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { if (!f) continue; let fName = f.name; if (fName.endsWith("?")) { - fName = fName.slice(0, -1); + fName = fName.slice(0, fName.indexOf("?")); } if (fName === fieldName) { return f.type; From 013071bb7680090795d7a76b825d8f39358605ef Mon Sep 17 00:00:00 2001 From: cs01 Date: Sun, 8 Mar 2026 11:46:18 -0700 Subject: [PATCH 12/12] fix: annotate semaIdx as number to avoid native compiler -1 mistype bug --- src/codegen/llvm-generator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 3ed1172c..70a5a9d6 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -1693,7 +1693,7 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { ) continue; - let semaIdx = -1; + let semaIdx: number = -1; for (let si = 0; si < this.semaSymbolCount; si++) { if (this.semaSymbolNames[si] === name) { semaIdx = si;