mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +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.
47 lines
1.1 KiB
TypeScript
47 lines
1.1 KiB
TypeScript
// Unbounded recursion throws Node's catchable RangeError; the program keeps
|
|
// running afterwards and bounded recursion still works.
|
|
function depth(n: number): number {
|
|
return n === 0 ? 0 : 1 + depth(n - 1);
|
|
}
|
|
|
|
function endless(n: number): number {
|
|
return endless(n + 1) + 1;
|
|
}
|
|
|
|
function sumTo(n: number, acc: number[]): number {
|
|
acc.push(n);
|
|
return n === 0 ? 0 : n + sumTo(n - 1, acc);
|
|
}
|
|
|
|
console.log("before", depth(3000));
|
|
try {
|
|
console.log("unreachable", endless(0));
|
|
} catch (e) {
|
|
const error = e as Error;
|
|
console.log(e instanceof RangeError, e instanceof Error, error.name);
|
|
console.log(error.message);
|
|
console.log(String(error));
|
|
}
|
|
|
|
let attempts = 0;
|
|
for (let round = 0; round < 3; round++) {
|
|
try {
|
|
endless(round);
|
|
} catch (e) {
|
|
if (e instanceof RangeError) attempts++;
|
|
}
|
|
}
|
|
console.log("caught rounds", attempts);
|
|
|
|
const trail: number[] = [];
|
|
console.log("after", depth(4000), sumTo(2500, trail), trail.length);
|
|
|
|
function guarded(): string {
|
|
try {
|
|
return String(endless(1));
|
|
} catch (e) {
|
|
return (e as Error).name + " handled";
|
|
}
|
|
}
|
|
console.log(guarded());
|