Files
scriptc/packages/compiler/src/executable/executable-cache.test.ts
T
Chris Tate 140990d257 Add --large-pages: move executable code onto transparent huge pages
A large program's hot code spans hundreds of 4 KiB pages, more than the
instruction TLB holds. tsc-ts has 12 MB of code, and 90% of its
main-thread samples at --checkers 1 fall in 274 distinct code pages.

`scriptc build --large-pages` links the new runtime unit
scr_text_pages.c, whose constructor moves the executable's code onto
2 MiB transparent huge pages before main. It copies the executable
segment, from its first to its last 2 MiB boundary, into anonymous memory
advised MADV_HUGEPAGE, makes the copy read-only and executable, and moves
it over the original range with one mremap, so addresses and instructions
stay the same. The move runs only on Linux, only when THP is "always" or
"madvise", and only in executables. If a step fails, the code stays
file-mapped. Like Node's --use-largepages, it is off by default: without
the flag the unit is not linked, and executables are unchanged.

The move costs about 3 ms per 10 MiB of code at startup, and all of the
moved code stays resident as private memory. The flag is part of the
executable cache key and the runtime-pack selection, and is refused for
non-executable output, like --detached-exit.
2026-10-26 23:41:46 -05:00

653 lines
23 KiB
TypeScript

