Merge "Avoid to compute dominator tree when is not useful"
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 3639d9e..210a632 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.2.8-dev";
+  public static final String LABEL = "v1.2.9-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/benchmarks/IncrementalDexingBenchmark.java b/src/main/java/com/android/tools/r8/benchmarks/IncrementalDexingBenchmark.java
index fec86c5..0aaefd9 100644
--- a/src/main/java/com/android/tools/r8/benchmarks/IncrementalDexingBenchmark.java
+++ b/src/main/java/com/android/tools/r8/benchmarks/IncrementalDexingBenchmark.java
@@ -25,6 +25,7 @@
         D8Command.builder()
             .addProgramFiles(Paths.get("build/test/examples/arithmetic.jar"))
             .setMode(CompilationMode.DEBUG)
+            .setDisableDesugaring(true)
             .setProgramConsumer(
                 new DexIndexedConsumer.ForwardingConsumer(null) {
                   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
index f587642..0111aa1 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
@@ -141,6 +141,10 @@
     set(Constants.ACC_ANNOTATION);
   }
 
+  public void unsetAnnotation() {
+    unset(Constants.ACC_ANNOTATION);
+  }
+
   public boolean isEnum() {
     return isSet(Constants.ACC_ENUM);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 06e72a3..d762340 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -74,7 +74,7 @@
       DexAnnotation annotation, DexItemFactory factory) {
     DexValueType typeValue =
         (DexValueType) getSystemValueAnnotationValue(factory.annotationEnclosingClass, annotation);
-    return typeValue.value;
+    return typeValue == null ? null : typeValue.value;
   }
 
   public static DexAnnotation createEnclosingMethodAnnotation(DexMethod enclosingMethod,
@@ -88,7 +88,7 @@
     DexValueMethod methodValue =
         (DexValueMethod)
             getSystemValueAnnotationValue(factory.annotationEnclosingMethod, annotation);
-    return methodValue.value;
+    return methodValue == null ? null : methodValue.value;
   }
 
   public static boolean isEnclosingClassAnnotation(DexAnnotation annotation,
@@ -157,6 +157,9 @@
       DexAnnotation annotation, DexItemFactory factory) {
     DexValueArray membersArray =
         (DexValueArray) getSystemValueAnnotationValue(factory.annotationMemberClasses, annotation);
+    if (membersArray == null) {
+      return null;
+    }
     List<DexType> types = new ArrayList<>(membersArray.getValues().length);
     for (DexValue value : membersArray.getValues()) {
       types.add(((DexValueType) value).value);
@@ -228,7 +231,9 @@
   private static DexValue getSystemValueAnnotationValue(DexType type, DexAnnotation annotation) {
     assert annotation.visibility == VISIBILITY_SYSTEM;
     assert annotation.annotation.type == type;
-    return annotation.annotation.elements[0].value;
+    return annotation.annotation.elements.length == 0
+        ? null
+        : annotation.annotation.elements[0].value;
   }
 
   public static boolean isThrowingAnnotation(DexAnnotation annotation,
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..d437da3 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;
@@ -26,6 +27,15 @@
 
 public class IRCode {
 
+  // Stack marker to denote when all successors of a block have been processed when topologically
+  // sorting.
+  private static class BlockMarker {
+    final BasicBlock block;
+    BlockMarker(BasicBlock block) {
+      this.block = block;
+    }
+  }
+
   // When numbering instructions we number instructions only with even numbers. This allows us to
   // use odd instruction numbers for the insertion of moves during spilling.
   public static final int INSTRUCTION_NUMBER_DELTA = 2;
@@ -252,25 +262,37 @@
    * 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() {
+    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;
       }
-      builder.add(block);
+      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.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 15a90e9..898a2b2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -151,6 +151,7 @@
     ClassAccessFlags companionClassFlags = iface.accessFlags.copy();
     companionClassFlags.unsetAbstract();
     companionClassFlags.unsetInterface();
+    companionClassFlags.unsetAnnotation();
     companionClassFlags.setFinal();
     companionClassFlags.setSynthetic();
     // Companion class must be public so moved methods can be called from anywhere.
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 31eb337..87a5f83 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
@@ -131,9 +131,7 @@
   // The set of registers that are free for allocation.
   private TreeSet<Integer> freeRegisters = new TreeSet<>();
   // The max register number used.
-  private int maxRegisterNumber = 0;
-  // The next available register number not yet included in the set of used registers.
-  private int nextUnusedRegisterNumber = 0;
+  private int maxRegisterNumber = -1;
 
   // List of all top-level live intervals for all SSA values.
   private List<LiveIntervals> liveIntervals = new ArrayList<>();
@@ -164,6 +162,10 @@
         RESERVED_MOVE_EXCEPTION_REGISTER;
   }
 
+  private int getNextUnusedRegisterNumber() {
+    return maxRegisterNumber + 1;
+  }
+
   public LinearScanRegisterAllocator(IRCode code, InternalOptions options) {
     this.code = code;
     this.options = options;
@@ -677,8 +679,7 @@
 
   private void clearRegisterAssignments() {
     freeRegisters.clear();
-    maxRegisterNumber = 0;
-    nextUnusedRegisterNumber = 0;
+    maxRegisterNumber = -1;
     active.clear();
     inactive.clear();
     unhandled.clear();
@@ -928,7 +929,7 @@
         if (destIntervals.getRegister() == NO_REGISTER) {
           // Save the current register allocation state so we can restore it at the end.
           TreeSet<Integer> savedFreeRegisters = new TreeSet<>(freeRegisters);
-          int savedUnusedRegisterNumber = nextUnusedRegisterNumber;
+          int savedUnusedRegisterNumber = getNextUnusedRegisterNumber();
           List<LiveIntervals> savedActive = new LinkedList<>(active);
           List<LiveIntervals> savedInactive = new LinkedList<>(inactive);
 
@@ -956,7 +957,7 @@
           allocateLinkedIntervals(destIntervals);
           // Restore the register allocation state.
           freeRegisters = savedFreeRegisters;
-          for (int i = savedUnusedRegisterNumber; i < nextUnusedRegisterNumber; i++) {
+          for (int i = savedUnusedRegisterNumber, j = getNextUnusedRegisterNumber(); i < j; i++) {
             freeRegisters.add(i);
           }
           active = savedActive;
@@ -1033,17 +1034,13 @@
   // Update the information about used registers when |register| has been selected for use.
   private void updateRegisterState(int register, boolean needsRegisterPair) {
     int maxRegister = register + (needsRegisterPair ? 1 : 0);
-    if (maxRegister >= nextUnusedRegisterNumber) {
-      nextUnusedRegisterNumber = maxRegister + 1;
-    }
     maxRegisterNumber = Math.max(maxRegisterNumber, maxRegister);
   }
 
   private int getSpillRegister(LiveIntervals intervals) {
-    int registerNumber = nextUnusedRegisterNumber++;
+    int registerNumber = getNextUnusedRegisterNumber();
     maxRegisterNumber = registerNumber;
     if (intervals.getType().isWide()) {
-      nextUnusedRegisterNumber++;
       maxRegisterNumber++;
     }
     return registerNumber;
@@ -2176,22 +2173,7 @@
             if (options.isGeneratingDex()) {
               int inConstraint = instruction.maxInValueRegister();
               LiveIntervals useIntervals = use.getLiveIntervals();
-              // Arguments are always kept in their original, incoming register. For every
-              // unconstrained use of an argument we therefore use its incoming register.
-              // As a result, we do not need to record that the argument is being used at the
-              // current instruction.
-              //
-              // For ranged invoke instructions that use a subset of the arguments in the current
-              // order, registering a use for the arguments at the invoke can cause us to run out of
-              // registers. That is because all arguments are forced back into a chosen register at
-              // all uses. Therefore, if we register a use of an argument where we can actually use
-              // it in the argument register, the register allocator would use two registers for the
-              // argument but in reality only use one.
-              boolean isUnconstrainedArgumentUse =
-                  use.isArgument() && inConstraint == Constants.U16BIT_MAX;
-              if (!isUnconstrainedArgumentUse) {
-                useIntervals.addUse(new LiveIntervalsUse(instruction.getNumber(), inConstraint));
-              }
+              useIntervals.addUse(new LiveIntervalsUse(instruction.getNumber(), inConstraint));
             }
           }
         }
@@ -2388,7 +2370,6 @@
       }
     }
     freeRegisters.addAll(unused);
-    maxRegisterNumber = Math.max(maxRegisterNumber, first + numberOfRegister - 1);
     return first;
   }
 
@@ -2396,7 +2377,8 @@
     if (freeRegisters.size() > 0) {
       return freeRegisters.pollFirst();
     }
-    return nextUnusedRegisterNumber++;
+    maxRegisterNumber = getNextUnusedRegisterNumber();
+    return maxRegisterNumber;
   }
 
   private void excludeRegistersForInterval(LiveIntervals intervals, Set<Integer> excluded) {
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/B77240639.java b/src/test/java/com/android/tools/r8/ir/regalloc/B77240639.java
index 28a6fa3..440f4f3 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/B77240639.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/B77240639.java
@@ -16,6 +16,7 @@
 import org.junit.Test;
 
 public class B77240639 extends TestBase {
+  @Ignore("b/77240639")
   @Test
   public void test() throws Exception {
     AndroidApp app = compileWithD8(readClasses(TestClass.class));
diff --git a/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java b/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
new file mode 100644
index 0000000..033183c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
@@ -0,0 +1,42 @@
+// 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 com.android.tools.r8.jasmin;
+
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DexInspector;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class AnnotationCompanionClassTest extends JasminTestBase {
+
+  private JasminBuilder buildClass() {
+    JasminBuilder builder = new JasminBuilder(JasminBuilder.ClassFileVersion.JDK_1_4);
+    JasminBuilder.ClassBuilder clazz =
+        builder.addInterface("MyAnnotation", "java/lang/annotation/Annotation");
+
+    clazz.setAccess("public interface abstract annotation");
+
+    clazz.addStaticMethod(
+        "staticMethod", ImmutableList.of(), "V",
+        ".limit stack 0",
+        ".limit locals 0",
+        "  return");
+    return builder;
+  }
+
+  @Test
+  public void test() throws Exception {
+    JasminBuilder builder = buildClass();
+    AndroidApp androidApp = compileWithD8(builder);
+
+    DexInspector dexInspector = new DexInspector(androidApp);
+    assertFalse(
+        dexInspector
+            .clazz("LMyAnnotation" + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX + ";")
+            .isAnnotation());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/DexInspector.java b/src/test/java/com/android/tools/r8/utils/DexInspector.java
index af460ef..0cea762 100644
--- a/src/test/java/com/android/tools/r8/utils/DexInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/DexInspector.java
@@ -329,6 +329,8 @@
 
     public abstract boolean isAbstract();
 
+    public abstract boolean isAnnotation();
+
     public String dumpMethods() {
       StringBuilder dump = new StringBuilder();
       forAllMethods((FoundMethodSubject method) ->
@@ -385,6 +387,11 @@
     }
 
     @Override
+    public boolean isAnnotation() {
+      return false;
+    }
+
+    @Override
     public DexClass getDexClass() {
       return null;
     }
@@ -516,6 +523,11 @@
       return dexClass.accessFlags.isAbstract();
     }
 
+    @Override
+    public boolean isAnnotation() {
+      return dexClass.accessFlags.isAnnotation();
+    }
+
     private DexEncodedField findField(DexEncodedField[] fields, DexField dexField) {
       for (DexEncodedField field : fields) {
         if (field.field.equals(dexField)) {
diff --git a/tools/test_gradle_benchmarks.py b/tools/test_gradle_benchmarks.py
index 189b9da..608c055 100755
--- a/tools/test_gradle_benchmarks.py
+++ b/tools/test_gradle_benchmarks.py
@@ -43,16 +43,18 @@
   cleanCommand = ""
   env = {}
 
-  def __init__(self, displayName, benchmarkDir, moduleName, buildCommand, cleanCommand):
+  def __init__(self, displayName, benchmarkDir, moduleName, buildCommand,
+               cleanCommand):
     self.displayName = displayName
-    self.rootDirPath = os.path.join(BENCHMARKS_ROOT_DIR, benchmarkDir.split(os.sep)[0])
+    self.rootDirPath = os.path.join(BENCHMARKS_ROOT_DIR,
+                                    benchmarkDir.split(os.sep)[0])
     self.appPath = os.path.join(BENCHMARKS_ROOT_DIR, benchmarkDir)
     self.moduleName = moduleName
     self.buildCommand = buildCommand
     self.cleanCommand = cleanCommand
     self.env = os.environ.copy()
-    self.env["ANDROID_HOME"] = os.path.join(utils.REPO_ROOT, 'third_party', 'benchmarks',
-                                            'android-sdk')
+    self.env["ANDROID_HOME"] = os.path.join(utils.REPO_ROOT, 'third_party',
+                                            'benchmarks', 'android-sdk')
 
   def RunGradle(self, command, tool, desugarMode):
 
@@ -82,7 +84,9 @@
 
   def Clean(self):
     # tools and desugar mode not relevant for clean
-    return self.RunGradle(self.cleanCommand, self.Tools.D8, self.DesugarMode.D8_DESUGARING)
+    return self.RunGradle(self.cleanCommand,
+                          self.Tools.D8,
+                          self.DesugarMode.D8_DESUGARING)
 
   def EnsurePresence(self):
     EnsurePresence(self.rootDirPath, self.displayName)
@@ -123,17 +127,25 @@
       taskName = commaSplit[1][(len(benchmark.moduleName) + 1):]
 
       # Just a temporary assumption.
-      # This means we have submodules, so we'll need to check their configuration
-      # so that the right r8/d8 is taken. For now it shouldn't be the case.
+      # This means we have submodules, so we'll need to check their
+      # configuration so that the right r8/d8 is taken. For now it shouldn't
+      # be the case.
       assert taskName.find(':') == -1, taskName
 
-      # Output example:
-      # SantaTracker-transformClassesWithDexBuilderForDevelopmentDebug(RunTimeRaw): 748 ms
-
-      golemBenchmarkValue = benchmark.displayName + '-' + taskName + '(RunTimeRaw): '
       if TaskFilter(taskName):
-        print('{}(RunTimeRaw): {} ms'
-              .format(benchmark.displayName + '-' + taskName, commaSplit[2]))
+        # taskName looks like:
+        #  transformClassesWithDexBuilderForDevelopmentDebug
+        # we don't want unimportant information in UI, so we strip it down to:
+        #  ClassesDexBuilderDevelopment
+        # Output example:
+        # SantaTracker-ClassesDexBuilderDevelopment(RunTimeRaw): 748 ms
+        assert taskName.startswith('transform')
+        taskName = taskName[len('transform'):]
+        taskName = taskName.replace('With', '')
+        taskName = taskName.replace('For', '')
+        taskName = taskName.replace('Default', '')
+        benchmarkName = benchmark.displayName + '-' + taskName
+        print('{}(RunTimeRaw): {} ms'.format(benchmarkName, commaSplit[2]))
 
 def Main():
   args = parse_arguments()
@@ -154,17 +166,20 @@
     Benchmark('Maps',
               'gradle-java-1.6',
               ':maps',
-              [':maps:assembleDebug', '--settings-file', 'settings.gradle.maps'],
+              [':maps:assembleDebug', '--settings-file',
+               'settings.gradle.maps'],
               ['clean']),
     Benchmark('Music2',
               'gradle-java-1.6',
               ':music2Old',
-              [':music2Old:assembleDebug', '--settings-file', 'settings.gradle.music2Old'],
+              [':music2Old:assembleDebug', '--settings-file',
+               'settings.gradle.music2Old'],
               ['clean']),
     Benchmark('Velvet',
               'gradle-java-1.6',
               ':velvet',
-              [':velvet:assembleDebug', '--settings-file', 'settings.gradle.velvet'],
+              [':velvet:assembleDebug', '--settings-file',
+               'settings.gradle.velvet'],
               ['clean']),
     Benchmark('SantaTracker',
               'santa-tracker',