Skip to content

Commit 6f83e31

Browse files
committed
[mono][interp] Link try bblock with leave targets from catch block
Otherwise SSA dominance algorithms may fail to detect certain code flow and incorrectly manage phi nodes. public bool M() { bool ret = true; try { // throw NULL } catch (NullReferenceException) { goto Label; } ret = false; Label: return ret; } Without this fix, given the SSA cfg doesn't include EH bblocks, we would see the return opcode always reachable through the fallthrough from `ret = false`.
1 parent f313e8d commit 6f83e31

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/mono/mono/mini/interp/transform-opt.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,53 @@ interp_get_bb_links (InterpBasicBlock *bb)
533533
return str;
534534
}
535535

536+
// This method links a try bblock (which can be part of the no-eh path, aka basic blocks that are reachable
537+
// without an exception being thrown) with all exists from the catch bblock that go into no-eh bblocks.
538+
// This is needed because for no-eh bblocks we do dominance computation. So if a no-eh bblock can be
539+
// reached through an eh path, we need to have this information exposed.
540+
static void
541+
dfs_link_try_bblock (TransformData *td, InterpBasicBlock *catch_bb, InterpBasicBlock **stack, gboolean *marked)
542+
{
543+
int next_stack_index = 0;
544+
stack [next_stack_index++] = catch_bb;
545+
marked [catch_bb->dfs_index - td->bblocks_count_no_eh] = TRUE;
546+
547+
while (next_stack_index > 0) {
548+
// Pop last added element
549+
next_stack_index--;
550+
InterpBasicBlock *bb = stack [next_stack_index];
551+
552+
// Push all nodes to process next
553+
for (int i = 0; i < bb->out_count; i++) {
554+
InterpBasicBlock *out_bb = bb->out_bb [i];
555+
if (out_bb->dfs_index < td->bblocks_count_no_eh) {
556+
interp_link_bblocks (td, catch_bb->try_bblock, out_bb);
557+
if (td->verbose_level)
558+
g_print ("\t linked try_bb BB%d to leave target BB%d\n", catch_bb->try_bblock->index, out_bb->index);
559+
} else if (!marked [out_bb->dfs_index - td->bblocks_count_no_eh]) {
560+
stack [next_stack_index++] = out_bb;
561+
marked [out_bb->dfs_index - td->bblocks_count_no_eh] = TRUE;
562+
}
563+
}
564+
}
565+
}
566+
567+
static void
568+
link_try_bblocks (TransformData *td)
569+
{
570+
if (td->header->num_clauses) {
571+
int num_eh_bblocks = td->bblocks_count_eh - td->bblocks_count_no_eh;
572+
InterpBasicBlock **stack = (InterpBasicBlock**)g_malloc0 (sizeof (InterpBasicBlock*) * num_eh_bblocks);
573+
gboolean *marked = (gboolean*)g_malloc0 (sizeof (gboolean) * num_eh_bblocks);
574+
for (int i = td->bblocks_count_no_eh; i < td->bblocks_count_eh; i++) {
575+
if (td->bblocks [i]->try_bblock && td->bblocks [i]->try_bblock->dfs_index < td->bblocks_count_no_eh)
576+
dfs_link_try_bblock (td, td->bblocks [i], stack, marked);
577+
}
578+
}
579+
580+
td->linked_try_bblocks = TRUE;
581+
}
582+
536583
static int
537584
dfs_visit (TransformData *td)
538585
{
@@ -592,6 +639,9 @@ interp_compute_dfs_indexes (TransformData *td)
592639
}
593640
td->bblocks_count_eh = dfs_index;
594641

642+
if (!td->linked_try_bblocks)
643+
link_try_bblocks (td);
644+
595645
if (td->verbose_level) {
596646
InterpBasicBlock *bb;
597647
g_print ("\nBASIC BLOCK GRAPH:\n");

src/mono/mono/mini/interp/transform.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ typedef struct
360360
guint need_optimization_retry : 1;
361361
guint disable_ssa : 1;
362362
guint eh_vars_computed : 1;
363+
guint linked_try_bblocks : 1;
363364
guint retry_compilation : 1;
364365
guint retry_with_inlining : 1;
365366
} TransformData;

0 commit comments

Comments
 (0)