mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-29 07:04:09 +08:00
Native executables used to terminate with a signal when recursion exhausted the stack. Functions that can take part in unbounded recursion now compare the stack pointer against a per-stack guard on entry and throw Node's `RangeError: Maximum call stack size exceeded` through the ordinary exception path, so catch handlers, finally blocks, worker error events and the uncaught-error exit code behave as they do under Node. - The checked set is every function on a cycle of the call graph, where operations that can reenter compiled code indirectly (indirect calls, callbacks, dynamic and library operations) reach closure targets and class members. Non-recursive functions, including leaf callbacks, stay check-free, and the may-throw analysis accounts for the new throw. - The runtime installs the guard per context (main thread from the stack rlimit, workers from their thread attributes) and per async fiber, with a reserve for the throw, unwinding and error reporting. Worker threads now get an explicit 8 MiB stack. - Scalar call results pass through the unwind path as its dummy value, so calls in tail position keep tail-call and recursion elimination.
36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads";
|
|
|
|
function deep(n: number): number {
|
|
return n === 0 ? 0 : deep(n - 1) + 1;
|
|
}
|
|
function endless(n: number): number {
|
|
return endless(n + 1) + 1;
|
|
}
|
|
|
|
if (isMainThread) {
|
|
for (const mode of ["caught", "uncaught"]) {
|
|
await new Promise<void>((resolve) => {
|
|
const worker = new Worker(new URL(import.meta.url), { workerData: mode });
|
|
worker.on("message", (text: string) => console.log(mode, "message", text));
|
|
worker.on("error", (error: Error) =>
|
|
console.log(mode, "error", error.name, error.message, error instanceof RangeError),
|
|
);
|
|
worker.on("exit", (code: number) => {
|
|
console.log(mode, "exit", code);
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
console.log("main", deep(3000));
|
|
} else if (workerData === "caught") {
|
|
try {
|
|
endless(0);
|
|
} catch (e) {
|
|
parentPort!.postMessage(`${e instanceof RangeError} ${(e as Error).message}`);
|
|
}
|
|
parentPort!.postMessage(`still running ${deep(3000)}`);
|
|
} else {
|
|
parentPort!.postMessage(`before ${deep(2000)}`);
|
|
endless(0);
|
|
}
|