I must admit being curious too.
Go used to have split-stack, but I seem to remember they switched to a single growing stack instead because they had performance issues when the “edge” of the split-stack would find itself in a tight loop. Of course, moving the stack is a tad complicated in Rust, because pointers are not tracked.
On 64-bits platform, with 47-bits for user-space, split-stacks don’t seem very interesting. You can have a million 64 MB stacks in 46-bits, leaving half the user-space for heap allocations. The only requirement is to physically allocate 8KB (2 OS pages) per stack, one for the actual stack and one for the guard page, which requires 8GB of physical memory for this million stacks.
Performance is likely to be much better than with split stacks, while the benefits are mostly similar.
Is there a concrete use-case that motivates split stacks?
Regarding the RFC itself, there’s an issue with native function calls, which Go has as well.
Each time one switches to a native function, the stack need be big enough for that function:
- it cannot be expected for users to annotate each and every extern function with
#[no_split_stack]
, which means that all extern functions must “gain” this attribute by default. - I expect that most stacks will call an extern function, if only because memory allocation functions call into malloc…
How do you propose to solve this conundrum? Does anyone remember how it was solved in the libgreen era?