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',