Supply guard type to exceptional control flow transfer

Change-Id: I9d6f6abd6f8a1c4b0246c5e9cf397cea8f8e303c
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java b/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java
index 22aac9a..67f452d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfTryCatch.java
@@ -12,7 +12,9 @@
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 public class CfTryCatch {
@@ -29,6 +31,15 @@
     assert verifyAllNonNull(guards);
   }
 
+  public void forEach(BiConsumer<DexType, CfLabel> consumer) {
+    Iterator<DexType> guardIterator = guards.iterator();
+    Iterator<CfLabel> targetIterator = targets.iterator();
+    while (guardIterator.hasNext()) {
+      consumer.accept(guardIterator.next(), targetIterator.next());
+    }
+    assert !targetIterator.hasNext();
+  }
+
   public void forEachTarget(Consumer<CfLabel> consumer) {
     targets.forEach(consumer);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractTransferFunction.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractTransferFunction.java
index 57e5b6b..ad58a5c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractTransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractTransferFunction.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.ir.analysis.framework.intraprocedural;
 
+import com.android.tools.r8.graph.DexType;
+
 /**
  * A transfer function that defines the abstract semantics of the instructions in the program
  * according to some abstract state {@link StateType}.
@@ -48,7 +50,11 @@
    * true.
    */
   default StateType computeExceptionalBlockEntryState(
-      Block block, Block throwBlock, Instruction throwInstruction, StateType throwState) {
+      Block block,
+      DexType guard,
+      Block throwBlock,
+      Instruction throwInstruction,
+      StateType throwState) {
     return throwState;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
index ecf6287..a0a7ba0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
@@ -4,8 +4,11 @@
 
 package com.android.tools.r8.ir.analysis.framework.intraprocedural;
 
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.TraversalUtils;
+import com.android.tools.r8.utils.TriFunction;
+import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -29,7 +32,10 @@
   }
 
   default boolean hasExceptionalSuccessors(Block block) {
-    return TraversalUtils.hasNext(counter -> traverseExceptionalSuccessors(block, counter));
+    return TraversalUtils.hasNext(
+        counter ->
+            traverseExceptionalSuccessors(
+                block, (exceptionalSuccessor, guard) -> counter.apply(exceptionalSuccessor)));
   }
 
   default boolean hasUniquePredecessor(Block block) {
@@ -77,8 +83,9 @@
   }
 
   default <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
-      Block block, Function<? super Block, TraversalContinuation<BT, CT>> fn) {
-    return traverseExceptionalSuccessors(block, (successor, ignore) -> fn.apply(successor), null);
+      Block block, BiFunction<? super Block, DexType, TraversalContinuation<BT, CT>> fn) {
+    return traverseExceptionalSuccessors(
+        block, (successor, guard, ignore) -> fn.apply(successor, guard), null);
   }
 
   // Block traversal with result.
@@ -110,7 +117,10 @@
     return traverseNormalSuccessors(block, fn, initialValue)
         .ifContinueThen(
             continuation ->
-                traverseExceptionalSuccessors(block, fn, continuation.getValueOrDefault(null)));
+                traverseExceptionalSuccessors(
+                    block,
+                    (exceptionalSuccessor, guard, value) -> fn.apply(exceptionalSuccessor, value),
+                    continuation.getValueOrDefault(null)));
   }
 
   <BT, CT> TraversalContinuation<BT, CT> traverseNormalSuccessors(
@@ -120,7 +130,7 @@
 
   <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
       Block block,
-      BiFunction<? super Block, ? super CT, TraversalContinuation<BT, CT>> fn,
+      TriFunction<? super Block, DexType, ? super CT, TraversalContinuation<BT, CT>> fn,
       CT initialValue);
 
   // Block iteration.
@@ -150,7 +160,8 @@
 
   default void forEachSuccessor(Block block, Consumer<Block> consumer) {
     forEachNormalSuccessor(block, consumer);
-    forEachExceptionalSuccessor(block, consumer);
+    forEachExceptionalSuccessor(
+        block, (exceptionalSuccessor, guard) -> consumer.accept(exceptionalSuccessor));
   }
 
   default void forEachNormalSuccessor(Block block, Consumer<Block> consumer) {
@@ -162,11 +173,11 @@
         });
   }
 
