@@ -18,11 +18,16 @@ const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB
1818const STACK_PER_RECURSION : usize = 16 * 1024 * 1024 ; // 16MB
1919
2020thread_local ! {
21- static TIMES_GROWN : Cell <u16 > = const { Cell :: new( 0 ) } ;
21+ static TIMES_GROWN : Cell <u32 > = const { Cell :: new( 0 ) } ;
2222}
2323
24- // Give up if we expand the stack this many times and are still trying to recurse deeper.
25- const MAX_STACK_GROWTH : u16 = 1000 ;
24+ /// Give up if we expand the stack this many times and are still trying to recurse deeper.
25+ const MAX_STACK_GROWTH : u32 = 1000 ;
26+ /// Estimate number of frames used per call to `grow`.
27+ ///
28+ /// This is only used on platforms where we can't tell how much stack we have left, so we `grow`
29+ /// unconditionally.
30+ const ESTIMATED_FRAME_SIZE : u32 = 10000 ;
2631
2732/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
2833/// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit
@@ -32,15 +37,15 @@ const MAX_STACK_GROWTH: u16 = 1000;
3237pub fn ensure_sufficient_stack < R > ( f : impl FnOnce ( ) -> R ) -> R {
3338 // if we can't guess the remaining stack (unsupported on some platforms) we immediately grow
3439 // the stack and then cache the new stack size (which we do know now because we allocated it.
35- let enough_space = match stacker:: remaining_stack ( ) {
36- Some ( remaining) => remaining >= RED_ZONE ,
37- None => false ,
40+ let ( enough_space, max_stack ) = match stacker:: remaining_stack ( ) {
41+ Some ( remaining) => ( remaining >= RED_ZONE , MAX_STACK_GROWTH ) ,
42+ None => ( false , MAX_STACK_GROWTH * ESTIMATED_FRAME_SIZE ) ,
3843 } ;
3944 if likely ( enough_space) {
4045 f ( )
4146 } else {
4247 let times = TIMES_GROWN . get ( ) ;
43- if unlikely ( times > MAX_STACK_GROWTH ) {
48+ if unlikely ( times > max_stack ) {
4449 too_much_stack ( ) ;
4550 }
4651 TIMES_GROWN . set ( times + 1 ) ;
0 commit comments