Merge "Check parsing of SynthesizedClassMapMessage"
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 0f0b38f..9b79616 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -9,8 +9,6 @@
import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.ir.conversion.IRConverter;
@@ -168,8 +166,6 @@
AndroidApp inputApp, InternalOptions options, ExecutorService executor)
throws IOException, CompilationException {
try {
- assert !inputApp.hasPackageDistribution();
-
// Disable global optimizations.
options.skipMinification = true;
options.inlineAccessors = false;
@@ -191,7 +187,7 @@
new CompilationResult(
new ApplicationWriter(
app, appInfo, options, marker, null, NamingLens.getIdentityLens(), null)
- .write(null, executor),
+ .write(executor),
app,
appInfo);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 1306e3b..0b16963 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.naming.Minifier;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.BridgeMethodAnalysis;
-import com.android.tools.r8.optimize.DebugStripper;
import com.android.tools.r8.optimize.MemberRebindingAnalysis;
import com.android.tools.r8.optimize.VisibilityBridgeRemover;
import com.android.tools.r8.shaking.AbstractMethodRemover;
@@ -45,7 +44,6 @@
import com.android.tools.r8.utils.CfgPrinter;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.PackageDistribution;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.google.common.io.ByteStreams;
@@ -63,9 +61,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -98,14 +94,13 @@
byte[] deadCode,
NamingLens namingLens,
byte[] proguardSeedsData,
- PackageDistribution packageDistribution,
InternalOptions options)
throws ExecutionException, DexOverflowException {
try {
Marker marker = getMarker(options);
return new ApplicationWriter(
application, appInfo, options, marker, deadCode, namingLens, proguardSeedsData)
- .write(packageDistribution, executorService);
+ .write(executorService);
} catch (IOException e) {
throw new RuntimeException("Cannot write dex application", e);
}
@@ -142,17 +137,6 @@
timing.end();
}
- if (!options.skipDebugInfoOpt && (application.getProguardMap() != null)) {
- try {
- timing.begin("DebugStripper");
- DebugStripper stripper =
- new DebugStripper(application.getProguardMap(), options, appInfo.dexItemFactory);
- application.classes().forEach(stripper::processClass);
- } finally {
- timing.end();
- }
- }
-
if (options.printCfg) {
if (options.printCfgFile == null || options.printCfgFile.isEmpty()) {
System.out.print(printer.toString());
@@ -373,13 +357,6 @@
return null;
}
- PackageDistribution packageDistribution = null;
- if (inputApp.hasPackageDistribution()) {
- try (Closer closer = Closer.create()) {
- packageDistribution = PackageDistribution.load(inputApp.getPackageDistribution(closer));
- }
- }
-
// Generate the resulting application resources.
AndroidApp androidApp =
writeApplication(
@@ -389,7 +366,6 @@
application.deadCode,
namingLens,
proguardSeedsData,
- packageDistribution,
options);
options.printWarnings();
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 301c266..4076a5a 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -37,7 +37,6 @@
private Optional<Boolean> minification = Optional.empty();
private boolean ignoreMissingClasses = false;
private Path printMappingFile = null;
- private Path packageDistributionFile = null;
private Builder() {
super(CompilationMode.RELEASE);
@@ -160,14 +159,6 @@
}
/**
- * Set a package distribution file resource.
- */
- public Builder setPackageDistributionFile(Path path) {
- packageDistributionFile = path;
- return self();
- }
-
- /**
* Deprecated flag to avoid failing if classes are missing during compilation.
*
* <p>TODO: Make compilation safely assume this flag to be true and remove the flag.
@@ -189,10 +180,6 @@
throw new CompilationException(
"Option --main-dex-list-output require --main-dex-rules and/or --main-dex-list");
}
- if (getMode() == CompilationMode.DEBUG && packageDistributionFile != null) {
- throw new CompilationException(
- "Package distribution file is not supported in debug mode");
- }
}
@Override
@@ -237,10 +224,6 @@
// TODO(b/64802420): setProguardMapFile if configuration.hasApplyMappingFile
- if (packageDistributionFile != null) {
- getAppBuilder().setPackageDistributionFile(packageDistributionFile);
- }
-
boolean useTreeShaking = treeShaking.orElse(configuration.isShrinking());
boolean useDiscardedChecker = discardedChecker.orElse(true);
boolean useMinification = minification.orElse(configuration.isObfuscating());
@@ -280,7 +263,6 @@
" --min-api # Minimum Android API level compatibility.",
" --pg-conf <file> # Proguard configuration <file> (implies tree",
" # shaking/minification).",
- " --pg-map <file> # Proguard map <file>.",
" --print-mapping <file> # Write name/line mapping to <file>.",
" --no-tree-shaking # Force disable tree shaking of unreachable classes.",
" --no-discarded-checker # Force disable the discarded checker (when tree shaking).",
@@ -367,8 +349,6 @@
builder.setMainDexListOutputPath(Paths.get(args[++i]));
} else if (arg.equals("--pg-conf")) {
builder.addProguardConfigurationFiles(Paths.get(args[++i]));
- } else if (arg.equals("--pg-map")) {
- builder.setProguardMapFile(Paths.get(args[++i]));
} else if (arg.equals("--ignore-missing-classes")) {
builder.setIgnoreMissingClasses(true);
} else if (arg.equals("--print-mapping")) {
@@ -460,6 +440,14 @@
assert !internal.debug;
internal.debug = getMode() == CompilationMode.DEBUG;
internal.minApiLevel = getMinApiLevel();
+ // -dontoptimize disables optimizations by flipping related flags.
+ if (!proguardConfiguration.isOptimizing()) {
+ internal.skipDebugLineNumberOpt = true;
+ internal.skipClassMerging = true;
+ internal.inlineAccessors = false;
+ internal.removeSwitchMaps = false;
+ internal.outline.enabled = false;
+ }
assert !internal.skipMinification;
internal.skipMinification = !useMinification() || !proguardConfiguration.isObfuscating();
assert internal.useTreeShaking;
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 81d5f9a..b2c02b0 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -179,7 +179,7 @@
InternalOptions options = new InternalOptions();
AppInfo appInfo = new AppInfo(app);
ApplicationWriter writer = new ApplicationWriter(app, appInfo, options, null, null, null, null);
- AndroidApp outApp = writer.write(null, executor);
+ AndroidApp outApp = writer.write(executor);
outApp.writeToDirectory(output, OutputMode.Indexed);
}
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 58c3a5b..6f92740 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -26,7 +26,6 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OutputMode;
-import com.android.tools.r8.utils.PackageDistribution;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
@@ -126,7 +125,7 @@
this.proguardSeedsData = proguardSeedsData;
}
- public AndroidApp write(PackageDistribution packageDistribution, ExecutorService executorService)
+ public AndroidApp write(ExecutorService executorService)
throws IOException, ExecutionException, DexOverflowException {
application.timing.begin("DexApplication.write");
try {
@@ -139,24 +138,11 @@
// Distribute classes into dex files.
VirtualFile.Distributor distributor = null;
if (options.outputMode == OutputMode.FilePerInputClass) {
- assert packageDistribution == null :
- "Cannot combine package distribution definition with file-per-class option.";
distributor = new VirtualFile.FilePerInputClassDistributor(this);
} 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 +"."
- + " For API level < " + Constants.ANDROID_L_API + ", main dex classes list or"
- + " rules must be specified.");
- }
distributor = new VirtualFile.MonoDexDistributor(this);
- } else if (packageDistribution != null) {
- assert !options.minimalMainDex :
- "Cannot combine package distribution definition with minimal-main-dex option.";
- distributor =
- new VirtualFile.PackageMapDistributor(this, packageDistribution, executorService);
} else {
distributor = new VirtualFile.FillFilesDistributor(this, options.minimalMainDex);
}
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 32fb175..746c62e 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -24,16 +24,11 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.PackageDistribution;
-import com.android.tools.r8.utils.ThreadUtils;
+
import com.google.common.collect.Iterators;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -44,13 +39,10 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
import java.util.function.Function;
public class VirtualFile {
@@ -402,95 +394,6 @@
}
}
- public static class PackageMapDistributor extends DistributorBase {
- private final PackageDistribution packageDistribution;
- private final ExecutorService executorService;
-
- PackageMapDistributor(
- ApplicationWriter writer,
- PackageDistribution packageDistribution,
- ExecutorService executorService) {
- super(writer);
- this.packageDistribution = packageDistribution;
- this.executorService = executorService;
- }
-
- @Override
- public Map<Integer, VirtualFile> run()
- throws ExecutionException, IOException, DexOverflowException {
- // Strategy for distributing classes for write out:
- // 1. Place all files in the package distribution file in the proposed files (if any).
- // 2. Place the remaining files based on their packages in sorted order.
-
- assert nameToFileMap.size() == 1;
- assert nameToFileMap.containsKey(0);
- int maxReferencedIndex = packageDistribution.maxReferencedIndex();
- for (int index = 1; index <= maxReferencedIndex; index++) {
- VirtualFile file = new VirtualFile(index, writer.namingLens);
- nameToFileMap.put(index, file);
- }
-
- // First fill required classes into the main dex file.
- fillForMainDexList(classes);
-
- // Sort the remaining classes based on the original names.
- // This with make classes from the same package be adjacent.
- classes = sortClassesByPackage(classes, originalNames);
-
- Set<String> usedPrefixes = fillForDistribution(classes, originalNames);
-
- // TODO(zerny): Add the package map to AndroidApp and refactor its generation.
- Map<String, Integer> newAssignments;
- if (classes.isEmpty()) {
- newAssignments = Collections.emptyMap();
- } else {
- newAssignments =
- new PackageSplitPopulator(
- nameToFileMap, classes, originalNames, usedPrefixes, application.dexItemFactory,
- FillStrategy.LEAVE_SPACE_FOR_GROWTH, writer.namingLens)
- .call();
- if (!newAssignments.isEmpty() && nameToFileMap.size() > 1) {
- System.err.println(" * The used package map is missing entries. The following default "
- + "mappings have been used:");
- writeAssignments(newAssignments, new OutputStreamWriter(System.err));
- System.err.println(" * Consider updating the map.");
- }
- }
-
- Path newPackageMap = Paths.get("package.map");
- System.out.println(" - " + newPackageMap.toString());
- PackageDistribution.writePackageToFileMap(newPackageMap, newAssignments, packageDistribution);
-
- return nameToFileMap;
- }
-
- private Set<String> fillForDistribution(Set<DexProgramClass> classes,
- Map<DexProgramClass, String> originalNames) throws ExecutionException {
- Set<String> usedPrefixes = null;
- if (packageDistribution != null) {
- ArrayList<Future<List<DexProgramClass>>> futures = new ArrayList<>(nameToFileMap.size());
- usedPrefixes = packageDistribution.getFiles();
- for (VirtualFile file : nameToFileMap.values()) {
- PackageMapPopulator populator =
- new PackageMapPopulator(file, classes, packageDistribution, originalNames);
- futures.add(executorService.submit(populator));
- }
- ThreadUtils.awaitFutures(futures).forEach(classes::removeAll);
- }
- return usedPrefixes;
- }
-
- private void writeAssignments(Map<String, Integer> assignments, Writer output)
- throws IOException{
- for (Entry<String, Integer> entry : assignments.entrySet()) {
- output.write(" ");
- PackageDistribution.formatEntry(entry, output);
- output.write("\n");
- }
- output.flush();
- }
- }
-
private static class VirtualFileIndexedItemCollection implements IndexedItemCollection {
final int id;
@@ -719,96 +622,6 @@
}
/**
- * Adds all classes from the given set that are covered by a corresponding package map
- * specification to the given file.
- */
- private static class PackageMapPopulator implements Callable<List<DexProgramClass>> {
-
- private final VirtualFile file;
- private final Collection<DexProgramClass> classes;
- private final PackageDistribution packageDistribution;
- private final Map<DexProgramClass, String> originalNames;
-
- PackageMapPopulator(
- VirtualFile file,
- Collection<DexProgramClass> classes,
- PackageDistribution packageDistribution,
- Map<DexProgramClass, String> originalNames) {
- this.file = file;
- this.classes = classes;
- this.packageDistribution = packageDistribution;
- this.originalNames = originalNames;
- }
-
- @Override
- public List<DexProgramClass> call() {
- String currentPrefix = null;
- int currentFileId = -1;
- List<DexProgramClass> inserted = new ArrayList<>();
- for (DexProgramClass clazz : classes) {
- String originalName = originalNames.get(clazz);
- assert originalName != null;
- if (!coveredByPrefix(originalName, currentPrefix)) {
- if (currentPrefix != null) {
- file.commitTransaction();
- }
- currentPrefix = lookupPrefixFor(originalName);
- if (currentPrefix == null) {
- currentFileId = -1;
- } else {
- currentFileId = packageDistribution.get(currentPrefix);
- }
- }
- if (currentFileId == file.id) {
- file.addClass(clazz);
- inserted.add(clazz);
- }
- if (file.isFull()) {
- throw new CompilationError(
- "Cannot fit package " + currentPrefix
- + " in requested dex file, consider removing mapping.");
- }
- }
- file.commitTransaction();
- return inserted;
- }
-
- private String lookupPrefixFor(String originalName) {
- // First, check whether we have a match on the full package name.
- int lastIndexOfDot = originalName.lastIndexOf('.');
- if (lastIndexOfDot < 0) {
- return null;
- }
- String prefix = originalName.substring(0, lastIndexOfDot);
- if (packageDistribution.containsFile(prefix)) {
- return prefix;
- }
- // Second, look for .* qualified entries.
- int index;
- prefix = originalName;
- while ((index = prefix.lastIndexOf('.')) != -1) {
- prefix = prefix.substring(0, index);
- if (packageDistribution.containsFile(prefix + ".*")) {
- return prefix + ".*";
- }
- }
- return null;
- }
-
- static boolean coveredByPrefix(String originalName, String currentPrefix) {
- if (currentPrefix == null) {
- return false;
- }
- if (currentPrefix.endsWith(".*")) {
- return originalName.startsWith(currentPrefix.substring(0, currentPrefix.length() - 2));
- } else {
- return originalName.startsWith(currentPrefix)
- && originalName.lastIndexOf('.') == currentPrefix.length();
- }
- }
- }
-
- /**
* Helper class to cycle through the set of virtual files.
*
* Iteration starts at the first file and iterates through all files.
@@ -915,6 +728,18 @@
this.cycler = new VirtualFileCycler(files, namingLens, fillStrategy);
}
+ static boolean coveredByPrefix(String originalName, String currentPrefix) {
+ if (currentPrefix == null) {
+ return false;
+ }
+ if (currentPrefix.endsWith(".*")) {
+ return originalName.startsWith(currentPrefix.substring(0, currentPrefix.length() - 2));
+ } else {
+ return originalName.startsWith(currentPrefix)
+ && originalName.lastIndexOf('.') == currentPrefix.length();
+ }
+ }
+
private String getOriginalName(DexProgramClass clazz) {
return originalNames != null ? originalNames.get(clazz) : clazz.toString();
}
@@ -931,7 +756,7 @@
for (int classIndex = 0; classIndex < classes.size(); classIndex++) {
DexProgramClass clazz = classes.get(classIndex);
String originalName = getOriginalName(clazz);
- if (!PackageMapPopulator.coveredByPrefix(originalName, currentPrefix)) {
+ if (!coveredByPrefix(originalName, currentPrefix)) {
if (currentPrefix != null) {
current.commitTransaction();
// Reset the cycler to again iterate over all files, starting with the current one.
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 c1dad50..14e5288 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -63,11 +63,6 @@
this.factory = factory;
}
- // Public method for the DebugStripper.
- public void setPosition(int pc, int line) {
- emitDebugPosition(pc, line, null);
- }
-
/** Add events at pc for instruction. */
public void add(int pc, Instruction instruction) {
// Initialize locals state on block entry.
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 7dca5bd..716db5e 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
@@ -133,9 +133,9 @@
}
/**
- * Create an IR converter for processing methods without full program optimization enabled.
+ * Create an IR converter for processing methods with full program optimization disabled.
*
- * The argument <code>enableDesugaring</code> if desugaing is enabled.
+ * The argument <code>enableDesugaring</code> if desugaring is enabled.
*/
public IRConverter(
DexApplication application,
diff --git a/src/main/java/com/android/tools/r8/optimize/DebugStripper.java b/src/main/java/com/android/tools/r8/optimize/DebugStripper.java
deleted file mode 100644
index 0eda1e5..0000000
--- a/src/main/java/com/android/tools/r8/optimize/DebugStripper.java
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright (c) 2016, 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.optimize;
-
-import com.android.tools.r8.graph.DexCode;
-import com.android.tools.r8.graph.DexDebugEntry;
-import com.android.tools.r8.graph.DexDebugEventBuilder;
-import com.android.tools.r8.graph.DexDebugInfo;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.ClassNaming;
-import com.android.tools.r8.naming.MemberNaming;
-import com.android.tools.r8.naming.MemberNaming.Range;
-import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.android.tools.r8.utils.InternalOptions;
-
-import it.unimi.dsi.fastutil.objects.Reference2IntMap;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
-
-import java.util.List;
-
-public class DebugStripper {
-
- private static final int USED_MORE_THAN_ONCE = 0;
- private static final int USED_ONCE = -1;
-
- private final ClassNameMapper classNameMapper;
- private final InternalOptions options;
- private final DexItemFactory dexItemFactory;
-
- public DebugStripper(
- ClassNameMapper classNameMapper, InternalOptions options, DexItemFactory dexItemFactory) {
- this.classNameMapper = classNameMapper;
- this.options = options;
- this.dexItemFactory = dexItemFactory;
- }
-
- private String descriptorToName(String descriptor) {
- // The format is L<name>; and '/' is used as package separator.
- return descriptor.substring(1, descriptor.length() - 1).replace('/', '.');
- }
-
- private Range findRange(int value, List<Range> ranges, Range defaultRange) {
- for (Range range : ranges) {
- if (range.contains(value)) {
- return range;
- }
- }
- return defaultRange;
- }
-
- private static class NumberedDebugInfo {
-
- final int numberOfEntries;
- final DexDebugInfo info;
-
- public NumberedDebugInfo(int numberOfEntries, DexDebugInfo info) {
- this.numberOfEntries = numberOfEntries;
- this.info = info;
- }
- }
-
- private NumberedDebugInfo processDebugInfo(
- DexEncodedMethod method, DexDebugInfo info, MemberNaming naming, int startLine) {
- if (info == null || naming == null) {
- return new NumberedDebugInfo(0, null);
- }
- List<Range> ranges = naming.getInlineRanges();
- // Maintain line and address but only when entering or leaving a range of line numbers
- // that pertains to a different method body.
- Range currentRange = naming.topLevelRange;
- DexDebugEventBuilder builder = new DexDebugEventBuilder(method, dexItemFactory);
- // Below we insert the start-line at pc-0 except if another entry already defines pc-0.
- int entryCount = 0;
- for (DexDebugEntry entry : info.computeEntries()) {
- boolean addEntry = false;
- // We are in a range, check whether we have left it.
- if (currentRange != null && !currentRange.contains(entry.line)) {
- currentRange = null;
- addEntry = true;
- }
- // We have no range (because we left the old one or never were in a range).
- if (currentRange == null) {
- currentRange = findRange(entry.line, ranges, naming.topLevelRange);
- // We entered a new Range, emit this entry.
- if (currentRange != null) {
- addEntry = true;
- }
- }
- if (addEntry) {
- if (entryCount == 0 && entry.address > 0) {
- ++entryCount;
- builder.setPosition(0, startLine);
- }
- int line = options.skipDebugLineNumberOpt
- ? entry.line
- : startLine + ranges.indexOf(currentRange) + 1;
- builder.setPosition(entry.address, line);
- ++entryCount;
- }
- }
- if (entryCount == 0) {
- ++entryCount;
- builder.setPosition(0, startLine);
- }
- return new NumberedDebugInfo(entryCount, builder.build());
- }
-
- private void processCode(DexEncodedMethod encodedMethod, MemberNaming naming,
- Reference2IntMap<DexString> nameCounts) {
- if (encodedMethod.getCode() == null) {
- return;
- }
- DexCode code = encodedMethod.getCode().asDexCode();
- DexString name = encodedMethod.method.name;
- DexDebugInfo originalInfo = code.getDebugInfo();
- if (originalInfo == null) {
- return;
- }
- int startLine;
- boolean isUsedOnce = false;
- if (options.skipDebugLineNumberOpt) {
- startLine = originalInfo.startLine;
- } else {
- int nameCount = nameCounts.getInt(name);
- if (nameCount == USED_ONCE) {
- isUsedOnce = true;
- startLine = 0;
- } else {
- startLine = nameCount;
- }
- }
-
- NumberedDebugInfo numberedInfo =
- processDebugInfo(encodedMethod, originalInfo, naming, startLine);
- DexDebugInfo newInfo = numberedInfo.info;
- if (!options.skipDebugLineNumberOpt) {
- // Fix up the line information.
- int previousCount = nameCounts.getInt(name);
- nameCounts.put(name, previousCount + numberedInfo.numberOfEntries);
- // If we don't actually need line information and there are no debug entries, throw it away.
- if (newInfo != null && isUsedOnce && newInfo.events.length == 0) {
- newInfo = null;
- } else if (naming != null && newInfo != null) {
- naming.setCollapsedStartLineNumber(startLine);
- // Preserve the line number information we had.
- naming.setOriginalStartLineNumber(originalInfo.startLine);
- }
- }
- code.setDebugInfo(newInfo);
- }
-
- private void processMethod(DexEncodedMethod method, ClassNaming classNaming,
- Reference2IntMap<DexString> nameCounts) {
- MemberNaming naming = null;
- if (classNaming != null) {
- Signature renamedSignature = classNameMapper.getRenamedMethodSignature(method.method);
- naming = classNaming.lookup(renamedSignature);
- }
- processCode(method, naming, nameCounts);
- }
-
- public void processClass(DexProgramClass clazz) {
- if (!clazz.hasMethodsOrFields()) {
- return;
- }
- String name = descriptorToName(clazz.type.toDescriptorString());
- ClassNaming naming = classNameMapper == null ? null : classNameMapper.getClassNaming(name);
- Reference2IntMap<DexString> nameCounts = new Reference2IntOpenHashMap<>();
- clazz.forEachMethod(method -> setIntialNameCounts(nameCounts, method));
- clazz.forEachMethod(method -> processMethod(method, naming, nameCounts));
- }
-
- private void setIntialNameCounts(Reference2IntMap<DexString> nameCounts,
- DexEncodedMethod method) {
- if (nameCounts.containsKey(method.method.name)) {
- nameCounts.put(method.method.name, USED_MORE_THAN_ONCE);
- } else {
- nameCounts.put(method.method.name, USED_ONCE);
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 87a36e6..87b425b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -24,7 +24,7 @@
private String packagePrefix = "";
private boolean allowAccessModification = false;
private boolean ignoreWarnings = false;
- private boolean optimize = true;
+ private boolean optimizing = true;
private boolean obfuscating = true;
private boolean shrinking = true;
private boolean printUsage = false;
@@ -79,8 +79,8 @@
this.ignoreWarnings = ignoreWarnings;
}
- public void setOptimize(boolean optimize) {
- this.optimize = optimize;
+ public void setOptimizing(boolean optimizing) {
+ this.optimizing = optimizing;
}
public void setObfuscating(boolean obfuscate) {
@@ -172,6 +172,7 @@
packagePrefix,
allowAccessModification,
ignoreWarnings,
+ optimizing,
obfuscating,
shrinking,
printUsage,
@@ -200,6 +201,7 @@
private final String packagePrefix;
private final boolean allowAccessModification;
private final boolean ignoreWarnings;
+ private final boolean optimizing;
private final boolean obfuscating;
private final boolean shrinking;
private final boolean printUsage;
@@ -227,6 +229,7 @@
String packagePrefix,
boolean allowAccessModification,
boolean ignoreWarnings,
+ boolean optimizing,
boolean obfuscating,
boolean shrinking,
boolean printUsage,
@@ -252,6 +255,7 @@
this.packagePrefix = packagePrefix;
this.allowAccessModification = allowAccessModification;
this.ignoreWarnings = ignoreWarnings;
+ this.optimizing = optimizing;
this.obfuscating = obfuscating;
this.shrinking = shrinking;
this.printUsage = printUsage;
@@ -327,6 +331,10 @@
return ignoreWarnings;
}
+ public boolean isOptimizing() {
+ return optimizing;
+ }
+
public boolean isObfuscating() {
return obfuscating;
}
@@ -393,6 +401,7 @@
"" /* package prefix */,
false /* allowAccessModification */,
false /* ignoreWarnings */,
+ true /* optimizing */,
false /* obfuscating */,
false /* shrinking */,
false /* printUsage */,
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 9a90c68..bcbfc8b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -168,8 +168,7 @@
ProguardWhyAreYouKeepingRule rule = parseWhyAreYouKeepingRule();
configurationBuilder.addRule(rule);
} else if (acceptString("dontoptimize")) {
- configurationBuilder.setOptimize(false);
- warnIgnoringOptions("dontoptimize");
+ configurationBuilder.setOptimizing(false);
} else if (acceptString("optimizationpasses")) {
skipWhitespace();
Integer expectedOptimizationPasses = acceptInteger();
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 9b99be5..439c1d9 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -63,7 +63,6 @@
private final Resource deadCode;
private final Resource proguardMap;
private final Resource proguardSeeds;
- private final Resource packageDistribution;
private final List<Resource> mainDexListResources;
private final List<String> mainDexClasses;
private final Resource mainDexListOutput;
@@ -78,7 +77,6 @@
Resource deadCode,
Resource proguardMap,
Resource proguardSeeds,
- Resource packageDistribution,
List<Resource> mainDexListResources,
List<String> mainDexClasses,
Resource mainDexListOutput) {
@@ -90,7 +88,6 @@
this.deadCode = deadCode;
this.proguardMap = proguardMap;
this.proguardSeeds = proguardSeeds;
- this.packageDistribution = packageDistribution;
this.mainDexListResources = mainDexListResources;
this.mainDexClasses = mainDexClasses;
this.mainDexListOutput = mainDexListOutput;
@@ -255,20 +252,6 @@
}
/**
- * True if the package distribution resource exists.
- */
- public boolean hasPackageDistribution() {
- return packageDistribution != null;
- }
-
- /**
- * Get the input stream of the package distribution resource if it exists.
- */
- public InputStream getPackageDistribution(Closer closer) throws IOException {
- return packageDistribution == null ? null : closer.register(packageDistribution.getStream());
- }
-
- /**
* True if the main dex list resources exists.
*/
public boolean hasMainDexList() {
@@ -464,7 +447,6 @@
private Resource deadCode;
private Resource proguardMap;
private Resource proguardSeeds;
- private Resource packageDistribution;
private List<Resource> mainDexListResources = new ArrayList<>();
private List<String> mainDexListClasses = new ArrayList<>();
private Resource mainDexListOutput;
@@ -484,7 +466,6 @@
deadCode = app.deadCode;
proguardMap = app.proguardMap;
proguardSeeds = app.proguardSeeds;
- packageDistribution = app.packageDistribution;
mainDexListResources = app.mainDexListResources;
mainDexListClasses = app.mainDexClasses;
mainDexListOutput = app.mainDexListOutput;
@@ -685,14 +666,6 @@
}
/**
- * Set the package-distribution file.
- */
- public Builder setPackageDistributionFile(Path file) {
- packageDistribution = file == null ? null : Resource.fromFile(null, file);
- return this;
- }
-
- /**
* Add a main-dex list file.
*/
public Builder addMainDexListFiles(Path... files) throws IOException {
@@ -773,7 +746,6 @@
deadCode,
proguardMap,
proguardSeeds,
- packageDistribution,
mainDexListResources,
mainDexListClasses,
mainDexListOutput);
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 c03c3d6..36e19bf 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -45,10 +45,13 @@
public final int NOT_SPECIFIED = -1;
public boolean printTimes = false;
- // Skipping optimizations.
- public boolean skipDebugInfoOpt = false;
+
+ // Optimization-related flags. These should conform to -dontoptimize.
public boolean skipDebugLineNumberOpt = false;
public boolean skipClassMerging = true;
+ public boolean inlineAccessors = true;
+ public boolean removeSwitchMaps = true;
+ public final OutlineOptions outline = new OutlineOptions();
// Number of threads to use while processing the dex files.
public int numberOfThreads = NOT_SPECIFIED;
@@ -99,10 +102,7 @@
public Path printMainDexListFile;
public boolean ignoreMissingClasses = false;
public boolean skipMinification = false;
- public boolean inlineAccessors = true;
- public boolean removeSwitchMaps = true;
public boolean disableAssertions = true;
- public final OutlineOptions outline = new OutlineOptions();
public boolean debugKeepRules = false;
public final AttributeRemovalOptions attributeRemoval = new AttributeRemovalOptions();
public boolean allowParameterName = false;
diff --git a/src/main/java/com/android/tools/r8/utils/PackageDistribution.java b/src/main/java/com/android/tools/r8/utils/PackageDistribution.java
deleted file mode 100644
index b242b9d..0000000
--- a/src/main/java/com/android/tools/r8/utils/PackageDistribution.java
+++ /dev/null
@@ -1,171 +0,0 @@
-// 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.utils;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-public class PackageDistribution {
-
- private static final String OLDFILE_PREFIX_TEXT =
- "\n"
- + "# Below follow the original package to file mapping rules. These have not been\n"
- + "# changed by R8.\n"
- + "\n";
-
- private static final String APPENDED_PREFIX_TEXT =
- "# The following packages had no mapping in the supplied package file. The\n"
- + "# mapping rules provided below reflect the mapping that was used by R8. Please\n"
- + "# use this updated map moving forward to ensure stability of package placement\n"
- + "# in DEX files (and thus minimize patch size).\n"
- + "#\n"
- + "# Note that the updated package placement might not be optimal. Shifting the new\n"
- + "# packages to DEX files that contain related packages might yield smaller DEX\n"
- + "# file sizes.\n"
- + "\n";
-
- private static final String NEW_PACKAGE_MAP_PREFIX_TEXT =
- "# This file provides a mapping of classes to DEX files in an Android multi-dex\n"
- +"# application. It is used in conjunction with the R8 DEX file optimizer\n"
- + "# to enforce a fixed distribution of classes to DEX files.\n"
- + "#\n"
- + "# Fixing the class distribution serves two purposes:\n"
- + "#\n"
- + "# 1. Keeping classes in the same DEX file reduces the size of patches between\n"
- + "# two versions of an application.\n"
- + "# 2. Co-locating classes with their uses can reduce DEX file size. For example,\n"
- + "# one might want to place the helper classes for credit card processing in\n"
- + "# the same DEX file that contains the payment related logic.\n"
- + "#\n"
- + "# Entries in this file have the following form:\n"
- + "#\n"
- + "# <packageSpec>:<file number>\n"
- + "#\n"
- + "# Where packageSpec is either the name of a package, e.g., 'com.google.foo', or\n"
- + "# a package wildcard of the form 'com.google.bar.*'. The former matches exactly\n"
- + "# the classes in the given package, whereas the latter also matches classes in\n"
- + "# subpackages. PackageSpec entries may not overlap.\n"
- + "#\n"
- + "# Empty lines and lines starting with a '#' are ignored.\n"
- + "\n";
-
- private static final String NO_PACKAGE_MAP_REQUIRED_TEXT =
- "\n"
- + "# Intentionally empty, as the output only has a single DEX file.\n"
- + "\n";
-
- private final Map<String, Integer> map;
-
- private PackageDistribution(Map<String, Integer> map) {
- this.map = map;
- }
-
- public static PackageDistribution load(InputStream input) throws IOException {
- return read(new BufferedReader(new InputStreamReader(input)));
- }
-
- public static PackageDistribution load(Path path) {
- try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
- return read(reader);
- } catch (IOException e) {
- throw new RuntimeException("Error reading file " + path, e);
- }
- }
-
- private static PackageDistribution read(BufferedReader reader) throws IOException {
- String line = null;
- try {
- Map<String, Integer> result = new HashMap<>();
- while ((line = reader.readLine()) != null) {
- if (line.length() == 0 || line.startsWith("#")) {
- continue;
- }
- String[] parts = line.split(":");
- if (parts.length != 2) {
- throw new RuntimeException("Error parsing package map line " + line);
- }
- String prefix = parts[0];
- if (result.containsKey(prefix)) {
- throw new RuntimeException("Prefix is assigned twice: " + prefix);
- }
- int file = Integer.parseInt(parts[1]);
- result.put(prefix, file);
- }
- return new PackageDistribution(result);
- } catch (NumberFormatException e) {
- throw new RuntimeException("Error parsing package map line " + line, e);
- }
- }
-
- public static void formatEntry(Entry<String, Integer> entry, Writer writer) throws IOException {
- writer.write(entry.getKey());
- writer.write(":");
- writer.write(entry.getValue().toString());
- }
-
- public static void writePackageToFileMap(
- Path target, Map<String, Integer> mappings, PackageDistribution original) throws IOException {
- BufferedWriter writer = Files.newBufferedWriter(target, StandardCharsets.UTF_8);
- if (mappings.isEmpty()) {
- if (original != null) {
- copyOriginalPackageMap(original, writer);
- } else {
- writer.write(NEW_PACKAGE_MAP_PREFIX_TEXT);
- writer.write(NO_PACKAGE_MAP_REQUIRED_TEXT);
- }
- writer.close();
- return;
- }
- if (original == null) {
- writer.write(NEW_PACKAGE_MAP_PREFIX_TEXT);
- } else {
- writer.write(APPENDED_PREFIX_TEXT);
- }
- for (Entry<String, Integer> entry : mappings.entrySet()) {
- formatEntry(entry, writer);
- writer.newLine();
- }
- if (original != null) {
- // Copy the original
- writer.write(OLDFILE_PREFIX_TEXT);
- copyOriginalPackageMap(original, writer);
- }
- writer.close();
- }
-
- private static void copyOriginalPackageMap(PackageDistribution original, BufferedWriter writer)
- throws IOException {
- for (Entry<String, Integer> entry : original.map.entrySet()) {
- formatEntry(entry, writer);
- writer.newLine();
- }
- }
-
- public int maxReferencedIndex() {
- return map.values().stream().max(Integer::compare).orElse(0);
- }
-
- public Set<String> getFiles() {
- return map.keySet();
- }
-
- public int get(String file) {
- return map.getOrDefault(file, -1);
- }
-
- public boolean containsFile(String file) {
- return map.containsKey(file);
- }
-}
diff --git a/src/test/examples/classmerging/keep-rules-dontoptimize.txt b/src/test/examples/classmerging/keep-rules-dontoptimize.txt
new file mode 100644
index 0000000..b2c1ff4
--- /dev/null
+++ b/src/test/examples/classmerging/keep-rules-dontoptimize.txt
@@ -0,0 +1,11 @@
+# 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.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class classmerging.Test {
+ public static void main(...);
+}
+
+-dontoptimize
diff --git a/src/test/examples/classmerging/keep-rules.txt b/src/test/examples/classmerging/keep-rules.txt
index 58b262b..f83adbd 100644
--- a/src/test/examples/classmerging/keep-rules.txt
+++ b/src/test/examples/classmerging/keep-rules.txt
@@ -7,6 +7,3 @@
-keep public class classmerging.Test {
public static void main(...);
}
-
-# allow access modification to enable minification
--allowaccessmodification
diff --git a/src/test/examples/memberrebinding/package.map b/src/test/examples/memberrebinding/package.map
deleted file mode 100644
index e9bfd68..0000000
--- a/src/test/examples/memberrebinding/package.map
+++ /dev/null
@@ -1,4 +0,0 @@
-#
-# package.map file used by java/com/android/tools/r8/dex/ExtraFileTest.java
-#
-memberrebinding.subpackage:1
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index 932a61f..718cde9 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -4513,7 +4513,7 @@
// java.lang.AssertionError: Destroyed thread group was not finalized
.put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A01",
- match(D8_COMPILER, runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+ match(D8_COMPILER, runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
// 1) t02
// java.lang.IllegalThreadStateException: Thread group still contains threads: Test group
// 2) t04
@@ -4793,6 +4793,12 @@
// 1) t02
// java.lang.AssertionError: java.lang.AssertionError: expected:<7> but was:<6>
+ .put("lang.ref.PhantomReference.clear.PhantomReference_clear_A01",
+ match(runtimes(DexVm.ART_4_4_4)))
+ .put("lang.ref.SoftReference.clear.SoftReference_clear_A01",
+ match(runtimes(DexVm.ART_4_4_4)))
+ // Passes or fails randomly. Have seen out of memory and assertion errors.
+
.put("lang.ref.PhantomReference.isEnqueued.PhantomReference_isEnqueued_A01",
match(runtimes(DexVm.ART_4_4_4)))
.put("lang.ref.WeakReference.isEnqueued.WeakReference_isEnqueued_A01",
diff --git a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
index 7bd18e0..a1692c8 100644
--- a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
@@ -1,16 +1,21 @@
package com.android.tools.r8.classmerging;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import com.android.tools.r8.CompilationException;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.List;
import java.util.concurrent.ExecutionException;
-import org.junit.Assert;
-import org.junit.Before;
+import java.util.function.Consumer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -21,54 +26,76 @@
.resolve("classmerging.jar");
private static final Path EXAMPLE_KEEP = Paths.get(ToolHelper.EXAMPLES_DIR)
.resolve("classmerging").resolve("keep-rules.txt");
+ private static final Path DONT_OPTIMIZE = Paths.get(ToolHelper.EXAMPLES_DIR)
+ .resolve("classmerging").resolve("keep-rules-dontoptimize.txt");
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
- @Before
- public void runR8()
+ private void configure(InternalOptions options) {
+ options.skipClassMerging = false;
+ }
+
+ private void runR8(Path proguardConfig, Consumer<InternalOptions> optionsConsumer)
throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
- // Disable access modification, as it otherwise is difficult to test visibility bridge methods.
ToolHelper.runR8(
R8Command.builder()
.setOutputPath(Paths.get(temp.getRoot().getCanonicalPath()))
.addProgramFiles(EXAMPLE_JAR)
- .addProguardConfigurationFiles(EXAMPLE_KEEP)
+ .addProguardConfigurationFiles(proguardConfig)
.setMinification(false)
- .build(), o -> {
- o.skipClassMerging = false;
- });
+ .build(),
+ optionsConsumer);
inspector = new DexInspector(
Paths.get(temp.getRoot().getCanonicalPath()).resolve("classes.dex"));
}
private DexInspector inspector;
+ private final List<String> CAN_BE_MERGED = ImmutableList.of(
+ "classmerging.GenericInterface",
+ "classmerging.GenericAbstractClass",
+ "classmerging.Outer$SuperClass",
+ "classmerging.SuperClass"
+ );
+
@Test
- public void testClassesHaveBeenMerged() throws IOException, ExecutionException {
+ public void testClassesHaveBeenMerged()
+ throws IOException, ExecutionException, CompilationException, ProguardRuleParserException {
+ runR8(EXAMPLE_KEEP, this::configure);
// GenericInterface should be merged into GenericInterfaceImpl.
- Assert.assertFalse(inspector.clazz("classmerging.GenericInterface").isPresent());
- Assert.assertTrue(inspector.clazz("classmerging.GenericInterfaceImpl").isPresent());
- Assert.assertFalse(inspector.clazz("classmerging.GenericAbstractClass").isPresent());
- Assert.assertTrue(inspector.clazz("classmerging.GenericInterfaceImpl").isPresent());
- Assert.assertFalse(inspector.clazz("classmerging.Outer$SuperClass").isPresent());
- Assert.assertTrue(inspector.clazz("classmerging.Outer$SubClass").isPresent());
- Assert.assertFalse(inspector.clazz("classmerging.SuperClass").isPresent());
- Assert.assertTrue(inspector.clazz("classmerging.SubClass").isPresent());
- }
-
-
- @Test
- public void testConflictWasDetected() throws IOException, ExecutionException {
- Assert.assertTrue(inspector.clazz("classmerging.ConflictingInterface").isPresent());
- Assert.assertTrue(inspector.clazz("classmerging.ConflictingInterfaceImpl").isPresent());
+ for (String candidate : CAN_BE_MERGED) {
+ assertFalse(inspector.clazz(candidate).isPresent());
+ }
+ assertTrue(inspector.clazz("classmerging.GenericInterfaceImpl").isPresent());
+ assertTrue(inspector.clazz("classmerging.GenericInterfaceImpl").isPresent());
+ assertTrue(inspector.clazz("classmerging.Outer$SubClass").isPresent());
+ assertTrue(inspector.clazz("classmerging.SubClass").isPresent());
}
@Test
- public void testSuperCallWasDetected() throws IOException, ExecutionException {
- Assert.assertTrue(inspector.clazz("classmerging.SuperClassWithReferencedMethod").isPresent());
- Assert
- .assertTrue(inspector.clazz("classmerging.SubClassThatReferencesSuperMethod").isPresent());
+ public void testClassesShouldNotMerged()
+ throws IOException, ExecutionException, CompilationException, ProguardRuleParserException {
+ runR8(DONT_OPTIMIZE, null);
+ for (String candidate : CAN_BE_MERGED) {
+ assertTrue(inspector.clazz(candidate).isPresent());
+ }
+ }
+
+ @Test
+ public void testConflictWasDetected()
+ throws IOException, ExecutionException, CompilationException, ProguardRuleParserException {
+ runR8(EXAMPLE_KEEP, this::configure);
+ assertTrue(inspector.clazz("classmerging.ConflictingInterface").isPresent());
+ assertTrue(inspector.clazz("classmerging.ConflictingInterfaceImpl").isPresent());
+ }
+
+ @Test
+ public void testSuperCallWasDetected()
+ throws IOException, ExecutionException, CompilationException, ProguardRuleParserException {
+ runR8(EXAMPLE_KEEP, this::configure);
+ assertTrue(inspector.clazz("classmerging.SuperClassWithReferencedMethod").isPresent());
+ assertTrue(inspector.clazz("classmerging.SubClassThatReferencesSuperMethod").isPresent());
}
}
diff --git a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java b/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
deleted file mode 100644
index 6114f61..0000000
--- a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2016, 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.dex;
-
-import com.android.tools.r8.CompilationException;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.shaking.ProguardRuleParserException;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-
-public class ExtraFileTest {
-
- private static final String EXAMPLE_DIR = ToolHelper.EXAMPLES_BUILD_DIR;
- private static final String EXAMPLE_DEX = "memberrebinding/classes.dex";
- private static final String EXAMPLE_LIB = "memberrebindinglib/classes.dex";
- private static final String EXAMPLE_CLASS = "memberrebinding.Memberrebinding";
- private static final String EXAMPLE_PACKAGE_MAP = "memberrebinding/package.map";
- private static final String EXAMPLE_PROGUARD_MAP = "memberrebinding/proguard.map";
-
- @Rule
- public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void splitMemberRebindingTwoFilesRelease()
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
- if (!ToolHelper.artSupported()) {
- return;
- }
-
- Path out = temp.getRoot().toPath();
- Path original = Paths.get(EXAMPLE_DIR, EXAMPLE_DEX);
- Path packageMap = Paths.get(ToolHelper.EXAMPLES_DIR, EXAMPLE_PACKAGE_MAP);
- Path proguardMap = Paths.get(ToolHelper.EXAMPLES_DIR, EXAMPLE_PROGUARD_MAP);
- R8Command command =
- R8Command.builder()
- .addProgramFiles(original)
- .setMode(CompilationMode.RELEASE)
- .setOutputPath(out)
- .setMinApiLevel(Constants.ANDROID_L_API) // Allow native multidex.
- .setProguardMapFile(proguardMap)
- .setPackageDistributionFile(packageMap)
- .build();
- ToolHelper.runR8(command);
- List<String> outs =
- new ArrayList<>(
- ImmutableList.of(
- out.resolve("classes.dex").toString(),
- out.resolve("classes2.dex").toString(),
- EXAMPLE_DIR + EXAMPLE_LIB));
- outs.forEach(f -> Assert.assertTrue("Failed to find file " + f, Files.exists(Paths.get(f))));
- ToolHelper.checkArtOutputIdentical(
- ImmutableList.of(original.toString(), EXAMPLE_DIR + EXAMPLE_LIB),
- outs,
- EXAMPLE_CLASS,
- null,
- null);
- }
-
- @Test
- public void splitMemberRebindingTwoFilesDebug()
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
- thrown.expect(CompilationException.class);
- Path out = temp.getRoot().toPath();
- Path original = Paths.get(EXAMPLE_DIR, EXAMPLE_DEX);
- Path packageMap = Paths.get(ToolHelper.EXAMPLES_DIR, EXAMPLE_PACKAGE_MAP);
- Path proguardMap = Paths.get(ToolHelper.EXAMPLES_DIR, EXAMPLE_PROGUARD_MAP);
- R8Command command =
- R8Command.builder()
- .addProgramFiles(original)
- .setMode(CompilationMode.DEBUG)
- .setOutputPath(out)
- .setMinApiLevel(Constants.ANDROID_L_API) // Allow native multidex.
- .setProguardMapFile(proguardMap)
- .setPackageDistributionFile(packageMap)
- .build();
- ToolHelper.runR8(command);
- }
-}
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 92a755e..9da8e0e 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -98,7 +98,6 @@
null,
NamingLens.getIdentityLens(),
null,
- null,
options);
return runOnArt(outputApp, main);
}
@@ -183,7 +182,6 @@
null,
NamingLens.getIdentityLens(),
null,
- null,
options);
} catch (ExecutionException e) {
throw new RuntimeException(e);
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 a316969..0acd445 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -597,7 +597,7 @@
application, appInfo, options, null, null, NamingLens.getIdentityLens(), null);
ExecutorService executor = ThreadUtils.getExecutorService(options);
try {
- return writer.write(null, executor);
+ return writer.write(executor);
} finally {
executor.shutdown();
}
diff --git a/src/test/java/com/android/tools/r8/optimize/R8DebugStrippingTest.java b/src/test/java/com/android/tools/r8/optimize/R8DebugStrippingTest.java
deleted file mode 100644
index 6609ff2..0000000
--- a/src/test/java/com/android/tools/r8/optimize/R8DebugStrippingTest.java
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright (c) 2016, 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.optimize;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.tools.r8.CompilationException;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.graph.DexCode;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.ClassNaming;
-import com.android.tools.r8.naming.MemberNaming;
-import com.android.tools.r8.naming.MemberNaming.InlineInformation;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.android.tools.r8.naming.ProguardMapReader;
-import com.android.tools.r8.shaking.ProguardRuleParserException;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DexInspector;
-import com.android.tools.r8.utils.DexInspector.ClassSubject;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class R8DebugStrippingTest {
-
- private static final String ROOT = ToolHelper.EXAMPLES_BUILD_DIR;
- private static final String EXAMPLE_DEX = "throwing/classes.dex";
- private static final String EXAMPLE_MAP = "throwing/throwing.map";
- private static final String EXAMPLE_CLASS = "throwing.Throwing";
- private static final String EXAMPLE_JAVA = "Throwing.java";
-
- private static final String MAIN_NAME = "main";
- private static final String[] MAIN_PARAMETERS = new String[]{"java.lang.String[]"};
- private static final String VOID_RETURN = "void";
-
- private static final String OTHER_NAME = "throwInAFunctionThatIsNotInlinedAndCalledTwice";
- private static final String[] NO_PARAMETERS = new String[0];
- private static final String INT_RETURN = "int";
-
- private static final String THIRD_NAME = "aFunctionThatCallsAnInlinedMethodThatThrows";
- private static final String[] LIST_PARAMETER = new String[]{"java.util.List"};
-
- private static final String FORTH_NAME = "anotherFunctionThatCallsAnInlinedMethodThatThrows";
- private static final String[] STRING_PARAMETER = new String[]{"java.lang.String"};
-
- private static final Map<String, Signature> SIGNATURE_MAP = ImmutableMap.of(
- MAIN_NAME, new MethodSignature(MAIN_NAME, VOID_RETURN, MAIN_PARAMETERS),
- OTHER_NAME, new MethodSignature(OTHER_NAME, INT_RETURN, NO_PARAMETERS),
- THIRD_NAME, new MethodSignature(THIRD_NAME, INT_RETURN, LIST_PARAMETER),
- FORTH_NAME, new MethodSignature(FORTH_NAME, INT_RETURN, STRING_PARAMETER)
- );
-
- private ClassNameMapper mapper;
-
- @Parameter(0)
- public boolean compressRanges;
-
- @Rule
- public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
- @Before
- public void loadRangeInformation() throws IOException {
- mapper = ProguardMapReader.mapperFromFile(Paths.get(ROOT, EXAMPLE_MAP));
- }
-
- @Parameters(name = "compressLineNumers={0}")
- public static Object[] parameters() {
- return new Object[]{true, false};
- }
-
- @Test
- public void testStackTraces()
- throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
-
- // Temporary directory for R8 output.
- Path out = temp.getRoot().toPath();
-
- R8Command command =
- R8Command.builder()
- .addProgramFiles(Paths.get(ROOT, EXAMPLE_DEX))
- .setOutputPath(out)
- .setProguardMapFile(Paths.get(ROOT, EXAMPLE_MAP))
- .build();
-
- // Generate R8 processed version.
- AndroidApp result =
- ToolHelper.runR8(command, (options) -> options.skipDebugLineNumberOpt = !compressRanges);
-
- ClassNameMapper classNameMapper;
- try (InputStream is = result.getProguardMap()) {
- classNameMapper = ProguardMapReader.mapperFromInputStream(is);
- }
- if (compressRanges) {
- classNameMapper.forAllClassNamings(this::ensureRangesAreUniquePerClass);
- }
-
- if (!ToolHelper.artSupported()) {
- return;
- }
- // Run art on original.
- String originalOutput =
- ToolHelper.runArtNoVerificationErrors(ROOT + EXAMPLE_DEX, EXAMPLE_CLASS);
- // Run art on R8 processed version.
- String otherOutput =
- ToolHelper.runArtNoVerificationErrors(out + "/classes.dex", EXAMPLE_CLASS);
- // Check that exceptions are in same range
- assertStacktracesMatchRanges(originalOutput, otherOutput, classNameMapper);
-
- // Check that we have debug information in all the places required.
- DexInspector inspector = new DexInspector(out.resolve("classes.dex"));
- BiMap<String, String> obfuscationMap
- = classNameMapper.getObfuscatedToOriginalMapping().inverse();
- ClassSubject overloaded = inspector.clazz(obfuscationMap.get("throwing.Overloaded"));
- assertTrue(overloaded.isPresent());
- ensureDebugInfosExist(overloaded);
- }
-
- private void ensureDebugInfosExist(ClassSubject overloaded) {
- final Map<DexString, Boolean> hasDebugInfo = Maps.newIdentityHashMap();
- overloaded.forAllMethods(method -> {
- if (!method.isAbstract()) {
- DexCode code = method.getMethod().getCode().asDexCode();
- DexString name = method.getMethod().method.name;
- Boolean previous = hasDebugInfo.get(name);
- boolean current = code.getDebugInfo() != null;
- // If we have seen one before, it should be the same as now.
- assertTrue(previous == null || (previous == current));
- hasDebugInfo.put(name, current);
- }
- }
- );
- }
-
- private void ensureRangesAreUniquePerClass(ClassNaming naming) {
- final Map<String, Set<Integer>> rangeMap = new HashMap<>();
- naming.forAllMemberNaming(memberNaming -> {
- if (memberNaming.isMethodNaming()) {
- if (memberNaming.topLevelRange != MemberNaming.fakeZeroRange) {
- int startLine = memberNaming.topLevelRange.from;
- Set<Integer> used = rangeMap
- .computeIfAbsent(memberNaming.getRenamedName(), any -> new HashSet<>());
- assertFalse(used.contains(startLine));
- used.add(startLine);
- }
- }
- });
- }
-
- private String extractRangeIndex(String line, ClassNameMapper mapper) {
- int position = line.lastIndexOf(EXAMPLE_JAVA);
- if (position == -1 && ToolHelper.getDexVm() == DexVm.ART_4_4_4) {
- assert line.contains("dalvik.system.NativeStart.main(Native Method)");
- return "Native Method";
- }
- assertNotSame("Malformed stackframe: " + line, -1, position);
- String numberPart = line.substring(position + EXAMPLE_JAVA.length() + 1, line.lastIndexOf(')'));
- int number = Integer.parseInt(numberPart);
- // Search the signature map for all signatures that actually match. We do this by first looking
- // up the renamed signature and then checking whether it is contained in the line. We prepend
- // the class name to make sure we do not match random characters in the line.
- for (Entry<String, Signature> entry : SIGNATURE_MAP.entrySet()) {
- MemberNaming naming = mapper.getClassNaming(EXAMPLE_CLASS)
- .lookupByOriginalSignature(entry.getValue());
- if (!line.contains(EXAMPLE_CLASS + "." + naming.getRenamedName())) {
- continue;
- }
- if (naming.topLevelRange.contains(number)) {
- return entry.getKey() + ":" + 0;
- }
- int rangeNo = 1;
- for (InlineInformation inlineInformation : naming.inlineInformation) {
- if (inlineInformation.inlinedRange.contains(number)) {
- return entry.getKey() + ":" + rangeNo;
- }
- rangeNo++;
- }
- }
- fail("Number not in any range " + number);
- return null;
- }
-
- private MemberNaming selectRanges(String line, ClassNameMapper mapper) {
- Signature signature;
- for (Entry<String, Signature> entry : SIGNATURE_MAP.entrySet()) {
- if (line.contains(entry.getKey())) {
- return mapper.getClassNaming(EXAMPLE_CLASS).lookup(entry.getValue());
- }
- }
- Assert.fail("unknown method in line " + line);
- return null;
- }
-
- private void assertStacktracesMatchRanges(String before, String after,
- ClassNameMapper newMapper) {
- String[] beforeLines = before.split("\n");
- String[] afterLines = after.split("\n");
- assertEquals("Output length differs", beforeLines.length,
- afterLines.length);
- for (int i = 0; i < beforeLines.length; i++) {
- if (!beforeLines[i].startsWith("FRAME:")) {
- continue;
- }
- String beforeLine = beforeLines[i];
- String expected = extractRangeIndex(beforeLine, mapper);
- String afterLine = afterLines[i];
- String generated = extractRangeIndex(afterLine, newMapper);
- assertEquals("Ranges match", expected, generated);
- }
- }
-}
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 2e3088a..42e289a 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -588,7 +588,6 @@
null,
NamingLens.getIdentityLens(),
null,
- null,
options);
} catch (ExecutionException e) {
throw new RuntimeException(e);
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 92ad06d..941ba84 100644
--- a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
@@ -54,7 +54,6 @@
assertFalse(ToolHelper.getApp(command).hasMainDexListResources());
assertFalse(ToolHelper.getApp(command).hasProguardMap());
assertFalse(ToolHelper.getApp(command).hasProguardSeeds());
- assertFalse(ToolHelper.getApp(command).hasPackageDistribution());
assertNull(command.getOutputPath());
assertEquals(CompilationMode.DEBUG, command.getMode());
}
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 322f15e..2054b22 100644
--- a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
@@ -56,7 +56,6 @@
assertFalse(ToolHelper.getApp(command).hasMainDexListResources());
assertFalse(ToolHelper.getApp(command).hasProguardMap());
assertFalse(ToolHelper.getApp(command).hasProguardSeeds());
- assertFalse(ToolHelper.getApp(command).hasPackageDistribution());
assertNull(command.getOutputPath());
assertFalse(command.useMinification());
assertFalse(command.useTreeShaking());
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index 93edf4d..6a26a1a 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -106,7 +106,7 @@
app, options, new Timing("smali")).read(executor);
ApplicationWriter writer = new ApplicationWriter(
dexApp, null, options, null, null, NamingLens.getIdentityLens(), null);
- AndroidApp trimmed = writer.write(null, executor);
+ AndroidApp trimmed = writer.write(executor);
return ByteStreams.toByteArray(trimmed.getDexProgramResources().get(0).getStream());
} finally {
executor.shutdown();