import { chmod, mkdtemp, readFile, readdir, rm, stat, utimes, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, expect, test, vi } from "vitest";
import {
FrontendInputTracker,
trackedFileExists,
trackedReadFile,
} from "../frontend/input-tracker.js";
import {
nativeArtifactDependenciesStillMatch,
snapshotNativeArtifactDependencies,
} from "../backend/native-toolchain.js";
import { installDarwinDebugSymbols, readDarwinDebugSymbols } from "../backend/debug-symbols.js";
import {
hasEarlyExecutableNativeBuild,
publishEarlyExecutableCache,
readEarlyExecutableCache,
readRoutedExecutableCache,
recordEarlyExecutableNativeBuild,
type EarlyExecutableCacheOptions,
type EarlyExecutableNativeFeatures,
} from "./executable-cache.js";
const scratch: string[] = [];
afterEach(async () => {
await Promise.all(scratch.splice(0).map((path) => rm(path, { recursive: true, force: true })));
});
const native: EarlyExecutableNativeFeatures = {
backend: "llvm",
regex: false,
copying: false,
textDecoderLegacy: false,
fileHandle: false,
fetch: true,
zlib: false,
assert: false,
inspect: false,
dynInvoke: false,
dc: false,
dynAsync: false,
events: false,
emitter: false,
symbol: false,
bigint: false,
searchParams: false,
qs: false,
utilPromisify: false,
dynBuiltinClass: false,
dynBuiltinStream: false,
parseArgs: false,
stream: false,
net: false,
http: false,
http2: false,
dgram: false,
dnsPromises: false,
dgramDyn: false,
textCodecDyn: false,
watch: false,
foreignFfi: false,
nodeTest: false,
tls: false,
tlsCa: false,
cipher: false,
ecdh: false,
dh: false,
pki: false,
ed25519: false,
x509: false,
webcrypto: false,
perfLoop: false,
};
async function fixture(): Promise<{
root: string;
options: EarlyExecutableCacheOptions;
source: string;
missing: string;
llvmPath: string;
irPath: string;
}> {
const dir = await mkdtemp(join(tmpdir(), "scriptc-early-executable-"));
scratch.push(dir);
const source = join(dir, "entry.ts");
const llvmPath = join(dir, "entry.ll");
const irPath = join(dir, "entry.ir.json");
await Promise.all([
writeFile(source, 'console.log("hello");\n'),
writeFile(llvmPath, "; generated llvm\n"),
writeFile(irPath, '{"irVersion":6}\n'),
]);
return {
root: join(dir, "cache"),
source,
missing: join(dir, "missing.ts"),
llvmPath,
irPath,
options: {
entryPath: source,
outDir: dir,
outPath: join(dir, "entry"),
emitIr: true,
sanitize: false,
backend: "llvm",
npmStatic: null,
ffiProfile: null,
target: "test",
compiler: ["clang"],
nativeEnvironment: "test-native-environment",
nodeVersion: "v24-test",
implementation: "a".repeat(64),
implementationDependencies: [],
},
};
}
test("early executable cache restores the emitted TU, IR, and native feature gates", async () => {
const f = await fixture();
const tracker = new FrontendInputTracker();
tracker.run(() => {
trackedReadFile(f.source);
trackedFileExists(f.missing);
});
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: false,
frontend: tracker.snapshot(),
});
await Promise.all([rm(f.llvmPath), rm(f.irPath)]);
const alternateC = join(f.options.outDir, "entry.c");
await writeFile(alternateC, "/* user-owned native source */\n");
const hit = await readEarlyExecutableCache(f.root, f.options);
expect(hit?.native).toEqual(native);
expect(hit?.executableRestored).toBe(false);
// The build compiles private copies beside the shared names and installs
// them there when it is done.
expect(hit?.llvmPath).toBe(f.llvmPath);
expect(hit?.irPath).toBe(f.irPath);
expect(hit?.llvmSourcePath).toMatch(/[/\\]\.scriptc-llvm-[^/\\]*\.ll$/);
expect(hit?.irSourcePath).toMatch(/[/\\]\.scriptc-ir-/);
expect(await readFile(hit!.llvmSourcePath!, "utf8")).toBe("; generated llvm\n");
expect(await readFile(hit!.irSourcePath!, "utf8")).toContain("irVersion");
await expect(stat(f.llvmPath)).rejects.toThrow();
expect(await readFile(alternateC, "utf8")).toBe("/* user-owned native source */\n");
});
test("early dev cache restores the matching dSYM and rejects a missing payload", async () => {
const f = await fixture();
f.options.optimization = "dev";
f.options.target = "native:darwin:arm64:runtime-pack";
const tracker = new FrontendInputTracker();
tracker.run(() => trackedReadFile(f.source));
await writeFile(f.options.outPath, "native binary");
const symbols = Buffer.concat([
Buffer.from("SCDSYM01"),
Buffer.from([5, 0, 0, 0]),
Buffer.from("plistDWARF"),
]);
await installDarwinDebugSymbols(symbols, f.options.outPath);
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native: { ...native, optimization: "dev" },
executableRestored: true,
nativeDependencies: [],
frontend: tracker.snapshot(),
});
await rm(`${f.options.outPath}.dSYM`, { recursive: true });
expect((await readEarlyExecutableCache(f.root, f.options))?.executableRestored).toBe(true);
expect(await readDarwinDebugSymbols(f.options.outPath)).toEqual(symbols);
const files = await readdir(f.root, { recursive: true });
const cachedSymbols = files.find((file) => file.endsWith("program.dsym"));
expect(cachedSymbols).toBeDefined();
await rm(join(f.root, cachedSymbols!));
expect(await readEarlyExecutableCache(f.root, f.options)).toBeNull();
});
test("early executable cache preserves worker runtime selection when only frontend output restores", async () => {
const f = await fixture();
const tracker = new FrontendInputTracker();
tracker.run(() => trackedReadFile(f.source));
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native: { ...native, workers: true },
executableRestored: false,
frontend: tracker.snapshot(),
});
const restored = await readEarlyExecutableCache(f.root, f.options);
expect(restored?.native.workers).toBe(true);
expect(restored?.executableRestored).toBe(false);
});
test("early executable cache misses on source and resolution changes", async () => {
const f = await fixture();
const tracker = new FrontendInputTracker();
tracker.run(() => {
trackedReadFile(f.source);
trackedFileExists(f.missing);
});
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: false,
frontend: tracker.snapshot(),
});
await writeFile(f.source, 'console.log("edited");\n');
expect(await readEarlyExecutableCache(f.root, f.options)).toBeNull();
await writeFile(f.source, 'console.log("hello");\n');
expect(await readEarlyExecutableCache(f.root, f.options)).not.toBeNull();
await writeFile(f.missing, "export {};\n");
expect(await readEarlyExecutableCache(f.root, f.options)).toBeNull();
});
test("early executable keys isolate compile modes, paths, implementation, checker, function layouts, and FFI manifests", async () => {
const f = await fixture();
const tracker = new FrontendInputTracker();
tracker.run(() => trackedReadFile(f.source));
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: false,
frontend: tracker.snapshot(),
});
const variants: EarlyExecutableCacheOptions[] = [
{ ...f.options, emitIr: false },
{ ...f.options, sanitize: true },
{ ...f.options, optimization: "dev" },
{ ...f.options, optimization: "speed" },
{ ...f.options, detachedExit: true },
{ ...f.options, largePages: true },
{ ...f.options, targetCpu: "x86-64-v3" },
{ ...f.options, targetCpu: "x86-64-v4" },
{ ...f.options, cpuDispatch: true },
{ ...f.options, profile: "profile-generate:/tmp/%p.profraw" },
{ ...f.options, profile: "profile-use:digest" },
{ ...f.options, functionLayout: "layout-digest" },
{ ...f.options, checker: "tsc-ts-executable-identity" },
{ ...f.options, npmStatic: "auto" },
{ ...f.options, npmStatic: ["commander"] },
{ ...f.options, outPath: join(f.options.outDir, "other") },
{ ...f.options, target: "other" },
{ ...f.options, compiler: ["zig", "cc"] },
{ ...f.options, nativeEnvironment: "other-native-environment" },
{ ...f.options, nodeVersion: "v24-other" },
{ ...f.options, implementation: "other-implementation" },
{
...f.options,
ffiProfile: { path: join(f.options.outDir, "ffi.json"), bytes: Buffer.from("one") },
},
];
for (const options of variants) {
expect(await readEarlyExecutableCache(f.root, options)).toBeNull();
}
});
test("speed entries round-trip their posture and stay isolated from release and dev", async () => {
const f = await fixture();
const speedOptions: EarlyExecutableCacheOptions = { ...f.options, optimization: "speed" };
const tracker = new FrontendInputTracker();
tracker.run(() => trackedReadFile(f.source));
await publishEarlyExecutableCache(f.root, speedOptions, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native: { ...native, optimization: "speed" },
executableRestored: false,
frontend: tracker.snapshot(),
});
expect((await readEarlyExecutableCache(f.root, speedOptions))?.native).toEqual({
...native,
optimization: "speed",
});
expect(await readEarlyExecutableCache(f.root, f.options)).toBeNull();
expect(await readEarlyExecutableCache(f.root, { ...f.options, optimization: "dev" })).toBeNull();
});
test("early executable cache rejects corruption and refreshes payload LRU times", async () => {
const f = await fixture();
const tracker = new FrontendInputTracker();
tracker.run(() => trackedReadFile(f.source));
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: false,
frontend: tracker.snapshot(),
});
const [key] = await readdir(join(f.root, "early-exe"));
const directory = join(f.root, "early-exe", key!);
const paths = [
join(directory, "stamp.json"),
join(directory, "program.tu"),
join(directory, "program.ir.json"),
];
const old = new Date("2000-01-01T00:00:00.000Z");
await Promise.all(paths.map((path) => utimes(path, old, old)));
expect(await readEarlyExecutableCache(f.root, f.options)).not.toBeNull();
for (const path of paths) expect((await stat(path)).mtimeMs).toBeGreaterThan(old.getTime());
await writeFile(join(directory, "program.tu"), "; poisoned\n");
expect(await readEarlyExecutableCache(f.root, f.options)).toBeNull();
});
test("early executable cache restores a validated final binary", async () => {
const f = await fixture();
const dependency = join(f.options.outDir, "native-tool");
await writeFile(dependency, "tool-v1\n");
const info = await stat(dependency);
const outMode = 0o777 & ~process.umask();
await writeFile(f.options.outPath, "native-v1\n", { mode: outMode });
await chmod(f.options.outPath, outMode);
const tracker = new FrontendInputTracker();
tracker.run(() => trackedReadFile(f.source));
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: true,
nativeDependencies: [
{
path: dependency,
kind: "file",
dev: info.dev,
ino: info.ino,
size: info.size,
mtimeMs: info.mtimeMs,
ctimeMs: info.ctimeMs,
},
],
frontend: tracker.snapshot(),
});
await writeFile(f.options.outPath, "caller-modified\n");
const hit = await readEarlyExecutableCache(f.root, f.options);
expect(hit?.executableRestored).toBe(true);
expect(await readFile(f.options.outPath, "utf8")).toBe("native-v1\n");
await writeFile(dependency, "tool-v2\n");
await writeFile(f.options.outPath, "keep-current\n");
const staleNative = await readEarlyExecutableCache(f.root, f.options);
expect(staleNative?.executableRestored).toBe(false);
expect(await readFile(f.options.outPath, "utf8")).toBe("keep-current\n");
});
test("routed executable hits require an unchanged compiler implementation proof", async () => {
const f = await fixture();
const dependency = join(f.options.outDir, "compiler-file.js");
const nativeDependency = join(f.options.outDir, "native-tool");
await Promise.all([
writeFile(dependency, "compiler-v1\n"),
writeFile(nativeDependency, "tool-v1\n"),
writeFile(f.options.outPath, "native-v1\n"),
]);
const [implementationInfo, nativeInfo] = await Promise.all([
stat(dependency),
stat(nativeDependency),
]);
f.options.implementationDependencies = [
{
path: dependency,
kind: "file",
dev: implementationInfo.dev,
ino: implementationInfo.ino,
size: implementationInfo.size,
mtimeMs: implementationInfo.mtimeMs,
ctimeMs: implementationInfo.ctimeMs,
},
];
const tracker = new FrontendInputTracker();
tracker.run(() => trackedReadFile(f.source));
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: true,
nativeDependencies: [
{
path: nativeDependency,
kind: "file",
dev: nativeInfo.dev,
ino: nativeInfo.ino,
size: nativeInfo.size,
mtimeMs: nativeInfo.mtimeMs,
ctimeMs: nativeInfo.ctimeMs,
},
],
frontend: tracker.snapshot(),
});
const route = { ...f.options };
delete (route as Partial<EarlyExecutableCacheOptions>).implementation;
delete (route as Partial<EarlyExecutableCacheOptions>).implementationDependencies;
const routeDirectory = join(f.root, "early-exe-route");
const [routeName] = await readdir(routeDirectory);
const routePath = join(routeDirectory, routeName!);
const proofInstallDirectory = join(f.root, "early-exe-implementation");
const [proofInstall] = await readdir(proofInstallDirectory);
const proofPath = join(proofInstallDirectory, proofInstall!, f.options.implementation);
const old = new Date("2000-01-01T00:00:00.000Z");
await Promise.all([routePath, proofPath].map((path) => utimes(path, old, old)));
expect(await readRoutedExecutableCache(f.root, route)).not.toBeNull();
for (const path of [routePath, proofPath]) {
expect((await stat(path)).mtimeMs).toBeGreaterThan(old.getTime());
}
// Publishing the same route again must replace its metadata on every
// platform (notably Windows, whose rename does not overwrite files).
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: true,
nativeDependencies: [
{
path: nativeDependency,
kind: "file",
dev: nativeInfo.dev,
ino: nativeInfo.ino,
size: nativeInfo.size,
mtimeMs: nativeInfo.mtimeMs,
ctimeMs: nativeInfo.ctimeMs,
},
],
frontend: tracker.snapshot(),
});
expect(await readRoutedExecutableCache(f.root, route)).not.toBeNull();
await writeFile(dependency, "compiler-v2\n");
expect(await readRoutedExecutableCache(f.root, route)).toBeNull();
});
test("native dependency validation rejects malformed cache data", async () => {
expect(
await nativeArtifactDependenciesStillMatch([
{ path: "/tmp/not-enough-fields", kind: "file" },
] as never),
).toBe(false);
});
async function routedFixture(executableRestored = true) {
const f = await fixture();
const implementation = join(f.options.outDir, "compiler-file.js");
const nativeDependency = join(f.options.outDir, "native-tool");
const declarations = join(f.options.outDir, "dependency.d.ts");
await Promise.all([
writeFile(implementation, "compiler-v1\n"),
writeFile(nativeDependency, "native-v1\n"),
writeFile(declarations, "export const value: number;\n"),
writeFile(f.options.outPath, "cached executable\n"),
]);
const info = await stat(implementation);
f.options.implementationDependencies = [
{
path: implementation,
kind: "file",
dev: info.dev,
ino: info.ino,
size: info.size,
mtimeMs: info.mtimeMs,
ctimeMs: info.ctimeMs,
},
];
const tracker = new FrontendInputTracker();
tracker.run(() => {
trackedReadFile(f.source);
trackedReadFile(declarations);
trackedFileExists(f.missing);
});
await publishEarlyExecutableCache(f.root, f.options, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored,
...(executableRestored
? { nativeDependencies: await snapshotNativeArtifactDependencies([nativeDependency]) }
: {}),
frontend: tracker.snapshot(),
});
await Promise.all([
writeFile(f.options.outPath, "current executable\n"),
writeFile(f.llvmPath, "; current LLVM\n"),
writeFile(f.irPath, "current IR\n"),
]);
return { ...f, implementation, nativeDependency, declarations };
}
test("missing and disabled routes skip deferred native driver discovery", async () => {
const f = await fixture();
const discover = vi.fn(async () => f.options.nativeEnvironment);
expect(
await readRoutedExecutableCache(null, { ...f.options, nativeEnvironment: discover }),
).toBeNull();
expect(
await readRoutedExecutableCache(f.root, { ...f.options, nativeEnvironment: discover }),
).toBeNull();
expect(discover).not.toHaveBeenCalled();
});
test.each(["source", "payload", "frontend-only"])(
"%s misses skip deferred driver discovery and preserve caller outputs",
async (miss) => {
const f = await routedFixture(miss !== "frontend-only");
if (miss === "source") await writeFile(f.source, 'console.log("edited");\n');
if (miss === "payload") {
const [key] = await readdir(join(f.root, "early-exe"));
await writeFile(join(f.root, "early-exe", key!, "program.bin"), "corrupt executable\n");
}
const discover = vi.fn(async () => f.options.nativeEnvironment);
expect(
await readRoutedExecutableCache(f.root, { ...f.options, nativeEnvironment: discover }),
).toBeNull();
expect(discover).not.toHaveBeenCalled();
expect(await readFile(f.options.outPath, "utf8")).toBe("current executable\n");
expect(await readFile(f.llvmPath, "utf8")).toBe("; current LLVM\n");
expect(await readFile(f.irPath, "utf8")).toBe("current IR\n");
},
);
test("a deferred driver fingerprint is checked once before restoring a routed hit", async () => {
const f = await routedFixture();
const discover = vi.fn(async () => f.options.nativeEnvironment);
expect(
(await readRoutedExecutableCache(f.root, { ...f.options, nativeEnvironment: discover }))
?.executableRestored,
).toBe(true);
expect(discover).toHaveBeenCalledTimes(1);
expect(await readFile(f.options.outPath, "utf8")).toBe("cached executable\n");
expect(await readFile(f.llvmPath, "utf8")).toBe("; generated llvm\n");
expect(await readFile(f.irPath, "utf8")).toContain("irVersion");
});
test.each(["environment", "failure", "source", "declarations", "implementation", "native"])(
"%s changes during deferred discovery refuse restoration",
async (change) => {
const f = await routedFixture();
const discover = vi.fn(async () => {
if (change === "failure") throw new Error("driver discovery failed");
if (change === "source") await writeFile(f.source, 'console.log("edited");\n');
if (change === "declarations")
await writeFile(f.declarations, "export const value: string;\n");
if (change === "implementation") await writeFile(f.implementation, "compiler-v2\n");
if (change === "native") await writeFile(f.nativeDependency, "native-v2\n");
return change === "environment" ? "another driver" : f.options.nativeEnvironment;
});
expect(
await readRoutedExecutableCache(f.root, { ...f.options, nativeEnvironment: discover }),
).toBeNull();
expect(discover).toHaveBeenCalledTimes(1);
expect(await readFile(f.options.outPath, "utf8")).toBe("current executable\n");
expect(await readFile(f.llvmPath, "utf8")).toBe("; current LLVM\n");
expect(await readFile(f.irPath, "utf8")).toBe("current IR\n");
},
);
test.each(["implementation", "native", "declarations", "resolution"])(
"a stale %s proof refuses a deferred routed hit",
async (change) => {
const f = await routedFixture();
const path = {
implementation: f.implementation,
native: f.nativeDependency,
declarations: f.declarations,
resolution: f.missing,
}[change]!;
await writeFile(path, "changed before discovery\n");
expect(
await readRoutedExecutableCache(f.root, {
...f.options,
nativeEnvironment: async () => f.options.nativeEnvironment,
}),
).toBeNull();
expect(await readFile(f.options.outPath, "utf8")).toBe("current executable\n");
expect(await readFile(f.llvmPath, "utf8")).toBe("; current LLVM\n");
expect(await readFile(f.irPath, "utf8")).toBe("current IR\n");
},
);
test("the route index still isolates eager and deferred native environments", async () => {
const f = await routedFixture();
expect(
await readRoutedExecutableCache(f.root, { ...f.options, nativeEnvironment: "another driver" }),
).toBeNull();
await publishEarlyExecutableCache(
f.root,
{ ...f.options, nativeEnvironment: "another driver" },
{
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: true,
nativeDependencies: await snapshotNativeArtifactDependencies([f.nativeDependency]),
frontend: (await readEarlyExecutableCache(f.root, f.options))!.frontend,
},
);
expect(await readRoutedExecutableCache(f.root, f.options)).toBeNull();
expect(
await readRoutedExecutableCache(f.root, {
...f.options,
nativeEnvironment: async () => f.options.nativeEnvironment,
}),
).toBeNull();
expect(
(
await readRoutedExecutableCache(f.root, {
...f.options,
nativeEnvironment: async () => "another driver",
})
)?.executableRestored,
).toBe(true);
});
test("a recorded native build is found by its invocation", async () => {
const f = await fixture();
expect(await hasEarlyExecutableNativeBuild(null, f.options)).toBe(false);
expect(await hasEarlyExecutableNativeBuild(f.root, f.options)).toBe(false);
await recordEarlyExecutableNativeBuild(null, f.options);
await recordEarlyExecutableNativeBuild(f.root, f.options);
expect(await hasEarlyExecutableNativeBuild(f.root, f.options)).toBe(true);
// The record does not depend on the compiler implementation or the native environment.
const rebuilt: EarlyExecutableCacheOptions = {
...f.options,
implementation: "b".repeat(64),
nativeEnvironment: "another driver",
};
expect(await hasEarlyExecutableNativeBuild(f.root, rebuilt)).toBe(true);
expect(
await hasEarlyExecutableNativeBuild(f.root, {
...f.options,
outPath: join(f.options.outDir, "other"),
}),
).toBe(false);
expect(await hasEarlyExecutableNativeBuild(f.root, { ...f.options, sanitize: true })).toBe(false);
// Publishing an executable does not record a native build.
const other = { ...f.options, outPath: join(f.options.outDir, "published") };
const tracker = new FrontendInputTracker();
tracker.run(() => trackedReadFile(f.source));
await publishEarlyExecutableCache(f.root, other, {
llvmPath: f.llvmPath,
irPath: f.irPath,
native,
executableRestored: false,
frontend: tracker.snapshot(),
});
expect(await hasEarlyExecutableNativeBuild(f.root, other)).toBe(false);
});