mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-24 06:14:01 +08:00
The self-hosted compiler's compact IR is ~515-528M characters, a few million below V8's maximum string length (2^29 - 24). serializeModule joined it into one string, deserializeModule parsed one string, and the native bootstrap comparison read cli.ir.json and cli.ll as utf8 strings, so any compiler growth crashed --emit=ir and the bootstrap tests with "RangeError: Invalid string length". - serializeModuleParts returns the compact encoding as ordered parts (header, one part per function, remainder). serializeModule(mod, true) is their join, so the on-disk format is byte-identical. - deserializeModuleBytes splits a UTF-8 Buffer at the root object's "functions" array with a byte-level scanner and parses the header and each function separately. Malformed input falls back to the whole-document parse for its exact error. - The Node API writes --emit=ir, --emit-ir sidecars and --emit=llvm through writeTextParts (the former writeLlvmSource batching writer). - The native bootstrap harness decodes IR per function and compares LLVM as Buffers, removing ABI-check lines at the byte level. - The self-hosting serialization fixture gains a "bytes" mode so the scriptc-compiled serializer exercises both new entry points. Self-hosted compiler IR (514.6 MB, macOS arm64, Node 24.12): read old 5.85 s / 4.26 GB max RSS -> new 5.84 s / 1.36 GB write old 2.05-2.53 s / 4.48 GB -> new 2.30-2.37 s / 2.10 GB 2x module (1.03 GB): old serialize and read throw; new round-trips. The remaining per-string bound is the largest function (16.3M chars, ~33x headroom) and the header (2.3M chars).
38 lines
1.4 KiB
TypeScript
38 lines
1.4 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import {
|
|
deserializeModule,
|
|
deserializeModuleBytes,
|
|
serializeModule,
|
|
serializeModuleParts,
|
|
} from "../../../packages/compiler/src/ir/serialize.js";
|
|
import { validateModule } from "../../../packages/compiler/src/ir/validate.js";
|
|
|
|
try {
|
|
// "bytes" exercises the compiler-scale path: per-function decoding and
|
|
// compact parts, as the native compiler uses for its own IR.
|
|
const bytes = process.argv[3] === "bytes";
|
|
const mod = bytes
|
|
? deserializeModuleBytes(readFileSync(process.argv[2]!))
|
|
: deserializeModule(readFileSync(process.argv[2]!, "utf8"));
|
|
const errors = validateModule(mod);
|
|
if (errors.length > 0) {
|
|
console.log(JSON.stringify(errors));
|
|
process.exitCode = 1;
|
|
} else {
|
|
// Introduce a native NaN before serialization, independently of the
|
|
// input document's sentinel decoding.
|
|
if (process.argv[3] === "nan") {
|
|
const statement = mod.functions[0]!.body[0];
|
|
if (statement?.kind === "exprStmt" && statement.expr.kind === "numLit") statement.expr.value = NaN;
|
|
}
|
|
if (bytes) {
|
|
for (const part of serializeModuleParts(mod)) process.stdout.write(part);
|
|
process.stdout.write("\n");
|
|
} else console.log(serializeModule(mod, process.argv[3] === "compact"));
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof Error) console.log(error.name + ": " + error.message);
|
|
else console.log("unexpected thrown value");
|
|
process.exitCode = 1;
|
|
}
|