Merge "Make usage of basic block marks more explicit"
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 6544ea9..e9a84fa 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -76,7 +76,7 @@
     }
   }
 
-  void addDirectSubtype(DexType type) {
+  synchronized void addDirectSubtype(DexType type) {
     assert hierarchyLevel != UNKNOWN_LEVEL;
     ensureDirectSubTypeSet();
     directSubtypes.add(type);
@@ -96,7 +96,7 @@
     return hierarchyLevel == INTERFACE_LEVEL;
   }
 
-  void addInterfaceSubtype(DexType type) {
+  synchronized void addInterfaceSubtype(DexType type) {
     // Interfaces all inherit from java.lang.Object. However, we assign a special level to
     // identify them later on.
     setLevel(INTERFACE_LEVEL);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 2c0e3b0..7af0451 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -73,7 +73,6 @@
 
   public static final int REGISTER_CANDIDATE_NOT_FOUND = -1;
   public static final int MIN_CONSTANT_FREE_FOR_POSITIONS = 5;
-  private static final int RESERVED_MOVE_EXCEPTION_REGISTER = 0;
 
   private enum ArgumentReuseMode {
     ALLOW_ARGUMENT_REUSE,
@@ -142,9 +141,6 @@
   // List of intervals that no register has been allocated to sorted by first live range.
   protected PriorityQueue<LiveIntervals> unhandled = new PriorityQueue<>();
 
-  // List of intervals for the result of move-exception instructions.
-  private List<LiveIntervals> moveExceptionIntervals = new ArrayList<>();
-
   // The first register used for parallel moves. After register allocation the parallel move
   // temporary registers are [firstParallelMoveTemporary, maxRegisterNumber].
   private int firstParallelMoveTemporary = NO_REGISTER;
@@ -157,11 +153,6 @@
   // register.
   private boolean hasDedicatedMoveExceptionRegister = false;
 
-  private int getMoveExceptionRegister() {
-    return numberOfArgumentRegisters + NUMBER_OF_SENTINEL_REGISTERS +
-        RESERVED_MOVE_EXCEPTION_REGISTER;
-  }
-
   public LinearScanRegisterAllocator(IRCode code, InternalOptions options) {
     this.code = code;
     this.options = options;
@@ -672,7 +663,6 @@
     active.clear();
     inactive.clear();
     unhandled.clear();
-    moveExceptionIntervals.clear();
     for (LiveIntervals intervals : liveIntervals) {
       intervals.clearRegisterAssignment();
     }
@@ -762,6 +752,7 @@
       // Force all move exception ranges to start out with the exception in a fixed register. Split
       // their live ranges which will force another register if used.
       int moveExceptionRegister = NO_REGISTER;
+      List<LiveIntervals> moveExceptionIntervals = new ArrayList<>();
       boolean overlappingMoveExceptionIntervals = false;
       for (BasicBlock block : code.blocks) {
         for (Instruction instruction : block.getInstructions()) {
@@ -770,12 +761,8 @@
             Value exceptionValue = instruction.outValue();
             LiveIntervals intervals = exceptionValue.getLiveIntervals();
             unhandled.remove(intervals);
-            moveExceptionIntervals.add(intervals);
             if (moveExceptionRegister == NO_REGISTER) {
-              assert RESERVED_MOVE_EXCEPTION_REGISTER == 0;
               moveExceptionRegister = getFreeConsecutiveRegisters(1);
-              assert moveExceptionRegister == getMoveExceptionRegister();
-              assert !freeRegisters.contains(moveExceptionRegister);
             }
             intervals.setRegister(moveExceptionRegister);
             if (!overlappingMoveExceptionIntervals) {
@@ -783,6 +770,7 @@
                 overlappingMoveExceptionIntervals |= other.overlaps(intervals);
               }
             }
+            moveExceptionIntervals.add(intervals);
           }
         }
       }
@@ -1136,47 +1124,6 @@
     return false;
   }
 
-  // Intervals overlap a move exception interval if one of the splits of the intervals does.
-  // Since spill and restore moves are always put after the move exception we cannot give
-  // a non-move exception interval the same register as a move exception instruction.
-  //
-  // For example:
-  //
-  // B0:
-  //   const v0, 0
-  //   invoke throwing_method v0 (catch handler B2)
-  //   goto B1
-  // B1:
-  //   ...
-  // B2:
-  //   move-exception v1
-  //   invoke method v0
-  //   return
-  //
-  // During register allocation we could split the const number intervals into multiple
-  // parts. We have to avoid assigning the same register to v1 and and v0 in B0 even
-  // if v0 has a different register in B2. That is because the spill/restore move when
-  // transitioning from B0 to B2 has to be after the move-exception instruction.
-  //
-  // Assuming that v0 has register 0 in B0 and register 4 in B2 and v1 has register 0 in B2
-  // we would generate the following incorrect code:
-  //
-  // B0:
-  //   const r0, 0
-  //   invoke throwing_method r0 (catch handler B2)
-  //   goto B1
-  // B1:
-  //   ...
-  // B2:
-  //   move-exception r0
-  //   move r4, r0  // Whoops.
-  //   invoke method r4
-  //   return
-  private boolean overlapsMoveExceptionInterval(LiveIntervals intervals) {
-    return hasDedicatedMoveExceptionRegister &&
-        moveExceptionIntervals.stream().anyMatch((i) -> intervals.anySplitOverlaps(i));
-  }
-
   private boolean allocateSingleInterval(LiveIntervals unhandledInterval, ArgumentReuseMode mode) {
     int registerConstraint = unhandledInterval.getRegisterLimit();
     assert registerConstraint <= Constants.U16BIT_MAX;
@@ -1235,8 +1182,8 @@
     // register. If we cannot find a free valid register for the move exception value we have no
     // place to put a spill move (because the move exception instruction has to be the
     // first instruction in the handler block).
-    if (overlapsMoveExceptionInterval(unhandledInterval)) {
-      int moveExceptionRegister = getMoveExceptionRegister();
+    if (hasDedicatedMoveExceptionRegister) {
+      int moveExceptionRegister = numberOfArgumentRegisters + NUMBER_OF_SENTINEL_REGISTERS;
       if (moveExceptionRegister <= registerConstraint) {
         freePositions.set(moveExceptionRegister, 0);
       }
@@ -1583,8 +1530,8 @@
     }
 
     // Disallow reuse of the move exception register if we have reserved one.
-    if (overlapsMoveExceptionInterval(unhandledInterval)) {
-      usePositions.set(getMoveExceptionRegister(), 0);
+    if (hasDedicatedMoveExceptionRegister) {
+      usePositions.set(numberOfArgumentRegisters + NUMBER_OF_SENTINEL_REGISTERS, 0);
     }
 
     // Treat active linked argument intervals as pinned. They cannot be given another register
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
index 2bbdaf9..b6d8b79 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
@@ -325,19 +325,6 @@
     return nextOverlap(other) != -1;
   }
 
-  public boolean anySplitOverlaps(LiveIntervals other) {
-    LiveIntervals parent = getSplitParent();
-    if (parent.overlaps(other)) {
-      return true;
-    }
-    for (LiveIntervals child : parent.getSplitChildren()) {
-      if (child.overlaps(other)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
   public int nextOverlap(LiveIntervals other) {
     Iterator<LiveRange> it = other.ranges.iterator();
     LiveRange otherRange = it.next();