Defer pruning of missing startup items until after desugaring
Change-Id: I9a4a0814a05f7add7d2498d814c9e008f821a659
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 52735a5..abf8844 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -311,6 +311,7 @@
appView.setArtProfileCollection(
appView.getArtProfileCollection().withoutMissingItems(appView));
+ assert appView.getStartupProfile().isEmpty();
finalizeApplication(appView, executor, timing);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 3f0da93..41ea658 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -699,6 +699,7 @@
appView.setArtProfileCollection(
appView.getArtProfileCollection().withoutMissingItems(appView));
+ appView.setStartupProfile(appView.getStartupProfile().withoutMissingItems(appView));
if (appView.appInfo().hasLiveness()) {
SyntheticFinalization.finalizeWithLiveness(appView.withLiveness(), executorService, timing);
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 e434115..08b14b8 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -244,7 +244,7 @@
StartupProfile startupProfile =
appView.appInfo().hasClassHierarchy()
? appView.getStartupProfile()
- : StartupProfile.createInitialStartupOrderForD8(appView);
+ : StartupProfile.createInitialStartupProfileForD8(appView);
distributor =
new VirtualFile.FillFilesDistributor(
this, classes, options, executorService, startupProfile);
diff --git a/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
index da63c75..60055c9 100644
--- a/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
+++ b/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
@@ -23,13 +23,13 @@
public static MixedSectionLayoutStrategy create(
AppView<?> appView, MixedSectionOffsets mixedSectionOffsets, VirtualFile virtualFile) {
StartupProfile startupProfileForWriting;
- if (virtualFile.getStartupOrder().isEmpty()) {
+ if (virtualFile.getStartupProfile().isEmpty()) {
startupProfileForWriting = StartupProfile.empty();
} else {
assert virtualFile.getId() == 0;
startupProfileForWriting =
appView.options().getStartupOptions().isStartupLayoutOptimizationsEnabled()
- ? virtualFile.getStartupOrder().toStartupOrderForWriting(appView)
+ ? virtualFile.getStartupProfile().toStartupProfileForWriting(appView)
: StartupProfile.empty();
}
MixedSectionLayoutStrategy mixedSectionLayoutStrategy =
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 cf56867..270fcf2 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -137,7 +137,7 @@
return featureSplit;
}
- public StartupProfile getStartupOrder() {
+ public StartupProfile getStartupProfile() {
return startupProfile;
}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java
index a2e3fe9..7f2a248 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java
@@ -64,7 +64,12 @@
}
@Override
- public EmptyStartupProfile toStartupOrderForWriting(AppView<?> appView) {
+ public EmptyStartupProfile toStartupProfileForWriting(AppView<?> appView) {
+ return this;
+ }
+
+ @Override
+ public StartupProfile withoutMissingItems(AppView<?> appView) {
return this;
}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java
index 2fa1094..e3699f7 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ThrowNullCode;
+import com.android.tools.r8.startup.diagnostic.MissingStartupProfileItemsDiagnostic;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
@@ -27,7 +28,8 @@
this.startupProfile =
appView.hasClassHierarchy()
? appView.getStartupProfile()
- : StartupProfile.createInitialStartupOrder(appView.options(), null);
+ : StartupProfile.createInitialStartupProfile(
+ appView.options(), origin -> MissingStartupProfileItemsDiagnostic.Builder.nop());
}
/**
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
index 3e4f660..e8be76e 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
@@ -11,11 +11,11 @@
import com.android.tools.r8.experimental.startup.profile.StartupProfileRule;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.profile.AbstractProfile;
import com.android.tools.r8.profile.AbstractProfileRule;
import com.android.tools.r8.profile.art.ArtProfileBuilderUtils;
@@ -34,6 +34,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Function;
public abstract class StartupProfile
implements AbstractProfile<StartupProfileClassRule, StartupProfileMethodRule> {
@@ -44,6 +45,10 @@
return new Builder();
}
+ public static Builder builderWithCapacity(int capacity) {
+ return new Builder(capacity);
+ }
+
public static Builder builder(
InternalOptions options,
MissingStartupProfileItemsDiagnostic.Builder missingItemsDiagnosticBuilder,
@@ -51,9 +56,12 @@
return new Builder(options, missingItemsDiagnosticBuilder, startupProfileProvider);
}
- public static StartupProfile createInitialStartupOrder(
- InternalOptions options, DexDefinitionSupplier definitions) {
- StartupProfile startupProfile = StartupProfile.parseStartupProfile(options, definitions);
+ public static StartupProfile createInitialStartupProfile(
+ InternalOptions options,
+ Function<Origin, MissingStartupProfileItemsDiagnostic.Builder>
+ missingItemsDiagnosticBuilderFactory) {
+ StartupProfile startupProfile =
+ StartupProfile.parseStartupProfile(options, missingItemsDiagnosticBuilderFactory);
if (startupProfile == null || startupProfile.isEmpty()) {
return empty();
}
@@ -64,12 +72,18 @@
return builder.build();
}
- public static StartupProfile createInitialStartupOrderForD8(AppView<?> appView) {
- return createInitialStartupOrder(appView.options(), appView);
+ public static StartupProfile createInitialStartupProfileForD8(AppView<?> appView) {
+ return createInitialStartupProfile(
+ appView.options(),
+ origin -> new MissingStartupProfileItemsDiagnostic.Builder(appView).setOrigin(origin));
}
- public static StartupProfile createInitialStartupOrderForR8(DexApplication application) {
- return createInitialStartupOrder(application.options, application);
+ public static StartupProfile createInitialStartupProfileForR8(DexApplication application) {
+ // In R8 we expect a startup profile that matches the input app. Since profiles gathered from
+ // running on ART will include synthetics, and these synthetics are not in the input app, we do
+ // not raise warnings if some rules in the profile do not match anything.
+ return createInitialStartupProfile(
+ application.options, origin -> MissingStartupProfileItemsDiagnostic.Builder.nop());
}
public static StartupProfile empty() {
@@ -100,7 +114,9 @@
* </pre>
*/
public static StartupProfile parseStartupProfile(
- InternalOptions options, DexDefinitionSupplier definitions) {
+ InternalOptions options,
+ Function<Origin, MissingStartupProfileItemsDiagnostic.Builder>
+ missingItemsDiagnosticBuilderFactory) {
if (!options.getStartupOptions().hasStartupProfileProviders()) {
return null;
}
@@ -109,8 +125,7 @@
List<StartupProfile> startupProfiles = new ArrayList<>(startupProfileProviders.size());
for (StartupProfileProvider startupProfileProvider : startupProfileProviders) {
MissingStartupProfileItemsDiagnostic.Builder missingItemsDiagnosticBuilder =
- new MissingStartupProfileItemsDiagnostic.Builder(definitions)
- .setOrigin(startupProfileProvider.getOrigin());
+ missingItemsDiagnosticBuilderFactory.apply(startupProfileProvider.getOrigin());
StartupProfile.Builder startupProfileBuilder =
StartupProfile.builder(options, missingItemsDiagnosticBuilder, startupProfileProvider);
startupProfileProvider.getStartupProfile(startupProfileBuilder);
@@ -128,7 +143,9 @@
public abstract StartupProfile rewrittenWithLens(GraphLens graphLens);
- public abstract StartupProfile toStartupOrderForWriting(AppView<?> appView);
+ public abstract StartupProfile toStartupProfileForWriting(AppView<?> appView);
+
+ public abstract StartupProfile withoutMissingItems(AppView<?> appView);
public abstract StartupProfile withoutPrunedItems(
PrunedItems prunedItems, SyntheticItems syntheticItems);
@@ -143,13 +160,21 @@
private Reporter reporter;
private final StartupProfileProvider startupProfileProvider;
- private final LinkedHashMap<DexReference, StartupProfileRule> startupItems =
- new LinkedHashMap<>();
+ private final LinkedHashMap<DexReference, StartupProfileRule> startupItems;
Builder() {
this.dexItemFactory = null;
this.missingItemsDiagnosticBuilder = null;
this.reporter = null;
+ this.startupItems = new LinkedHashMap<>();
+ this.startupProfileProvider = null;
+ }
+
+ Builder(int capacity) {
+ this.dexItemFactory = null;
+ this.missingItemsDiagnosticBuilder = null;
+ this.reporter = null;
+ this.startupItems = new LinkedHashMap<>(capacity);
this.startupProfileProvider = null;
}
@@ -160,6 +185,7 @@
this.dexItemFactory = options.dexItemFactory();
this.missingItemsDiagnosticBuilder = missingItemsDiagnosticBuilder;
this.reporter = options.reporter;
+ this.startupItems = new LinkedHashMap<>();
this.startupProfileProvider = startupProfileProvider;
}
@@ -237,6 +263,10 @@
return this;
}
+ public int size() {
+ return startupItems.size();
+ }
+
@Override
public StartupProfile build() {
if (startupItems.isEmpty()) {
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java
index 90a8e7d..ab251a8 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java
@@ -5,7 +5,9 @@
package com.android.tools.r8.experimental.startup.profile;
import com.android.tools.r8.experimental.startup.StartupProfile;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexReference;
@@ -16,6 +18,7 @@
import com.android.tools.r8.utils.ThrowingConsumer;
import java.util.Collection;
import java.util.LinkedHashMap;
+import java.util.function.BiConsumer;
public class NonEmptyStartupProfile extends StartupProfile {
@@ -68,26 +71,17 @@
@Override
public StartupProfile rewrittenWithLens(GraphLens graphLens) {
- LinkedHashMap<DexReference, StartupProfileRule> rewrittenStartupItems =
- new LinkedHashMap<>(startupItems.size());
- for (StartupProfileRule startupItem : startupItems.values()) {
- // TODO(b/271822426): This should account for one-to-many mappings. e.g., when a bridge is
- // created.
- startupItem.apply(
- startupClass ->
- rewrittenStartupItems.put(
- startupClass.getReference(),
- StartupProfileClassRule.builder()
- .setClassReference(graphLens.lookupType(startupClass.getReference()))
- .build()),
- startupMethod ->
- rewrittenStartupItems.put(
- startupMethod.getReference(),
- StartupProfileMethodRule.builder()
- .setMethod(graphLens.getRenamedMethodSignature(startupMethod.getReference()))
- .build()));
- }
- return createNonEmpty(rewrittenStartupItems);
+ return transform(
+ (classRule, builder) ->
+ builder.addClassRule(
+ StartupProfileClassRule.builder()
+ .setClassReference(graphLens.lookupType(classRule.getReference()))
+ .build()),
+ (methodRule, builder) ->
+ builder.addMethodRule(
+ StartupProfileMethodRule.builder()
+ .setMethod(graphLens.getRenamedMethodSignature(methodRule.getReference()))
+ .build()));
}
public int size() {
@@ -95,109 +89,97 @@
}
/**
- * This is called to process the startup order before computing the startup layouts.
+ * This is called to process the startup profile before computing the startup layouts.
*
- * <p>This processing makes two key changes to the startup order:
+ * <p>This processing makes the following key change to the startup profile: A {@link
+ * StartupProfileClassRule} is inserted for all supertypes of a given class next to the class in
+ * the startup profile. This ensures that the classes from the super hierarchy will be laid out
+ * close to their subclasses, at the point where the subclasses are used during startup.
*
- * <ul>
- * <li>Synthetic startup classes on the form "SLcom/example/SyntheticContext;" represents that
- * any method of any synthetic class that have been synthesized from SyntheticContext has
- * been executed. This pass removes such entries from the startup order, and replaces them
- * by all the methods from all of the synthetics that have been synthesized from
- * SyntheticContext.
- * <li>Moreover, this inserts a StartupClass event for all supertypes of a given class next to
- * the class in the startup order. This ensures that the classes from the super hierarchy
- * will be laid out close to their subclasses, at the point where the subclasses are used
- * during startup.
- * <p>Note that this normally follows from the trace already, except that the class
- * initializers of interfaces are not executed when a subclass is used.
- * </ul>
+ * <p>This normally follows from the trace already, except that the class initializers of
+ * interfaces are not executed when a subclass is used.
*/
@Override
- public StartupProfile toStartupOrderForWriting(AppView<?> appView) {
- LinkedHashMap<DexReference, StartupProfileRule> rewrittenStartupItems =
- new LinkedHashMap<>(startupItems.size());
- for (StartupProfileRule startupItem : startupItems.values()) {
- addStartupItem(startupItem, rewrittenStartupItems, appView);
- }
- return createNonEmpty(rewrittenStartupItems);
+ public StartupProfile toStartupProfileForWriting(AppView<?> appView) {
+ return transform(
+ (classRule, builder) -> addStartupItem(classRule, builder, appView),
+ (methodRule, builder) -> addStartupItem(methodRule, builder, appView));
}
private static void addStartupItem(
- StartupProfileRule startupItem,
- LinkedHashMap<DexReference, StartupProfileRule> rewrittenStartupItems,
- AppView<?> appView) {
+ StartupProfileRule startupItem, Builder builder, AppView<?> appView) {
startupItem.accept(
- startupClass ->
- addClassAndParentClasses(startupClass.getReference(), rewrittenStartupItems, appView),
- startupMethod -> rewrittenStartupItems.put(startupItem.getReference(), startupItem));
+ classRule -> addClassAndParentClasses(classRule.getReference(), builder, appView),
+ builder::addMethodRule);
}
- private static boolean addClass(
- DexProgramClass clazz,
- LinkedHashMap<DexReference, StartupProfileRule> rewrittenStartupItems) {
- StartupProfileRule previous =
- rewrittenStartupItems.put(
- clazz.getType(),
- StartupProfileClassRule.builder().setClassReference(clazz.getType()).build());
- return previous == null;
+ private static boolean addClass(DexProgramClass clazz, Builder builder) {
+ int oldSize = builder.size();
+ builder.addClassRule(
+ StartupProfileClassRule.builder().setClassReference(clazz.getType()).build());
+ return builder.size() > oldSize;
}
- private static void addClassAndParentClasses(
- DexType type,
- LinkedHashMap<DexReference, StartupProfileRule> rewrittenStartupItems,
- AppView<?> appView) {
+ private static void addClassAndParentClasses(DexType type, Builder builder, AppView<?> appView) {
DexProgramClass definition = appView.app().programDefinitionFor(type);
if (definition != null) {
- addClassAndParentClasses(definition, rewrittenStartupItems, appView);
+ addClassAndParentClasses(definition, builder, appView);
}
}
private static void addClassAndParentClasses(
- DexProgramClass clazz,
- LinkedHashMap<DexReference, StartupProfileRule> rewrittenStartupItems,
- AppView<?> appView) {
- if (addClass(clazz, rewrittenStartupItems)) {
- addParentClasses(clazz, rewrittenStartupItems, appView);
+ DexProgramClass clazz, Builder builder, AppView<?> appView) {
+ if (addClass(clazz, builder)) {
+ addParentClasses(clazz, builder, appView);
}
}
- private static void addParentClasses(
- DexProgramClass clazz,
- LinkedHashMap<DexReference, StartupProfileRule> rewrittenStartupItems,
- AppView<?> appView) {
+ private static void addParentClasses(DexProgramClass clazz, Builder builder, AppView<?> appView) {
clazz.forEachImmediateSupertype(
- supertype -> addClassAndParentClasses(supertype, rewrittenStartupItems, appView));
+ supertype -> addClassAndParentClasses(supertype, builder, appView));
+ }
+
+ @Override
+ public StartupProfile withoutMissingItems(AppView<?> appView) {
+ AppInfo appInfo = appView.appInfo();
+ return transform(
+ (classRule, builder) -> {
+ if (appInfo.hasDefinitionForWithoutExistenceAssert(classRule.getReference())) {
+ builder.addClassRule(classRule);
+ }
+ },
+ (methodRule, builder) -> {
+ DexClass clazz =
+ appInfo.definitionForWithoutExistenceAssert(
+ methodRule.getReference().getHolderType());
+ if (methodRule.getReference().isDefinedOnClass(clazz)) {
+ builder.addMethodRule(methodRule);
+ }
+ });
}
@Override
public StartupProfile withoutPrunedItems(PrunedItems prunedItems, SyntheticItems syntheticItems) {
- LinkedHashMap<DexReference, StartupProfileRule> rewrittenStartupItems =
- new LinkedHashMap<>(startupItems.size());
- for (StartupProfileRule startupItem : startupItems.values()) {
- // Only prune non-synthetic classes, since the pruning of a class does not imply that all
- // classes synthesized from it have been pruned.
- startupItem.accept(
- startupClass -> {
- if (!prunedItems.isRemoved(startupClass.getReference())) {
- rewrittenStartupItems.put(startupClass.getReference(), startupItem);
- }
- },
- startupMethod -> {
- if (!prunedItems.isRemoved(startupMethod.getReference())) {
- rewrittenStartupItems.put(startupMethod.getReference(), startupItem);
- }
- });
- }
- return createNonEmpty(rewrittenStartupItems);
+ return transform(
+ (classRule, builder) -> {
+ if (!prunedItems.isRemoved(classRule.getReference())) {
+ builder.addClassRule(classRule);
+ }
+ },
+ (methodRule, builder) -> {
+ if (!prunedItems.isRemoved(methodRule.getReference())) {
+ builder.addMethodRule(methodRule);
+ }
+ });
}
- private StartupProfile createNonEmpty(
- LinkedHashMap<DexReference, StartupProfileRule> startupItems) {
- if (startupItems.isEmpty()) {
- assert false;
- return empty();
- }
- return new NonEmptyStartupProfile(startupItems);
+ private StartupProfile transform(
+ BiConsumer<StartupProfileClassRule, Builder> classRuleTransformer,
+ BiConsumer<StartupProfileMethodRule, Builder> methodRuleTransformer) {
+ Builder builder = builderWithCapacity(startupItems.size());
+ forEachRule(
+ classRule -> classRuleTransformer.accept(classRule, builder),
+ methodRule -> methodRuleTransformer.accept(methodRule, builder));
+ return builder.build();
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index d7d5948..92848aa 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -253,7 +253,7 @@
return new AppView<>(
appInfo,
ArtProfileCollection.createInitialArtProfileCollection(appInfo, appInfo.options()),
- StartupProfile.createInitialStartupOrderForR8(application),
+ StartupProfile.createInitialStartupProfileForR8(application),
WholeProgramOptimizations.ON,
defaultTypeRewriter(appInfo));
}