mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
Appending a ScrDynHandleTag used to grow the always-linked scr_dynh_ops table, which shifted .bss and code addresses in every program, including programs that never box the new handle (Blob and File paid this when they were added). The table is now sized by SCR_DYNH_CAPACITY (128; 52 tags are in use), so a link-gated unit can add a tag without changing any other program's executable. This change is the one layout shift that makes later tags free. Structured clone between threads (postMessage, workerData) rejected every handle other than MessagePorts and buffers. A handle's ops can now carry a ScrDynHandleTransfer (share on the sender, adopt on the receiver, drop with the message), which scr_message.c uses for any tag, so a gated unit such as a future WebAssembly.Module needs no reference from the message encoder and no per-tag registry. No handle declares the hooks yet; scr_message.test.c exercises them across threads through a test handle in the last capacity slot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
1.6 KiB
TypeScript
46 lines
1.6 KiB
TypeScript
import { execFile } from "node:child_process";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { expect, test } from "vitest";
|
|
import { EXECUTABLE_RUNTIME_SOURCES } from "../../compiler/src/backend/native-toolchain.js";
|
|
|
|
const exec = promisify(execFile);
|
|
|
|
test.skipIf(process.platform === "win32")(
|
|
"message data outlives its sender and decodes into a separate runtime heap",
|
|
async () => {
|
|
const dir = await mkdtemp(join(tmpdir(), "scriptc-message-"));
|
|
try {
|
|
const bin = join(dir, "messages");
|
|
await exec("clang", [
|
|
"-std=c11",
|
|
"-O1",
|
|
"-pthread",
|
|
"-DSCR_WORKERS",
|
|
"-DSCR_RC_AUDIT",
|
|
"-fsanitize=address,undefined",
|
|
"-Wno-deprecated-declarations",
|
|
...(process.platform === "linux" ? ["-D_GNU_SOURCE"] : []),
|
|
join(import.meta.dirname, "scr_message.test.c"),
|
|
join(import.meta.dirname, "scr_message.c"),
|
|
...EXECUTABLE_RUNTIME_SOURCES.map((name) => join(import.meta.dirname, name)),
|
|
...(process.platform === "linux" ? ["-lm"] : []),
|
|
"-o",
|
|
bin,
|
|
]);
|
|
const result = await exec(bin, [], {
|
|
env: { ...process.env, UBSAN_OPTIONS: "halt_on_error=1" },
|
|
});
|
|
expect(result.stdout).toBe(
|
|
"message graphs preserve identity, sparse values, byte aliases and getter order\n" +
|
|
"native handles cross threads through their transfer hooks\n",
|
|
);
|
|
expect(result.stderr).toBe("");
|
|
} finally {
|
|
await rm(dir, { recursive: true, force: true });
|
|
}
|
|
},
|
|
);
|