Make virtual files for distribution explicit in cycler
Change-Id: Ie97a86d79598a9443b8a2f2fb20bdcf7b0648ff3
diff --git a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
index 92671f2..9978311 100644
--- a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
+++ b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.IntBox;
import com.android.tools.r8.utils.ThreadUtils;
import com.google.common.collect.Maps;
import java.util.ArrayList;
@@ -279,26 +280,29 @@
}
private final VirtualFile mainDex;
- private final List<VirtualFile> dexes;
+ private final List<VirtualFile> files;
+ private final List<VirtualFile> filesForDistribution;
private final BitSet fullDex = new BitSet();
private final Set<DexProgramClass> classes;
private final AppView<?> appView;
- private final int dexIndexOffset;
+ private final IntBox nextFileId;
private final NamingLens namingLens;
private final DirectSubClassesInfo directSubClasses;
public InheritanceClassInDexDistributor(
VirtualFile mainDex,
- List<VirtualFile> dexes,
+ List<VirtualFile> files,
+ List<VirtualFile> filesForDistribution,
Set<DexProgramClass> classes,
- int dexIndexOffset,
+ IntBox nextFileId,
NamingLens namingLens,
AppView<?> appView,
ExecutorService executorService) {
this.mainDex = mainDex;
- this.dexes = dexes;
+ this.files = files;
+ this.filesForDistribution = filesForDistribution;
this.classes = classes;
- this.dexIndexOffset = dexIndexOffset;
+ this.nextFileId = nextFileId;
this.namingLens = namingLens;
this.appView = appView;
this.executorService = executorService;
@@ -315,6 +319,8 @@
// Allocate member of groups depending on
// the main dex members
+ VirtualFileCycler cycler =
+ new VirtualFileCycler(files, filesForDistribution, appView, namingLens, nextFileId);
for (Iterator<ClassGroup> iter = remainingInheritanceGroups.iterator(); iter.hasNext();) {
ClassGroup group = iter.next();
if (group.dependsOnMainDexClasses) {
@@ -344,19 +350,19 @@
new ClassGroup(groupSplit.mainDexIndependents);
Collection<VirtualFile> mainDexInpendentsDexes =
- assignGroup(mainDexIndependentGroup, Collections.singletonList(mainDex));
+ assignGroup(mainDexIndependentGroup, cycler, Collections.singletonList(mainDex));
Set<DexProgramClass> classesWithLinkingError =
new HashSet<>(groupSplit.dependentsOfMainDexIndependents);
classesWithLinkingError.addAll(classesMissingMainDex);
- assignClassesWithLinkingError(classesWithLinkingError, mainDexInpendentsDexes);
+ assignClassesWithLinkingError(classesWithLinkingError, cycler, mainDexInpendentsDexes);
}
}
// Allocate member of groups independents from the main dex members
for (ClassGroup group : remainingInheritanceGroups) {
if (!group.dependsOnMainDexClasses) {
- assignGroup(group, Collections.emptyList());
+ assignGroup(group, cycler, Collections.emptyList());
}
}
}
@@ -369,11 +375,13 @@
return groupClassNumber;
}
- private Collection<VirtualFile> assignGroup(ClassGroup group, List<VirtualFile> exclude) {
- VirtualFileCycler cycler = new VirtualFileCycler(dexes, appView, namingLens, dexIndexOffset);
+ private Collection<VirtualFile> assignGroup(
+ ClassGroup group, VirtualFileCycler cycler, List<VirtualFile> exclude) {
if (group.members.isEmpty()) {
return Collections.emptyList();
- } else if (group.canFitInOneDex()) {
+ }
+ cycler.reset();
+ if (group.canFitInOneDex()) {
VirtualFile currentDex;
while (true) {
currentDex = cycler.nextOrCreate(dex -> !exclude.contains(dex) && !isDexFull(dex));
@@ -399,7 +407,8 @@
Collection<VirtualFile> newExclude = new HashSet<>(exclude);
newExclude.add(dexForLinkingClasses);
- Collection<VirtualFile> usedDex = assignClassesWithLinkingError(remaining, newExclude);
+ Collection<VirtualFile> usedDex =
+ assignClassesWithLinkingError(remaining, cycler, newExclude);
usedDex.add(dexForLinkingClasses);
return usedDex;
}
@@ -412,14 +421,11 @@
* @param classes set of classes to assign, the set will be destroyed during assignment.
*/
private Collection<VirtualFile> assignClassesWithLinkingError(
- Set<DexProgramClass> classes, Collection<VirtualFile> exclude) {
-
+ Set<DexProgramClass> classes, VirtualFileCycler cycler, Collection<VirtualFile> exclude) {
List<ClassGroup> layers = collectNoDirectInheritanceGroups(classes);
-
Collections.sort(layers);
Collection<VirtualFile> usedDex = new ArrayList<>();
- VirtualFileCycler cycler = new VirtualFileCycler(dexes, appView, namingLens, dexIndexOffset);
// Don't modify exclude. Think about modifying the input collection considering this
// is private API.
Set<VirtualFile> currentExclude = new HashSet<>(exclude);
@@ -456,10 +462,8 @@
dexForLayer.commitTransaction();
break;
}
-
}
}
-
}
return usedDex;
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 7f39bfc..f0a460f 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -34,10 +34,12 @@
import com.android.tools.r8.synthesis.SyntheticNaming;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.IntBox;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
@@ -46,6 +48,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -320,11 +323,7 @@
if (!combineSyntheticClassesWithPrimaryClass
|| !appView.getSyntheticItems().isSyntheticClass(clazz)) {
VirtualFile file =
- new VirtualFile(
- virtualFiles.size(),
- writer.appView,
- writer.namingLens,
- clazz);
+ new VirtualFile(virtualFiles.size(), appView, writer.namingLens, clazz);
virtualFiles.add(file);
file.addClass(clazz);
files.put(clazz, file);
@@ -362,7 +361,7 @@
this.classes = SetUtils.newIdentityHashSet(classes);
// Create the primary dex file. The distribution will add more if needed.
- mainDexFile = new VirtualFile(0, writer.appView, writer.namingLens);
+ mainDexFile = new VirtualFile(0, appView, writer.namingLens);
assert virtualFiles.isEmpty();
virtualFiles.add(mainDexFile);
addMarkers(mainDexFile);
@@ -435,25 +434,27 @@
if (featureSplitClasses.isEmpty()) {
return;
}
- List<VirtualFile> filesForDistribution;
for (Map.Entry<FeatureSplit, Set<DexProgramClass>> featureSplitSetEntry :
featureSplitClasses.entrySet()) {
// Add a new virtual file, start from index 0 again
+ IntBox nextFileId = new IntBox();
VirtualFile featureFile =
new VirtualFile(
- 0,
- writer.appView,
+ nextFileId.getAndIncrement(),
+ appView,
writer.namingLens,
featureSplitSetEntry.getKey());
virtualFiles.add(featureFile);
addMarkers(featureFile);
- filesForDistribution = virtualFiles.subList(virtualFiles.size() - 1, virtualFiles.size());
+ List<VirtualFile> files = virtualFiles;
+ List<VirtualFile> filesForDistribution = ImmutableList.of(featureFile);
new PackageSplitPopulator(
+ files,
filesForDistribution,
appView,
featureSplitSetEntry.getValue(),
originalNames,
- 0,
+ nextFileId,
writer.namingLens)
.run();
}
@@ -474,6 +475,9 @@
@Override
public List<VirtualFile> run() throws IOException {
+ assert virtualFiles.size() == 1;
+ assert virtualFiles.get(0).isEmpty();
+
int totalClassNumber = classes.size();
// First fill required classes into the main dex file.
fillForMainDexList(classes);
@@ -483,37 +487,37 @@
}
List<VirtualFile> filesForDistribution = virtualFiles;
- int fileIndexOffset = 0;
boolean multidexLegacy = !mainDexFile.isEmpty();
if (options.minimalMainDex && multidexLegacy) {
- assert !virtualFiles.get(0).isEmpty();
assert virtualFiles.size() == 1;
- // The main dex file is filtered out, so ensure at least one file for the remaining classes.
- virtualFiles.add(new VirtualFile(1, writer.appView, writer.namingLens));
- filesForDistribution = virtualFiles.subList(1, virtualFiles.size());
- fileIndexOffset = 1;
+ assert !virtualFiles.get(0).isEmpty();
+ // Don't consider the main dex for distribution.
+ filesForDistribution = Collections.emptyList();
}
Map<FeatureSplit, Set<DexProgramClass>> featureSplitClasses =
removeFeatureSplitClassesGetMapping();
+ IntBox nextFileId = new IntBox(1);
if (multidexLegacy && options.enableInheritanceClassInDexDistributor) {
new InheritanceClassInDexDistributor(
mainDexFile,
+ virtualFiles,
filesForDistribution,
classes,
- fileIndexOffset,
+ nextFileId,
writer.namingLens,
- writer.appView,
+ appView,
executorService)
.distribute();
} else {
new PackageSplitPopulator(
+ virtualFiles,
filesForDistribution,
appView,
classes,
originalNames,
- fileIndexOffset,
+ nextFileId,
writer.namingLens)
.run();
}
@@ -820,33 +824,36 @@
static class VirtualFileCycler {
private final List<VirtualFile> files;
+ private final List<VirtualFile> filesForDistribution;
private final AppView<?> appView;
private final NamingLens namingLens;
- private int nextFileId;
+ private final IntBox nextFileId;
private Iterator<VirtualFile> allFilesCyclic;
private Iterator<VirtualFile> activeFiles;
- private FeatureSplit featuresplit;
+ private FeatureSplit featureSplit;
VirtualFileCycler(
List<VirtualFile> files,
+ List<VirtualFile> filesForDistribution,
AppView<?> appView,
NamingLens namingLens,
- int fileIndexOffset) {
+ IntBox nextFileId) {
this.files = files;
+ this.filesForDistribution = new ArrayList<>(filesForDistribution);
this.appView = appView;
this.namingLens = namingLens;
+ this.nextFileId = nextFileId;
- nextFileId = files.size() + fileIndexOffset;
- if (files.size() > 0) {
- featuresplit = files.get(0).getFeatureSplit();
+ if (filesForDistribution.size() > 0) {
+ featureSplit = filesForDistribution.get(0).getFeatureSplit();
}
reset();
}
void reset() {
- allFilesCyclic = Iterators.cycle(files);
+ allFilesCyclic = Iterators.cycle(filesForDistribution);
restart();
}
@@ -863,11 +870,10 @@
*/
VirtualFile nextOrCreate() {
if (hasNext()) {
- return activeFiles.next();
+ return next();
} else {
- VirtualFile newFile = new VirtualFile(nextFileId++, appView, namingLens, featuresplit);
- files.add(newFile);
- allFilesCyclic = Iterators.cycle(files);
+ VirtualFile newFile = internalAddFile();
+ allFilesCyclic = Iterators.cycle(filesForDistribution);
return newFile;
}
}
@@ -892,16 +898,29 @@
// Start a new iteration over all files, starting at the current one.
void restart() {
- activeFiles = Iterators.limit(allFilesCyclic, files.size());
+ activeFiles = Iterators.limit(allFilesCyclic, filesForDistribution.size());
}
VirtualFile addFile() {
- VirtualFile newFile = new VirtualFile(nextFileId++, appView, namingLens, featuresplit);
- files.add(newFile);
-
+ VirtualFile newFile = internalAddFile();
reset();
return newFile;
}
+
+ private VirtualFile internalAddFile() {
+ VirtualFile newFile =
+ new VirtualFile(nextFileId.getAndIncrement(), appView, namingLens, featureSplit);
+ files.add(newFile);
+ filesForDistribution.add(newFile);
+ return newFile;
+ }
+
+ VirtualFileCycler ensureFile() {
+ if (filesForDistribution.isEmpty()) {
+ addFile();
+ }
+ return this;
+ }
}
/**
@@ -1029,16 +1048,18 @@
PackageSplitPopulator(
List<VirtualFile> files,
+ List<VirtualFile> filesForDistribution,
AppView<?> appView,
Collection<DexProgramClass> classes,
Map<DexProgramClass, String> originalNames,
- int fileIndexOffset,
+ IntBox nextFileId,
NamingLens namingLens) {
this.classPartioning = PackageSplitClassPartioning.create(classes, appView, originalNames);
this.originalNames = originalNames;
this.dexItemFactory = appView.dexItemFactory();
this.options = appView.options();
- this.cycler = new VirtualFileCycler(files, appView, namingLens, fileIndexOffset);
+ this.cycler =
+ new VirtualFileCycler(files, filesForDistribution, appView, namingLens, nextFileId);
}
static boolean coveredByPrefix(String originalName, String currentPrefix) {
@@ -1064,6 +1085,11 @@
}
private void addStartupClasses() {
+ List<DexProgramClass> startupClasses = classPartioning.getStartupClasses();
+ if (startupClasses.isEmpty()) {
+ return;
+ }
+
// In practice, all startup classes should fit in a single dex file, so optimistically try to
// commit the startup classes using a single transaction.
VirtualFile virtualFile = cycler.next();
@@ -1099,7 +1125,7 @@
int transactionStartIndex = 0;
String currentPrefix = null;
Object2IntMap<String> packageAssignments = new Object2IntOpenHashMap<>();
- VirtualFile current = cycler.next();
+ VirtualFile current = cycler.ensureFile().next();
List<DexProgramClass> classes = classPartioning.getNonStartupClasses();
List<DexProgramClass> nonPackageClasses = new ArrayList<>();
for (int classIndex = 0; classIndex < classes.size(); classIndex++) {