Merge "Do not shared too much constants in dominator block of usages"
diff --git a/src/main/java/com/android/tools/r8/BaseCommand.java b/src/main/java/com/android/tools/r8/BaseCommand.java
index 85c430a..aa0e396 100644
--- a/src/main/java/com/android/tools/r8/BaseCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCommand.java
@@ -22,6 +22,7 @@
private final OutputMode outputMode;
private final CompilationMode mode;
private final int minApiLevel;
+ private final boolean overwriteOutputs;
BaseCommand(boolean printHelp, boolean printVersion) {
this.printHelp = printHelp;
@@ -32,10 +33,11 @@
this.outputMode = OutputMode.Indexed;
this.mode = null;
this.minApiLevel = 0;
+ this.overwriteOutputs = true;
}
BaseCommand(AndroidApp app, Path outputPath,
- OutputMode outputMode, CompilationMode mode, int minApiLevel) {
+ OutputMode outputMode, CompilationMode mode, int minApiLevel, boolean overwriteOutputs) {
assert app != null;
assert mode != null;
assert minApiLevel > 0;
@@ -44,6 +46,7 @@
this.outputMode = outputMode;
this.mode = mode;
this.minApiLevel = minApiLevel;
+ this.overwriteOutputs = overwriteOutputs;
// Print options are not set.
printHelp = false;
printVersion = false;
@@ -81,6 +84,10 @@
return outputMode;
}
+ public boolean isOverwriteOutputs() {
+ return overwriteOutputs;
+ }
+
abstract static class Builder<C extends BaseCommand, B extends Builder<C, B>> {
private boolean printHelp = false;
@@ -90,6 +97,7 @@
private OutputMode outputMode = OutputMode.Indexed;
private CompilationMode mode;
private int minApiLevel = Constants.DEFAULT_ANDROID_API;
+ private boolean overwriteOutputs = true;
protected Builder(CompilationMode mode) {
this(AndroidApp.builder(), mode);
@@ -197,9 +205,9 @@
return outputMode;
}
- /** Set an output path. Must be an existing directory or a non-existent zip file. */
- public B setOutputPath(Path outputPath) throws CompilationException {
- this.outputPath = FileUtils.validateOutputFile(outputPath);
+ /** Set an output path. Must be an existing directory or a zip file. */
+ public B setOutputPath(Path outputPath) {
+ this.outputPath = outputPath;
return self();
}
@@ -248,5 +256,17 @@
this.printVersion = printVersion;
return self();
}
+
+ protected boolean isOverwriteOutputs() {
+ return overwriteOutputs;
+ }
+
+ protected void setOverwriteOutputs(boolean overwriteOutputs) {
+ this.overwriteOutputs = overwriteOutputs;
+ }
+
+ protected void validate() throws CompilationException {
+ FileUtils.validateOutputFile(outputPath, overwriteOutputs);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index fb19e9b..f15a124 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -162,7 +162,7 @@
Timing timing = new Timing("DX timer");
DexApplication app = new ApplicationReader(inputApp, options, timing).read(executor);
AppInfo appInfo = new AppInfo(app);
- app = optimize(app, appInfo, options, executor);
+ app = optimize(app, appInfo, options, timing, executor);
// If a method filter is present don't produce output since the application is likely partial.
if (options.hasMethodsFilter()) {
@@ -191,11 +191,11 @@
private static DexApplication optimize(
DexApplication application, AppInfo appInfo, InternalOptions options,
- ExecutorService executor)
+ Timing timing, ExecutorService executor)
throws IOException, ExecutionException {
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
- IRConverter converter = new IRConverter(application, appInfo, options, printer);
+ IRConverter converter = new IRConverter(timing, application, appInfo, options, printer);
application = converter.convertToDex(executor);
if (options.printCfg) {
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 62cb5a5..0ef9728 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -101,8 +101,10 @@
if (isPrintHelp() || isPrintVersion()) {
return new D8Command(isPrintHelp(), isPrintVersion());
}
+
+ validate();
return new D8Command(getAppBuilder().build(),
- getOutputPath(), getOutputMode(), getMode(), getMinApiLevel());
+ getOutputPath(), getOutputMode(), getMode(), getMinApiLevel(), isOverwriteOutputs());
}
}
@@ -180,8 +182,8 @@
}
private D8Command(AndroidApp inputApp, Path outputPath,
- OutputMode outputMode, CompilationMode mode, int minApiLevel) {
- super(inputApp, outputPath, outputMode, mode, minApiLevel);
+ OutputMode outputMode, CompilationMode mode, int minApiLevel, boolean overwriteOutputs) {
+ super(inputApp, outputPath, outputMode, mode, minApiLevel, overwriteOutputs);
}
private D8Command(boolean printHelp, boolean printVersion) {
@@ -194,7 +196,7 @@
assert !internal.debug;
internal.debug = getMode() == CompilationMode.DEBUG;
internal.minApiLevel = getMinApiLevel();
- internal.overwriteOutputs = true;
+ internal.overwriteOutputs = isOverwriteOutputs();
// Assert and fixup defaults.
assert !internal.skipMinification;
internal.skipMinification = true;
diff --git a/src/main/java/com/android/tools/r8/DexSegments.java b/src/main/java/com/android/tools/r8/DexSegments.java
index 501fecc..09eb21e 100644
--- a/src/main/java/com/android/tools/r8/DexSegments.java
+++ b/src/main/java/com/android/tools/r8/DexSegments.java
@@ -41,12 +41,14 @@
if (isPrintHelp()) {
return new Command(isPrintHelp());
}
+ validate();
return new Command(
getAppBuilder().build(),
getOutputPath(),
getOutputMode(),
getMode(),
- getMinApiLevel());
+ getMinApiLevel(),
+ isOverwriteOutputs());
}
}
@@ -89,8 +91,9 @@
Path outputPath,
OutputMode outputMode,
CompilationMode mode,
- int minApiLevel) {
- super(inputApp, outputPath, outputMode, mode, minApiLevel);
+ int minApiLevel,
+ boolean isOverwrite) {
+ super(inputApp, outputPath, outputMode, mode, minApiLevel, isOverwrite);
}
private Command(boolean printHelp) {
diff --git a/src/main/java/com/android/tools/r8/Disassemble.java b/src/main/java/com/android/tools/r8/Disassemble.java
index b183ecc..7d73895 100644
--- a/src/main/java/com/android/tools/r8/Disassemble.java
+++ b/src/main/java/com/android/tools/r8/Disassemble.java
@@ -46,13 +46,15 @@
return new DisassembleCommand(isPrintHelp(), isPrintVersion());
}
+ validate();
return new DisassembleCommand(
getAppBuilder().build(),
getOutputPath(),
getOutputMode(),
getMode(),
getMinApiLevel(),
- useSmali);
+ useSmali,
+ isOverwriteOutputs());
}
}
@@ -108,8 +110,9 @@
OutputMode outputMode,
CompilationMode mode,
int minApiLevel,
- boolean useSmali) {
- super(inputApp, outputPath, outputMode, mode, minApiLevel);
+ boolean useSmali,
+ boolean isOverwrite) {
+ super(inputApp, outputPath, outputMode, mode, minApiLevel, isOverwrite);
//assert getOutputMode() == OutputMode.Indexed : "Only regular mode is supported in R8";
this.useSmali = useSmali;
}
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 7d01462..7fd1c6f 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -136,6 +136,7 @@
return new R8Command(isPrintHelp(), isPrintVersion());
}
+ validate();
DexItemFactory factory = new DexItemFactory();
ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
if (this.mainDexRules.isEmpty()) {
@@ -178,7 +179,8 @@
getMinApiLevel(),
useTreeShaking,
useMinification,
- ignoreMissingClasses);
+ ignoreMissingClasses,
+ isOverwriteOutputs());
}
}
@@ -321,8 +323,9 @@
int minApiLevel,
boolean useTreeShaking,
boolean useMinification,
- boolean ignoreMissingClasses) {
- super(inputApp, outputPath, outputMode, mode, minApiLevel);
+ boolean ignoreMissingClasses,
+ boolean overwriteOutputs) {
+ super(inputApp, outputPath, outputMode, mode, minApiLevel, overwriteOutputs);
assert proguardConfiguration != null;
assert mainDexKeepRules != null;
assert getOutputMode() == OutputMode.Indexed : "Only regular mode is supported in R8";
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index f24f4de..6d6f858 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -176,7 +176,7 @@
return this;
}
// At least one method needs a jumbo string.
- IRConverter converter = new IRConverter(application, appInfo, options, null, false);
+ IRConverter converter = new IRConverter(application, appInfo, options, false);
for (DexProgramClass clazz : classes) {
rewriteCodeWithJumboStrings(converter, clazz.directMethods());
rewriteCodeWithJumboStrings(converter, clazz.virtualMethods());
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 9e3e118..503bc89 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -138,16 +138,15 @@
*/
public DexEncodedMethod lookupSingleVirtualTarget(DexMethod method) {
assert method != null;
+ DexClass holder = definitionFor(method.holder);
+ if ((holder == null) || holder.isLibraryClass()) {
+ return null;
+ }
if (method.isSingleVirtualMethodCached()) {
return method.getSingleVirtualMethodCache();
}
DexEncodedMethod result = null;
// First add the target for receiver type method.type.
- DexClass root = definitionFor(method.holder);
- if (root == null) {
- // type specified in method does not have a materialized class.
- return null;
- }
DexEncodedMethod topMethod = lookupVirtualTarget(method.holder, method);
// The top method might be absent if this is an abstract class.
if (topMethod != null) {
@@ -203,6 +202,10 @@
public DexEncodedMethod lookupSingleInterfaceTarget(DexMethod method) {
assert method != null;
+ DexClass holder = definitionFor(method.holder);
+ if ((holder == null) || holder.isLibraryClass()) {
+ return null;
+ }
DexEncodedMethod result = null;
Set<DexType> set = subtypes(method.holder);
if (set != null) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 9ea50d2..984215b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -100,6 +100,7 @@
public DexString thisName = createString("this");
private DexString charArrayDescriptor = createString("[C");
+ private DexType charArrayType = createType(charArrayDescriptor);
public DexString throwableArrayDescriptor = createString("[Ljava/lang/Throwable;");
public DexType booleanType = createType(booleanDescriptor);
@@ -128,10 +129,11 @@
public DexType annotationType = createType(annotationDescriptor);
public DexType throwableType = createType(throwableDescriptor);
- public StringBuildingMethods stringBuilderMethods =
- new StringBuildingMethods(createString("Ljava/lang/StringBuilder;"));
- public StringBuildingMethods stringBufferMethods =
- new StringBuildingMethods(createString("Ljava/lang/StringBuffer;"));
+ public DexType stringBuilderType = createType(createString("Ljava/lang/StringBuilder;"));
+ public DexType stringBufferType = createType(createString("Ljava/lang/StringBuffer;"));
+
+ public StringBuildingMethods stringBuilderMethods = new StringBuildingMethods(stringBuilderType);
+ public StringBuildingMethods stringBufferMethods = new StringBuildingMethods(stringBufferType);
public ObjectsMethods objectsMethods = new ObjectsMethods();
public ObjectMethods objectMethods = new ObjectMethods();
public LongMethods longMethods = new LongMethods();
@@ -213,34 +215,42 @@
public DexMethod appendStringBuffer;
public DexMethod toString;
- private StringBuildingMethods(DexString receiver) {
- DexString sbuf = createString("Ljava/lang/StringBuffer;");
- DexString charSequence = createString("Ljava/lang/CharSequence;");
+ private StringBuildingMethods(DexType receiver) {
+ DexType sbufType = createType(createString("Ljava/lang/StringBuffer;"));
+ DexType charSequenceType = createType(createString("Ljava/lang/CharSequence;"));
DexString append = createString("append");
DexString toStringMethodName = createString("toString");
- appendBoolean = createMethod(receiver, append, receiver, new DexString[]{booleanDescriptor});
- appendChar = createMethod(receiver, append, receiver, new DexString[]{charDescriptor});
- appendCharArray = createMethod(receiver, append, receiver, new DexString[]{
- charArrayDescriptor});
- appendSubCharArray = createMethod(receiver, append, receiver,
- new DexString[]{charArrayDescriptor, intDescriptor, intDescriptor});
- appendCharSequence = createMethod(receiver, append, receiver,
- new DexString[]{charSequence});
- appendSubCharSequence = createMethod(receiver, append, receiver,
- new DexString[]{charSequence, intDescriptor, intDescriptor});
- appendInt = createMethod(receiver, append, receiver, new DexString[]{intDescriptor});
- appendDouble = createMethod(receiver, append, receiver, new DexString[]{doubleDescriptor});
- appendFloat = createMethod(receiver, append, receiver, new DexString[]{floatDescriptor});
- appendLong = createMethod(receiver, append, receiver, new DexString[]{longDescriptor});
- appendObject = createMethod(receiver, append, receiver, new DexString[]{objectDescriptor});
- appendString = createMethod(receiver, append, receiver, new DexString[]{stringDescriptor});
- appendStringBuffer = createMethod(receiver, append, receiver, new DexString[]{sbuf});
- toString = createMethod(receiver, toStringMethodName, stringDescriptor,
- DexString.EMPTY_ARRAY);
+
+ appendBoolean =
+ createMethod(receiver, createProto(receiver, new DexType[]{booleanType}), append);
+ appendChar = createMethod(receiver, createProto(receiver, new DexType[]{charType}), append);
+ appendCharArray =
+ createMethod(receiver, createProto(receiver, new DexType[]{charArrayType}), append);
+ appendSubCharArray =
+ createMethod(receiver,
+ createProto(receiver, new DexType[]{charArrayType, intType, intType}), append);
+ appendCharSequence =
+ createMethod(receiver, createProto(receiver, new DexType[]{charSequenceType}), append);
+ appendSubCharSequence =
+ createMethod(receiver,
+ createProto(receiver, new DexType[]{charSequenceType, intType, intType}), append);
+ appendInt = createMethod(receiver, createProto(receiver, new DexType[]{intType}), append);
+ appendDouble =
+ createMethod(receiver, createProto(receiver, new DexType[]{doubleType}), append);
+ appendFloat = createMethod(receiver, createProto(receiver, new DexType[]{floatType}), append);
+ appendLong = createMethod(receiver, createProto(receiver, new DexType[]{longType}), append);
+ appendObject =
+ createMethod(receiver, createProto(receiver, new DexType[]{objectType}), append);
+ appendString =
+ createMethod(receiver, createProto(receiver, new DexType[]{stringType}), append);
+ appendStringBuffer =
+ createMethod(receiver, createProto(receiver, new DexType[]{sbufType}), append);
+ toString =
+ createMethod(receiver, createProto(stringType, DexType.EMPTY_ARRAY), toStringMethodName);
}
- public void forEeachAppendMethod(Consumer<DexMethod> consumer) {
+ public void forEachAppendMethod(Consumer<DexMethod> consumer) {
consumer.accept(appendBoolean);
consumer.accept(appendChar);
consumer.accept(appendCharArray);
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 234773f..4d3d8cb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -19,6 +19,8 @@
public class DexType extends IndexedDexItem implements PresortedComparable<DexType> {
+ public static final DexType[] EMPTY_ARRAY = new DexType[]{};
+
private final static int ROOT_LEVEL = 0;
private final static int UNKNOWN_LEVEL = -1;
private final static int INTERFACE_LEVEL = -2;
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 aa3dc10..1586496 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
@@ -38,9 +38,11 @@
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -69,35 +71,82 @@
private DexString highestSortingString;
- public IRConverter(
+ private IRConverter(
+ Timing timing,
DexApplication application,
AppInfo appInfo,
+ GraphLense graphLense,
InternalOptions options,
CfgPrinter printer,
- boolean enableDesugaring) {
- this.timing = new Timing("Testing");
+ boolean enableDesugaring,
+ boolean enableWholeProgramOptimizations) {
+ assert application != null;
+ assert appInfo != null;
+ assert options != null;
+ this.timing = timing != null ? timing : new Timing("internal");
this.application = application;
this.appInfo = appInfo;
+ this.graphLense = graphLense != null ? graphLense : GraphLense.getIdentityLense();
this.options = options;
this.printer = printer;
- this.graphLense = GraphLense.getIdentityLense();
- this.inliner = null;
- this.outliner = null;
- this.codeRewriter = new CodeRewriter(appInfo);
- this.memberValuePropagation = null;
+ Set<DexType> libraryClassesWithOptimizationInfo = markLibraryMethodsReturningReceiver();
+ this.codeRewriter = new CodeRewriter(appInfo, libraryClassesWithOptimizationInfo);
this.lambdaRewriter = enableDesugaring ? new LambdaRewriter(this) : null;
this.interfaceMethodRewriter =
(enableDesugaring && enableInterfaceMethodDesugaring())
? new InterfaceMethodRewriter(this) : null;
- lensCodeRewriter = null;
- markLibraryMethodsReturningReceiver();
+ if (enableWholeProgramOptimizations) {
+ assert appInfo.withSubtyping() != null;
+ this.inliner = new Inliner(appInfo.withSubtyping(), graphLense, options);
+ this.outliner = new Outliner(appInfo, options);
+ this.memberValuePropagation = new MemberValuePropagation(appInfo);
+ this.lensCodeRewriter = new LensCodeRewriter(graphLense, appInfo.withSubtyping());
+ } else {
+ this.inliner = null;
+ this.outliner = null;
+ this.memberValuePropagation = null;
+ this.lensCodeRewriter = null;
+ }
}
+ /**
+ * Create an IR converter for processing methods with full program optimization disabled.
+ */
public IRConverter(
- DexApplication application, AppInfo appInfo, InternalOptions options, CfgPrinter printer) {
- this(application, appInfo, options, printer, true);
+ DexApplication application,
+ AppInfo appInfo,
+ InternalOptions options) {
+ this(null, application, appInfo, null, options, null, true, false);
}
+ /**
+ * Create an IR converter for processing methods without full program optimization enabled.
+ *
+ * The argument <code>enableDesugaring</code> if desugaing is enabled.
+ */
+ public IRConverter(
+ DexApplication application,
+ AppInfo appInfo,
+ InternalOptions options,
+ boolean enableDesugaring) {
+ this(null, application, appInfo, null, options, null, enableDesugaring, false);
+ }
+
+ /**
+ * Create an IR converter for processing methods with full program optimization disabled.
+ */
+ public IRConverter(
+ Timing timing,
+ DexApplication application,
+ AppInfo appInfo,
+ InternalOptions options,
+ CfgPrinter printer) {
+ this(timing, application, appInfo, null, options, printer, true, false);
+ }
+
+ /**
+ * Create an IR converter for processing methods with full program optimization enabled.
+ */
public IRConverter(
Timing timing,
DexApplication application,
@@ -105,21 +154,7 @@
InternalOptions options,
CfgPrinter printer,
GraphLense graphLense) {
- this.timing = timing;
- this.application = application;
- this.appInfo = appInfo;
- this.options = options;
- this.printer = printer;
- this.graphLense = graphLense;
- this.codeRewriter = new CodeRewriter(appInfo);
- this.outliner = new Outliner(appInfo, options);
- this.memberValuePropagation = new MemberValuePropagation(appInfo);
- this.inliner = new Inliner(appInfo, graphLense, options);
- this.lambdaRewriter = new LambdaRewriter(this);
- this.interfaceMethodRewriter = enableInterfaceMethodDesugaring()
- ? new InterfaceMethodRewriter(this) : null;
- lensCodeRewriter = new LensCodeRewriter(graphLense, appInfo);
- markLibraryMethodsReturningReceiver();
+ this(timing, application, appInfo, graphLense, options, printer, true, true);
}
private boolean enableInterfaceMethodDesugaring() {
@@ -142,10 +177,11 @@
throw new Unreachable();
}
- private void markLibraryMethodsReturningReceiver() {
+ private Set<DexType> markLibraryMethodsReturningReceiver() {
DexItemFactory dexItemFactory = appInfo.dexItemFactory;
- dexItemFactory.stringBuilderMethods.forEeachAppendMethod(this::markReturnsReceiver);
- dexItemFactory.stringBufferMethods.forEeachAppendMethod(this::markReturnsReceiver);
+ dexItemFactory.stringBuilderMethods.forEachAppendMethod(this::markReturnsReceiver);
+ dexItemFactory.stringBufferMethods.forEachAppendMethod(this::markReturnsReceiver);
+ return ImmutableSet.of(dexItemFactory.stringBuilderType, dexItemFactory.stringBufferType);
}
private void markReturnsReceiver(DexMethod method) {
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 2d06dfc..764beb5 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
@@ -87,10 +87,12 @@
private final AppInfo appInfo;
private final DexItemFactory dexItemFactory;
+ private final Set<DexType> libraryClassesWithOptimizationInfo;
- public CodeRewriter(AppInfo appInfo) {
+ public CodeRewriter(AppInfo appInfo, Set<DexType> libraryClassesWithOptimizationInfo) {
this.appInfo = appInfo;
this.dexItemFactory = appInfo.dexItemFactory;
+ this.libraryClassesWithOptimizationInfo = libraryClassesWithOptimizationInfo;
}
/**
@@ -694,6 +696,12 @@
InvokeMethod invoke = current.asInvokeMethod();
if (invoke.outValue() != null) {
DexEncodedMethod target = invoke.computeSingleTarget(appInfo.withSubtyping());
+ // We have a set of library classes with optimization information - consider those
+ // as well.
+ if ((target == null) &&
+ libraryClassesWithOptimizationInfo.contains(invoke.getInvokedMethod().getHolder())) {
+ target = appInfo.definitionFor(invoke.getInvokedMethod());
+ }
if (target != null) {
DexMethod invokedMethod = target.method;
// Check if the invoked method is known to return one of its arguments.
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 631f8b2..eb0aa77 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
@@ -1808,7 +1808,7 @@
addLiveRange(use, block, number);
}
LiveIntervals useIntervals = use.getLiveIntervals();
- useIntervals.addUse(new LiveIntervalsUse(number, Constants.U16BIT_MAX));
+ useIntervals.addUse(new LiveIntervalsUse(number, Constants.U16BIT_MAX, true));
}
Value use = instruction.getPreviousLocalValue();
if (use != null) {
@@ -1818,7 +1818,7 @@
addLiveRange(use, block, number);
}
LiveIntervals useIntervals = use.getLiveIntervals();
- useIntervals.addUse(new LiveIntervalsUse(number, Constants.U16BIT_MAX));
+ useIntervals.addUse(new LiveIntervalsUse(number, Constants.U16BIT_MAX, true));
}
}
}
@@ -1850,27 +1850,14 @@
Value previous = null;
for (int i = 0; i < arguments.size(); i++) {
Value argument = arguments.get(i);
- Value newArgument = argument;
- // In debug mode, we have debug instructions that are also moves. Do not generate another
- // move if there already is a move instruction that we can use. We generate moves if:
- //
- // 1. the argument is not defined by a move,
- //
- // 2. the argument is already linked or would cause a cycle if linked, or
- //
- // 3. the argument has a register constraint (the argument moves are there to make the
- // input value to a ranged invoke unconstrained.)
- if (argument.definition == null ||
- !argument.definition.isMove() ||
- argument.isLinked() ||
- argument == previous ||
- argument.hasRegisterConstraint()) {
- newArgument = createValue(argument.outType());
- Move move = new Move(newArgument, argument);
- move.setBlock(invoke.getBlock());
- replaceArgument(invoke, i, newArgument);
- insertAt.add(move);
- }
+ // TODO(ager): Conditionally create a new argument if it is not already a move.
+ // Reverted optimization from CL: https://r8-review.googlesource.com/c/1985/
+ // Not considering debug-uses causes a unlinked/non-consecutive register in some cases.
+ Value newArgument = createValue(argument.outType());
+ Move move = new Move(newArgument, argument);
+ move.setBlock(invoke.getBlock());
+ replaceArgument(invoke, i, newArgument);
+ insertAt.add(move);
if (previous != null) {
previous.linkTo(newArgument);
}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
index 06b33f4..9c28724 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
@@ -319,7 +319,7 @@
public int firstUseAfter(int unhandledStart) {
for (LiveIntervalsUse use : uses) {
- if (use.getPosition() >= unhandledStart) {
+ if (use.getPosition() >= unhandledStart && !use.isDebugUse()) {
return use.getPosition();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java
index a602134..edf876d 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java
@@ -6,12 +6,18 @@
import static com.android.tools.r8.dex.Constants.U16BIT_MAX;
public class LiveIntervalsUse implements Comparable<LiveIntervalsUse> {
- private int position;
- private int limit;
+ private final int position;
+ private final int limit;
+ private final boolean debugUse;
public LiveIntervalsUse(int position, int limit) {
+ this(position, limit, false);
+ }
+
+ public LiveIntervalsUse(int position, int limit, boolean debugUse) {
this.position = position;
this.limit = limit;
+ this.debugUse = debugUse;
}
public int getPosition() {
@@ -47,4 +53,8 @@
public boolean hasConstraint() {
return limit < U16BIT_MAX;
}
+
+ public boolean isDebugUse() {
+ return debugUse;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java
index 3f69c2e..6a70845 100644
--- a/src/main/java/com/android/tools/r8/utils/FileUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java
@@ -73,10 +73,10 @@
Files.write(file, Arrays.asList(lines));
}
- public static Path validateOutputFile(Path path) throws CompilationException {
+ public static Path validateOutputFile(Path path, boolean allowOverwrite) throws CompilationException {
if (path != null) {
if (isZipFile(path)) {
- if (Files.exists(path)) {
+ if ((!allowOverwrite) && Files.exists(path)) {
throw new CompilationException("Cannot write to existing output file: " + path);
}
} else if (!(Files.exists(path) && Files.isDirectory(path))) {
diff --git a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
index 77eb5eb0..66853cb 100644
--- a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
+++ b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
@@ -36,8 +36,7 @@
DexApplication application =
new ApplicationReader(input, new InternalOptions(), timing).read(executorService);
IRConverter converter =
- new IRConverter(
- application, new AppInfoWithSubtyping(application), new InternalOptions(), null);
+ new IRConverter(application, new AppInfoWithSubtyping(application), new InternalOptions());
converter.optimize();
DexProgramClass clazz = application.classes().iterator().next();
assertEquals(4, clazz.directMethods().length);
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index e74eb2c..e039e9e 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -725,4 +725,10 @@
public static AndroidApp getApp(BaseCommand command) {
return command.getInputApp();
}
+
+ public static <T extends BaseCommand, U extends BaseCommand.Builder<T, U>>
+ U setOverwrite(U commandBuilder, boolean overwrite) {
+ commandBuilder.setOverwriteOutputs(overwrite);
+ return commandBuilder;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
index d5e66b8..4b2ee49 100644
--- a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
@@ -48,6 +48,11 @@
compiler, mode, referenceApk, pgMap, pgConf, Arrays.asList(inputs));
}
+ public AndroidApp runAndCheckVerification(D8Command command, String referenceApk)
+ throws IOException, ExecutionException {
+ return checkVerification(ToolHelper.runD8(command), referenceApk);
+ }
+
public AndroidApp runAndCheckVerification(
CompilerUnderTest compiler,
CompilationMode mode,
@@ -83,6 +88,11 @@
.setMinApiLevel(Constants.ANDROID_L_API)
.build());
}
+ return checkVerification(outputApp, referenceApk);
+ }
+
+ public AndroidApp checkVerification(AndroidApp outputApp, String referenceApk)
+ throws IOException, ExecutionException {
Path out = temp.getRoot().toPath().resolve("all.zip");
Path oatFile = temp.getRoot().toPath().resolve("all.oat");
outputApp.writeToZip(out, OutputMode.Indexed);
diff --git a/src/test/java/com/android/tools/r8/internal/D8FrameworkVerificationTest.java b/src/test/java/com/android/tools/r8/internal/D8FrameworkVerificationTest.java
new file mode 100644
index 0000000..a4f33d5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/internal/D8FrameworkVerificationTest.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.internal;
+
+import com.android.tools.r8.CompilationException;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.shaking.ProguardRuleParserException;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+
+public class D8FrameworkVerificationTest extends CompilationTestBase {
+ private static final int MIN_SDK = 24;
+ private static final String JAR = "third_party/framework/framework_160115954.jar";
+
+ @Test
+ public void verifyDebugBuild()
+ throws ExecutionException, IOException, ProguardRuleParserException, CompilationException {
+ runAndCheckVerification(
+ D8Command.builder()
+ .addProgramFiles(Paths.get(JAR))
+ .setMode(CompilationMode.DEBUG)
+ .setMinApiLevel(MIN_SDK)
+ .build(),
+ JAR);
+ }
+
+ @Test
+ public void verifyReleaseBuild()
+ throws ExecutionException, IOException, ProguardRuleParserException, CompilationException {
+ runAndCheckVerification(
+ D8Command.builder()
+ .addProgramFiles(Paths.get(JAR))
+ .setMode(CompilationMode.RELEASE)
+ .setMinApiLevel(MIN_SDK)
+ .build(),
+ JAR);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java b/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
index 8890df8..6ee0b66 100644
--- a/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
+++ b/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
@@ -72,6 +72,16 @@
return dexVm == DexVm.ART_DEFAULT;
}
+ static final Map<String, TestPredicate> FLAKY_TESTS =
+ ImmutableMap.<String, TestPredicate>builder()
+ // Build bot is failing with ART segmentation faults on the following tests. b/63317743
+ .put("StackFrame.GetValues002Test", RunJdwpTests::isAndroidMOrAbove)
+ .put("ObjectReference.ReferringObjectsTest", RunJdwpTests::isAndroidMOrAbove)
+ .put("VirtualMachine.InstanceCountsTest", RunJdwpTests::isAndroidMOrAbove)
+ .put("ReferenceType.InstancesTest", RunJdwpTests::isAndroidMOrAbove)
+ .put("EventModifiers.InstanceOnlyModifierTest", RunJdwpTests::isAndroidMOrAbove)
+ .build();
+
static final Map<String, TestPredicate> FAILING_TESTS =
ImmutableMap.<String, TestPredicate>builder()
.put("ArrayReference.SetValues003Test", RunJdwpTests::isAndroidNOrAbove)
@@ -175,6 +185,8 @@
if (!RUN_ALL_TESTS) {
Assume.assumeTrue("Skipping non-smoke test " + test, SMOKE_TESTS.contains(test));
}
+ Assume.assumeTrue("Skipping flaky test " + test,
+ !FLAKY_TESTS.containsKey(test) || FLAKY_TESTS.get(test).test(getDexVm(), tool));
if (tool != Tool.JAVAC) {
// Can we run the test on the current ART runtime ?
Assume.assumeTrue("Skipping test " + test + " because ART is not supported",
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
index 6b377f4..8ce4f40 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -343,7 +343,7 @@
public String run() {
AppInfo appInfo = new AppInfo(application);
- IRConverter converter = new IRConverter(application, appInfo, options, null);
+ IRConverter converter = new IRConverter(application, appInfo, options);
converter.replaceCodeForTesting(method, code);
return runArt(application, options);
}
diff --git a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
index be72756..b086910 100644
--- a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
@@ -58,7 +58,7 @@
@Test
public void defaultOutIsCwd() throws IOException, InterruptedException {
Path working = temp.getRoot().toPath();
- Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar").toAbsolutePath();
+ Path input = Paths.get(EXAMPLES_BUILD_DIR + "/arithmetic.jar").toAbsolutePath();
Path output = working.resolve("classes.dex");
assertFalse(Files.exists(output));
assertEquals(0, ToolHelper.forkD8(working, input.toString()).exitCode);
@@ -91,9 +91,15 @@
}
@Test
- public void existingOutputZip() throws Throwable {
+ public void existingOutputZipNoOverwrite() throws Throwable {
thrown.expect(CompilationException.class);
Path existingZip = temp.newFile("an-existing-archive.zip").toPath();
+ ToolHelper.setOverwrite(D8Command.builder().setOutputPath(existingZip), false).build();
+ }
+
+ @Test
+ public void existingOutputZip() throws Throwable {
+ Path existingZip = temp.newFile("an-existing-archive.zip").toPath();
D8Command.builder().setOutputPath(existingZip).build();
}
@@ -113,7 +119,6 @@
@Test
public void existingOutputZipParse() throws Throwable {
- thrown.expect(CompilationException.class);
Path existingZip = temp.newFile("an-existing-archive.zip").toPath();
parse("--output", existingZip.toString());
}
diff --git a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
index 935275a..15df84f 100644
--- a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
@@ -98,12 +98,18 @@
@Test
public void existingOutputZip() throws Throwable {
- thrown.expect(CompilationException.class);
Path existingZip = temp.newFile("an-existing-archive.zip").toPath();
R8Command.builder().setOutputPath(existingZip).build();
}
@Test
+ public void existingOutputZipNoOverwrite() throws Throwable {
+ thrown.expect(CompilationException.class);
+ Path existingZip = temp.newFile("an-existing-archive.zip").toPath();
+ ToolHelper.setOverwrite(R8Command.builder().setOutputPath(existingZip), false).build();
+ }
+
+ @Test
public void invalidOutputFileType() throws Throwable {
thrown.expect(CompilationException.class);
Path invalidType = temp.getRoot().toPath().resolve("an-invalid-output-file-type.foobar");
@@ -119,7 +125,6 @@
@Test
public void existingOutputZipParse() throws Throwable {
- thrown.expect(CompilationException.class);
Path existingZip = temp.newFile("an-existing-archive.zip").toPath();
parse("--output", existingZip.toString());
}
diff --git a/tools/run_proguard_dx_on_gmscore.py b/tools/run_proguard_dx_on_gmscore.py
index a67868b..ca0b5e9 100755
--- a/tools/run_proguard_dx_on_gmscore.py
+++ b/tools/run_proguard_dx_on_gmscore.py
@@ -3,7 +3,7 @@
# 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.
-# Run ProGuard and the DX tool on GmsCore V10.
+# Run ProGuard and the DX or CompatDX (= D8) tool on GmsCore V10.
from __future__ import print_function
from os import makedirs
@@ -20,13 +20,14 @@
import utils
BLAZE_BUILD_DIR = join(gmscore_data.V10_BASE,
- 'blaze-out/intel-linux-android-4.8-libcxx-x86-opt/bin/java/com/google/'
- 'android/gmscore/integ')
+ 'blaze-out', 'intel-linux-android-4.8-libcxx-x86-opt', 'bin', 'java',
+ 'com', 'google', 'android', 'gmscore', 'integ')
PROGUARDED_OUTPUT = join(BLAZE_BUILD_DIR,
'GmsCore_prod_alldpi_release_all_locales_proguard.jar')
GMSCORE_SEEDS_FILE = join(BLAZE_BUILD_DIR,
'GmsCore_prod_alldpi_release_all_locales_proguard.seeds')
-DX_EXECUTABLE = join(utils.REPO_ROOT, 'tools/linux/dx/bin/dx')
+DX_JAR = join(utils.REPO_ROOT, 'tools', 'linux', 'dx', 'framework', 'dx.jar')
+COMPATDX_JAR = join(utils.REPO_ROOT, 'build', 'libs', 'compatdx.jar')
def parse_arguments():
parser = argparse.ArgumentParser(
@@ -39,6 +40,10 @@
help = 'Prints the line \'<BENCHMARKNAME>(RunTimeRaw): <elapsed>' +
' ms\' at the end where <elapsed> is the elapsed time in' +
' milliseconds.')
+ parser.add_argument('--compatdx',
+ help = 'Use CompatDx (D8) instead of DX.',
+ default = False,
+ action = 'store_true')
return parser.parse_args()
def Main():
@@ -70,8 +75,15 @@
proguard.run(args)
# run dex on the result
- check_call([DX_EXECUTABLE, '-JXmx5256M', '--multi-dex', '--output=' + outdir,
- '--dex', PROGUARDED_OUTPUT])
+ if options.compatdx:
+ jar = COMPATDX_JAR
+ else:
+ jar = DX_JAR
+
+ cmd = ['java', '-jar', jar, '--min-sdk-version=26', '--multi-dex',
+ '--output=' + outdir, '--dex', PROGUARDED_OUTPUT];
+ utils.PrintCmd(cmd);
+ check_call(cmd)
if options.print_runtimeraw:
print('{}(RunTimeRaw): {} ms'