mir_analyzer/
recursion.rs1use std::ops::ControlFlow;
9
10use php_ast::owned::visitor::{walk_owned_block, walk_owned_expr, walk_owned_stmt, OwnedVisitor};
11use php_ast::owned::{Block, Expr, Stmt};
12
13pub const STACK_SIZE: usize = 16 * 1024 * 1024;
15
16const RED_ZONE: usize = 512 * 1024;
19const SEGMENT_SIZE: usize = 8 * 1024 * 1024;
20
21const PHASE_RED_ZONE: usize = 4 * 1024 * 1024;
24const PHASE_SEGMENT_SIZE: usize = 32 * 1024 * 1024;
25
26#[inline]
28pub fn ensure_stack<R>(f: impl FnOnce() -> R) -> R {
29 grow(RED_ZONE, SEGMENT_SIZE, f)
30}
31
32#[inline]
34pub fn ensure_phase_stack<R>(f: impl FnOnce() -> R) -> R {
35 grow(PHASE_RED_ZONE, PHASE_SEGMENT_SIZE, f)
36}
37
38pub struct GuardedParse(Option<php_rs_parser::ParseResult>);
40
41impl std::ops::Deref for GuardedParse {
42 type Target = php_rs_parser::ParseResult;
43
44 fn deref(&self) -> &Self::Target {
45 self.0.as_ref().expect("present until dropped")
46 }
47}
48
49impl Drop for GuardedParse {
50 fn drop(&mut self) {
51 let parsed = self.0.take();
52 ensure_phase_stack(|| drop(parsed));
53 }
54}
55
56pub fn parse_versioned(source: &str, version: php_rs_parser::PhpVersion) -> GuardedParse {
58 GuardedParse(Some(ensure_phase_stack(|| {
59 php_rs_parser::parse_versioned(source, version)
60 })))
61}
62
63pub fn parse(source: &str) -> GuardedParse {
65 GuardedParse(Some(ensure_phase_stack(|| php_rs_parser::parse(source))))
66}
67
68#[cfg(not(target_arch = "wasm32"))]
69fn grow<R>(red_zone: usize, segment: usize, f: impl FnOnce() -> R) -> R {
70 stacker::maybe_grow(red_zone, segment, f)
71}
72
73#[cfg(target_arch = "wasm32")]
74fn grow<R>(_red_zone: usize, _segment: usize, f: impl FnOnce() -> R) -> R {
75 f()
76}
77
78pub fn walk_expr<V: OwnedVisitor + ?Sized>(visitor: &mut V, expr: &Expr) -> ControlFlow<()> {
80 ensure_stack(|| walk_owned_expr(visitor, expr))
81}
82
83pub fn walk_stmt<V: OwnedVisitor + ?Sized>(visitor: &mut V, stmt: &Stmt) -> ControlFlow<()> {
85 ensure_stack(|| walk_owned_stmt(visitor, stmt))
86}
87
88pub fn walk_block<V: OwnedVisitor + ?Sized>(visitor: &mut V, block: &Block) -> ControlFlow<()> {
90 ensure_stack(|| walk_owned_block(visitor, block))
91}