Use an iterative implementation for depthFirstSorting.

Bug: 77626496
Change-Id: Ie4b37088942dbe8c095df4671f82f02e44ae5082
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 2613aae..4adcf5a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -13,6 +13,7 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.Deque;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
@@ -252,25 +253,44 @@
    * no sorting.
    */
   public ImmutableList<BasicBlock> topologicallySortedBlocks() {
-    Set<BasicBlock> visitedBlock = new HashSet<>();
-    ImmutableList.Builder<BasicBlock> builder = ImmutableList.builder();
-    BasicBlock entryBlock = blocks.getFirst();
-    depthFirstSorting(visitedBlock, entryBlock, builder);
-    ImmutableList<BasicBlock> ordered = builder.build().reverse();
+    ImmutableList<BasicBlock> ordered = depthFirstSorting();
     return options.testing.placeExceptionalBlocksLast
         ? reorderExceptionalBlocksLastForTesting(ordered)
         : ordered;
   }
 
-  private void depthFirstSorting(Set<BasicBlock> visitedBlock, BasicBlock block,
-      ImmutableList.Builder<BasicBlock> builder) {
-    if (!visitedBlock.contains(block)) {
-      visitedBlock.add(block);
-      for (BasicBlock succ : block.getSuccessors()) {
-        depthFirstSorting(visitedBlock, succ, builder);
+  private ImmutableList<BasicBlock> depthFirstSorting() {
+    // Stack marker to denote when all successors of a block have been processed.
+    class BlockMarker {
+      final BasicBlock block;
+      public BlockMarker(BasicBlock block) {
+        this.block = block;
       }
-      builder.add(block);
     }
+    ArrayList<BasicBlock> reverseOrdered = new ArrayList<>(blocks.size());
+    Set<BasicBlock> visitedBlocks = new HashSet<>(blocks.size());
+    Deque<Object> worklist = new ArrayDeque<>(blocks.size());
+    worklist.addLast(blocks.getFirst());
+    while (!worklist.isEmpty()) {
+      Object item = worklist.removeLast();
+      if (item instanceof BlockMarker) {
+        reverseOrdered.add(((BlockMarker) item).block);
+        continue;
+      }
+      BasicBlock block = (BasicBlock) item;
+      if (!visitedBlocks.contains(block)) {
+        visitedBlocks.add(block);
+        worklist.addLast(new BlockMarker(block));
+        for (int i = block.getSuccessors().size() - 1; i >= 0; i--) {
+          worklist.addLast(block.getSuccessors().get(i));
+        }
+      }
+    }
+    ImmutableList.Builder<BasicBlock> builder = ImmutableList.builder();
+    for (int i = reverseOrdered.size() - 1; i >= 0; i--) {
+      builder.add(reverseOrdered.get(i));
+    }
+    return builder.build();
   }
 
   // Reorder the blocks forcing all exceptional blocks to be at the end.