-  default void forEachExceptionalSuccessor(Block block, Consumer<Block> consumer) {
+  default void forEachExceptionalSuccessor(Block block, BiConsumer<Block, DexType> consumer) {
     traverseExceptionalSuccessors(
         block,
-        exceptionalSuccessor -> {
-          consumer.accept(exceptionalSuccessor);
+        (exceptionalSuccessor, guard) -> {
+          consumer.accept(exceptionalSuccessor, guard);
           return TraversalContinuation.doContinue();
         });
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
index dbd2a45..d7dbeb3 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
@@ -190,10 +190,10 @@
       Block block, Instruction instruction, StateType state) {
     cfg.forEachExceptionalSuccessor(
         block,
-        exceptionalSuccessor -> {
+        (exceptionalSuccessor, guard) -> {
           StateType edgeState =
               transfer.computeExceptionalBlockEntryState(
-                  exceptionalSuccessor, block, instruction, state);
+                  exceptionalSuccessor, guard, block, instruction, state);
           updateBlockEntryStateForBlock(
               exceptionalSuccessor, edgeState, exceptionalBlockEntryStates);
         });
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java
index 942cb97..7986623 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java
@@ -6,10 +6,12 @@
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.SetUtils;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -31,7 +33,7 @@
   final List<CfBlock> exceptionalPredecessors = new ArrayList<>();
 
   // The exceptional successors of the block (i.e., the catch handlers of the block).
-  final List<CfBlock> exceptionalSuccessors = new ArrayList<>();
+  final LinkedHashMap<DexType, CfBlock> exceptionalSuccessors = new LinkedHashMap<>();
 
   public CfInstruction getFallthroughInstruction(CfCode code) {
     int fallthroughInstructionIndex = getLastInstructionIndex() + 1;
@@ -56,15 +58,11 @@
     return predecessors;
   }
 
-  // TODO(b/214496607): This currently only encodes the graph, but we likely need to include the
-  //  guard types here.
   public List<CfBlock> getExceptionalPredecessors() {
     return exceptionalPredecessors;
   }
 
-  // TODO(b/214496607): This currently only encodes the graph, but we likely need to include the
-  //  guard types here.
-  public List<CfBlock> getExceptionalSuccessors() {
+  public LinkedHashMap<DexType, CfBlock> getExceptionalSuccessors() {
     return exceptionalSuccessors;
   }
 
@@ -79,8 +77,9 @@
       exceptionalPredecessors.add(block);
     }
 
-    void addExceptionalSuccessor(CfBlock block) {
-      exceptionalSuccessors.add(block);
+    void addExceptionalSuccessor(CfBlock block, DexType guard) {
+      assert !exceptionalSuccessors.containsKey(guard);
+      exceptionalSuccessors.put(guard, block);
     }
 
     void setFirstInstructionIndex(int firstInstructionIndex) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
index 4fe4724..2b58157 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
@@ -10,12 +10,14 @@
 import com.android.tools.r8.cf.code.CfLabel;
 import com.android.tools.r8.cf.code.CfTryCatch;
 import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.framework.intraprocedural.ControlFlowGraph;
 import com.android.tools.r8.ir.analysis.framework.intraprocedural.cf.CfBlock.MutableCfBlock;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.TraversalUtils;
+import com.android.tools.r8.utils.TriFunction;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
 import java.util.ArrayDeque;
@@ -23,10 +25,9 @@
 import java.util.Deque;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
-import java.util.LinkedHashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.function.BiFunction;
 
 /**
@@ -64,7 +65,7 @@
 
   @Override
   public CfBlock getEntryBlock() {
-    return getBlock(code.getInstructions().get(0));
+    return getBlock(code.getInstruction(0));
   }
 
   @Override
@@ -97,9 +98,12 @@
   @Override
   public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
       CfBlock block,
-      BiFunction<? super CfBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+      TriFunction<? super CfBlock, DexType, ? super CT, TraversalContinuation<BT, CT>> fn,
       CT initialValue) {
-    return TraversalUtils.traverseIterable(block.getExceptionalSuccessors(), fn, initialValue);
+    return TraversalUtils.traverseMap(
+        block.getExceptionalSuccessors(),
+        (guard, exceptionalSuccessor, value) -> fn.apply(exceptionalSuccessor, guard, value),
+        initialValue);
   }
 
   @Override
@@ -112,7 +116,7 @@
     for (int instructionIndex = block.getFirstInstructionIndex();
         instructionIndex <= block.getLastInstructionIndex();
         instructionIndex++) {
-      CfInstruction instruction = code.getInstructions().get(instructionIndex);
+      CfInstruction instruction = code.getInstruction(instructionIndex);
       traversalContinuation = fn.apply(instruction, traversalContinuation.asContinue().getValue());
       if (traversalContinuation.shouldBreak()) {
         break;
@@ -255,11 +259,11 @@
       }
 
       // Visit each instruction belonging to the current block.
-      Set<CfLabel> exceptionalSuccessors = new LinkedHashSet<>();
+      Map<DexType, CfLabel> exceptionalSuccessors = new LinkedHashMap<>();
       Iterator<CfTryCatch> activeCatchHandlerIterator = activeCatchHandlers.descendingIterator();
       while (activeCatchHandlerIterator.hasNext()) {
         CfTryCatch activeCatchHandler = activeCatchHandlerIterator.next();
-        activeCatchHandler.forEachTarget(exceptionalSuccessors::add);
+        activeCatchHandler.forEach(exceptionalSuccessors::putIfAbsent);
       }
 
       do {
@@ -269,7 +273,7 @@
         if (isBlockExit(instructionIndex)) {
           break;
         }
-        instruction = code.getInstructions().get(++instructionIndex);
+        instruction = code.getInstruction(++instructionIndex);
       } while (true);
 
       // Record the index of the last instruction of the block.
@@ -282,9 +286,9 @@
 
       // Add the current block as an exceptional predecessor of the exceptional successor blocks.
       exceptionalSuccessors.forEach(
-          exceptionalSuccessor -> {
+          (guard, exceptionalSuccessor) -> {
             MutableCfBlock exceptionalSuccessorBlock = getBlock(exceptionalSuccessor);
-            block.addExceptionalSuccessor(exceptionalSuccessorBlock);
+            block.addExceptionalSuccessor(exceptionalSuccessorBlock, guard);
             exceptionalSuccessorBlock.addExceptionalPredecessor(block);
           });
 
@@ -307,7 +311,7 @@
       if (instructionIndex == lastInstructionIndex) {
         return true;
       }
-      CfInstruction nextInstruction = code.getInstructions().get(instructionIndex + 1);
+      CfInstruction nextInstruction = code.getInstruction(instructionIndex + 1);
       return isBlockEntry(nextInstruction);
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 0d1bf75..432311b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -26,6 +26,7 @@
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.StringUtils.BraceType;
 import com.android.tools.r8.utils.TraversalContinuation;
+import com.android.tools.r8.utils.TriFunction;
 import com.google.common.base.Equivalence;
 import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.collect.ImmutableList;
@@ -243,14 +244,17 @@
   }
 
   public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
-      BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+      TriFunction<? super BasicBlock, DexType, ? super CT, TraversalContinuation<BT, CT>> fn,
       CT initialValue) {
     int numberOfExceptionalSuccessors = numberOfExceptionalSuccessors();
     TraversalContinuation<BT, CT> traversalContinuation =
         TraversalContinuation.doContinue(initialValue);
     for (int i = 0; i < numberOfExceptionalSuccessors; i++) {
       traversalContinuation =
-          fn.apply(successors.get(i), traversalContinuation.asContinue().getValueOrDefault(null));
+          fn.apply(
+              successors.get(i),
+              catchHandlers.getGuard(i),
+              traversalContinuation.asContinue().getValueOrDefault(null));
       if (traversalContinuation.isBreak()) {
         break;
       }
diff --git a/src/main/java/com/android/tools/r8/ir/code/CatchHandlers.java b/src/main/java/com/android/tools/r8/ir/code/CatchHandlers.java
index 6005e1f..03771cd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CatchHandlers.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CatchHandlers.java
@@ -64,6 +64,10 @@
     return guards;
   }
 
+  public DexType getGuard(int index) {
+    return guards.get(index);
+  }
+
   public List<T> getAllTargets() {
     return targets;
   }
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 8f310c8..409d050 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
@@ -35,6 +35,7 @@
 import com.android.tools.r8.utils.SetUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.TraversalContinuation;
+import com.android.tools.r8.utils.TriFunction;
 import com.android.tools.r8.utils.WorkList;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -1402,7 +1403,7 @@
   @Override
   public <BT, CT> TraversalContinuation<BT, CT> traverseExceptionalSuccessors(
       BasicBlock block,
-      BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
+      TriFunction<? super BasicBlock, DexType, ? super CT, TraversalContinuation<BT, CT>> fn,
       CT initialValue) {
     return block.traverseExceptionalSuccessors(fn, initialValue);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
index a955882..f6bc6e6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
@@ -152,6 +152,7 @@
   @Override
   public ParameterUsages computeExceptionalBlockEntryState(
       BasicBlock block,
+      DexType guard,
       BasicBlock throwBlock,
       Instruction throwInstruction,
       ParameterUsages throwState) {
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
index 121b5ab..049a279 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
@@ -102,6 +102,7 @@
     @Override
     public CfFrameState computeExceptionalBlockEntryState(
         CfBlock block,
+        DexType guard,
         CfBlock throwBlock,
         CfInstruction throwInstruction,
         CfFrameState throwState) {
diff --git a/src/main/java/com/android/tools/r8/utils/TraversalUtils.java b/src/main/java/com/android/tools/r8/utils/TraversalUtils.java
index b705d02..627ee79 100644
--- a/src/main/java/com/android/tools/r8/utils/TraversalUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/TraversalUtils.java
@@ -6,6 +6,8 @@
 
 import static com.android.tools.r8.utils.FunctionUtils.ignoreArgument;
 
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -64,4 +66,23 @@
     }
     return traversalContinuation;
   }
+
+  public static <S, T, BT, CT> TraversalContinuation<BT, CT> traverseMap(
+      Map<S, T> map,
+      TriFunction<? super S, ? super T, ? super CT, TraversalContinuation<BT, CT>> fn,
+      CT initialValue) {
+    TraversalContinuation<BT, CT> traversalContinuation =
+        TraversalContinuation.doContinue(initialValue);
+    for (Entry<S, T> entry : map.entrySet()) {
+      traversalContinuation =
+          fn.apply(
+              entry.getKey(),
+              entry.getValue(),
+              traversalContinuation.asContinue().getValueOrDefault(null));
+      if (traversalContinuation.isBreak()) {
+        break;
+      }
+    }
+    return traversalContinuation;
+  }
 }