Merge "Revert "Run CF backend on Art tests""
diff --git a/build.gradle b/build.gradle
index f857f9e..716f983 100644
--- a/build.gradle
+++ b/build.gradle
@@ -36,7 +36,7 @@
     joptSimpleVersion = '4.6'
     jsonSimpleVersion = '1.1'
     junitVersion = '4.12'
-    kotlinVersion = '1.2.0'
+    kotlinVersion = '1.2.30'
     protobufVersion = '3.0.0'
     smaliVersion = '2.2b4'
 }
@@ -300,7 +300,7 @@
                 "android_jar/lib-v25",
                 "android_jar/lib-v26",
                 "proguard/proguard5.2.1",
-                "proguard/proguard6.0",
+                "proguard/proguard6.0.1",
                 "gradle/gradle",
                 "jdwp-tests",
                 "jasmin",
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 670211f..9404e68 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "v1.1.9-dev";
+  public static final String LABEL = "v1.1.10-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 42acb7c..d6b15eb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -146,6 +146,46 @@
     return result;
   }
 
+  /**
+   * For all annotations on the class and all annotations on its methods and fields apply the
+   * specified consumer.
+   */
+  public void forEachAnnotation(Consumer<DexAnnotation> consumer) {
+    for (DexAnnotation annotation : annotations.annotations) {
+      consumer.accept(annotation);
+    }
+    for (DexEncodedMethod method : directMethods()) {
+      for (DexAnnotation annotation : method.annotations.annotations) {
+        consumer.accept(annotation);
+      }
+      for (DexAnnotationSet parameterAnnotations : method.parameterAnnotations.values) {
+        for (DexAnnotation annotation : parameterAnnotations.annotations) {
+          consumer.accept(annotation);
+        }
+      }
+    }
+    for (DexEncodedMethod method : virtualMethods()) {
+      for (DexAnnotation annotation : method.annotations.annotations) {
+        consumer.accept(annotation);
+      }
+      for (DexAnnotationSet parameterAnnotations : method.parameterAnnotations.values) {
+        for (DexAnnotation annotation : parameterAnnotations.annotations) {
+          consumer.accept(annotation);
+        }
+      }
+    }
+    for (DexEncodedField field : instanceFields()) {
+      for (DexAnnotation annotation : field.annotations.annotations) {
+        consumer.accept(annotation);
+      }
+    }
+    for (DexEncodedField field : staticFields()) {
+      for (DexAnnotation annotation : field.annotations.annotations) {
+        consumer.accept(annotation);
+      }
+    }
+  }
+
   public void forEachField(Consumer<DexEncodedField> consumer) {
     for (DexEncodedField field : staticFields()) {
       consumer.accept(field);
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index b75cf1f..dd08190 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -91,6 +91,8 @@
     throw new Unreachable("No default value for unexpected type " + type);
   }
 
+  public abstract Object getBoxedValue();
+
   // Returns a const instruction for the non default value.
   public Instruction asConstInstruction(boolean hasClassInitializer, Value dest) {
     return null;
@@ -141,6 +143,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      throw new Unreachable();
+    }
+
+    @Override
     public Object asAsmEncodedObject() {
       throw new Unreachable();
     }
@@ -213,6 +220,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return getValue();
+    }
+
+    @Override
     public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
       writeHeader(VALUE_BYTE, 0, dest);
       dest.putSignedEncodedValue(value, 1);
@@ -265,6 +277,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return getValue();
+    }
+
+    @Override
     public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
       writeIntegerTo(VALUE_SHORT, value, Short.BYTES, dest);
     }
@@ -316,6 +333,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return getValue();
+    }
+
+    @Override
     public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
       dest.forward(1);
       int length = dest.putUnsignedEncodedValue(value, 2);
@@ -371,6 +393,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return getValue();
+    }
+
+    @Override
     public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
       writeIntegerTo(VALUE_INT, value, Integer.BYTES, dest);
     }
@@ -422,6 +449,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return getValue();
+    }
+
+    @Override
     public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
       writeIntegerTo(VALUE_LONG, value, Long.BYTES, dest);
     }
@@ -473,6 +505,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return getValue();
+    }
+
+    @Override
     public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
       dest.forward(1);
       int length = EncodedValueUtils.putFloat(dest, value);
@@ -526,6 +563,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return getValue();
+    }
+
+    @Override
     public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
       dest.forward(1);
       int length = EncodedValueUtils.putDouble(dest, value);
@@ -580,6 +622,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      throw new Unreachable("No boxed value for DexValue " + this.getClass().getSimpleName());
+    }
+
+    @Override
     public Object asAsmEncodedObject() {
       throw new Unreachable("No ASM conversion for DexValue " + this.getClass().getSimpleName());
     }
@@ -750,6 +797,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      throw new Unreachable("No boxed value for DexValueArray");
+    }
+
+    @Override
     public Object asAsmEncodedObject() {
       throw new Unreachable("No ASM conversion for DexValueArray");
     }
@@ -804,6 +856,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      throw new Unreachable("No boxed value for DexValueAnnotation");
+    }
+
+    @Override
     public Object asAsmEncodedObject() {
       throw new Unreachable("No ASM conversion for DexValueAnnotation");
     }
@@ -854,6 +911,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return null;
+    }
+
+    @Override
     public Object asAsmEncodedObject() {
       return null;
     }
@@ -899,6 +961,11 @@
     }
 
     @Override
