Merge "Handle several implementations of default methods"
diff --git a/src/main/java/com/android/tools/r8/BaseOutput.java b/src/main/java/com/android/tools/r8/BaseOutput.java
index 16e8264..b1b9166 100644
--- a/src/main/java/com/android/tools/r8/BaseOutput.java
+++ b/src/main/java/com/android/tools/r8/BaseOutput.java
@@ -8,6 +8,7 @@
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.List;
abstract class BaseOutput {
@@ -39,9 +40,9 @@
* resources.get(N - 1) ~=~ classesN.dex (where N > 0).
* </pre>
*
- * @return list of compiled DEX resources.
+ * @return an immutable list of compiled DEX resources.
*/
- public ImmutableList<Resource> getDexResources() {
+ public List<Resource> getDexResources() {
return ImmutableList.copyOf(app.getDexProgramResources());
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index cbd16fd..6ac5f1e 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -33,6 +33,9 @@
* Builder for constructing a D8Command.
*/
public static class Builder extends BaseCommand.Builder<D8Command, Builder> {
+
+ private boolean intermediate = false;
+
private Builder() {
super(CompilationMode.DEBUG);
}
@@ -44,18 +47,23 @@
/** Add classpath file resources. */
public Builder addClasspathFiles(Path... files) throws IOException {
getAppBuilder().addClasspathFiles(files);
- return this;
+ return self();
}
/** Add classpath file resources. */
public Builder addClasspathFiles(Collection<Path> files) throws IOException {
getAppBuilder().addClasspathFiles(files);
- return this;
+ return self();
}
public Builder addClasspathResourceProvider(ClassFileResourceProvider provider) {
getAppBuilder().addClasspathResourceProvider(provider);
- return this;
+ return self();
+ }
+
+ public Builder setIntermediate(boolean value) {
+ this.intermediate = value;
+ return self();
}
@Override
@@ -74,7 +82,12 @@
validate();
return new D8Command(
- getAppBuilder().build(), getOutputPath(), getOutputMode(), getMode(), getMinApiLevel());
+ getAppBuilder().build(),
+ getOutputPath(),
+ getOutputMode(),
+ getMode(),
+ getMinApiLevel(),
+ intermediate);
}
}
@@ -89,10 +102,13 @@
" --lib <file> # Add <file> as a library resource.",
" --classpath <file> # Add <file> as a classpath resource.",
" --min-api # Minimum Android API level compatibility",
+ " --intermediate # Compile an intermediate result intended for later merging.",
" --file-per-class # Produce a separate dex file per class",
" --version # Print the version of d8.",
" --help # Print this message."));
+ private boolean intermediate = false;
+
public static Builder builder() {
return new Builder();
}
@@ -142,6 +158,8 @@
builder.addClasspathFiles(Paths.get(args[++i]));
} else if (arg.equals("--min-api")) {
builder.setMinApiLevel(Integer.valueOf(args[++i]));
+ } else if (arg.equals("--intermediate")) {
+ builder.setIntermediate(true);
} else {
if (arg.startsWith("--")) {
throw new CompilationException("Unknown option: " + arg);
@@ -160,8 +178,10 @@
Path outputPath,
OutputMode outputMode,
CompilationMode mode,
- int minApiLevel) {
+ int minApiLevel,
+ boolean intermediate) {
super(inputApp, outputPath, outputMode, mode, minApiLevel);
+ this.intermediate = intermediate;
}
private D8Command(boolean printHelp, boolean printVersion) {
@@ -174,6 +194,7 @@
assert !internal.debug;
internal.debug = getMode() == CompilationMode.DEBUG;
internal.minApiLevel = getMinApiLevel();
+ internal.intermediate = intermediate;
// 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 9902d3b..3827cae 100644
--- a/src/main/java/com/android/tools/r8/DexSegments.java
+++ b/src/main/java/com/android/tools/r8/DexSegments.java
@@ -110,7 +110,7 @@
Map<String, Integer> result = new HashMap<>();
try (Closer closer = Closer.create()) {
for (Resource resource : app.getDexProgramResources()) {
- for (Segment segment: DexFileReader.parseMapFrom(resource.getStream(closer))) {
+ for (Segment segment: DexFileReader.parseMapFrom(closer.register(resource.getStream()))) {
int value = result.computeIfAbsent(segment.typeName(), (key) -> 0);
result.put(segment.typeName(), value + segment.size());
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 3f6fcd4..19fc358 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -68,8 +68,7 @@
private final Timing timing = new Timing("R8");
private final InternalOptions options;
- // TODO(zerny): Refactor tests to go through testing methods and make this private.
- public R8(InternalOptions options) {
+ private R8(InternalOptions options) {
this.options = options;
options.itemFactory.resetSortedIndices();
}
@@ -93,14 +92,25 @@
}
}
- public DexApplication optimize(DexApplication application, AppInfoWithSubtyping appInfo)
+ static DexApplication optimize(
+ DexApplication application,
+ AppInfoWithSubtyping appInfo,
+ InternalOptions options)
+ throws ProguardRuleParserException, ExecutionException, IOException {
+ return new R8(options).optimize(application, appInfo);
+ }
+
+ private DexApplication optimize(DexApplication application, AppInfoWithSubtyping appInfo)
throws IOException, ProguardRuleParserException, ExecutionException {
return optimize(application, appInfo, GraphLense.getIdentityLense(),
Executors.newSingleThreadExecutor());
}
- public DexApplication optimize(DexApplication application, AppInfoWithSubtyping appInfo,
- GraphLense graphLense, ExecutorService executorService)
+ private DexApplication optimize(
+ DexApplication application,
+ AppInfoWithSubtyping appInfo,
+ GraphLense graphLense,
+ ExecutorService executorService)
throws IOException, ProguardRuleParserException, ExecutionException {
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 71a193c..3b88ba8 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -50,7 +50,7 @@
*/
public Builder setTreeShaking(boolean useTreeShaking) {
treeShaking = Optional.of(useTreeShaking);
- return this;
+ return self();
}
/**
@@ -58,7 +58,7 @@
*/
public Builder setMinification(boolean useMinification) {
minification = Optional.of(useMinification);
- return this;
+ return self();
}
/**
@@ -66,7 +66,7 @@
*/
public Builder addMainDexRules(Path... paths) {
Collections.addAll(mainDexRules, paths);
- return this;
+ return self();
}
/**
@@ -74,7 +74,7 @@
*/
public Builder addMainDexRules(List<Path> paths) {
mainDexRules.addAll(paths);
- return this;
+ return self();
}
/**
@@ -85,14 +85,14 @@
*/
public Builder setMinimalMainDex(boolean value) {
minimalMainDex = value;
- return this;
+ return self();
}
/**
* Add proguard configuration file resources.
*/
public Builder addProguardConfigurationFiles(Path... paths) {
Collections.addAll(proguardConfigFiles, paths);
- return this;
+ return self();
}
/**
@@ -100,7 +100,7 @@
*/
public Builder addProguardConfigurationFiles(List<Path> paths) {
proguardConfigFiles.addAll(paths);
- return this;
+ return self();
}
/**
@@ -108,7 +108,7 @@
*/
public Builder setProguardMapFile(Path path) {
getAppBuilder().setProguardMapFile(path);
- return this;
+ return self();
}
/**
@@ -116,7 +116,7 @@
*/
public Builder setPackageDistributionFile(Path path) {
getAppBuilder().setPackageDistributionFile(path);
- return this;
+ return self();
}
/**
@@ -126,7 +126,7 @@
*/
Builder setIgnoreMissingClasses(boolean ignoreMissingClasses) {
this.ignoreMissingClasses = ignoreMissingClasses;
- return this;
+ return self();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/Resource.java b/src/main/java/com/android/tools/r8/Resource.java
index eaabc99..3208e52 100644
--- a/src/main/java/com/android/tools/r8/Resource.java
+++ b/src/main/java/com/android/tools/r8/Resource.java
@@ -4,7 +4,6 @@
package com.android.tools.r8;
-import com.google.common.io.Closer;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
@@ -48,7 +47,7 @@
public abstract Set<String> getClassDescriptors();
/** Get the resource as a stream. */
- public abstract InputStream getStream(Closer closer) throws IOException;
+ public abstract InputStream getStream() throws IOException;
/** File based application resource. */
private static class FileResource extends Resource {
@@ -66,8 +65,8 @@
}
@Override
- public InputStream getStream(Closer closer) throws IOException {
- return closer.register(new FileInputStream(file.toFile()));
+ public InputStream getStream() throws IOException {
+ return new FileInputStream(file.toFile());
}
}
@@ -89,8 +88,7 @@
}
@Override
- public InputStream getStream(Closer closer) throws IOException {
- // Note: closing a byte-array input stream is a no-op.
+ public InputStream getStream() throws IOException {
return new ByteArrayInputStream(bytes);
}
}
diff --git a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
index c871e75..6bbb406 100644
--- a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
+++ b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
@@ -472,8 +472,7 @@
+ "Reduce the input-program size or run with --multi-dex enabled");
}
if (isDexFile(output)) {
- try (Closer closer = Closer.create()) {
- InputStream stream = result.getDexResources().get(0).getStream(closer);
+ try (InputStream stream = result.getDexResources().get(0).getStream()) {
Files.copy(stream, output, StandardCopyOption.REPLACE_EXISTING);
}
return;
@@ -544,7 +543,7 @@
// Add dex files.
List<Resource> dexProgramSources = output.getDexResources();
for (int i = 0; i < dexProgramSources.size(); i++) {
- addEntry(getDexFileName(i), dexProgramSources.get(i).getStream(closer), out);
+ addEntry(getDexFileName(i), closer.register(dexProgramSources.get(i).getStream()), out);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 36b65d7..355080f 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -183,7 +183,7 @@
List<DexFileReader> fileReaders = new ArrayList<>(dexSources.size());
int computedMinApiLevel = options.minApiLevel;
for (Resource input : dexSources) {
- DexFile file = new DexFile(input.getStream(closer));
+ DexFile file = new DexFile(closer.register(input.getStream()));
computedMinApiLevel = verifyOrComputeMinApiLevel(computedMinApiLevel, file);
fileReaders.add(new DexFileReader(file, classKind, itemFactory));
}
@@ -207,7 +207,7 @@
JarClassFileReader reader = new JarClassFileReader(
application, classKind.bridgeConsumer(classes::add));
for (Resource input : classSources) {
- reader.read(DEFAULT_DEX_FILENAME, classKind, input.getStream(closer));
+ reader.read(DEFAULT_DEX_FILENAME, classKind, closer.register(input.getStream()));
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index c9da10b..6586a57 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -135,9 +135,9 @@
assert packageDistribution == null :
"Cannot combine package distribution definition with file-per-class option.";
distributor = new FilePerClassDistributor(this);
- } else if (options.minApiLevel < Constants.ANDROID_L_API
- && options.mainDexKeepRules.isEmpty()
- && application.mainDexList.isEmpty()) {
+ } else if (!options.canUseMultidex()
+ && options.mainDexKeepRules.isEmpty()
+ && application.mainDexList.isEmpty()) {
if (packageDistribution != null) {
throw new CompilationError("Cannot apply package distribution. Multidex is not"
+ " supported with API level " + options.minApiLevel +"."
diff --git a/src/main/java/com/android/tools/r8/dex/Constants.java b/src/main/java/com/android/tools/r8/dex/Constants.java
index a5645a1..977d703 100644
--- a/src/main/java/com/android/tools/r8/dex/Constants.java
+++ b/src/main/java/com/android/tools/r8/dex/Constants.java
@@ -12,6 +12,7 @@
public static final int ANDROID_N_API = 24;
public static final int ANDROID_L_API = 21;
public static final int ANDROID_K_API = 19;
+ public static final int ANDROID_I_API = 14;
public static final int DEFAULT_ANDROID_API = 1;
/** dex file version number for Android O (API level 26) */
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index c468613..ffaf42b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.ir.code.DebugLocalsChange;
import com.android.tools.r8.ir.code.DebugPosition;
import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.MoveException;
import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
@@ -51,12 +52,6 @@
private DexString emittedFile = null;
private Int2ReferenceMap<DebugLocalInfo> emittedLocals;
- // If lastMoveInstructionPc != NO_PC_INFO, then the last pc-advancing instruction was a
- // move-exception at lastMoveInstructionPc. This is needed to maintain the art/dx specific
- // behaviour that the move-exception pc is associated with the catch-declaration line.
- // See debug.ExceptionTest.testStepOnCatch().
- private int lastMoveInstructionPc = NO_PC_INFO;
-
// Emitted events.
private final List<DexDebugEvent> events = new ArrayList<>();
@@ -81,23 +76,21 @@
}
assert pendingLocals != null;
- // If this is a position emit and exit as it always emits events.
if (instruction.isDebugPosition()) {
emitDebugPosition(pc, instruction.asDebugPosition());
- return;
- }
-
- if (instruction.isArgument()) {
+ } else if (instruction.isMoveException()) {
+ MoveException move = instruction.asMoveException();
+ if (move.getPosition() != null) {
+ emitDebugPosition(pc, move.getPosition());
+ }
+ } else if (instruction.isArgument()) {
startArgument(instruction.asArgument());
} else if (instruction.isDebugLocalsChange()) {
updateLocals(instruction.asDebugLocalsChange());
} else if (instruction.getBlock().exit() == instruction) {
- // If this is the end of the block clear out the pending state and exit.
+ // If this is the end of the block clear out the pending state.
pendingLocals = null;
pendingLocalChanges = false;
- return;
- } else if (instruction.isMoveException()) {
- lastMoveInstructionPc = pc;
} else {
// For non-exit / pc-advancing instructions emit any pending changes.
emitLocalChanges(pc);
@@ -111,7 +104,7 @@
if (startLine == NO_LINE_INFO) {
return null;
}
- DexString[] params = new DexString[method.method.proto.parameters.values.length];
+ DexString[] params = new DexString[method.method.getArity()];
if (arguments != null) {
assert params.length == arguments.size();
for (int i = 0; i < arguments.size(); i++) {
@@ -159,7 +152,7 @@
private void startArgument(Argument argument) {
if (arguments == null) {
- arguments = new ArrayList<>(method.method.proto.parameters.values.length);
+ arguments = new ArrayList<>(method.method.getArity());
}
if (!argument.outValue().isThis()) {
arguments.add(argument.getLocalInfo());
@@ -191,18 +184,16 @@
}
private void emitDebugPosition(int pc, int line, DexString file) {
- int emitPc = lastMoveInstructionPc != NO_PC_INFO ? lastMoveInstructionPc : pc;
- lastMoveInstructionPc = NO_PC_INFO;
// The position requires a pc change event and possible events for line, file and local changes.
// Verify that we do not ever produce two subsequent positions at the same pc.
- assert emittedPc != emitPc;
+ assert emittedPc != pc;
if (startLine == NO_LINE_INFO) {
assert emittedLine == NO_LINE_INFO;
startLine = line;
emittedLine = line;
}
- emitAdvancementEvents(emittedPc, emittedLine, emittedFile, emitPc, line, file, events, factory);
- emittedPc = emitPc;
+ emitAdvancementEvents(emittedPc, emittedLine, emittedFile, pc, line, file, events, factory);
+ emittedPc = pc;
emittedLine = line;
emittedFile = file;
if (localsChanged()) {
@@ -215,11 +206,9 @@
private void emitLocalChanges(int pc) {
// If pc advanced since the locals changed and locals indeed have changed, emit the changes.
if (localsChanged()) {
- int emitPc = lastMoveInstructionPc != NO_PC_INFO ? lastMoveInstructionPc : pc;
- lastMoveInstructionPc = NO_PC_INFO;
emitAdvancementEvents(
- emittedPc, emittedLine, emittedFile, emitPc, emittedLine, emittedFile, events, factory);
- emittedPc = emitPc;
+ emittedPc, emittedLine, emittedFile, pc, emittedLine, emittedFile, events, factory);
+ emittedPc = pc;
emitLocalChangeEvents(emittedLocals, pendingLocals, lastKnownLocals, events, factory);
pendingLocalChanges = false;
assert localsEqual(emittedLocals, pendingLocals);
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 572bea9..400b42f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -144,7 +144,7 @@
public void setCode(
IRCode ir, RegisterAllocator registerAllocator, DexItemFactory dexItemFactory) {
final DexBuilder builder = new DexBuilder(ir, registerAllocator, dexItemFactory);
- code = builder.build(method.proto.parameters.values.length);
+ code = builder.build(method.getArity());
}
// Replaces the dex code in the method by setting code to result of compiling the IR.
@@ -152,7 +152,7 @@
DexItemFactory dexItemFactory, DexString firstJumboString) {
final DexBuilder builder =
new DexBuilder(ir, registerAllocator, dexItemFactory, firstJumboString);
- code = builder.build(method.proto.parameters.values.length);
+ code = builder.build(method.getArity());
}
public String toString() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index a066d24..f8b3c8c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -32,6 +32,10 @@
return "Method " + holder + "." + name + " " + proto.toString();
}
+ public int getArity() {
+ return proto.parameters.size();
+ }
+
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems) {
if (indexedItems.addMethod(this)) {
@@ -132,7 +136,7 @@
builder.append(".");
builder.append(name);
builder.append("(");
- for (int i = 0; i < proto.parameters.values.length; i++) {
+ for (int i = 0; i < getArity(); i++) {
if (i != 0) {
builder.append(", ");
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
index 39226d8..5de71a1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -58,6 +58,10 @@
return values.length == 0;
}
+ public int size() {
+ return values.length;
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 290a1a2..16bc790 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -1120,11 +1120,13 @@
List<BasicBlock> predecessors = this.getPredecessors();
boolean hasMoveException = entry().isMoveException();
MoveException move = null;
+ DebugPosition position = null;
if (hasMoveException) {
// Remove the move-exception instruction.
move = entry().asMoveException();
+ position = move.getPosition();
assert move.getPreviousLocalValue() == null;
- this.getInstructions().remove(0);
+ getInstructions().remove(0);
}
// Create new predecessor blocks.
List<BasicBlock> newPredecessors = new ArrayList<>();
@@ -1140,7 +1142,11 @@
Value value = new Value(
valueNumberGenerator.next(), MoveType.OBJECT, move.getDebugInfo());
values.add(value);
- newBlock.add(new MoveException(value));
+ MoveException newMove = new MoveException(value);
+ newBlock.add(newMove);
+ if (position != null) {
+ newMove.setPosition(new DebugPosition(position.line, position.file));
+ }
}
newBlock.add(new Goto());
newBlock.close(null);
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 e1e9a99..7c37649 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
@@ -363,7 +363,7 @@
}
}
assert arguments.size()
- == method.method.proto.parameters.values.length + (method.accessFlags.isStatic() ? 0 : 1);
+ == method.method.getArity() + (method.accessFlags.isStatic() ? 0 : 1);
return arguments;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index 2691eed..554e71f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -9,6 +9,8 @@
public class MoveException extends Instruction {
+ private DebugPosition position = null;
+
public MoveException(Value dest) {
super(dest);
}
@@ -17,6 +19,14 @@
return outValue;
}
+ public DebugPosition getPosition() {
+ return position;
+ }
+
+ public void setPosition(DebugPosition position) {
+ this.position = position;
+ }
+
@Override
public void buildDex(DexBuilder builder) {
int dest = builder.allocatedRegister(dest(), getNumber());
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 9b1aa3f..9e07ad6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -234,7 +234,7 @@
}
private List<MoveType> computeArgumentTypes() {
- List<MoveType> types = new ArrayList<>(proto.parameters.values.length);
+ List<MoveType> types = new ArrayList<>(proto.parameters.size());
String shorty = proto.shorty.toString();
for (int i = 1; i < proto.shorty.size; i++) {
MoveType moveType = MoveType.fromTypeDescriptorChar(shorty.charAt(i));
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 ba63d80..809e3ac 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
@@ -86,6 +86,8 @@
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntSet;
+import it.unimi.dsi.fastutil.longs.Long2ObjectArrayMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -241,11 +243,11 @@
private BasicBlock currentBlock = null;
// Mappings for canonicalizing constants of a given type at IR construction time.
- private Map<Long, ConstNumber> intConstants = new HashMap<>();
- private Map<Long, ConstNumber> longConstants = new HashMap<>();
- private Map<Long, ConstNumber> floatConstants = new HashMap<>();
- private Map<Long, ConstNumber> doubleConstants = new HashMap<>();
- private Map<Long, ConstNumber> nullConstants = new HashMap<>();
+ private Long2ObjectMap<ConstNumber> intConstants = new Long2ObjectArrayMap<>();
+ private Long2ObjectMap<ConstNumber> longConstants = new Long2ObjectArrayMap<>();
+ private Long2ObjectMap<ConstNumber> floatConstants = new Long2ObjectArrayMap<>();
+ private Long2ObjectMap<ConstNumber> doubleConstants = new Long2ObjectArrayMap<>();
+ private Long2ObjectMap<ConstNumber> nullConstants = new Long2ObjectArrayMap<>();
private List<BasicBlock> exitBlocks = new ArrayList<>();
private BasicBlock normalExitBlock;
@@ -669,7 +671,7 @@
// to disable constant canonicalization in debug builds to make sure we have separate values
// for separate locals.
private void canonicalizeAndAddConst(
- ConstType type, int dest, long value, Map<Long, ConstNumber> table) {
+ ConstType type, int dest, long value, Long2ObjectMap<ConstNumber> table) {
ConstNumber existing = table.get(value);
if (existing != null) {
currentBlock.writeCurrentDefinition(dest, existing.outValue(), ThrowingInfo.NO_THROW);
@@ -1977,6 +1979,16 @@
if (currentDebugPosition != null) {
DebugPosition position = currentDebugPosition;
currentDebugPosition = null;
+ if (!currentBlock.getInstructions().isEmpty()) {
+ MoveException move = currentBlock.getInstructions().getLast().asMoveException();
+ if (move != null && move.getPosition() == null) {
+ // Set the position on the move-exception instruction.
+ // ART/DX associates the move-exception pc with the catch-declaration line.
+ // See debug.ExceptionTest.testStepOnCatch().
+ move.setPosition(position);
+ return;
+ }
+ }
addInstruction(position);
}
}
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 d1b1577..a84e082 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
@@ -62,8 +62,7 @@
// TODO(ager): Should we give the new first parameter an actual name? Maybe 'this'?
dexCode.setDebugInfo(dexCode.debugInfoWithAdditionalFirstParameter(null));
assert (dexCode.getDebugInfo() == null)
- || (companionMethod.proto.parameters.values.length
- == dexCode.getDebugInfo().parameters.length);
+ || (companionMethod.getArity() == dexCode.getDebugInfo().parameters.length);
companionMethods.add(new DexEncodedMethod(companionMethod,
newFlags, virtual.annotations, virtual.parameterAnnotations, code));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index c2600b4..55e6296 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -459,8 +459,7 @@
DexCode dexCode = newMethod.getCode().asDexCode();
dexCode.setDebugInfo(dexCode.debugInfoWithAdditionalFirstParameter(null));
assert (dexCode.getDebugInfo() == null)
- || (callTarget.proto.parameters.values.length
- == dexCode.getDebugInfo().parameters.length);
+ || (callTarget.getArity() == dexCode.getDebugInfo().parameters.length);
directMethods[i] = newMethod;
return true;
}
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 0bd7188..f51c136 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
@@ -28,7 +28,6 @@
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.HashMultiset;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multiset;
import com.google.common.collect.Multiset.Entry;
import com.google.common.collect.Multisets;
@@ -288,7 +287,7 @@
}
for (BasicBlock block : blocks) {
- boolean blockEntry = true;
+ block.setLocalsAtEntry(new Int2ReferenceOpenHashMap<>(currentLocals));
ListIterator<Instruction> instructionIterator = block.listIterator();
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
@@ -307,8 +306,8 @@
}
}
while (nextStartingRange != null && nextStartingRange.start <= index) {
- // If the full range is between the two debug positions ignore it.
- if (nextStartingRange.end > index) {
+ // If the range is live at this index open it.
+ if (index < nextStartingRange.end) {
openRanges.add(nextStartingRange);
assert !currentLocals.containsKey(nextStartingRange.register);
currentLocals.put(nextStartingRange.register, nextStartingRange.local);
@@ -317,10 +316,7 @@
}
nextStartingRange = rangeIterator.hasNext() ? rangeIterator.next() : null;
}
- if (blockEntry) {
- blockEntry = false;
- block.setLocalsAtEntry(new Int2ReferenceOpenHashMap<>(currentLocals));
- } else if (localsChanged && shouldEmitChangesAtInstruction(instruction)) {
+ if (localsChanged && shouldEmitChangesAtInstruction(instruction)) {
DebugLocalsChange change = createLocalsChange(ending, starting);
if (change != null) {
if (instruction.isDebugPosition() || instruction.isJumpInstruction()) {
@@ -368,18 +364,6 @@
|| (instruction.isGoto() && instruction.asGoto().getTarget() == code.getNormalExitBlock());
}
- private boolean verifyLocalsEqual(
- ImmutableMap<Integer, DebugLocalInfo> a, Map<Integer, DebugLocalInfo> b) {
- int size = 0;
- for (Map.Entry<Integer, DebugLocalInfo> entry : b.entrySet()) {
- if (entry.getValue() != null) {
- assert a.get(entry.getKey()) == entry.getValue();
- ++size;
- }
- }
- return a.size() == size;
- }
-
private void clearState() {
liveAtEntrySets = null;
liveIntervals = null;
@@ -1664,14 +1648,8 @@
for (Phi phi : successor.getPhis()) {
LiveIntervals toIntervals = phi.getLiveIntervals().getSplitCovering(toInstruction);
Value operand = phi.getOperand(predIndex);
- LiveIntervals fromIntervals = operand.getLiveIntervals();
- if (operand.isPhi() && operand != phi && successor.getPhis().contains(operand)) {
- // If the input to this phi is another phi in this block we want the value after
- // merging which is the value for that phi at the from instruction.
- fromIntervals = fromIntervals.getSplitCovering(fromInstruction);
- } else {
- fromIntervals = fromIntervals.getSplitCovering(fromInstruction);
- }
+ LiveIntervals fromIntervals =
+ operand.getLiveIntervals().getSplitCovering(fromInstruction);
if (fromIntervals != toIntervals && !toIntervals.isArgumentInterval()) {
assert block.getSuccessors().size() == 1;
spillMoves.addPhiMove(fromInstruction - 1, toIntervals, fromIntervals);
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
index 9c45617..1537f05 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -271,7 +271,7 @@
}
public static MethodSignature fromDexMethod(DexMethod method) {
- String[] paramNames = new String[method.proto.parameters.values.length];
+ String[] paramNames = new String[method.getArity()];
DexType[] values = method.proto.parameters.values;
for (int i = 0; i < values.length; i++) {
paramNames[i] = values[i].toSourceString();
diff --git a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
index 1a28332..f538125 100644
--- a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.optimize.InvokeSingleTargetExtractor.InvokeKind;
-
import java.util.IdentityHashMap;
import java.util.Map;
@@ -40,8 +39,7 @@
method.getCode().registerReachableDefinitions(targetExtractor);
DexMethod target = targetExtractor.getTarget();
InvokeKind kind = targetExtractor.getKind();
- if (target != null &&
- target.proto.parameters.values.length == method.method.proto.parameters.values.length) {
+ if (target != null && target.getArity() == method.method.getArity()) {
assert !method.accessFlags.isPrivate() && !method.accessFlags.isConstructor();
target = lense.lookupMethod(target, method);
if (kind == InvokeKind.STATIC) {
@@ -73,7 +71,6 @@
}
-
private static class BridgeLense extends GraphLense {
private final GraphLense previousLense;
diff --git a/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java b/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
index d03c74b..e01439d 100644
--- a/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
@@ -571,7 +571,7 @@
for (DexMethod method : invokes) {
Int2IntMap positionsMap = seenPositions.get(method.name);
if (positionsMap != null) {
- int arity = method.proto.parameters.values.length;
+ int arity = method.getArity();
int previous = positionsMap.get(arity);
if (previous != NOT_FOUND) {
assert previous != 0;
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 15ca87b..e767030 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -182,7 +182,7 @@
* Get the input stream of the dead-code resource if exists.
*/
public InputStream getDeadCode(Closer closer) throws IOException {
- return deadCode == null ? null : deadCode.getStream(closer);
+ return deadCode == null ? null : closer.register(deadCode.getStream());
}
/**
@@ -196,7 +196,7 @@
* Get the input stream of the proguard-map resource if it exists.
*/
public InputStream getProguardMap(Closer closer) throws IOException {
- return proguardMap == null ? null : proguardMap.getStream(closer);
+ return proguardMap == null ? null : closer.register(proguardMap.getStream());
}
/**
@@ -210,7 +210,7 @@
* Get the input stream of the proguard-seeds resource if it exists.
*/
public InputStream getProguardSeeds(Closer closer) throws IOException {
- return proguardSeeds == null ? null : proguardSeeds.getStream(closer);
+ return proguardSeeds == null ? null : closer.register(proguardSeeds.getStream());
}
/**
@@ -224,7 +224,7 @@
* Get the input stream of the package distribution resource if it exists.
*/
public InputStream getPackageDistribution(Closer closer) throws IOException {
- return packageDistribution == null ? null : packageDistribution.getStream(closer);
+ return packageDistribution == null ? null : closer.register(packageDistribution.getStream());
}
/**
@@ -238,7 +238,7 @@
* Get the input stream of the main dex list resource if it exists.
*/
public InputStream getMainDexList(Closer closer) throws IOException {
- return mainDexList == null ? null : mainDexList.getStream(closer);
+ return mainDexList == null ? null : closer.register(mainDexList.getStream());
}
/**
@@ -271,7 +271,7 @@
if (!Files.exists(filePath.getParent())) {
Files.createDirectories(filePath.getParent());
}
- Files.copy(dexProgramSources.get(i).getStream(closer), filePath, options);
+ Files.copy(closer.register(dexProgramSources.get(i).getStream()), filePath, options);
}
}
}
@@ -307,7 +307,7 @@
List<Resource> dexProgramSources = getDexProgramResources();
for (int i = 0; i < dexProgramSources.size(); i++) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ByteStreams.copy(dexProgramSources.get(i).getStream(closer), out);
+ ByteStreams.copy(closer.register(dexProgramSources.get(i).getStream()), out);
dex.add(out.toByteArray());
}
// TODO(sgjesse): Add Proguard map and seeds.
@@ -326,7 +326,8 @@
List<Resource> dexProgramSources = getDexProgramResources();
for (int i = 0; i < dexProgramSources.size(); i++) {
ZipEntry zipEntry = new ZipEntry(outputMode.getOutputPath(dexProgramSources.get(i), i));
- byte[] bytes = ByteStreams.toByteArray(dexProgramSources.get(i).getStream(closer));
+ byte[] bytes =
+ ByteStreams.toByteArray(closer.register(dexProgramSources.get(i).getStream()));
zipEntry.setSize(bytes.length);
out.putNextEntry(zipEntry);
out.write(bytes);
diff --git a/src/main/java/com/android/tools/r8/utils/ClassProvider.java b/src/main/java/com/android/tools/r8/utils/ClassProvider.java
index 25abdce..63a847a 100644
--- a/src/main/java/com/android/tools/r8/utils/ClassProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/ClassProvider.java
@@ -100,7 +100,7 @@
try (Closer closer = Closer.create()) {
JarClassFileReader classReader =
new JarClassFileReader(reader, classKind.bridgeConsumer(classConsumer));
- classReader.read(DEFAULT_DEX_FILENAME, classKind, resource.getStream(closer));
+ classReader.read(DEFAULT_DEX_FILENAME, classKind, closer.register(resource.getStream()));
} catch (IOException e) {
throw new CompilationError("Failed to load class: " + descriptor, e);
}
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 d1f8290..eb746d7 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -47,6 +47,8 @@
public List<String> methodsFilter = ImmutableList.of();
public int minApiLevel = Constants.DEFAULT_ANDROID_API;
+ // Skipping min_api check and compiling an intermediate result intended for later merging.
+ public boolean intermediate = false;
public List<String> logArgumentsFilter = ImmutableList.of();
// Defines interface method rewriter behavior.
@@ -273,6 +275,14 @@
return minApiLevel >= Constants.ANDROID_N_API;
}
+ public boolean canUsePrivateInterfaceMethods() {
+ return minApiLevel >= Constants.ANDROID_N_API;
+ }
+
+ public boolean canUseMultidex() {
+ return intermediate || minApiLevel >= Constants.ANDROID_L_API;
+ }
+
public boolean canUseLongCompareAndObjectsNonNull() {
return minApiLevel >= Constants.ANDROID_K_API;
}
@@ -281,10 +291,6 @@
return minApiLevel >= Constants.ANDROID_K_API;
}
- public boolean canUsePrivateInterfaceMethods() {
- return minApiLevel >= Constants.ANDROID_N_API;
- }
-
// APIs for accessing parameter names annotations are not available before Android O, thus does
// not emit them to avoid wasting space in Dex files because runtimes before Android O will ignore
// them.
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index d8b9bbc..803d760 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -294,7 +294,7 @@
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[16384];
try (Closer closer = Closer.create()) {
- InputStream stream = resource.getStream(closer);
+ InputStream stream = closer.register(resource.getStream());
int read;
while ((read = stream.read(buffer, 0, buffer.length)) != -1) {
output.write(buffer, 0, read);
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 9aec981..38868b6 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -61,18 +61,16 @@
}
TestRunner withClassCheck(Consumer<FoundClassSubject> check) {
- withDexCheck(inspector -> inspector.forAllClasses(check));
- return this;
+ return withDexCheck(inspector -> inspector.forAllClasses(check));
}
TestRunner withMethodCheck(Consumer<FoundMethodSubject> check) {
- withClassCheck(clazz -> clazz.forAllMethods(check));
- return this;
+ return withClassCheck(clazz -> clazz.forAllMethods(check));
}
- <T extends InstructionSubject> TestRunner
- withInstructionCheck(Predicate<InstructionSubject> filter, Consumer<T> check) {
- withMethodCheck(method -> {
+ <T extends InstructionSubject> TestRunner withInstructionCheck(
+ Predicate<InstructionSubject> filter, Consumer<T> check) {
+ return withMethodCheck(method -> {
if (method.isAbstract()) {
return;
}
@@ -81,7 +79,6 @@
check.accept(iterator.next());
}
});
- return this;
}
TestRunner withOptionConsumer(Consumer<InternalOptions> consumer) {
@@ -267,7 +264,7 @@
@Test
public void paramNames() throws Throwable {
test("paramnames", "paramnames", "ParameterNames")
- .withMinApiLevel(26)
+ .withMinApiLevel(ANDROID_O_API)
.withOptionConsumer((internalOptions) -> internalOptions.allowParameterName = true)
.run();
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index e01ecc0..d0032cd 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
@@ -56,7 +57,7 @@
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
- private static final int DEFAULT_MIN_SDK = 14;
+ private static final int DEFAULT_MIN_SDK = Constants.ANDROID_I_API;
public enum DexVm {
ART_4_4_4("4.4.4"),
@@ -487,6 +488,14 @@
.build());
}
+ public static DexApplication optimizeWithR8(
+ DexApplication application,
+ AppInfoWithSubtyping appInfo,
+ InternalOptions options)
+ throws ProguardRuleParserException, ExecutionException, IOException {
+ return R8.optimize(application, appInfo, options);
+ }
+
public static AndroidApp runD8(AndroidApp app) throws CompilationException, IOException {
return runD8(app, null);
}
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
index 8fdcfa5..fc9ee3f 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
@@ -62,8 +62,8 @@
List<Resource> files2 = app2.getDexProgramResources();
assertEquals(files1.size(), files2.size());
for (int index = 0; index < files1.size(); index++) {
- InputStream file1 = files1.get(index).getStream(closer);
- InputStream file2 = files2.get(index).getStream(closer);
+ InputStream file1 = closer.register(files1.get(index).getStream());
+ InputStream file2 = closer.register(files2.get(index).getStream());
byte[] bytes1 = ByteStreams.toByteArray(file1);
byte[] bytes2 = ByteStreams.toByteArray(file2);
assertArrayEquals("File index " + index, bytes1, bytes2);
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreTreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreTreeShakeJarVerificationTest.java
index d28c37d..fa193d4 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreTreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreTreeShakeJarVerificationTest.java
@@ -34,7 +34,7 @@
int bytes = 0;
try (Closer closer = Closer.create()) {
for (Resource dex : app.getDexProgramResources()) {
- bytes += ByteStreams.toByteArray(dex.getStream(closer)).length;
+ bytes += ByteStreams.toByteArray(closer.register(dex.getStream())).length;
}
}
assertTrue("Expected max size of " + maxSize + ", got " + bytes, bytes < maxSize);
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeTreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeTreeShakeJarVerificationTest.java
index b26d1aa..8ee3674 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeTreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeTreeShakeJarVerificationTest.java
@@ -36,7 +36,7 @@
int bytes = 0;
try (Closer closer = Closer.create()) {
for (Resource dex : app.getDexProgramResources()) {
- bytes += ByteStreams.toByteArray(dex.getStream(closer)).length;
+ bytes += ByteStreams.toByteArray(closer.register(dex.getStream())).length;
}
}
assertTrue("Expected max size of " + maxSize + ", got " + bytes, bytes < maxSize);
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
index e5bbad6..04d84e4 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -132,6 +132,6 @@
protected static DexApplication process(DexApplication app, InternalOptions options)
throws IOException, ProguardRuleParserException, ExecutionException {
- return new R8(options).optimize(app, new AppInfoWithSubtyping(app));
+ return ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), options);
}
}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 001883f..69fdd65 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -121,6 +121,10 @@
return generatedApplicationsFolder.getRoot().toPath().resolve("many-classes-stereo.zip");
}
+ private static Path getManyClassesForceMultiDexAppPath() {
+ return generatedApplicationsFolder.getRoot().toPath().resolve("many-classes-stereo-forced.zip");
+ }
+
@Rule
public ExpectedException thrown = ExpectedException.none();
@@ -308,6 +312,32 @@
}
}
+ @Test
+ public void checkIntermediateMultiDex() throws Exception {
+ // Generates an application with many classes, every even in one package and every odd in
+ // another. Add enough methods so the application cannot fit into one dex file.
+ // Notice that this one allows multidex while using lower API.
+ AndroidApp generated = generateApplication(
+ MANY_CLASSES, Constants.ANDROID_K_API, true, MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS);
+ generated.write(getManyClassesForceMultiDexAppPath(), OutputMode.Indexed);
+ // Make sure the generated app indeed has multiple dex files.
+ assertTrue(generated.getDexProgramResources().size() > 1);
+ }
+
+ @Test
+ public void testMultiDexFailDueToMinApi() throws Exception {
+ // Generates an application with many classes, every even in one package and every odd in
+ // another. Add enough methods so the application cannot fit into one dex file.
+ // Notice that this one fails due to the min API.
+ try {
+ generateApplication(
+ MANY_CLASSES, Constants.ANDROID_K_API, false, MANY_CLASSES_MULTI_DEX_METHODS_PER_CLASS);
+ fail("Expect to fail, for there are many classes while multidex is not enabled.");
+ } catch (CompilationError e) {
+ assertTrue(e.getMessage().contains("Cannot fit all classes in a single dex file."));
+ }
+ }
+
private void addMainListFile(ArrayList<Path> mainLists, List<String> content)
throws IOException {
Path listFile = temp.newFile().toPath();
@@ -393,9 +423,16 @@
public static AndroidApp generateApplication(List<String> classes, int minApi, int methodCount)
throws IOException, ExecutionException {
+ return generateApplication(classes, minApi, false, methodCount);
+ }
+
+ private static AndroidApp generateApplication(
+ List<String> classes, int minApi, boolean intermediate, int methodCount)
+ throws IOException, ExecutionException {
Timing timing = new Timing("MainDexListTests");
InternalOptions options = new InternalOptions();
options.minApiLevel = minApi;
+ options.intermediate = intermediate;
DexItemFactory factory = options.itemFactory;
DexApplication.Builder builder = new DexApplication.Builder(factory, timing);
for (String clazz : classes) {
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index 2549ff1..57c8cf6 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.maindexlist;
+import static com.android.tools.r8.dex.Constants.ANDROID_I_API;
import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.ZIP_EXTENSION;
@@ -44,7 +45,7 @@
EXAMPLE_BUILD_DIR,
Paths.get(EXAMPLE_SRC_DIR, "multidex", "main-dex-rules.txt"),
Paths.get(EXAMPLE_SRC_DIR, "multidex001", "ref-list-1.txt"),
- 14);
+ ANDROID_I_API);
}
@Test
@@ -55,7 +56,7 @@
EXAMPLE_BUILD_DIR,
Paths.get(EXAMPLE_SRC_DIR, "multidex001", "main-dex-rules-2.txt"),
Paths.get(EXAMPLE_SRC_DIR, "multidex001", "ref-list-2.txt"),
- 14);
+ ANDROID_I_API);
}
@Test
@@ -66,7 +67,7 @@
EXAMPLE_BUILD_DIR,
Paths.get(EXAMPLE_SRC_DIR, "multidex", "main-dex-rules.txt"),
Paths.get(EXAMPLE_SRC_DIR, "multidex002", "ref-list-1.txt"),
- 14);
+ ANDROID_I_API);
}
@Test
@@ -77,7 +78,7 @@
EXAMPLE_BUILD_DIR,
Paths.get(EXAMPLE_SRC_DIR, "multidex", "main-dex-rules.txt"),
Paths.get(EXAMPLE_SRC_DIR, "multidex003", "ref-list-1.txt"),
- 14);
+ ANDROID_I_API);
}
@Test
@@ -88,7 +89,7 @@
EXAMPLE_O_BUILD_DIR,
Paths.get(EXAMPLE_SRC_DIR, "multidex", "main-dex-rules.txt"),
Paths.get(EXAMPLE_O_SRC_DIR, "multidex004", "ref-list-1.txt"),
- 14);
+ ANDROID_I_API);
}
private void doTest(
@@ -137,9 +138,9 @@
CompilationResult result = ToolHelper.runR8WithFullResult(command, optionsConsumer);
List<String> resultMainDexList =
result.dexApplication.mainDexList.stream()
- .filter(dexType -> isApplicationClass(dexType, result) != null)
- .map(dexType -> dexType.descriptor.toString())
- .collect(Collectors.toList());
+ .filter(dexType -> isApplicationClass(dexType, result))
+ .map(dexType -> dexType.descriptor.toString())
+ .collect(Collectors.toList());
Collections.sort(resultMainDexList);
String[] refList = new String(Files.readAllBytes(
expectedMainDexList), StandardCharsets.UTF_8).split("\n");
@@ -161,7 +162,7 @@
}
}
- private Object isApplicationClass(DexType dexType, CompilationResult result) {
+ private boolean isApplicationClass(DexType dexType, CompilationResult result) {
DexClass clazz = result.appInfo.definitionFor(dexType);
return clazz != null && clazz.isProgramClass();
}
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 9a12d3e..f070130 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -385,8 +385,7 @@
protected DexApplication processApplication(DexApplication application, InternalOptions options) {
try {
- R8 r8 = new R8(options);
- return r8.optimize(application, new AppInfoWithSubtyping(application));
+ return ToolHelper.optimizeWithR8(application, new AppInfoWithSubtyping(application), options);
} catch (IOException | ProguardRuleParserException | ExecutionException e) {
throw new RuntimeException(e);
}
diff --git a/src/test/java/com/android/tools/r8/smali/SwitchRewritingTest.java b/src/test/java/com/android/tools/r8/smali/SwitchRewritingTest.java
index e49ea84..f10add0 100644
--- a/src/test/java/com/android/tools/r8/smali/SwitchRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/smali/SwitchRewritingTest.java
@@ -8,6 +8,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.R8;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.code.Const;
import com.android.tools.r8.code.Const4;
import com.android.tools.r8.code.ConstHigh16;
@@ -284,7 +285,7 @@
" return");
DexApplication app = builder.read();
- app = new R8(new InternalOptions()).optimize(app, new AppInfoWithSubtyping(app));
+ app = ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), new InternalOptions());
MethodSignature signature = new MethodSignature("Test", "test", "int", ImmutableList.of("int"));
DexEncodedMethod method = getMethod(app, signature);
@@ -344,7 +345,7 @@
" return");
DexApplication app = builder.read();
- app = new R8(new InternalOptions()).optimize(app, new AppInfoWithSubtyping(app));
+ app = ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), new InternalOptions());
MethodSignature signature = new MethodSignature("Test", "test", "int", ImmutableList.of("int"));
DexEncodedMethod method = getMethod(app, signature);
@@ -417,7 +418,7 @@
" return");
DexApplication app = builder.read();
- app = new R8(new InternalOptions()).optimize(app, new AppInfoWithSubtyping(app));
+ app = ToolHelper.optimizeWithR8(app, new AppInfoWithSubtyping(app), new InternalOptions());
MethodSignature signature = new MethodSignature("Test", "test", "int", ImmutableList.of("int"));
DexEncodedMethod method = getMethod(app, signature);