Merge "Shorten names of gradle benchmarks"
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index eb6718d..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.7-dev";
+  public static final String LABEL = "v1.2.9-dev";
 
   private Version() {
   }
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/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 1e010ce..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;
@@ -2373,7 +2370,6 @@
       }
     }
     freeRegisters.addAll(unused);
-    maxRegisterNumber = Math.max(maxRegisterNumber, first + numberOfRegister - 1);
     return first;
   }
 
@@ -2381,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/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 a32b2a5..608c055 100755
--- a/tools/test_gradle_benchmarks.py
+++ b/tools/test_gradle_benchmarks.py
@@ -3,7 +3,6 @@
 # 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.
 
-
 from __future__ import print_function
 import argparse
 import os
@@ -12,7 +11,6 @@
 import gradle
 from enum import Enum
 
-
 BENCHMARKS_ROOT_DIR = os.path.join(utils.REPO_ROOT, 'third_party', 'benchmarks')
 
 def parse_arguments():
@@ -24,9 +22,10 @@
                       choices=['dx', 'd8'],
                       required=True,
                       help='Compiler tool to use.')
+  parser.add_argument('--benchmark',
+                      help='Which benchmark to run, default all')
   return parser.parse_args()
 
-
 class Benchmark:
   class Tools(Enum):
     D8 = 1
@@ -92,7 +91,6 @@
   def EnsurePresence(self):
     EnsurePresence(self.rootDirPath, self.displayName)
 
-
 def EnsurePresence(dir, displayName):
   if not os.path.exists(dir) or os.path.getmtime(dir + '.tar.gz')\
           < os.path.getmtime(dir + '.tar.gz.sha1'):
@@ -115,7 +113,6 @@
 
   return any(namePattern in taskname for namePattern in acceptedGradleTasks)
 
-
 def PrintBuildTimeForGolem(benchmark, stdOut):
   for line in stdOut.splitlines():
     if 'BENCH' in line and benchmark.moduleName in line:
@@ -150,7 +147,6 @@
         benchmarkName = benchmark.displayName + '-' + taskName
         print('{}(RunTimeRaw): {} ms'.format(benchmarkName, commaSplit[2]))
 
-
 def Main():
   args = parse_arguments()
 
@@ -206,10 +202,16 @@
 
   ]
 
-  EnsurePresence(os.path.join('third_party', 'benchmarks', 'android-sdk'), 'android SDK')
-  EnsurePresence(os.path.join('third_party', 'gradle-plugin'), 'Android Gradle plugin')
-
-  for benchmark in buildTimeBenchmarks:
+  EnsurePresence(os.path.join('third_party', 'benchmarks', 'android-sdk'),
+                 'android SDK')
+  EnsurePresence(os.path.join('third_party', 'gradle-plugin'),
+                 'Android Gradle plugin')
+  toRun = buildTimeBenchmarks
+  if args.benchmark:
+    toRun = [b for b in toRun if b.displayName == args.benchmark]
+    if len(toRun) != 1:
+      raise AssertionError("Unknown benchmark: " + args.benchmark)
+  for benchmark in toRun:
     benchmark.EnsurePresence()
     benchmark.Clean()
     stdOut = benchmark.Build(tool, desugarMode)