Skip to content

Commit

Permalink
Impl Drop for ast::Tree to avoid stack overflows
Browse files Browse the repository at this point in the history
  • Loading branch information
developedby committed Apr 5, 2024
1 parent 503a548 commit 8c690f6
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 12 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ opt-level = 3
panic = "abort"
debug = "full"

[profile.test]
opt-level = 3
debug = "full"

[dependencies]
arrayvec = "0.7.4"
clap = { version = "4.5.1", features = ["derive"] }
Expand Down
42 changes: 40 additions & 2 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,12 @@ impl Tree {
}
}

pub fn legacy_mat(arms: Tree, out: Tree) -> Option<Tree> {
let Tree::Ctr { lab: 0, ports } = arms else { None? };
pub fn legacy_mat(mut arms: Tree, out: Tree) -> Option<Tree> {
let ports = if let Tree::Ctr { lab: 0, ports } = &mut arms {
std::mem::take(ports)
} else {
return None;
};
let Ok([zero, succ]) = <[_; 2]>::try_from(ports) else { None? };
let zero = Box::new(zero);
let succ = Box::new(succ);
Expand Down Expand Up @@ -529,6 +533,7 @@ impl fmt::Display for Tree {
})
}
}

impl Clone for Tree {
fn clone(&self) -> Tree {
maybe_grow(|| match self {
Expand All @@ -548,3 +553,36 @@ impl Clone for Tree {
})
}
}

impl Drop for Tree {
fn drop(&mut self) {
fn take_children(tree: &mut Tree, stack: &mut Vec<Tree>) {
match tree {
Tree::Ctr { ports, .. } => stack.append(ports),
Tree::Op { rhs, out, .. } => {
stack.push(std::mem::take(rhs.as_mut()));
stack.push(std::mem::take(out.as_mut()));
}
Tree::Mat { zero, succ, out } => {
stack.push(std::mem::take(zero.as_mut()));
stack.push(std::mem::take(succ.as_mut()));
stack.push(std::mem::take(out.as_mut()));
}
Tree::Adt { fields, .. } => stack.append(fields),
Tree::Era | Tree::Num { .. } | Tree::Ref { .. } | Tree::Var { .. } => {}
}
}

// Shortcut if we know it has no children
if matches!(self, Tree::Era | Tree::Num { .. } | Tree::Ref { .. } | Tree::Var { .. }) {
return;
}

let mut stack = vec![];
take_children(self, &mut stack);

while let Some(mut term) = stack.pop() {
take_children(&mut term, &mut stack);
}
}
}
7 changes: 4 additions & 3 deletions src/host/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,14 @@ impl<'a, E: Encoder> State<'a, E> {
self.visit_tree(tree, trg);
}
fn visit_tree(&mut self, tree: &'a Tree, trg: E::Trg) {
static ERA: Tree = Tree::Era;
maybe_grow(move || match tree {
Tree::Era => self.encoder.link_const(trg, Port::ERA),
Tree::Num { val } => self.encoder.link_const(trg, Port::new_num(*val)),
Tree::Ref { nam } => self.encoder.link_const(trg, Port::new_ref(&self.host.defs[nam])),
Tree::Ctr { lab, ports } => {
if ports.is_empty() {
return self.visit_tree(&Tree::Era, trg);
return self.visit_tree(&tree, trg);
}
let mut trg = trg;
for port in &ports[0 .. ports.len() - 1] {
Expand All @@ -81,7 +82,7 @@ impl<'a, E: Encoder> State<'a, E> {
let mut trg = trg;
for _ in 0 .. *variant_index {
let (l, r) = self.encoder.ctr(*lab, trg);
self.visit_tree(&Tree::Era, l);
self.visit_tree(&ERA, l);
trg = r;
}
let (mut l, mut r) = self.encoder.ctr(*lab, trg);
Expand All @@ -92,7 +93,7 @@ impl<'a, E: Encoder> State<'a, E> {
}
for _ in 0 .. (*variant_count - *variant_index - 1) {
let (x, y) = self.encoder.ctr(*lab, r);
self.visit_tree(&Tree::Era, x);
self.visit_tree(&ERA, x);
r = y;
}
self.encoder.link(l, r);
Expand Down
8 changes: 4 additions & 4 deletions src/transform/coalesce_ctrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ impl Tree {
maybe_grow(|| match self {
Tree::Ctr { lab, ports } => {
ports.iter_mut().for_each(Tree::coalesce_constructors);
match ports.pop() {
Some(Tree::Ctr { lab: inner_lab, ports: mut inner_ports })
if inner_lab == *lab && ports.len() + inner_ports.len() < MAX_ARITY =>
match &mut ports.pop() {
Some(Tree::Ctr { lab: inner_lab, ports: inner_ports })
if inner_lab == lab && ports.len() + inner_ports.len() < MAX_ARITY =>
{
ports.extend(inner_ports.drain(..));
}
Some(other) => ports.push(other),
Some(other) => ports.push(std::mem::take(other)),
None => (),
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/transform/encode_adts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ impl Tree {
}

if let Some((start, idx)) = get_adt_info(lab, ports) {
let fields = match ports.swap_remove(idx) {
Tree::Ctr { ports: mut fields, .. } => {
let fields = match &mut ports.swap_remove(idx) {
Tree::Ctr { ports: fields, .. } => {
fields.pop();
fields
std::mem::take(fields)
}
Tree::Var { .. } => vec![],
_ => unreachable!(),
Expand Down

0 comments on commit 8c690f6

Please sign in to comment.