Skip to main content

STACK_SIZE

Constant STACK_SIZE 

Source
pub const STACK_SIZE: usize = _; // 110_985_216usize
Expand description

How much stack the runtime gives every thread it runs Cove on.

A tree-walking interpreter spends native stack per Cove frame, so MAX_CALL_DEPTH keeps its promise only on a stack big enough to hold that many frames. Nothing gave the runtime such a stack before: a spawned task took the platform default of 2 MiB, and the entry took whatever the process main thread happened to have, which is 8 MiB on macOS and Linux and 1 MiB on Windows. In a debug build 8 MiB held 65 frames of the cheapest recursion Cove can write, so the limit of 256 was reached only on a release build’s main thread, and everywhere else an ordinary program with no capability granted at all could end the process by recursing.

So the size is derived from the limits rather than chosen beside them. Raising MAX_CALL_DEPTH raises this, which is the relationship the limit’s promise rests on, and it is now arithmetic rather than a coincidence that held on one thread of one profile. It works out at about 106 MiB in a debug build and about 8 MiB in a release one.

A number that large in a debug build is affordable because a thread stack is reserved address space that commits a page at a time as it is touched. That was checked rather than assumed: a debug run holding a hundred tasks alive at once reached a maximum resident set of 14.9 to 15.1 MB under this size and 15.07 MB under the old platform default of 2 MiB — a difference smaller than the variation between runs — while reserving over 10 GiB of address space. What the size costs is address space per live task and not memory per live task, which is a trade a 64-bit host does not notice, and max_tasks is the control for how many live tasks a run may hold in any case.

An embedder that calls Interpreter::run_entry on a thread of its own is the one case the runtime cannot size, and the one case where the promise is the embedder’s to keep; see that method for what to do about it.

cove_syntax’s MAX_NESTING_DEPTH answers the same question from the other side. The parser is handed a thread rather than making one, so it cannot size the stack and instead fixes the stack it is willing to promise — 2 MiB, what an unsized thread has — and derives its limit from what a level of nesting costs on it. Together the two bound both halves of a .cove file’s route through the toolchain: reading it and running it.