Optimizing: Rewrite DCE's MarkReachableBlocks().

Replace a recursive implementation with a loop using a work
list to avoid stack overflow that we would presumably hit
for 702-LargeBranchOffset in host debug build with -O0, once
the DCE block elimination is enabled for methods containing
try-catch.

Bug: 24133462
Change-Id: I41288ba368722bcb5d68259c7c147552c8928099
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 345ff72..b322759 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -16,49 +16,63 @@
 
 #include "dead_code_elimination.h"
 
+#include "utils/array_ref.h"
 #include "base/bit_vector-inl.h"
 #include "ssa_phi_elimination.h"
 
 namespace art {
 
-static void MarkReachableBlocks(HBasicBlock* block, ArenaBitVector* visited) {
-  int block_id = block->GetBlockId();
-  if (visited->IsBitSet(block_id)) {
-    return;
-  }
-  visited->SetBit(block_id);
+static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) {
+  ArenaVector<HBasicBlock*> worklist(graph->GetArena()->Adapter());
+  constexpr size_t kDefaultWorlistSize = 8;
+  worklist.reserve(kDefaultWorlistSize);
+  visited->SetBit(graph->GetEntryBlock()->GetBlockId());
+  worklist.push_back(graph->GetEntryBlock());
 
-  HInstruction* last_instruction = block->GetLastInstruction();
-  if (last_instruction->IsIf()) {
-    HIf* if_instruction = last_instruction->AsIf();
-    HInstruction* condition = if_instruction->InputAt(0);
-    if (!condition->IsIntConstant()) {
-      MarkReachableBlocks(if_instruction->IfTrueSuccessor(), visited);
-      MarkReachableBlocks(if_instruction->IfFalseSuccessor(), visited);
-    } else if (condition->AsIntConstant()->IsOne()) {
-      MarkReachableBlocks(if_instruction->IfTrueSuccessor(), visited);
-    } else {
-      DCHECK(condition->AsIntConstant()->IsZero());
-      MarkReachableBlocks(if_instruction->IfFalseSuccessor(), visited);
-    }
-  } else if (last_instruction->IsPackedSwitch() &&
-             last_instruction->AsPackedSwitch()->InputAt(0)->IsIntConstant()) {
-    HPackedSwitch* switch_instruction = last_instruction->AsPackedSwitch();
-    int32_t switch_value = switch_instruction->InputAt(0)->AsIntConstant()->GetValue();
-    int32_t start_value = switch_instruction->GetStartValue();
-    int32_t last_value = start_value + switch_instruction->GetNumEntries();
-    for (int32_t case_value = start_value; case_value <= last_value; case_value++) {
-      if (case_value == last_value) {
-        MarkReachableBlocks(switch_instruction->GetDefaultBlock(), visited);
+  while (!worklist.empty()) {
+    HBasicBlock* block = worklist.back();
+    worklist.pop_back();
+    int block_id = block->GetBlockId();
+    DCHECK(visited->IsBitSet(block_id));
+
+    ArrayRef<HBasicBlock* const> live_successors(block->GetSuccessors());
+    HInstruction* last_instruction = block->GetLastInstruction();
+    if (last_instruction->IsIf()) {
+      HIf* if_instruction = last_instruction->AsIf();
+      HInstruction* condition = if_instruction->InputAt(0);
+      if (condition->IsIntConstant()) {
+        if (condition->AsIntConstant()->IsOne()) {
+          live_successors = live_successors.SubArray(0u, 1u);
+          DCHECK_EQ(live_successors[0], if_instruction->IfTrueSuccessor());
+        } else {
+          DCHECK(condition->AsIntConstant()->IsZero());
+          live_successors = live_successors.SubArray(1u, 1u);
+          DCHECK_EQ(live_successors[0], if_instruction->IfFalseSuccessor());
+        }
       }
-      if (case_value == switch_value) {
-        MarkReachableBlocks(block->GetSuccessor(case_value - start_value), visited);
-        break;
+    } else if (last_instruction->IsPackedSwitch()) {
+      HPackedSwitch* switch_instruction = last_instruction->AsPackedSwitch();
+      HInstruction* switch_input = switch_instruction->InputAt(0);
+      if (switch_input->IsIntConstant()) {
+        int32_t switch_value = switch_input->AsIntConstant()->GetValue();
+        int32_t start_value = switch_instruction->GetStartValue();
+        uint32_t switch_index = static_cast<uint32_t>(switch_value - start_value);
+        if (switch_index < switch_instruction->GetNumEntries()) {
+          live_successors = live_successors.SubArray(switch_index, 1u);
+          DCHECK_EQ(live_successors[0], block->GetSuccessor(switch_index));
+        } else {
+          live_successors = live_successors.SubArray(switch_instruction->GetNumEntries(), 1u);
+          DCHECK_EQ(live_successors[0], switch_instruction->GetDefaultBlock());
+        }
       }
     }
-  } else {
-    for (HBasicBlock* successor : block->GetSuccessors()) {
-      MarkReachableBlocks(successor, visited);
+
+    for (HBasicBlock* successor : live_successors) {
+      // Add only those successors that have not been visited yet.
+      if (!visited->IsBitSet(successor->GetBlockId())) {
+        visited->SetBit(successor->GetBlockId());
+        worklist.push_back(successor);
+      }
     }
   }
 }
@@ -82,7 +96,7 @@
   ArenaBitVector live_blocks(allocator, graph_->GetBlocks().size(), false);
   ArenaBitVector affected_loops(allocator, graph_->GetBlocks().size(), false);
 
-  MarkReachableBlocks(graph_->GetEntryBlock(), &live_blocks);
+  MarkReachableBlocks(graph_, &live_blocks);
   bool removed_one_or_more_blocks = false;
 
   // Remove all dead blocks. Iterate in post order because removal needs the