+    public Object getBoxedValue() {
+      return getValue();
+    }
+
+    @Override
     public void writeTo(DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
       writeHeader(VALUE_BOOLEAN, value ? 1 : 0, dest);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Add.java b/src/main/java/com/android/tools/r8/ir/code/Add.java
index 783d672..2abc743 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Add.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Add.java
@@ -35,12 +35,6 @@
 
   @Override
   public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
-    // the first part of the result long before reading the second part of the input longs.
-    // Therefore, there can be no overlap of the second part of an input long and the first
-    // part of the output long.
-    assert dest != left + 1;
-    assert dest != right + 1;
     return new AddLong(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/And.java b/src/main/java/com/android/tools/r8/ir/code/And.java
index ad46715..c0bdb2a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/And.java
+++ b/src/main/java/com/android/tools/r8/ir/code/And.java
@@ -41,12 +41,6 @@
 
   @Override
   public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
-    // the first part of the result long before reading the second part of the input longs.
-    // Therefore, there can be no overlap of the second part of an input long and the first
-    // part of the output long.
-    assert dest != left + 1;
-    assert dest != right + 1;
     return new AndLong(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Or.java b/src/main/java/com/android/tools/r8/ir/code/Or.java
index 3df3a83..2cfe9b9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Or.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Or.java
@@ -40,12 +40,6 @@
 
   @Override
   public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
-    // the first part of the result long before reading the second part of the input longs.
-    // Therefore, there can be no overlap of the second part of an input long and the first
-    // part of the output long.
-    assert dest != left + 1;
-    assert dest != right + 1;
     return new OrLong(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Sub.java b/src/main/java/com/android/tools/r8/ir/code/Sub.java
index f9f5920..f2a173b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Sub.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Sub.java
@@ -39,12 +39,6 @@
 
   @Override
   public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
-    // the first part of the result long before reading the second part of the input longs.
-    // Therefore, there can be no overlap of the second part of an input long and the first
-    // part of the output long.
-    assert dest != left + 1;
-    assert dest != right + 1;
     return new SubLong(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Xor.java b/src/main/java/com/android/tools/r8/ir/code/Xor.java
index d2897ed..0f37a65 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Xor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Xor.java
@@ -39,12 +39,6 @@
 
   @Override
   public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
-    // the first part of the result long before reading the second part of the input longs.
-    // Therefore, there can be no overlap of the second part of an input long and the first
-    // part of the output long.
-    assert dest != left + 1;
-    assert dest != right + 1;
     return new XorLong(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 76a1a43..20051f9 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -396,10 +396,6 @@
     // necessary.
     ir.splitCriticalEdges();
 
-    // Create block order and make sure that all blocks are immediately followed by their
-    // fallthrough block if any.
-    ir.traceBlocks();
-
     // Clear the code so we don't build multiple times.
     source.clear();
     source = null;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 42b06ef..0f0b44a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -476,6 +476,7 @@
       Log.debug(getClass(), "Initial (SSA) flow graph for %s:\n%s", method.toSourceString(), code);
     }
     assert code.isConsistentSSA();
+    code.traceBlocks();
     RegisterAllocator registerAllocator = performRegisterAllocation(code, method);
     method.setCode(code, registerAllocator, options);
     if (Log.ENABLED) {
@@ -635,7 +636,6 @@
 
     if (options.testing.invertConditionals) {
       invertConditionalsForTesting(code);
-      code.traceBlocks();
     }
 
     if (options.enableNonNullTracking && nonNullTracker != null) {
@@ -699,6 +699,7 @@
   }
 
   private void finalizeIR(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
+    code.traceBlocks();
     if (options.isGeneratingClassFiles()) {
       finalizeToCf(method, code, feedback);
     } else {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index a6b29e8..30e9bae4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -565,7 +565,6 @@
     // being split on the way in but does not maintain this property. We therefore split
     // critical edges at exit.
     code.splitCriticalEdges();
-    code.traceBlocks();
     assert code.isConsistentSSA();
   }
 
@@ -2028,9 +2027,6 @@
     }
     code.removeMarkedBlocks(color);
     code.returnMarkingColor(color);
-    if (ifBranchFlipped) {
-      code.traceBlocks();
-    }
     assert code.isConsistentSSA();
   }
 
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 fefe8c5..85e0060 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
@@ -54,6 +54,8 @@
 import java.util.PriorityQueue;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
 
 /**
  * Linear scan register allocator.
@@ -1090,6 +1092,46 @@
     return arrayReg == register;
   }
 
+  private boolean needsSingleResultOverlappingLongOperandsWorkaround(LiveIntervals intervals) {
+    if (!options.canHaveCmpLongBug()) {
+      return false;
+    }
+    if (intervals.requiredRegisters() == 2) {
+      // Not the live range for a single value and therefore not the output of cmp-long.
+      return false;
+    }
+    if (intervals.getValue().isPhi()) {
+      // If this writes a new register pair it will be via a move and not an cmp-long operation.
+      return false;
+    }
+    if (intervals.getSplitParent() != intervals) {
+      // This is a split of a parent interval and therefore if this leads to a write of a
+      // register it will be via a move and not an cmp-long operation.
+      return false;
+    }
+    Instruction definition = intervals.getValue().definition;
+    return definition.isCmp() && definition.asCmp().inValues().get(0).outType().isWide();
+  }
+
+  private boolean singleOverlappingLong(int register1, int register2) {
+    return register1 == register2 || register1 == (register2 + 1);
+  }
+
+  // Is one of the cmp-long argument registers the same as the register we are
+  // allocating for the result?
+  private boolean isSingleResultOverlappingLongOperands(LiveIntervals intervals, int register) {
+    assert needsSingleResultOverlappingLongOperandsWorkaround(intervals);
+    Value left = intervals.getValue().definition.asCmp().leftValue();
+    Value right = intervals.getValue().definition.asCmp().rightValue();
+    int leftReg =
+        left.getLiveIntervals().getSplitCovering(intervals.getStart()).getRegister();
+    int rightReg =
+        right.getLiveIntervals().getSplitCovering(intervals.getStart()).getRegister();
+    assert leftReg != NO_REGISTER;
+    assert rightReg != NO_REGISTER;
+    return singleOverlappingLong(register, leftReg) || singleOverlappingLong(register, rightReg);
+  }
+
   // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
   // the first part of the result long before reading the second part of the input longs.
   //
@@ -1099,7 +1141,10 @@
   //
   // Dalvik would add v0 and v2 and write that to v3. It would then read v1 and v3 and produce
   // the wrong result.
-  private boolean needsOverlappingLongRegisterWorkaround(LiveIntervals intervals) {
+  private boolean needsLongResultOverlappingLongOperandsWorkaround(LiveIntervals intervals) {
+    if (!options.canHaveOverlappingLongRegisterBug()) {
+      return false;
+    }
     if (intervals.requiredRegisters() == 1) {
       // Not the live range for a wide value.
       return false;
@@ -1125,8 +1170,14 @@
     return false;
   }
 
-  private boolean hasOverlappingLongRegisters(LiveIntervals unhandledInterval, int register) {
-    assert needsOverlappingLongRegisterWorkaround(unhandledInterval);
+  private boolean longOverlappingLong(int register1, int register2) {
+    return register1 == register2 || register1 == (register2 + 1)
+        || (register1 + 1) == register2 || (register1 + 1) == (register2 + 1);
+  }
+
+  private boolean isLongResultOverlappingLongOperands(
+      LiveIntervals unhandledInterval, int register) {
+    assert needsLongResultOverlappingLongOperandsWorkaround(unhandledInterval);
     Value left = unhandledInterval.getValue().definition.asBinop().leftValue();
     Value right = unhandledInterval.getValue().definition.asBinop().rightValue();
     int leftReg =
@@ -1135,11 +1186,9 @@
         right.getLiveIntervals().getSplitCovering(unhandledInterval.getStart()).getRegister();
     assert leftReg != NO_REGISTER && rightReg != NO_REGISTER;
     // The dalvik bug is actually only for overlap with the second operand, For now we
-    // make sure that there is no overlap with either operand.
-    if ((leftReg + 1) == register || (rightReg + 1) == register) {
-      return true;
-    }
-    return false;
+    // make sure that there is no overlap with either register of either operand. Some vendor
+    // optimization have bees seen to need this more conservative check.
+    return longOverlappingLong(register, leftReg) || longOverlappingLong(register, rightReg);
   }
 
   // Intervals overlap a move exception interval if one of the splits of the intervals does.
@@ -1301,10 +1350,17 @@
     // free position.
     int candidate = getLargestValidCandidate(
         unhandledInterval, registerConstraint, needsRegisterPair, freePositions, Type.ANY);
-    assert candidate != REGISTER_CANDIDATE_NOT_FOUND;
-    int largestFreePosition = freePositions.get(candidate);
-    if (needsRegisterPair) {
-      largestFreePosition = Math.min(largestFreePosition, freePositions.get(candidate + 1));
+
+    // It is not always possible to find a largest valid candidate. If none of the usable register
+    // are free we typically get the last candidate. However, if that candidate has to be
+    // discarded in order to workaround bugs we get REGISTER_CANDIDATE_NOT_FOUND. In both cases
+    // we need to spill a valid candidate. That path is triggered when largestFreePosition is 0.
+    int largestFreePosition = 0;
+    if (candidate != REGISTER_CANDIDATE_NOT_FOUND) {
+      largestFreePosition = freePositions.get(candidate);
+      if (needsRegisterPair) {
+        largestFreePosition = Math.min(largestFreePosition, freePositions.get(candidate + 1));
+      }
     }
 
     // Determine what to do based on how long the selected candidate is free.
@@ -1416,8 +1472,8 @@
       }
       if (freePosition >= unhandledInterval.getEnd()) {
         // Check for overlapping long registers issue.
-        if (needsOverlappingLongRegisterWorkaround(unhandledInterval) &&
-            hasOverlappingLongRegisters(unhandledInterval, register)) {
+        if (needsLongResultOverlappingLongOperandsWorkaround(unhandledInterval) &&
+            isLongResultOverlappingLongOperands(unhandledInterval, register)) {
           return false;
         }
         // Check for aget-wide bug in recent Art VMs.
@@ -1507,42 +1563,47 @@
     return candidate;
   }
 
+  private int handleWorkaround(
+      Predicate<LiveIntervals> workaroundNeeded,
+      BiPredicate<LiveIntervals, Integer> workaroundNeededForCandidate,
+      int candidate, LiveIntervals unhandledInterval, int registerConstraint,
+      boolean needsRegisterPair, RegisterPositions freePositions, RegisterPositions.Type type) {
+    if (workaroundNeeded.test(unhandledInterval)) {
+      int lastCandidate = candidate;
+      while (workaroundNeededForCandidate.test(unhandledInterval, candidate)) {
+        // Make the unusable register unavailable for allocation and try again.
+        freePositions.set(candidate, 0);
+        candidate = getLargestCandidate(registerConstraint, freePositions, needsRegisterPair, type);
+        // If there are only invalid candidates of the give type we will end up with the same
+        // candidate returned again once we have tried them all. In that case we didn't find a
+        // valid register candidate and we need to broaden the search to other types.
+        if (lastCandidate == candidate) {
+          return REGISTER_CANDIDATE_NOT_FOUND;
+        }
+        lastCandidate = candidate;
+      }
+    }
+    return candidate;
+  }
+
   private int getLargestValidCandidate(LiveIntervals unhandledInterval, int registerConstraint,
       boolean needsRegisterPair, RegisterPositions freePositions, RegisterPositions.Type type) {
     int candidate = getLargestCandidate(registerConstraint, freePositions, needsRegisterPair, type);
     if (candidate == REGISTER_CANDIDATE_NOT_FOUND) {
       return candidate;
     }
-    if (needsOverlappingLongRegisterWorkaround(unhandledInterval)) {
-      int lastCandidate = candidate;
-      while (hasOverlappingLongRegisters(unhandledInterval, candidate)) {
-        // Make the overlapping register unavailable for allocation and try again.
-        freePositions.set(candidate, 0);
-        candidate = getLargestCandidate(registerConstraint, freePositions, needsRegisterPair, type);
-        // If there are only invalid candidates of the give type we will end up with the same
-        // candidate returned again once we have tried them all. In that case we didn't find a
-        // valid register candidate and we need to broaden the search to other types.
-        if (lastCandidate == candidate) {
-          return REGISTER_CANDIDATE_NOT_FOUND;
-        }
-        lastCandidate = candidate;
-      }
-    }
-    if (needsArrayGetWideWorkaround(unhandledInterval)) {
-      int lastCandidate = candidate;
-      while (isArrayGetArrayRegister(unhandledInterval, candidate)) {
-        // Make the overlapping register unavailable for allocation and try again.
-        freePositions.set(candidate, 0);
-        candidate = getLargestCandidate(registerConstraint, freePositions, needsRegisterPair, type);
-        // If there are only invalid candidates of the give type we will end up with the same
-        // candidate returned again once we have tried them all. In that case we didn't find a
-        // valid register candidate and we need to broaden the search to other types.
-        if (lastCandidate == candidate) {
-          return REGISTER_CANDIDATE_NOT_FOUND;
-        }
-        lastCandidate = candidate;
-      }
-    }
+    candidate = handleWorkaround(
+        this::needsLongResultOverlappingLongOperandsWorkaround,
+        this::isLongResultOverlappingLongOperands,
+        candidate, unhandledInterval, registerConstraint, needsRegisterPair, freePositions, type);
+    candidate = handleWorkaround(
+        this::needsSingleResultOverlappingLongOperandsWorkaround,
+        this::isSingleResultOverlappingLongOperands,
+        candidate, unhandledInterval, registerConstraint, needsRegisterPair, freePositions, type);
+    candidate = handleWorkaround(
+        this::needsArrayGetWideWorkaround,
+        this::isArrayGetArrayRegister,
+        candidate, unhandledInterval, registerConstraint, needsRegisterPair, freePositions, type);
     return candidate;
   }
 
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 3814e28..5eb2bb7 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -8,23 +8,46 @@
 import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.dex.ApplicationWriter;
 import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexAnnotationElement;
+import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexEncodedAnnotation;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
+import com.android.tools.r8.graph.DexValue.DexValueArray;
+import com.android.tools.r8.graph.DexValue.DexValueEnum;
+import com.android.tools.r8.graph.DexValue.DexValueField;
+import com.android.tools.r8.graph.DexValue.DexValueMethod;
+import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
+import com.android.tools.r8.graph.DexValue.DexValueMethodType;
+import com.android.tools.r8.graph.DexValue.DexValueString;
+import com.android.tools.r8.graph.DexValue.DexValueType;
+import com.android.tools.r8.graph.DexValue.UnknownDexValue;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.ProguardMapSupplier;
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.concurrent.ExecutorService;
+import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
 import org.objectweb.asm.tree.ClassNode;
 import org.objectweb.asm.tree.MethodNode;
 import org.objectweb.asm.util.CheckClassAdapter;
@@ -87,7 +110,7 @@
     int access = clazz.accessFlags.getAsCfAccessFlags();
     String desc = clazz.type.toDescriptorString();
     String name = clazz.type.getInternalName();
-    String signature = null; // TODO(zerny): Support generic signatures.
+    String signature = getSignature(clazz.annotations);
     String superName =
         clazz.type == options.itemFactory.objectType ? null : clazz.superType.getInternalName();
     String[] interfaces = new String[clazz.interfaces.values.length];
@@ -95,6 +118,8 @@
       interfaces[i] = clazz.interfaces.values[i].getInternalName();
     }
     writer.visit(version, access, name, signature, superName, interfaces);
+    writeAnnotations(writer::visitAnnotation, clazz.annotations.annotations);
+    ImmutableMap<DexString, DexValue> defaults = getAnnotationDefaults(clazz.annotations);
 
     if (clazz.getEnclosingMethod() != null) {
       clazz.getEnclosingMethod().write(writer);
@@ -111,10 +136,10 @@
       writeField(field, writer);
     }
     for (DexEncodedMethod method : clazz.directMethods()) {
-      writeMethod(method, writer);
+      writeMethod(method, writer, defaults);
     }
     for (DexEncodedMethod method : clazz.virtualMethods()) {
-      writeMethod(method, writer);
+      writeMethod(method, writer, defaults);
     }
     writer.visitEnd();
 
@@ -132,6 +157,62 @@
         options.reporter, handler -> consumer.accept(result, desc, handler));
   }
 
+  private DexValue getSystemAnnotationValue(DexAnnotationSet annotations, DexType type) {
+    DexAnnotation annotation = annotations.getFirstMatching(type);
+    if (annotation == null) {
+      return null;
+    }
+    assert annotation.visibility == DexAnnotation.VISIBILITY_SYSTEM;
+    DexEncodedAnnotation encodedAnnotation = annotation.annotation;
+    assert encodedAnnotation.elements.length == 1;
+    return encodedAnnotation.elements[0].value;
+  }
+
+  private String getSignature(DexAnnotationSet annotations) {
+    DexValueArray value =
+        (DexValueArray)
+            getSystemAnnotationValue(annotations, application.dexItemFactory.annotationSignature);
+    if (value == null) {
+      return null;
+    }
+    DexValue[] parts = value.getValues();
+    StringBuilder res = new StringBuilder();
+    for (DexValue part : parts) {
+      res.append(((DexValueString) part).getValue().toString());
+    }
+    return res.toString();
+  }
+
+  private ImmutableMap<DexString, DexValue> getAnnotationDefaults(DexAnnotationSet annotations) {
+    DexValueAnnotation value =
+        (DexValueAnnotation)
+            getSystemAnnotationValue(annotations, application.dexItemFactory.annotationDefault);
+    if (value == null) {
+      return ImmutableMap.of();
+    }
+    DexEncodedAnnotation annotation = value.value;
+    Builder<DexString, DexValue> builder = ImmutableMap.builder();
+    for (DexAnnotationElement element : annotation.elements) {
+      builder.put(element.name, element.value);
+    }
+    return builder.build();
+  }
+
+  private String[] getExceptions(DexAnnotationSet annotations) {
+    DexValueArray value =
+        (DexValueArray)
+            getSystemAnnotationValue(annotations, application.dexItemFactory.annotationThrows);
+    if (value == null) {
+      return null;
+    }
+    DexValue[] values = value.getValues();
+    String[] res = new String[values.length];
+    for (int i = 0; i < values.length; i++) {
+      res[i] = ((DexValueType) values[i]).value.getInternalName();
+    }
+    return res;
+  }
+
   private Object getStaticValue(DexEncodedField field) {
     if (!field.accessFlags.isStatic() || field.staticValue == null) {
       return null;
@@ -143,22 +224,110 @@
     int access = field.accessFlags.getAsCfAccessFlags();
     String name = field.field.name.toString();
     String desc = field.field.type.toDescriptorString();
-    String signature = null; // TODO(zerny): Support generic signatures.
+    String signature = getSignature(field.annotations);
     Object value = getStaticValue(field);
-    writer.visitField(access, name, desc, signature, value);
-    // TODO(zerny): Add annotations to the field.
+    FieldVisitor visitor = writer.visitField(access, name, desc, signature, value);
+    writeAnnotations(visitor::visitAnnotation, field.annotations.annotations);
+    visitor.visitEnd();
   }
 
-  private void writeMethod(DexEncodedMethod method, ClassWriter writer) {
+  private void writeMethod(
+      DexEncodedMethod method, ClassWriter writer, ImmutableMap<DexString, DexValue> defaults) {
     int access = method.accessFlags.getAsCfAccessFlags();
     String name = method.method.name.toString();
     String desc = method.descriptor();
-    String signature = null; // TODO(zerny): Support generic signatures.
-    String[] exceptions = null;
+    String signature = getSignature(method.annotations);
+    String[] exceptions = getExceptions(method.annotations);
     MethodVisitor visitor = writer.visitMethod(access, name, desc, signature, exceptions);
+    if (defaults.containsKey(method.method.name)) {
+      AnnotationVisitor defaultVisitor = visitor.visitAnnotationDefault();
+      if (defaultVisitor != null) {
+        writeAnnotationElement(defaultVisitor, null, defaults.get(method.method.name));
+        defaultVisitor.visitEnd();
+      }
+    }
+    writeAnnotations(visitor::visitAnnotation, method.annotations.annotations);
+    for (int i = 0; i < method.parameterAnnotations.values.length; i++) {
+      final int iFinal = i;
+      writeAnnotations(
+          (d, vis) -> visitor.visitParameterAnnotation(iFinal, d, vis),
+          method.parameterAnnotations.values[i].annotations);
+    }
     if (!method.accessFlags.isAbstract() && !method.accessFlags.isNative()) {
       writeCode(method.getCode(), visitor);
     }
+    visitor.visitEnd();
+  }
+
+  private interface AnnotationConsumer {
+    AnnotationVisitor visit(String desc, boolean visible);
+  }
+
+  private void writeAnnotations(AnnotationConsumer visitor, DexAnnotation[] annotations) {
+    for (DexAnnotation dexAnnotation : annotations) {
+      if (dexAnnotation.visibility == DexAnnotation.VISIBILITY_SYSTEM) {
+        // Annotations with VISIBILITY_SYSTEM are not annotations in CF, but are special
+        // annotations in Dex, i.e. default, enclosing class, enclosing method, member classes,
+        // signature, throws.
+        continue;
+      }
+      AnnotationVisitor v =
+          visitor.visit(
+              dexAnnotation.annotation.type.toDescriptorString(),
+              dexAnnotation.visibility == DexAnnotation.VISIBILITY_RUNTIME);
+      if (v != null) {
+        writeAnnotation(v, dexAnnotation.annotation);
+        v.visitEnd();
+      }
+    }
+  }
+
+  private void writeAnnotation(AnnotationVisitor v, DexEncodedAnnotation annotation) {
+    for (DexAnnotationElement element : annotation.elements) {
+      writeAnnotationElement(v, element.name.toString(), element.value);
+    }
+  }
+
+  private void writeAnnotationElement(AnnotationVisitor visitor, String name, DexValue value) {
+    if (value instanceof DexValueAnnotation) {
+      DexValueAnnotation valueAnnotation = (DexValueAnnotation) value;
+      AnnotationVisitor innerVisitor =
+          visitor.visitAnnotation(name, valueAnnotation.value.type.toDescriptorString());
+      if (innerVisitor != null) {
+        writeAnnotation(innerVisitor, valueAnnotation.value);
+        innerVisitor.visitEnd();
+      }
+    } else if (value instanceof DexValueArray) {
+      DexValue[] values = ((DexValueArray) value).getValues();
+      AnnotationVisitor innerVisitor = visitor.visitArray(name);
+      if (innerVisitor != null) {
+        for (DexValue arrayValue : values) {
+          writeAnnotationElement(innerVisitor, null, arrayValue);
+        }
+        innerVisitor.visitEnd();
+      }
+    } else if (value instanceof DexValueEnum) {
+      DexValueEnum en = (DexValueEnum) value;
+      visitor.visitEnum(name, en.value.type.toDescriptorString(), en.value.name.toString());
+    } else if (value instanceof DexValueField) {
+      throw new Unreachable("writeAnnotationElement of DexValueField");
+    } else if (value instanceof DexValueMethod) {
+      throw new Unreachable("writeAnnotationElement of DexValueMethod");
+    } else if (value instanceof DexValueMethodHandle) {
+      throw new Unreachable("writeAnnotationElement of DexValueMethodHandle");
+    } else if (value instanceof DexValueMethodType) {
+      throw new Unreachable("writeAnnotationElement of DexValueMethodType");
+    } else if (value instanceof DexValueString) {
+      DexValueString str = (DexValueString) value;
+      visitor.visit(name, str.getValue().toString());
+    } else if (value instanceof DexValueType) {
+      DexValueType ty = (DexValueType) value;
+      visitor.visit(name, Type.getType(ty.value.toDescriptorString()));
+    } else if (value instanceof UnknownDexValue) {
+      throw new Unreachable("writeAnnotationElement of UnknownDexValue");
+    } else {
+      visitor.visit(name, value.getBoxedValue());
+    }
   }
 
   private void writeCode(Code code, MethodVisitor visitor) {
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
index de21187..5c51786 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
@@ -85,13 +85,13 @@
         addMainDexType(dexType);
         continue;
       }
-      for (DexAnnotation annotation : clazz.annotations.annotations) {
-        if (annotation.visibility == DexAnnotation.VISIBILITY_RUNTIME
+      clazz.forEachAnnotation(annotation -> {
+        if (!mainDexTypes.contains(dexType)
+            && annotation.visibility == DexAnnotation.VISIBILITY_RUNTIME
             && isAnnotationWithEnum(annotation.annotation.type)) {
           addMainDexType(dexType);
-          break;
         }
-      }
+      });
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index b526973..e96de6f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -535,7 +535,7 @@
     private ProguardIfRule parseIfRule(TextPosition optionStart)
         throws ProguardRuleParserException {
       ProguardIfRule.Builder ifRuleBuilder = ProguardIfRule.builder();
-      parseClassSpec(ifRuleBuilder, true);
+      parseClassSpec(ifRuleBuilder, false);
 
       // Required a subsequent keep rule.
       skipWhitespace();
@@ -1086,15 +1086,52 @@
       return Integer.parseInt(s);
     }
 
+    private final Predicate<Character> CLASS_NAME_PREDICATE =
+        character -> IdentifierUtils.isDexIdentifierPart(character)
+            || character == '.'
+            || character == '*'
+            || character == '?'
+            || character == '%'
+            || character == '['
+            || character == ']';
+
     private String acceptClassName() {
-      return acceptString(character ->
-          IdentifierUtils.isDexIdentifierPart(character)
-              || character == '.'
-              || character == '*'
-              || character == '?'
-              || character == '%'
-              || character == '['
-              || character == ']');
+      return acceptString(CLASS_NAME_PREDICATE);
+    }
+
+    private String acceptClassNameWithNthWildcard() {
+      StringBuilder nthWildcard = null;
+      skipWhitespace();
+      int start = position;
+      int end = position;
+      while (!eof(end)) {
+        char current = contents.charAt(end);
+        if (nthWildcard != null) {
+          if (current == '>') {
+            try {
+              Integer.parseUnsignedInt(nthWildcard.toString());
+            } catch (NullPointerException | NumberFormatException e) {
+              return null;
+            }
+            nthWildcard = null;
+          } else {
+            nthWildcard.append(current);
+          }
+          end++;
+        } else if (CLASS_NAME_PREDICATE.test(current)) {
+          end++;
+        } else if (current == '<') {
+          nthWildcard = new StringBuilder();
+          end++;
+        } else {
+          break;
+        }
+      }
+      if (start == end) {
+        return null;
+      }
+      position = end;
+      return contents.substring(start, end);
     }
 
     private String acceptFieldNameOrIntegerForReturn() {
@@ -1194,7 +1231,7 @@
     }
 
     private String parseClassName() throws ProguardRuleParserException {
-      String name = acceptClassName();
+      String name = acceptClassNameWithNthWildcard();
       if (name == null) {
         throw parseError("Class name expected");
       }
diff --git a/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java b/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
index 46669ec..c37102c 100644
--- a/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLitePruner.java
@@ -348,7 +348,6 @@
     // the fallthrough label. This can introduce critical edges. Therefore, we split critical
     // edges to maintain our edge-split form.
     code.splitCriticalEdges();
-    code.traceBlocks();
     assert code.isConsistentSSA();
   }
 
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 3414d43..1073cf9 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -501,4 +501,17 @@
   public boolean canHaveThisTypeVerifierBug() {
     return minApiLevel < AndroidApiLevel.M.getLevel();
   }
+
+  // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
+  // the first part of the result long before reading the second part of the input longs.
+  public boolean canHaveOverlappingLongRegisterBug() {
+    return minApiLevel < AndroidApiLevel.L.getLevel();
+  }
+
+  // Some dalvik versions found in the wild perform invalid JIT compilation of cmp-long
+  // instructions where the result register overlaps with the input registers.
+  // See b/74084493.
+  public boolean canHaveCmpLongBug() {
+    return minApiLevel < AndroidApiLevel.L.getLevel();
+  }
 }
diff --git a/src/test/examples/multidex002/AnnotatedDirectMethod.java b/src/test/examples/multidex002/AnnotatedDirectMethod.java
new file mode 100644
index 0000000..761ea9a
--- /dev/null
+++ b/src/test/examples/multidex002/AnnotatedDirectMethod.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex002;
+
+public class AnnotatedDirectMethod {
+
+  @AnnotationWithEnum3(AnnotationWithEnum3.Value3.VAL3_2)
+  private void foo() {
+  }
+}
diff --git a/src/test/examples/multidex002/AnnotatedInstanceField.java b/src/test/examples/multidex002/AnnotatedInstanceField.java
new file mode 100644
index 0000000..0209f44
--- /dev/null
+++ b/src/test/examples/multidex002/AnnotatedInstanceField.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex002;
+
+public class AnnotatedInstanceField {
+
+  @AnnotationWithEnum3(AnnotationWithEnum3.Value3.VAL3_2)
+  public String value = "myValue";
+}
diff --git a/src/test/examples/multidex002/AnnotatedMethodParameter.java b/src/test/examples/multidex002/AnnotatedMethodParameter.java
new file mode 100644
index 0000000..49a9e6d
--- /dev/null
+++ b/src/test/examples/multidex002/AnnotatedMethodParameter.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex002;
+
+public class AnnotatedMethodParameter {
+
+  public void foo(@AnnotationWithEnum3(AnnotationWithEnum3.Value3.VAL3_2) String val) {
+  }
+}
diff --git a/src/test/examples/multidex002/AnnotatedNotKept.java b/src/test/examples/multidex002/AnnotatedNotKept.java
new file mode 100644
index 0000000..500e7f0
--- /dev/null
+++ b/src/test/examples/multidex002/AnnotatedNotKept.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex002;
+
+@AnnotationWithoutEnum
+public class AnnotatedNotKept {
+
+}
diff --git a/src/test/examples/multidex002/AnnotatedStaticField.java b/src/test/examples/multidex002/AnnotatedStaticField.java
new file mode 100644
index 0000000..385d1d9
--- /dev/null
+++ b/src/test/examples/multidex002/AnnotatedStaticField.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex002;
+
+public class AnnotatedStaticField {
+  @AnnotationWithEnum3(AnnotationWithEnum3.Value3.VAL3_2) public static String sValue = "myValue";
+}
diff --git a/src/test/examples/multidex002/AnnotatedVirtualMethod.java b/src/test/examples/multidex002/AnnotatedVirtualMethod.java
new file mode 100644
index 0000000..569bf84
--- /dev/null
+++ b/src/test/examples/multidex002/AnnotatedVirtualMethod.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex002;
+
+public class AnnotatedVirtualMethod {
+
+  @AnnotationWithEnum3(AnnotationWithEnum3.Value3.VAL3_2)
+  public void foo() {
+
+  }
+}
diff --git a/src/test/examples/multidex002/AnnotationWithEnum3.java b/src/test/examples/multidex002/AnnotationWithEnum3.java
new file mode 100644
index 0000000..a8f8344
--- /dev/null
+++ b/src/test/examples/multidex002/AnnotationWithEnum3.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex002;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnnotationWithEnum3 {
+
+  enum Value3 {
+    VAL3_1,
+    VAL3_2,
+  }
+
+  Value3 value();
+}
diff --git a/src/test/examples/multidex002/AnnotationWithoutEnum.java b/src/test/examples/multidex002/AnnotationWithoutEnum.java
new file mode 100644
index 0000000..5244971
--- /dev/null
+++ b/src/test/examples/multidex002/AnnotationWithoutEnum.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex002;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnnotationWithoutEnum {
+
+}
diff --git a/src/test/examples/multidex002/ref-list-1.txt b/src/test/examples/multidex002/ref-list-1.txt
index 26dae34..922d417 100644
--- a/src/test/examples/multidex002/ref-list-1.txt
+++ b/src/test/examples/multidex002/ref-list-1.txt
@@ -1,8 +1,15 @@
 Lmultidex002/Annotated2;
 Lmultidex002/Annotated;
+Lmultidex002/AnnotatedDirectMethod;
+Lmultidex002/AnnotatedInstanceField;
+Lmultidex002/AnnotatedMethodParameter;
+Lmultidex002/AnnotatedStaticField;
+Lmultidex002/AnnotatedVirtualMethod;
 Lmultidex002/AnnotationWithClass;
 Lmultidex002/AnnotationWithEnum2;
+Lmultidex002/AnnotationWithEnum3;
 Lmultidex002/AnnotationWithEnum;
+Lmultidex002/AnnotationWithoutEnum;
 Lmultidex002/InterfaceWithEnum;
 Lmultidex002/IntermediateClass;
 Lmultidex002/MainActivity;
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index 8ff72c7..c4351ce 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -4542,7 +4542,7 @@
           // java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/util/concurrent/PriorityBlockingQueue/serialization/PriorityBlockingQueue_serialization_A01.golden.0.ser
 
           .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A01",
-              match(D8_COMPILER, runtimesUpTo(Version.V6_0_1)))
+              match(runtimesUpTo(Version.V6_0_1)))
           // 1) t02
           // java.lang.IllegalThreadStateException: Thread group still contains threads: Test group
           // 2) t04
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index d1bed68..ba036dd 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -128,7 +128,6 @@
   @Override
   protected Map<String, TestCondition> getFailingRunCf() {
     return new ImmutableMap.Builder<String, TestCondition>()
-        .put("floating_point_annotations.FloatingPointValuedAnnotationTest", match(R8_COMPILER))
         .build();
   }
 
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 0c0cd84..1e07b94 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -91,7 +91,7 @@
   private static final AndroidApiLevel DEFAULT_MIN_SDK = AndroidApiLevel.I;
 
   private static final String PROGUARD5_2_1 = "third_party/proguard/proguard5.2.1/bin/proguard.sh";
-  private static final String PROGUARD6_0 = "third_party/proguard/proguard6.0/bin/proguard.sh";
+  private static final String PROGUARD6_0_1 = "third_party/proguard/proguard6.0.1/bin/proguard.sh";
   private static final String PROGUARD = PROGUARD5_2_1;
 
   public enum DexVm {
diff --git a/src/test/java/com/android/tools/r8/cf/AnnotationTest.java b/src/test/java/com/android/tools/r8/cf/AnnotationTest.java
new file mode 100644
index 0000000..d586bb2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/AnnotationTest.java
@@ -0,0 +1,46 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf;
+
+import java.lang.annotation.Annotation;
+
+public class AnnotationTest {
+  // @Deprecated is a runtime-visible annotation.
+  @Deprecated public static boolean foo = true;
+
+  @Deprecated
+  public static boolean bar() {
+    return true;
+  }
+
+  public static void main(String[] args) {
+    try {
+      testField();
+      testMethod();
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private static void testField() throws Exception {
+    checkDeprecated("field 'foo'", AnnotationTest.class.getDeclaredField("foo").getAnnotations());
+  }
+
+  private static void testMethod() throws Exception {
+    checkDeprecated("method 'bar'", AnnotationTest.class.getMethod("bar").getAnnotations());
+  }
+
+  private static void checkDeprecated(String what, Annotation[] annotations) {
+    Annotation n;
+    try {
+      n = annotations[0];
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new RuntimeException(what + ": No annotations, expected @Deprecated", e);
+    }
+    if (!(n instanceof Deprecated)) {
+      throw new RuntimeException(what + ": Expected @Deprecated, got: " + n);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/AnnotationTestRunner.java b/src/test/java/com/android/tools/r8/cf/AnnotationTestRunner.java
new file mode 100644
index 0000000..5c48073
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/AnnotationTestRunner.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.cf;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.ClassFileConsumer.DirectoryConsumer;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.origin.Origin;
+import java.nio.file.Path;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class AnnotationTestRunner {
+  static final Class CLASS = AnnotationTest.class;
+  @Rule public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+
+  @Test
+  @Ignore
+  public void test() throws Exception {
+    ProcessResult runInput =
+        ToolHelper.runJava(ToolHelper.getClassPathForTests(), CLASS.getCanonicalName());
+    assertEquals(0, runInput.exitCode);
+    Path out = temp.getRoot().toPath();
+    R8.run(
+        R8Command.builder()
+            .setMode(CompilationMode.DEBUG)
+            .addClassProgramData(ToolHelper.getClassAsBytes(CLASS), Origin.unknown())
+            .addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm()))
+            .setProgramConsumer(new DirectoryConsumer(out))
+            .build());
+    ProcessResult runOutput = ToolHelper.runJava(out, CLASS.getCanonicalName());
+    assertEquals(runInput.toString(), runOutput.toString());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 5f6a5cc..84f6a08 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -37,6 +37,7 @@
 import java.util.Collections;
 import java.util.List;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 public class ProguardConfigurationParserTest extends TestBase {
@@ -544,7 +545,7 @@
     assertTrue(
         config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
     assertTrue(
-        config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
+        config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobar;")));
     assertTrue(
         config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;")));
   }
@@ -561,12 +562,47 @@
     assertTrue(
         config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
     assertTrue(
-        config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
+        config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobar;")));
     assertTrue(
         config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;")));
   }
 
   @Test
+  public void testAdaptClassStringsNthWildcard() throws Exception {
+    DexItemFactory dexItemFactory = new DexItemFactory();
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(dexItemFactory, reporter);
+    String wildcard = "-adaptclassstrings *foo<1>";
+    parser.parse(createConfigurationForTesting(ImmutableList.of(wildcard)));
+    verifyParserEndsCleanly();
+    ProguardConfiguration config = parser.getConfig();
+    assertFalse(
+        config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;")));
+    assertFalse(
+        config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboofoobar;")));
+    // TODO(b/73800755): Use <n> while matching class name list.
+    //assertTrue(
+    //    config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboofooboo;")));
+  }
+
+  @Ignore("b/73800755: verify the range of <n>")
+  @Test
+  public void testAdaptClassStringsNthWildcard_outOfRange() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-adaptclassstrings *foo<2>"
+    );
+    try {
+      ProguardConfigurationParser parser =
+          new ProguardConfigurationParser(new DexItemFactory(), reporter);
+      parser.parse(proguardConfig);
+      fail();
+    } catch (AbortException e) {
+      checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+          "wildcard", "out", "range");
+    }
+  }
+
+  @Test
   public void testIdentifierNameString() throws Exception {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
@@ -1173,6 +1209,43 @@
   }
 
   @Test
+  public void parse_if_nthWildcard() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-if class **$R**",
+        "-keep class **$D<2>"  // <2> corresponds to the 2nd ** in -if rule.
+    );
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(proguardConfig);
+    checkDiagnostic(handler.warnings, proguardConfig, 1, 1,
+        "Ignoring", "-if");
+    ProguardConfiguration config = parser.getConfig();
+    assertEquals(1, config.getRules().size());
+    ProguardIfRule if0 = (ProguardIfRule) config.getRules().get(0);
+    assertEquals("**$R**", if0.getClassNames().toString());
+    assertEquals(ProguardKeepRuleType.KEEP, if0.subsequentRule.getType());
+    assertEquals("**$D<2>", if0.subsequentRule.getClassNames().toString());
+  }
+
+  @Ignore("b/73800755: verify the range of <n>")
+  @Test
+  public void parse_if_nthWildcard_outOfRange() throws Exception {
+    Path proguardConfig = writeTextToTempFile(
+        "-if class **$R**",
+        "-keep class **D<4>"  // There are 3 ** in this rule.
+    );
+    try {
+      ProguardConfigurationParser parser =
+          new ProguardConfigurationParser(new DexItemFactory(), reporter);
+      parser.parse(proguardConfig);
+      fail();
+    } catch (AbortException e) {
+      checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+          "wildcard", "out", "range");
+    }
+  }
+
+  @Test
   public void parse_if_if() throws Exception {
     Path proguardConfig = writeTextToTempFile(
         "-if   class **$$ModuleAdapter",
diff --git a/third_party/kotlin.tar.gz.sha1 b/third_party/kotlin.tar.gz.sha1
index e55712d..40f26fa 100644
--- a/third_party/kotlin.tar.gz.sha1
+++ b/third_party/kotlin.tar.gz.sha1
@@ -1 +1 @@
-6dc49791e5fcf4318ae5246eacc73718180508ce
\ No newline at end of file
+4b18d827485f53990ad47b81db2a025abaa325d1
\ No newline at end of file
diff --git a/third_party/proguard/README.google b/third_party/proguard/README.google
index 4f85601..abe0568 100644
--- a/third_party/proguard/README.google
+++ b/third_party/proguard/README.google
@@ -1,8 +1,8 @@
 URL: https://sourceforge.net/projects/proguard/files/proguard/5.2/
 URL: https://sourceforge.net/projects/proguard/files/proguard/6.0/
-Version: 5.2.1, 6.0
+Version: 5.2.1, 6.0.1
 License: GPL
-License File: proguard5.2.1/docs/license.html, proguard6.0/docs/license.html
+License File: proguard5.2.1/docs/license.html, proguard6.0.1/docs/license.html
 
 Description:
 ProGuard Java Optimizer and Obfuscator
diff --git a/third_party/proguard/proguard6.0.1.tar.gz.sha1 b/third_party/proguard/proguard6.0.1.tar.gz.sha1
new file mode 100644
index 0000000..e5e8e3c
--- /dev/null
+++ b/third_party/proguard/proguard6.0.1.tar.gz.sha1
@@ -0,0 +1 @@
+ef075c414299327dae5f96cce539422dc9088946
\ No newline at end of file
diff --git a/third_party/proguard/proguard6.0.tar.gz.sha1 b/third_party/proguard/proguard6.0.tar.gz.sha1
deleted file mode 100644
index 4596bc8..0000000
--- a/third_party/proguard/proguard6.0.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-57d0702f38196c81ff506d2e34a4a5569c3af583
\ No newline at end of file