Skip to content

Commit cf36e81

Browse files
authored
fix: trytable visit implementation (#295)
1 parent 5b7c88a commit cf36e81

File tree

2 files changed

+107
-9
lines changed

2 files changed

+107
-9
lines changed

src/ir/traversals.rs

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,16 @@ pub fn dfs_in_order<'instr>(
112112

113113
// Pause iteration through this sequence's instructions.
114114
// Traverse the try_table body.
115-
Instr::TryTable(TryTable { seq, .. }) => {
115+
Instr::TryTable(TryTable { seq, catches }) => {
116116
stack.push((seq_id, index + 1));
117+
// Visit catch clauses to mark tags as used.
118+
// Note: The labels in TryTable catches are branch targets, not handler
119+
// blocks. They reference blocks already in the control flow and will be
120+
// visited naturally during traversal.
121+
for catch in catches.iter() {
122+
log::trace!("dfs_in_order: ({:?}).visit(..)", catch);
123+
catch.visit(visitor);
124+
}
117125
stack.push((*seq, 0));
118126
continue 'traversing_blocks;
119127
}
@@ -242,7 +250,14 @@ pub fn dfs_pre_order_mut(
242250
stack.push(*consequent);
243251
}
244252

245-
Instr::TryTable(TryTable { seq, .. }) => {
253+
Instr::TryTable(TryTable { seq, catches }) => {
254+
// Visit catch clauses to mark tags as used.
255+
// Note: The labels in TryTable catches are branch targets, not handler
256+
// blocks. They reference blocks already in the control flow and will be
257+
// visited naturally during traversal.
258+
for catch in catches.iter_mut() {
259+
catch.visit_mut(visitor);
260+
}
246261
stack.push(*seq);
247262
}
248263

@@ -296,6 +311,14 @@ mod tests {
296311
fn visit_if_else(&mut self, _: &IfElse) {
297312
self.push("if-else");
298313
}
314+
315+
fn visit_try_table(&mut self, _: &TryTable) {
316+
self.push("try-table");
317+
}
318+
319+
fn visit_tag_id(&mut self, _: &crate::TagId) {
320+
self.push("tag");
321+
}
299322
}
300323

301324
impl VisitorMut for TestVisitor {
@@ -328,6 +351,14 @@ mod tests {
328351
fn visit_if_else_mut(&mut self, _: &mut IfElse) {
329352
self.push("if-else");
330353
}
354+
355+
fn visit_try_table_mut(&mut self, _: &mut TryTable) {
356+
self.push("try-table");
357+
}
358+
359+
fn visit_tag_id_mut(&mut self, _: &mut crate::TagId) {
360+
self.push("tag");
361+
}
331362
}
332363

333364
fn make_test_func(module: &mut crate::Module) -> &mut LocalFunction {
@@ -419,4 +450,78 @@ mod tests {
419450
expected.iter().map(|s| s.to_string()).collect::<Vec<_>>()
420451
);
421452
}
453+
454+
#[test]
455+
fn dfs_in_order_try_table() {
456+
let mut module = crate::Module::default();
457+
458+
let tag_type = module.types.add(&[crate::ValType::I32], &[]);
459+
let tag_id = module.tags.add(tag_type);
460+
461+
let block_ty = module.types.add(&[], &[]);
462+
let mut builder = crate::FunctionBuilder::new(&mut module.types, &[], &[]);
463+
464+
let mut func_body = builder.func_body();
465+
466+
// Build the try body
467+
let try_body = func_body.dangling_instr_seq(block_ty).id();
468+
func_body.instr_seq(try_body).i32_const(5).drop();
469+
470+
// Create dummy label targets (these are branch targets, not handler blocks)
471+
let catch_label = func_body.dangling_instr_seq(block_ty).id();
472+
let catch_all_label = func_body.dangling_instr_seq(block_ty).id();
473+
474+
func_body
475+
.i32_const(1)
476+
.drop()
477+
.instr(TryTable {
478+
seq: try_body,
479+
catches: vec![
480+
TryTableCatch::Catch {
481+
tag: tag_id,
482+
label: catch_label,
483+
},
484+
TryTableCatch::CatchAll {
485+
label: catch_all_label,
486+
},
487+
],
488+
})
489+
.i32_const(99)
490+
.drop();
491+
492+
let func_id = builder.finish(vec![], &mut module.funcs);
493+
let func = module.funcs.get_mut(func_id).kind.unwrap_local_mut();
494+
495+
let mut visitor = TestVisitor::default();
496+
crate::ir::dfs_in_order(&mut visitor, func, func.entry_block());
497+
498+
// Expected order:
499+
// - start (entry block)
500+
// - 1, drop (before try-table)
501+
// - try-table instruction
502+
// - tag (from Catch clause visiting tag ID)
503+
// - start, 5, drop, end (try body)
504+
// - 99, drop (after try-table)
505+
// - end (entry block)
506+
// Note: catch labels are branch targets, not separate blocks to traverse
507+
let expected = [
508+
"start",
509+
"1",
510+
"drop",
511+
"try-table",
512+
"tag",
513+
"start",
514+
"5",
515+
"drop",
516+
"end", // try body
517+
"99",
518+
"drop",
519+
"end",
520+
];
521+
522+
assert_eq!(
523+
visitor.visits,
524+
expected.iter().map(|s| s.to_string()).collect::<Vec<_>>()
525+
);
526+
}
422527
}

src/passes/used.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,4 @@ impl<'expr> Visitor<'expr> for UsedVisitor<'_> {
323323
fn visit_tag_id(&mut self, &tag: &TagId) {
324324
self.stack.push_tag(tag);
325325
}
326-
327-
fn visit_try_table(&mut self, instr: &TryTable) {
328-
// Visit the catches to mark tags as used
329-
for catch in &instr.catches {
330-
catch.visit(self);
331-
}
332-
}
333326
}

0 commit comments

Comments
 (0)