Merge "Test desugaring dependencies of an android test"
diff --git a/src/main/java/com/android/tools/r8/BaseCommand.java b/src/main/java/com/android/tools/r8/BaseCommand.java
index ec4f527..5eb67c4 100644
--- a/src/main/java/com/android/tools/r8/BaseCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCommand.java
@@ -248,6 +248,10 @@
}
protected void validate() throws CompilationException {
+ if (app.hasMainDexList() && outputMode == OutputMode.FilePerClass) {
+ throw new CompilationException(
+ "Option --main-dex-list cannot be used with --file-per-class");
+ }
FileUtils.validateOutputFile(outputPath);
}
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 6ac5f1e..b856556 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -71,6 +71,14 @@
return this;
}
+ protected void validate() throws CompilationException {
+ super.validate();
+ if (getAppBuilder().hasMainDexList() && intermediate) {
+ throw new CompilationException(
+ "Option --main-dex-list cannot be used with --intermediate");
+ }
+ }
+
/**
* Build the final D8Command.
*/
@@ -95,17 +103,19 @@
"Usage: d8 [options] <input-files>",
" where <input-files> are any combination of dex, class, zip, jar, or apk files",
" and options are:",
- " --debug # Compile with debugging information (default).",
- " --release # Compile without debugging information.",
- " --output <file> # Output result in <outfile>.",
- " # <file> must be an existing directory or a zip file.",
- " --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."));
+ " --debug # Compile with debugging information (default).",
+ " --release # Compile without debugging information.",
+ " --output <file> # Output result in <outfile>.",
+ " # <file> must be an existing directory or a zip file.",
+ " --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",
+ " --main-dex-list <file> # List of classes to place in the primary dex file.",
+ " --version # Print the version of d8.",
+ " --help # Print this message."));
private boolean intermediate = false;
@@ -121,6 +131,7 @@
public static Builder parse(String[] args) throws CompilationException, IOException {
CompilationMode modeSet = null;
Path outputPath = null;
+ String mainDexList = null;
Builder builder = builder();
try {
for (int i = 0; i < args.length; i++) {
@@ -156,6 +167,12 @@
builder.addLibraryFiles(Paths.get(args[++i]));
} else if (arg.equals("--classpath")) {
builder.addClasspathFiles(Paths.get(args[++i]));
+ } else if (arg.equals("--main-dex-list")) {
+ if (mainDexList != null) {
+ throw new CompilationException("Only one --main-dex-list supported");
+ }
+ mainDexList = args[++i];
+ builder.setMainDexListFile(Paths.get(mainDexList));
} else if (arg.equals("--min-api")) {
builder.setMinApiLevel(Integer.valueOf(args[++i]));
} else if (arg.equals("--intermediate")) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 3b88ba8..1f45dec 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -129,6 +129,14 @@
return self();
}
+ protected void validate() throws CompilationException {
+ super.validate();
+ if (minimalMainDex && mainDexRules.isEmpty() && !getAppBuilder().hasMainDexList()) {
+ throw new CompilationException(
+ "Option --minimal-main-dex require --main-dex-rules");
+ }
+ }
+
@Override
public R8Command build() throws CompilationException, IOException {
// If printing versions ignore everything else.
@@ -193,20 +201,23 @@
"Usage: r8 [options] <input-files>",
" where <input-files> are any combination of dex, class, zip, jar, or apk files",
" and options are:",
- " --release # Compile without debugging information (default).",
- " --debug # Compile with debugging information.",
- " --output <file> # Output result in <file>.",
- " # <file> must be an existing directory or a zip file.",
- " --lib <file> # Add <file> as a library resource.",
- " --min-api # Minimum Android API level compatibility.",
- " --pg-conf <file> # Proguard configuration <file> (implies tree shaking/minification).",
- " --pg-map <file> # Proguard map <file>.",
- " --no-tree-shaking # Force disable tree shaking of unreachable classes.",
- " --no-minification # Force disable minification of names.",
- " --multidex-rules <file> # Enable automatic classes partitioning for legacy multidex.",
- " # <file> is a Proguard configuration file (with only keep rules).",
- " --version # Print the version of r8.",
- " --help # Print this message."));
+ " --release # Compile without debugging information (default).",
+ " --debug # Compile with debugging information.",
+ " --output <file> # Output result in <file>.",
+ " # <file> must be an existing directory or a zip file.",
+ " --lib <file> # Add <file> as a library resource.",
+ " --min-api # Minimum Android API level compatibility.",
+ " --pg-conf <file> # Proguard configuration <file> (implies tree",
+ " # shaking/minification).",
+ " --pg-map <file> # Proguard map <file>.",
+ " --no-tree-shaking # Force disable tree shaking of unreachable classes.",
+ " --no-minification # Force disable minification of names.",
+ " --main-dex-rules <file> # Proguard keep rules for classes to place in the",
+ " # primary dex file.",
+ " --minimal-main-dex # Only place classes specified by --main-dex-rules",
+ " # in the primary dex file.",
+ " --version # Print the version of r8.",
+ " --help # Print this message."));
private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
private final boolean minimalMainDex;
@@ -271,9 +282,9 @@
builder.setTreeShaking(false);
} else if (arg.equals("--no-minification")) {
builder.setMinification(false);
- } else if (arg.equals("--multidex-rules")) {
+ } else if (arg.equals("--main-dex-rules")) {
builder.addMainDexRules(Paths.get(args[++i]));
- } else if (arg.equals("--minimal-maindex")) {
+ } else if (arg.equals("--minimal-main-dex")) {
builder.setMinimalMainDex(true);
} else if (arg.equals("--pg-conf")) {
builder.addProguardConfigurationFiles(Paths.get(args[++i]));
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 44721ae..5c9d171 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
@@ -1107,7 +1107,7 @@
catchSuccessor.splitCriticalExceptionEdges(
code.valueNumberGenerator,
newBlock -> {
- newBlock.setNumber(code.blocks.size());
+ newBlock.setNumber(code.getHighestBlockNumber() + 1);
blockIterator.add(newBlock);
});
}
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 6f1a9b2..398c87e 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
@@ -291,8 +291,37 @@
}
for (BasicBlock block : blocks) {
- boolean blockEntry = true;
ListIterator<Instruction> instructionIterator = block.listIterator();
+ // Close ranges up-to and including the first instruction. Ends are exclusive so the range is
+ // closed at entry.
+ int entryIndex = block.entry().getNumber();
+ {
+ ListIterator<LocalRange> it = openRanges.listIterator(0);
+ while (it.hasNext()) {
+ LocalRange openRange = it.next();
+ if (openRange.end <= entryIndex) {
+ it.remove();
+ assert currentLocals.get(openRange.register) == openRange.local;
+ currentLocals.remove(openRange.register);
+ }
+ }
+ }
+ // Open ranges up-to but excluding the first instruction. Starts are inclusive but entry is
+ // prior to the first instruction.
+ while (nextStartingRange != null && nextStartingRange.start < entryIndex) {
+ // If the range is live at this index open it.
+ if (entryIndex < nextStartingRange.end) {
+ openRanges.add(nextStartingRange);
+ assert !currentLocals.containsKey(nextStartingRange.register);
+ currentLocals.put(nextStartingRange.register, nextStartingRange.local);
+ }
+ nextStartingRange = rangeIterator.hasNext() ? rangeIterator.next() : null;
+ }
+ if (block.entry().isMoveException()) {
+ fixupSpillMovesAtMoveException(block, instructionIterator, openRanges, currentLocals);
+ } else {
+ block.setLocalsAtEntry(new Int2ReferenceOpenHashMap<>(currentLocals));
+ }
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
int index = instruction.getNumber();
@@ -320,25 +349,15 @@
}
nextStartingRange = rangeIterator.hasNext() ? rangeIterator.next() : null;
}
-
- if (blockEntry) {
- blockEntry = false;
- if (instruction.isMoveException()) {
- fixupSpillMovesAtMoveException(block, instructionIterator, openRanges, currentLocals);
- } else {
- block.setLocalsAtEntry(new Int2ReferenceOpenHashMap<>(currentLocals));
- }
- } else {
- if (localsChanged && shouldEmitChangesAtInstruction(instruction)) {
- DebugLocalsChange change = createLocalsChange(ending, starting);
- if (change != null) {
- if (instruction.isDebugPosition() || instruction.isJumpInstruction()) {
- instructionIterator.previous();
- instructionIterator.add(change);
- instructionIterator.next();
- } else {
- instructionIterator.add(change);
- }
+ if (localsChanged && shouldEmitChangesAtInstruction(instruction)) {
+ DebugLocalsChange change = createLocalsChange(ending, starting);
+ if (change != null) {
+ if (instruction.isDebugPosition() || instruction.isJumpInstruction()) {
+ instructionIterator.previous();
+ instructionIterator.add(change);
+ instructionIterator.next();
+ } else {
+ instructionIterator.add(change);
}
}
}
@@ -359,11 +378,13 @@
initialLocals.put(exceptionalRegister, open.local);
}
block.setLocalsAtEntry(new Int2ReferenceOpenHashMap<>(initialLocals));
- Int2ReferenceMap<DebugLocalInfo> clobberedLocals = new Int2ReferenceOpenHashMap<>();
- Iterator<Instruction> moveIterator = block.iterator();
+ Instruction entry = instructionIterator.next();
+ assert block.entry() == entry;
assert block.entry().isMoveException();
- int index = block.entry().getNumber();
+ Iterator<Instruction> moveIterator = block.iterator();
moveIterator.next();
+ int index = entry.getNumber();
+ Int2ReferenceMap<DebugLocalInfo> clobberedLocals = new Int2ReferenceOpenHashMap<>();
while (moveIterator.hasNext()) {
Instruction next = moveIterator.next();
if (next.getNumber() != -1) {
@@ -392,10 +413,10 @@
// Compute the final change in locals and emit it after all spill moves.
while (instructionIterator.hasNext()) {
if (instructionIterator.next().getNumber() != -1) {
- instructionIterator.previous();
break;
}
}
+ instructionIterator.previous();
Int2ReferenceMap<DebugLocalInfo> ending = new Int2ReferenceOpenHashMap<>();
Int2ReferenceMap<DebugLocalInfo> starting = new Int2ReferenceOpenHashMap<>();
for (Entry<DebugLocalInfo> initialLocal : initialLocals.int2ReferenceEntrySet()) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
index eb66537..bd7efce 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
@@ -155,6 +155,7 @@
if (receiver != null) {
receiverValue = builder.writeRegister(receiverRegister, MoveType.OBJECT, NO_THROW);
builder.add(new Argument(receiverValue));
+ receiverValue.markAsThis();
}
// Fill in the Argument instructions in the argument block.
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
index 4aca460..86670b8 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -140,24 +140,21 @@
if (holder != null && !holder.isLibraryClass()) {
NamingState<DexProto> state = states
.computeIfAbsent(type, k -> states.get(holder.superType).createChild());
- assignNamesToMethods(holder.directMethods(), state, doPrivates, renaming);
- assignNamesToMethods(holder.virtualMethods(), state, doPrivates, renaming);
+ holder.forEachMethod(method -> assignNameToMethod(method, state, doPrivates, renaming));
}
type.forAllExtendsSubtypes(
subtype -> assignNamesToClassesMethods(subtype, doPrivates, renaming));
}
- private void assignNamesToMethods(DexEncodedMethod[] methods,
+ private void assignNameToMethod(DexEncodedMethod encodedMethod,
NamingState<DexProto> state, boolean doPrivates, Map<DexMethod, DexString> renaming) {
- for (DexEncodedMethod encodedMethod : methods) {
- if (encodedMethod.accessFlags.isPrivate() != doPrivates) {
- continue;
- }
- DexMethod method = encodedMethod.method;
- if (!state.isReserved(method.name, method.proto)
- && !encodedMethod.accessFlags.isConstructor()) {
- renaming.put(method, state.assignNewNameFor(method.name, method.proto, !doPrivates));
- }
+ if (encodedMethod.accessFlags.isPrivate() != doPrivates) {
+ return;
+ }
+ DexMethod method = encodedMethod.method;
+ if (!state.isReserved(method.name, method.proto)
+ && !encodedMethod.accessFlags.isConstructor()) {
+ renaming.put(method, state.assignNewNameFor(method.name, method.proto, !doPrivates));
}
}
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 e767030..19d5153 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -579,6 +579,10 @@
return this;
}
+ public boolean hasMainDexList() {
+ return mainDexList != null;
+ }
+
/**
* Set the main-dex list data.
*/
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 a5e2309..8befa70 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -410,7 +410,7 @@
R8Command.builder()
.addProgramFiles(app)
.setMainDexListFile(mainDexList)
- .setMinimalMainDex(minimalMainDex)
+ .setMinimalMainDex(minimalMainDex && mainDex.size() > 0)
.setOutputPath(outDir)
.setTreeShaking(false)
.setMinification(false)
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 6f45137..ed146b72 100644
--- a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
@@ -156,6 +156,37 @@
}
@Test
+ public void mainDexList() throws Throwable {
+ Path mailDexList = temp.getRoot().toPath().resolve("main-dex-list.txt");
+ D8Command command = parse("--main-dex-list", mailDexList.toString());
+ assertTrue(ToolHelper.getApp(command).hasMainDexList());
+ }
+
+ @Test
+ public void multipleMainDexList() throws Throwable {
+ thrown.expect(CompilationException.class);
+ Path mailDexList1 = temp.getRoot().toPath().resolve("main-dex-list-1.txt");
+ Path mailDexList2 = temp.getRoot().toPath().resolve("main-dex-list-2.txt");
+ parse("--main-dex-list", mailDexList1.toString(), "--main-dex-list", mailDexList2.toString());
+ }
+
+ @Test
+ public void mainDexListWithFilePerClass() throws Throwable {
+ thrown.expect(CompilationException.class);
+ Path mailDexList = temp.getRoot().toPath().resolve("main-dex-list.txt");
+ D8Command command = parse("--main-dex-list", mailDexList.toString(), "--file-per-class");
+ assertTrue(ToolHelper.getApp(command).hasMainDexList());
+ }
+
+ @Test
+ public void mainDexListWithIntermediate() throws Throwable {
+ thrown.expect(CompilationException.class);
+ Path mailDexList = temp.getRoot().toPath().resolve("main-dex-list.txt");
+ D8Command command = parse("--main-dex-list", mailDexList.toString(), "--intermediate");
+ assertTrue(ToolHelper.getApp(command).hasMainDexList());
+ }
+
+ @Test
public void invalidOutputFileTypeParse() throws Throwable {
thrown.expect(CompilationException.class);
Path invalidType = temp.getRoot().toPath().resolve("an-invalid-output-file-type.foobar");
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 0c737b9..27f0367 100644
--- a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
@@ -89,6 +89,24 @@
}
@Test
+ public void mainDexRules() throws Throwable {
+ Path mailDexRules = temp.newFile("main-dex.rules").toPath();
+ parse("--main-dex-rules", mailDexRules.toString());
+ }
+
+ @Test
+ public void minimalMainDex() throws Throwable {
+ thrown.expect(CompilationException.class);
+ parse("--minimal-main-dex");
+ }
+
+ @Test
+ public void mainDexRulesWithMinimalMainDex() throws Throwable {
+ Path mailDexRules = temp.newFile("main-dex.rules").toPath();
+ parse("--main-dex-rules", mailDexRules.toString(), "--minimal-main-dex");
+ }
+
+ @Test
public void existingOutputDirWithDexFiles() throws Throwable {
Path existingDir = temp.newFolder().toPath();
List<Path> classesFiles = ImmutableList.of(
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index 1dabbd3..ee8981b 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -158,9 +158,9 @@
app_provided_pg_conf = True
if options.k:
args.extend(['--pg-conf', options.k])
- if 'multidexrules' in values:
- for rules in values['multidexrules']:
- args.extend(['--multidex-rules', rules])
+ if 'maindexrules' in values:
+ for rules in values['maindexrules']:
+ args.extend(['--main-dex-rules', rules])
if not options.no_libraries and 'libraries' in values:
for lib in values['libraries']:
diff --git a/tools/youtube_data.py b/tools/youtube_data.py
index a3d3791..114e6c7 100644
--- a/tools/youtube_data.py
+++ b/tools/youtube_data.py
@@ -77,7 +77,7 @@
'pgconf': [
'%s_proguard.config' % V12_22_PREFIX,
'%s/proguardsettings/YouTubeRelease_proguard.config' % THIRD_PARTY],
- 'multidexrules' : [
+ 'maindexrules' : [
os.path.join(V12_22_BASE, 'mainDexClasses.rules'),
os.path.join(V12_22_BASE, 'main-dex-classes-release.cfg'),
os.path.join(V12_22_BASE, 'main_dex_YouTubeRelease_proguard.cfg')],