Implement new startup API Change-Id: I32b5999179c4e5cbb8e95dd91659b25e07eaef4d
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java index 172bfa2..24df37d 100644 --- a/src/main/java/com/android/tools/r8/D8Command.java +++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -690,10 +690,7 @@ internal.configureAndroidPlatformBuild(getAndroidPlatformBuild()); - // TODO(b/238173796): Change StartupOptions to store a Collection<StartupProfileProvider>. - if (getStartupProfileProviders().size() == 1) { - internal.getStartupOptions().setStartupProfileProvider(getStartupProfileProviders().get(0)); - } + internal.getStartupOptions().setStartupProfileProviders(getStartupProfileProviders()); internal.setDumpInputFlags(getDumpInputFlags()); internal.dumpOptions = dumpOptions();
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java index 6adecce..c9fd4f2 100644 --- a/src/main/java/com/android/tools/r8/R8Command.java +++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -1067,10 +1067,7 @@ internal.configureAndroidPlatformBuild(getAndroidPlatformBuild()); - // TODO(b/238173796): Change StartupOptions to store a Collection<StartupProfileProvider>. - if (getStartupProfileProviders().size() == 1) { - internal.getStartupOptions().setStartupProfileProvider(getStartupProfileProviders().get(0)); - } + internal.getStartupOptions().setStartupProfileProviders(getStartupProfileProviders()); if (!DETERMINISTIC_DEBUGGING) { assert internal.threadCount == ThreadUtils.NOT_SPECIFIED;
diff --git a/src/main/java/com/android/tools/r8/StringResource.java b/src/main/java/com/android/tools/r8/StringResource.java index 515f2ab..4d097e0 100644 --- a/src/main/java/com/android/tools/r8/StringResource.java +++ b/src/main/java/com/android/tools/r8/StringResource.java
@@ -105,13 +105,5 @@ throw new ResourceException(origin, e); } } - - public String getStringWithRuntimeException() { - try { - return getString(); - } catch (ResourceException e) { - throw new RuntimeException(e); - } - } } }
diff --git a/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java index 4d9a8ca..0833358 100644 --- a/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java +++ b/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
@@ -82,21 +82,23 @@ virtualFile.classes().size()); LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(appView, true); StartupIndexedItemCollection indexedItemCollection = new StartupIndexedItemCollection(); - for (StartupItem<DexType, DexMethod, ?> startupItem : startupOrderForWriting.getItems()) { - // All synthetic startup items should be removed after calling - // StartupOrder#toStartupOrderForWriting. - assert !startupItem.isSynthetic(); + for (StartupItem startupItem : startupOrderForWriting.getItems()) { startupItem.accept( startupClass -> collectStartupItems(startupClass, indexedItemCollection, virtualFileDefinitions), startupMethod -> collectStartupItems( - startupMethod, indexedItemCollection, virtualFileDefinitions, rewriter)); + startupMethod, indexedItemCollection, virtualFileDefinitions, rewriter), + syntheticStartupMethod -> { + // All synthetic startup items should be removed after calling + // StartupOrder#toStartupOrderForWriting. + assert false; + }); } } private void collectStartupItems( - StartupClass<DexType, DexMethod> startupClass, + StartupClass startupClass, StartupIndexedItemCollection indexedItemCollection, Map<DexType, DexProgramClass> virtualFileDefinitions) { DexProgramClass definition = virtualFileDefinitions.get(startupClass.getReference()); @@ -119,7 +121,7 @@ } private void collectStartupItems( - StartupMethod<DexType, DexMethod> startupMethod, + StartupMethod startupMethod, StartupIndexedItemCollection indexedItemCollection, Map<DexType, DexProgramClass> virtualFileDefinitions, LensCodeRewriterUtils rewriter) {
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 fafe700..f6b057a 100644 --- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java +++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -1396,7 +1396,7 @@ return; } - assert options.getStartupOptions().hasStartupProfileProvider(); + assert options.getStartupOptions().hasStartupProfileProviders(); // In practice, all startup classes should fit in a single dex file, so optimistically try to // commit the startup classes using a single transaction.
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java index 8913368..fb1fc24 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java
@@ -6,7 +6,6 @@ import com.android.tools.r8.experimental.startup.profile.StartupItem; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.PrunedItems; @@ -24,7 +23,7 @@ } @Override - public Collection<StartupItem<DexType, DexMethod, ?>> getItems() { + public Collection<StartupItem> getItems() { return Collections.emptyList(); }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java index 164475b..76020fc 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java
@@ -7,11 +7,10 @@ import com.android.tools.r8.experimental.startup.profile.StartupClass; import com.android.tools.r8.experimental.startup.profile.StartupItem; import com.android.tools.r8.experimental.startup.profile.StartupMethod; +import com.android.tools.r8.experimental.startup.profile.SyntheticStartupMethod; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexApplication; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; -import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.PrunedItems; @@ -28,24 +27,22 @@ public class NonEmptyStartupOrder extends StartupOrder { - private final LinkedHashSet<StartupItem<DexType, DexMethod, ?>> startupItems; + private final LinkedHashSet<StartupItem> startupItems; // Sets to allow efficient querying without boxing. private final Set<DexType> nonSyntheticStartupClasses = Sets.newIdentityHashSet(); private final Set<DexType> syntheticStartupClasses = Sets.newIdentityHashSet(); - NonEmptyStartupOrder(LinkedHashSet<StartupItem<DexType, DexMethod, ?>> startupItems) { + NonEmptyStartupOrder(LinkedHashSet<StartupItem> startupItems) { assert !startupItems.isEmpty(); this.startupItems = startupItems; - for (StartupItem<DexType, DexMethod, ?> startupItem : startupItems) { - if (startupItem.isSynthetic()) { - assert startupItem.isStartupClass(); - syntheticStartupClasses.add(startupItem.asStartupClass().getReference()); - } else { - DexReference reference = - startupItem.apply(StartupClass::getReference, StartupMethod::getReference); - nonSyntheticStartupClasses.add(reference.getContextType()); - } + for (StartupItem startupItem : startupItems) { + startupItem.apply( + startupClass -> nonSyntheticStartupClasses.add(startupClass.getReference()), + startupMethod -> + nonSyntheticStartupClasses.add(startupMethod.getReference().getHolderType()), + syntheticStartupMethod -> + syntheticStartupClasses.add(syntheticStartupMethod.getSyntheticContextType())); } } @@ -72,7 +69,7 @@ } @Override - public Collection<StartupItem<DexType, DexMethod, ?>> getItems() { + public Collection<StartupItem> getItems() { return startupItems; } @@ -83,27 +80,28 @@ @Override public StartupOrder rewrittenWithLens(GraphLens graphLens) { - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems = - new LinkedHashSet<>(startupItems.size()); - for (StartupItem<DexType, DexMethod, ?> startupItem : startupItems) { - if (startupItem.isStartupClass()) { - StartupClass<DexType, DexMethod> startupClass = startupItem.asStartupClass(); - rewrittenStartupItems.add( - StartupClass.dexBuilder() - .setClassReference(graphLens.lookupType(startupClass.getReference())) - .setSynthetic(startupItem.isSynthetic()) - .build()); - } else { - assert !startupItem.isSynthetic(); - StartupMethod<DexType, DexMethod> startupMethod = startupItem.asStartupMethod(); - // TODO(b/238173796): This should account for one-to-many mappings. e.g., when a bridge is - // created. - rewrittenStartupItems.add( - StartupMethod.dexBuilder() - .setMethodReference( - graphLens.getRenamedMethodSignature(startupMethod.getReference())) - .build()); - } + LinkedHashSet<StartupItem> rewrittenStartupItems = new LinkedHashSet<>(startupItems.size()); + for (StartupItem startupItem : startupItems) { + // TODO(b/238173796): This should account for one-to-many mappings. e.g., when a bridge is + // created. + startupItem.apply( + startupClass -> + rewrittenStartupItems.add( + StartupClass.builder() + .setClassReference(graphLens.lookupType(startupClass.getReference())) + .build()), + startupMethod -> + rewrittenStartupItems.add( + StartupMethod.builder() + .setMethodReference( + graphLens.getRenamedMethodSignature(startupMethod.getReference())) + .build()), + syntheticStartupMethod -> + rewrittenStartupItems.add( + SyntheticStartupMethod.builder() + .setSyntheticContextReference( + graphLens.lookupType(syntheticStartupMethod.getSyntheticContextType())) + .build())); } return createNonEmpty(rewrittenStartupItems); } @@ -129,29 +127,27 @@ */ @Override public StartupOrder toStartupOrderForWriting(AppView<?> appView) { - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems = - new LinkedHashSet<>(startupItems.size()); + LinkedHashSet<StartupItem> rewrittenStartupItems = new LinkedHashSet<>(startupItems.size()); Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses = appView.getSyntheticItems().computeSyntheticContextsToSyntheticClasses(appView); - for (StartupItem<DexType, DexMethod, ?> startupItem : startupItems) { + for (StartupItem startupItem : startupItems) { addStartupItem( startupItem, rewrittenStartupItems, syntheticContextsToSyntheticClasses, appView); } - assert rewrittenStartupItems.stream().noneMatch(StartupItem::isSynthetic); + assert rewrittenStartupItems.stream().noneMatch(StartupItem::isSyntheticStartupMethod); return createNonEmpty(rewrittenStartupItems); } private static void addStartupItem( - StartupItem<DexType, DexMethod, ?> startupItem, - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems, + StartupItem startupItem, + LinkedHashSet<StartupItem> rewrittenStartupItems, Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses, AppView<?> appView) { - if (startupItem.isSynthetic()) { - assert startupItem.isStartupClass(); - StartupClass<DexType, DexMethod> startupClass = startupItem.asStartupClass(); + if (startupItem.isSyntheticStartupMethod()) { + SyntheticStartupMethod syntheticStartupMethod = startupItem.asSyntheticStartupMethod(); List<DexProgramClass> syntheticClassesForContext = syntheticContextsToSyntheticClasses.getOrDefault( - startupClass.getReference(), Collections.emptyList()); + syntheticStartupMethod.getSyntheticContextType(), Collections.emptyList()); for (DexProgramClass clazz : syntheticClassesForContext) { addClassAndParentClasses(clazz, rewrittenStartupItems, appView); addAllMethods(clazz, rewrittenStartupItems); @@ -167,16 +163,13 @@ } private static boolean addClass( - DexProgramClass clazz, - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems) { + DexProgramClass clazz, LinkedHashSet<StartupItem> rewrittenStartupItems) { return rewrittenStartupItems.add( - StartupClass.dexBuilder().setClassReference(clazz.getType()).build()); + StartupClass.builder().setClassReference(clazz.getType()).build()); } private static void addClassAndParentClasses( - DexType type, - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems, - AppView<?> appView) { + DexType type, LinkedHashSet<StartupItem> rewrittenStartupItems, AppView<?> appView) { DexProgramClass definition = appView.app().programDefinitionFor(type); if (definition != null) { addClassAndParentClasses(definition, rewrittenStartupItems, appView); @@ -184,54 +177,53 @@ } private static void addClassAndParentClasses( - DexProgramClass clazz, - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems, - AppView<?> appView) { + DexProgramClass clazz, LinkedHashSet<StartupItem> rewrittenStartupItems, AppView<?> appView) { if (addClass(clazz, rewrittenStartupItems)) { addParentClasses(clazz, rewrittenStartupItems, appView); } } private static void addParentClasses( - DexProgramClass clazz, - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems, - AppView<?> appView) { + DexProgramClass clazz, LinkedHashSet<StartupItem> rewrittenStartupItems, AppView<?> appView) { clazz.forEachImmediateSupertype( supertype -> addClassAndParentClasses(supertype, rewrittenStartupItems, appView)); } private static void addAllMethods( - DexProgramClass clazz, - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems) { + DexProgramClass clazz, LinkedHashSet<StartupItem> rewrittenStartupItems) { clazz.forEachProgramMethod( method -> rewrittenStartupItems.add( - StartupMethod.dexBuilder().setMethodReference(method.getReference()).build())); + StartupMethod.builder().setMethodReference(method.getReference()).build())); } @Override public StartupOrder withoutPrunedItems(PrunedItems prunedItems, SyntheticItems syntheticItems) { - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> rewrittenStartupItems = - new LinkedHashSet<>(startupItems.size()); + LinkedHashSet<StartupItem> rewrittenStartupItems = new LinkedHashSet<>(startupItems.size()); LazyBox<Set<DexType>> contextsOfLiveSynthetics = new LazyBox<>( () -> computeContextsOfLiveSynthetics(prunedItems.getPrunedApp(), syntheticItems)); - for (StartupItem<DexType, DexMethod, ?> startupItem : startupItems) { + for (StartupItem startupItem : startupItems) { // Only prune non-synthetic classes, since the pruning of a class does not imply that all // classes synthesized from it have been pruned. - if (startupItem.isSynthetic()) { - assert startupItem.isStartupClass(); - StartupClass<DexType, DexMethod> startupClass = startupItem.asStartupClass(); - if (contextsOfLiveSynthetics.computeIfAbsent().contains(startupClass.getReference())) { - rewrittenStartupItems.add(startupClass); - } - } else { - DexReference reference = - startupItem.apply(StartupClass::getReference, StartupMethod::getReference); - if (!prunedItems.isRemoved(reference)) { - rewrittenStartupItems.add(startupItem); - } - } + startupItem.accept( + startupClass -> { + if (!prunedItems.isRemoved(startupClass.getReference())) { + rewrittenStartupItems.add(startupItem); + } + }, + startupMethod -> { + if (!prunedItems.isRemoved(startupMethod.getReference())) { + rewrittenStartupItems.add(startupItem); + } + }, + syntheticStartupMethod -> { + if (contextsOfLiveSynthetics + .computeIfAbsent() + .contains(syntheticStartupMethod.getSyntheticContextType())) { + rewrittenStartupItems.add(syntheticStartupMethod); + } + }); } return createNonEmpty(rewrittenStartupItems); } @@ -248,8 +240,7 @@ return contextsOfLiveSynthetics; } - private StartupOrder createNonEmpty( - LinkedHashSet<StartupItem<DexType, DexMethod, ?>> startupItems) { + private StartupOrder createNonEmpty(LinkedHashSet<StartupItem> startupItems) { if (startupItems.isEmpty()) { assert false; return empty();
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 43e306a..e6a0f85 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
@@ -4,12 +4,9 @@ package com.android.tools.r8.experimental.startup; -import com.android.tools.r8.experimental.startup.profile.StartupClass; import com.android.tools.r8.experimental.startup.profile.StartupItem; -import com.android.tools.r8.experimental.startup.profile.StartupMethod; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; @@ -81,26 +78,20 @@ Set<DexReference> startupItems = Sets.newIdentityHashSet(); Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses = appView.getSyntheticItems().computeSyntheticContextsToSyntheticClasses(appView); - for (StartupItem<DexType, DexMethod, ?> startupItem : startupOrder.getItems()) { - if (startupItem.isSynthetic()) { - assert startupItem.isStartupClass(); - List<DexProgramClass> syntheticClasses = - syntheticContextsToSyntheticClasses.getOrDefault( - startupItem.asStartupClass().getReference(), Collections.emptyList()); - for (DexProgramClass syntheticClass : syntheticClasses) { - startupItems.add(syntheticClass.getType()); - syntheticClass.forEachProgramMethod(method -> startupItems.add(method.getReference())); - } - } else { - if (startupItem.isStartupClass()) { - StartupClass<DexType, DexMethod> startupClass = startupItem.asStartupClass(); - startupItems.add(startupClass.getReference()); - } else { - assert startupItem.isStartupMethod(); - StartupMethod<DexType, DexMethod> startupMethod = startupItem.asStartupMethod(); - startupItems.add(startupMethod.getReference()); - } - } + for (StartupItem startupItem : startupOrder.getItems()) { + startupItem.accept( + startupClass -> startupItems.add(startupClass.getReference()), + startupMethod -> startupItems.add(startupMethod.getReference()), + syntheticStartupMethod -> { + List<DexProgramClass> syntheticClasses = + syntheticContextsToSyntheticClasses.getOrDefault( + syntheticStartupMethod.getSyntheticContextType(), Collections.emptyList()); + for (DexProgramClass syntheticClass : syntheticClasses) { + startupItems.add(syntheticClass.getType()); + syntheticClass.forEachProgramMethod( + method -> startupItems.add(method.getReference())); + } + }); } return startupItems; }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java index 86df003..01bfd2b 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
@@ -6,13 +6,13 @@ import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault; -import com.android.tools.r8.StringResource; -import com.android.tools.r8.errors.Unimplemented; -import com.android.tools.r8.origin.Origin; -import com.android.tools.r8.startup.StartupProfileBuilder; import com.android.tools.r8.startup.StartupProfileProvider; +import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.SystemPropertyUtils; +import com.google.common.collect.ImmutableList; import java.nio.file.Paths; +import java.util.Collection; +import java.util.Collections; public class StartupOptions { @@ -52,28 +52,18 @@ private boolean enableStartupLayoutOptimizations = parseSystemPropertyForDevelopmentOrDefault("com.android.tools.r8.startup.layout", true); - private StartupProfileProvider startupProfileProvider = - SystemPropertyUtils.applySystemProperty( - "com.android.tools.r8.startup.profile", - propertyValue -> - new StartupProfileProvider() { - @Override - public String get() { - return StringResource.fromFile(Paths.get(propertyValue)) - .getStringWithRuntimeException(); - } + private Collection<StartupProfileProvider> startupProfileProviders; - @Override - public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) { - throw new Unimplemented(); - } - - @Override - public Origin getOrigin() { - return Origin.unknown(); - } - }, - () -> null); + public StartupOptions(InternalOptions options) { + this.startupProfileProviders = + SystemPropertyUtils.applySystemProperty( + "com.android.tools.r8.startup.profile", + propertyValue -> + ImmutableList.of( + StartupProfileProviderUtils.createFromFile( + Paths.get(propertyValue), options.reporter)), + Collections::emptyList); + } public boolean isMinimalStartupDexEnabled() { return enableMinimalStartupDex; @@ -112,16 +102,17 @@ return this; } - public boolean hasStartupProfileProvider() { - return startupProfileProvider != null; + public boolean hasStartupProfileProviders() { + return startupProfileProviders != null && !startupProfileProviders.isEmpty(); } - public StartupProfileProvider getStartupProfileProvider() { - return startupProfileProvider; + public Collection<StartupProfileProvider> getStartupProfileProviders() { + return startupProfileProviders; } - public StartupOptions setStartupProfileProvider(StartupProfileProvider startupProfileProvider) { - this.startupProfileProvider = startupProfileProvider; + public StartupOptions setStartupProfileProviders( + Collection<StartupProfileProvider> startupProfileProviders) { + this.startupProfileProviders = startupProfileProviders; return this; } }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java index aa3d454..78a5970 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java
@@ -7,7 +7,6 @@ import com.android.tools.r8.experimental.startup.profile.StartupItem; import com.android.tools.r8.experimental.startup.profile.StartupProfile; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.PrunedItems; @@ -34,7 +33,7 @@ public abstract boolean contains(DexType type, SyntheticItems syntheticItems); - public abstract Collection<StartupItem<DexType, DexMethod, ?>> getItems(); + public abstract Collection<StartupItem> getItems(); public abstract boolean isEmpty();
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java new file mode 100644 index 0000000..2924e48 --- /dev/null +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
@@ -0,0 +1,46 @@ +// Copyright (c) 2022, 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.experimental.startup; + +import com.android.tools.r8.experimental.startup.profile.StartupProfileParser; +import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.origin.PathOrigin; +import com.android.tools.r8.startup.StartupProfileBuilder; +import com.android.tools.r8.startup.StartupProfileProvider; +import com.android.tools.r8.utils.FileUtils; +import com.android.tools.r8.utils.Reporter; +import com.android.tools.r8.utils.StringDiagnostic; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Path; + +public class StartupProfileProviderUtils { + + public static StartupProfileProvider createFromFile(Path path, Reporter reporter) { + return new StartupProfileProvider() { + + @Override + public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) { + try { + StartupProfileParser.create() + .parseLines( + FileUtils.readAllLines(path).stream(), + startupProfileBuilder, + error -> + reporter.warning( + new StringDiagnostic( + "Invalid descriptor for startup class or method: " + error))); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public Origin getOrigin() { + return new PathOrigin(path); + } + }; + } +}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupClass.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupClass.java index baab7f9..dbd8ef6 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupClass.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupClass.java
@@ -4,79 +4,104 @@ package com.android.tools.r8.experimental.startup.profile; -import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.references.ClassReference; -import com.android.tools.r8.references.MethodReference; +import com.android.tools.r8.startup.StartupClassBuilder; +import com.android.tools.r8.utils.ClassReferenceUtils; import java.util.function.Consumer; import java.util.function.Function; -// TODO(b/238173796): When updating the compiler to have support for taking a list of startup -// methods, this class may likely be removed along with the StartupItem class, so that only -// StartupMethod remains. -public class StartupClass<C, M> extends StartupItem<C, M, C> { +public class StartupClass extends StartupItem { - public StartupClass(int flags, C reference) { - super(flags, reference); + private final DexType type; + + StartupClass(DexType type) { + this.type = type; } - public static <C, M> Builder<C, M> builder() { - return new Builder<>(); + public static Builder builder() { + return new Builder(); } - public static Builder<DexType, DexMethod> dexBuilder() { - return new Builder<>(); - } - - public static Builder<ClassReference, MethodReference> referenceBuilder() { - return new Builder<>(); + public static Builder builder(DexItemFactory dexItemFactory) { + return new Builder(dexItemFactory); } @Override public void accept( - Consumer<StartupClass<C, M>> classConsumer, Consumer<StartupMethod<C, M>> methodConsumer) { + Consumer<StartupClass> classConsumer, + Consumer<StartupMethod> methodConsumer, + Consumer<SyntheticStartupMethod> syntheticMethodConsumer) { classConsumer.accept(this); } @Override public <T> T apply( - Function<StartupClass<C, M>, T> classFunction, - Function<StartupMethod<C, M>, T> methodFunction) { + Function<StartupClass, T> classFunction, + Function<StartupMethod, T> methodFunction, + Function<SyntheticStartupMethod, T> syntheticMethodFunction) { return classFunction.apply(this); } + public DexType getReference() { + return type; + } + @Override public boolean isStartupClass() { return true; } @Override - public StartupClass<C, M> asStartupClass() { + public StartupClass asStartupClass() { return this; } @Override - public void serializeToString( - StringBuilder builder, - Function<C, String> classSerializer, - Function<M, String> methodSerializer) { - if (isSynthetic()) { - builder.append('S'); + public boolean equals(Object o) { + if (this == o) { + return true; } - builder.append(classSerializer.apply(getReference())); + if (o == null || getClass() != o.getClass()) { + return false; + } + StartupClass that = (StartupClass) o; + return type == that.type; } - public static class Builder<C, M> extends StartupItem.Builder<C, M, Builder<C, M>> { + @Override + public int hashCode() { + return type.hashCode(); + } - @Override - public Builder<C, M> setMethodReference(M reference) { - throw new Unreachable(); + public static class Builder implements StartupClassBuilder { + + private final DexItemFactory dexItemFactory; + + private DexType type; + + Builder() { + this(null); + } + + Builder(DexItemFactory dexItemFactory) { + this.dexItemFactory = dexItemFactory; } @Override - public StartupClass<C, M> build() { - return new StartupClass<>(flags, classReference); + public Builder setClassReference(ClassReference classReference) { + assert dexItemFactory != null; + return setClassReference(ClassReferenceUtils.toDexType(classReference, dexItemFactory)); + } + + public Builder setClassReference(DexType type) { + this.type = type; + return this; + } + + public StartupClass build() { + return new StartupClass(type); } } }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupItem.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupItem.java index 4590a3f..1854c07 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupItem.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupItem.java
@@ -4,35 +4,27 @@ package com.android.tools.r8.experimental.startup.profile; -import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.DexType; import java.util.function.Consumer; import java.util.function.Function; -public abstract class StartupItem<C, M, R> { - - private static final int FLAG_SYNTHETIC = 1; - - protected final int flags; - protected final R reference; - - public StartupItem(int flags, R reference) { - this.flags = flags; - this.reference = reference; - } +public abstract class StartupItem { public abstract void accept( - Consumer<StartupClass<C, M>> classConsumer, Consumer<StartupMethod<C, M>> methodConsumer); + Consumer<StartupClass> classConsumer, + Consumer<StartupMethod> methodConsumer, + Consumer<SyntheticStartupMethod> syntheticMethodConsumer); public abstract <T> T apply( - Function<StartupClass<C, M>, T> classFunction, - Function<StartupMethod<C, M>, T> methodFunction); + Function<StartupClass, T> classFunction, + Function<StartupMethod, T> methodFunction, + Function<SyntheticStartupMethod, T> syntheticMethodFunction); public boolean isStartupClass() { return false; } - public StartupClass<C, M> asStartupClass() { + public StartupClass asStartupClass() { + assert false; return null; } @@ -40,126 +32,17 @@ return false; } - public StartupMethod<C, M> asStartupMethod() { + public StartupMethod asStartupMethod() { + assert false; return null; } - public static <C, M> Builder<C, M, ?> builder() { - return new Builder<>(); + public boolean isSyntheticStartupMethod() { + return false; } - public static Builder<DexType, DexMethod, ?> dexBuilder() { - return new Builder<>(); - } - - public int getFlags() { - return flags; - } - - public R getReference() { - return reference; - } - - public boolean isSynthetic() { - return (flags & FLAG_SYNTHETIC) != 0; - } - - public abstract void serializeToString( - StringBuilder builder, - Function<C, String> classSerializer, - Function<M, String> methodSerializer); - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - StartupItem<?, ?, ?> startupItem = (StartupItem<?, ?, ?>) obj; - return flags == startupItem.flags && reference.equals(startupItem.reference); - } - - @Override - public int hashCode() { - return (reference.hashCode() << 1) | flags; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (isSynthetic()) { - builder.append('S'); - } - builder.append(reference); - return builder.toString(); - } - - public static class Builder<C, M, B extends Builder<C, M, B>> { - - protected int flags; - protected C classReference; - protected M methodReference; - - public B applyIf(boolean condition, Consumer<B> thenConsumer, Consumer<B> elseConsumer) { - if (condition) { - thenConsumer.accept(self()); - } else { - elseConsumer.accept(self()); - } - return self(); - } - - public B setFlags(int flags) { - this.flags = flags; - return self(); - } - - public B setClassReference(C reference) { - this.classReference = reference; - return self(); - } - - public B setMethodReference(M reference) { - this.methodReference = reference; - return self(); - } - - public B setSynthetic() { - this.flags |= FLAG_SYNTHETIC; - return self(); - } - - public B setSynthetic(boolean synthetic) { - if (synthetic) { - return setSynthetic(); - } - assert (flags & FLAG_SYNTHETIC) == 0; - return self(); - } - - public StartupItem<C, M, ?> build() { - if (classReference != null) { - return buildStartupClass(); - } else { - return buildStartupMethod(); - } - } - - public StartupClass<C, M> buildStartupClass() { - assert classReference != null; - return new StartupClass<>(flags, classReference); - } - - public StartupMethod<C, M> buildStartupMethod() { - assert methodReference != null; - return new StartupMethod<>(flags, methodReference); - } - - @SuppressWarnings("unchecked") - public B self() { - return (B) this; - } + public SyntheticStartupMethod asSyntheticStartupMethod() { + assert false; + return null; } }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupMethod.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupMethod.java index b6eb04b..9e45798 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupMethod.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupMethod.java
@@ -4,66 +4,104 @@ package com.android.tools.r8.experimental.startup.profile; -import com.android.tools.r8.errors.Unreachable; -import com.android.tools.r8.references.ClassReference; +import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.references.MethodReference; +import com.android.tools.r8.startup.StartupMethodBuilder; +import com.android.tools.r8.utils.MethodReferenceUtils; import java.util.function.Consumer; import java.util.function.Function; -public class StartupMethod<C, M> extends StartupItem<C, M, M> { +public class StartupMethod extends StartupItem { - public StartupMethod(int flags, M reference) { - super(flags, reference); + private final DexMethod method; + + StartupMethod(DexMethod method) { + this.method = method; } - public static Builder<ClassReference, MethodReference> referenceBuilder() { - return new Builder<>(); + public static Builder builder() { + return new Builder(); + } + + public static Builder builder(DexItemFactory dexItemFactory) { + return new Builder(dexItemFactory); } @Override public void accept( - Consumer<StartupClass<C, M>> classConsumer, Consumer<StartupMethod<C, M>> methodConsumer) { + Consumer<StartupClass> classConsumer, + Consumer<StartupMethod> methodConsumer, + Consumer<SyntheticStartupMethod> syntheticMethodConsumer) { methodConsumer.accept(this); } @Override public <T> T apply( - Function<StartupClass<C, M>, T> classFunction, - Function<StartupMethod<C, M>, T> methodFunction) { + Function<StartupClass, T> classFunction, + Function<StartupMethod, T> methodFunction, + Function<SyntheticStartupMethod, T> syntheticMethodFunction) { return methodFunction.apply(this); } + public DexMethod getReference() { + return method; + } + @Override public boolean isStartupMethod() { return true; } @Override - public StartupMethod<C, M> asStartupMethod() { + public StartupMethod asStartupMethod() { return this; } @Override - public void serializeToString( - StringBuilder builder, - Function<C, String> classSerializer, - Function<M, String> methodSerializer) { - if (isSynthetic()) { - builder.append('S'); + public boolean equals(Object o) { + if (this == o) { + return true; } - builder.append(methodSerializer.apply(getReference())); + if (o == null || getClass() != o.getClass()) { + return false; + } + StartupMethod that = (StartupMethod) o; + return method == that.method; } - public static class Builder<C, M> extends StartupItem.Builder<C, M, Builder<C, M>> { + @Override + public int hashCode() { + return method.hashCode(); + } - @Override - public Builder<C, M> setClassReference(C reference) { - throw new Unreachable(); + public static class Builder implements StartupMethodBuilder { + + private final DexItemFactory dexItemFactory; + + private DexMethod method; + + Builder() { + this(null); + } + + Builder(DexItemFactory dexItemFactory) { + this.dexItemFactory = dexItemFactory; } @Override - public StartupMethod<C, M> build() { - return new StartupMethod<>(flags, methodReference); + public Builder setMethodReference(MethodReference classReference) { + assert dexItemFactory != null; + return setMethodReference(MethodReferenceUtils.toDexMethod(classReference, dexItemFactory)); + } + + public Builder setMethodReference(DexMethod method) { + this.method = method; + return this; + } + + public StartupMethod build() { + return new StartupMethod(method); } } }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfile.java index c2e65b7..a0d6204 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfile.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfile.java
@@ -4,22 +4,23 @@ package com.android.tools.r8.experimental.startup.profile; -import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.startup.StartupClassBuilder; +import com.android.tools.r8.startup.StartupMethodBuilder; +import com.android.tools.r8.startup.StartupProfileBuilder; import com.android.tools.r8.startup.StartupProfileProvider; +import com.android.tools.r8.startup.SyntheticStartupMethodBuilder; import com.android.tools.r8.utils.InternalOptions; -import com.android.tools.r8.utils.StringDiagnostic; -import com.android.tools.r8.utils.StringUtils; import com.google.common.collect.ImmutableList; -import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.function.Consumer; public class StartupProfile { - private final List<StartupItem<DexType, DexMethod, ?>> startupItems; + private final List<StartupItem> startupItems; - public StartupProfile(List<StartupItem<DexType, DexMethod, ?>> startupItems) { + public StartupProfile(List<StartupItem> startupItems) { this.startupItems = startupItems; } @@ -27,6 +28,10 @@ return new Builder(); } + public static Builder builder(DexItemFactory dexItemFactory) { + return new Builder(dexItemFactory); + } + /** * Parses the supplied startup configuration, if any. The startup configuration is a list of class * and method descriptors. @@ -43,60 +48,63 @@ * </pre> */ public static StartupProfile parseStartupProfile(InternalOptions options) { - if (!options.getStartupOptions().hasStartupProfileProvider()) { + if (!options.getStartupOptions().hasStartupProfileProviders()) { return null; } - StartupProfileProvider resource = options.getStartupOptions().getStartupProfileProvider(); - List<String> startupDescriptors = StringUtils.splitLines(resource.get()); - return createStartupConfigurationFromLines(options, startupDescriptors); + Collection<StartupProfileProvider> startupProfileProviders = + options.getStartupOptions().getStartupProfileProviders(); + StartupProfile.Builder startupProfileBuilder = StartupProfile.builder(options.dexItemFactory()); + for (StartupProfileProvider startupProfileProvider : startupProfileProviders) { + startupProfileProvider.getStartupProfile(startupProfileBuilder); + } + return startupProfileBuilder.build(); } - public static StartupProfile createStartupConfigurationFromLines( - InternalOptions options, List<String> startupDescriptors) { - List<StartupItem<DexType, DexMethod, ?>> startupItems = new ArrayList<>(); - StartupProfileParser.createDexParser(options.dexItemFactory()) - .parseLines( - startupDescriptors, - startupItems::add, - startupItems::add, - error -> - options.reporter.warning( - new StringDiagnostic( - "Invalid descriptor for startup class or method: " + error))); - return new StartupProfile(startupItems); - } - - public List<StartupItem<DexType, DexMethod, ?>> getStartupItems() { + public List<StartupItem> getStartupItems() { return startupItems; } - public String serializeToString() { - StringBuilder builder = new StringBuilder(); - for (StartupItem<DexType, DexMethod, ?> startupItem : startupItems) { - startupItem.serializeToString(builder, DexType::toSmaliString, DexMethod::toSmaliString); - builder.append('\n'); + public static class Builder implements StartupProfileBuilder { + + private final DexItemFactory dexItemFactory; + private final ImmutableList.Builder<StartupItem> startupItemsBuilder = ImmutableList.builder(); + + Builder() { + this(null); } - return builder.toString(); - } - public static class Builder { + Builder(DexItemFactory dexItemFactory) { + this.dexItemFactory = dexItemFactory; + } - private final ImmutableList.Builder<StartupItem<DexType, DexMethod, ?>> startupItemsBuilder = - ImmutableList.builder(); + @Override + public Builder addStartupClass(Consumer<StartupClassBuilder> startupClassBuilderConsumer) { + StartupClass.Builder startupClassBuilder = StartupClass.builder(dexItemFactory); + startupClassBuilderConsumer.accept(startupClassBuilder); + return addStartupItem(startupClassBuilder.build()); + } - public Builder addStartupItem(StartupItem<DexType, DexMethod, ?> startupItem) { + @Override + public Builder addStartupMethod(Consumer<StartupMethodBuilder> startupMethodBuilderConsumer) { + StartupMethod.Builder startupMethodBuilder = StartupMethod.builder(dexItemFactory); + startupMethodBuilderConsumer.accept(startupMethodBuilder); + return addStartupItem(startupMethodBuilder.build()); + } + + @Override + public StartupProfileBuilder addSyntheticStartupMethod( + Consumer<SyntheticStartupMethodBuilder> syntheticStartupMethodBuilderConsumer) { + SyntheticStartupMethod.Builder syntheticStartupMethodBuilder = + SyntheticStartupMethod.builder(dexItemFactory); + syntheticStartupMethodBuilderConsumer.accept(syntheticStartupMethodBuilder); + return addStartupItem(syntheticStartupMethodBuilder.build()); + } + + private Builder addStartupItem(StartupItem startupItem) { this.startupItemsBuilder.add(startupItem); return this; } - public Builder addStartupClass(StartupClass<DexType, DexMethod> startupClass) { - return addStartupItem(startupClass); - } - - public Builder addStartupMethod(StartupMethod<DexType, DexMethod> startupMethod) { - return addStartupItem(startupMethod); - } - public Builder apply(Consumer<Builder> consumer) { consumer.accept(this); return this;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileParser.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileParser.java index a386c31..cc205bf 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileParser.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileParser.java
@@ -4,90 +4,49 @@ package com.android.tools.r8.experimental.startup.profile; -import com.android.tools.r8.graph.DexItemFactory; -import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.DexType; import com.android.tools.r8.references.ClassReference; import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; import com.android.tools.r8.references.TypeReference; +import com.android.tools.r8.startup.StartupProfileBuilder; +import com.android.tools.r8.utils.BooleanBox; import com.android.tools.r8.utils.DescriptorUtils; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -import java.util.function.Function; +import java.util.stream.Stream; -public class StartupProfileParser<C, M, T> { +public class StartupProfileParser { - interface MethodFactory<C, M, T> { - - M createMethod( - C methodHolder, String methodName, List<T> methodParameterTypes, T methodReturnType); - } - - private final Function<String, C> classFactory; - private final MethodFactory<C, M, T> methodFactory; - private final Function<String, T> typeFactory; - - StartupProfileParser( - Function<String, C> classFactory, - MethodFactory<C, M, T> methodFactory, - Function<String, T> typeFactory) { - this.classFactory = classFactory; - this.methodFactory = methodFactory; - this.typeFactory = typeFactory; - } - - public static StartupProfileParser<DexType, DexMethod, DexType> createDexParser( - DexItemFactory dexItemFactory) { - return new StartupProfileParser<>( - dexItemFactory::createType, - (methodHolder, methodName, methodParameters, methodReturnType) -> - dexItemFactory.createMethod( - methodHolder, - dexItemFactory.createProto(methodReturnType, methodParameters), - dexItemFactory.createString(methodName)), - dexItemFactory::createType); - } - - public static StartupProfileParser<ClassReference, MethodReference, TypeReference> - createReferenceParser() { - return new StartupProfileParser<>( - Reference::classFromDescriptor, Reference::method, Reference::returnTypeFromDescriptor); + public static StartupProfileParser create() { + return new StartupProfileParser(); } public void parseLines( - List<String> startupDescriptors, - Consumer<? super StartupClass<C, M>> startupClassConsumer, - Consumer<? super StartupMethod<C, M>> startupMethodConsumer, + Stream<String> startupDescriptors, + StartupProfileBuilder startupProfileBuilder, Consumer<String> parseErrorHandler) { - for (String startupDescriptor : startupDescriptors) { - if (!startupDescriptor.isEmpty()) { - parseLine( - startupDescriptor, startupClassConsumer, startupMethodConsumer, parseErrorHandler); - } - } + startupDescriptors.forEach( + startupDescriptor -> { + if (!startupDescriptor.isEmpty()) { + parseLine(startupDescriptor, startupProfileBuilder, parseErrorHandler); + } + }); } public void parseLine( String startupDescriptor, - Consumer<? super StartupClass<C, M>> startupClassConsumer, - Consumer<? super StartupMethod<C, M>> startupMethodConsumer, + StartupProfileBuilder startupProfileBuilder, Consumer<String> parseErrorHandler) { - StartupItem.Builder<C, M, ?> startupItemBuilder = StartupItem.builder(); - startupDescriptor = parseSyntheticFlag(startupDescriptor, startupItemBuilder); + BooleanBox syntheticFlag = new BooleanBox(); + startupDescriptor = parseSyntheticFlag(startupDescriptor, syntheticFlag); parseStartupClassOrMethod( - startupDescriptor, - startupItemBuilder, - startupClassConsumer, - startupMethodConsumer, - parseErrorHandler); + startupDescriptor, startupProfileBuilder, syntheticFlag, parseErrorHandler); } - private static String parseSyntheticFlag( - String startupDescriptor, StartupItem.Builder<?, ?, ?> startupItemBuilder) { + private static String parseSyntheticFlag(String startupDescriptor, BooleanBox syntheticFlag) { if (!startupDescriptor.isEmpty() && startupDescriptor.charAt(0) == 'S') { - startupItemBuilder.setSynthetic(); + syntheticFlag.set(); return startupDescriptor.substring(1); } return startupDescriptor; @@ -95,24 +54,34 @@ private void parseStartupClassOrMethod( String startupDescriptor, - StartupItem.Builder<C, M, ?> startupItemBuilder, - Consumer<? super StartupClass<C, M>> startupClassConsumer, - Consumer<? super StartupMethod<C, M>> startupMethodConsumer, + StartupProfileBuilder startupProfileBuilder, + BooleanBox syntheticFlag, Consumer<String> parseErrorHandler) { int arrowStartIndex = getArrowStartIndex(startupDescriptor); if (arrowStartIndex >= 0) { - M startupMethod = parseStartupMethodDescriptor(startupDescriptor, arrowStartIndex); - if (startupMethod != null) { - startupMethodConsumer.accept( - startupItemBuilder.setMethodReference(startupMethod).buildStartupMethod()); + if (syntheticFlag.isFalse()) { + MethodReference startupMethod = + parseStartupMethodDescriptor(startupDescriptor, arrowStartIndex); + if (startupMethod != null) { + startupProfileBuilder.addStartupMethod( + startupMethodBuilder -> startupMethodBuilder.setMethodReference(startupMethod)); + } else { + parseErrorHandler.accept(startupDescriptor); + } } else { parseErrorHandler.accept(startupDescriptor); } } else { - C startupClass = parseStartupClassDescriptor(startupDescriptor); + ClassReference startupClass = parseStartupClassDescriptor(startupDescriptor); if (startupClass != null) { - startupClassConsumer.accept( - startupItemBuilder.setClassReference(startupClass).buildStartupClass()); + if (syntheticFlag.isFalse()) { + startupProfileBuilder.addStartupClass( + startupClassBuilder -> startupClassBuilder.setClassReference(startupClass)); + } else { + startupProfileBuilder.addSyntheticStartupMethod( + syntheticStartupMethodBuilder -> + syntheticStartupMethodBuilder.setSyntheticContextReference(startupClass)); + } } else { parseErrorHandler.accept(startupDescriptor); } @@ -123,17 +92,18 @@ return startupDescriptor.indexOf("->"); } - private C parseStartupClassDescriptor(String startupClassDescriptor) { + private ClassReference parseStartupClassDescriptor(String startupClassDescriptor) { if (DescriptorUtils.isClassDescriptor(startupClassDescriptor)) { - return classFactory.apply(startupClassDescriptor); + return Reference.classFromDescriptor(startupClassDescriptor); } else { return null; } } - private M parseStartupMethodDescriptor(String startupMethodDescriptor, int arrowStartIndex) { + private MethodReference parseStartupMethodDescriptor( + String startupMethodDescriptor, int arrowStartIndex) { String classDescriptor = startupMethodDescriptor.substring(0, arrowStartIndex); - C methodHolder = parseStartupClassDescriptor(classDescriptor); + ClassReference methodHolder = parseStartupClassDescriptor(classDescriptor); if (methodHolder == null) { return null; } @@ -150,14 +120,15 @@ return parseStartupMethodProto(methodHolder, methodName, protoDescriptor); } - private M parseStartupMethodProto(C methodHolder, String methodName, String protoDescriptor) { - List<T> parameterTypes = new ArrayList<>(); + private MethodReference parseStartupMethodProto( + ClassReference methodHolder, String methodName, String protoDescriptor) { + List<TypeReference> parameterTypes = new ArrayList<>(); for (String parameterTypeDescriptor : DescriptorUtils.getArgumentTypeDescriptors(protoDescriptor)) { - parameterTypes.add(typeFactory.apply(parameterTypeDescriptor)); + parameterTypes.add(Reference.typeFromDescriptor(parameterTypeDescriptor)); } String returnTypeDescriptor = DescriptorUtils.getReturnTypeDescriptor(protoDescriptor); - T returnType = typeFactory.apply(returnTypeDescriptor); - return methodFactory.createMethod(methodHolder, methodName, parameterTypes, returnType); + TypeReference returnType = Reference.returnTypeFromDescriptor(returnTypeDescriptor); + return Reference.method(methodHolder, methodName, parameterTypes, returnType); } }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/SyntheticStartupMethod.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/SyntheticStartupMethod.java new file mode 100644 index 0000000..eedcadd --- /dev/null +++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/SyntheticStartupMethod.java
@@ -0,0 +1,108 @@ +// Copyright (c) 2022, 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.experimental.startup.profile; + +import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.references.ClassReference; +import com.android.tools.r8.startup.SyntheticStartupMethodBuilder; +import com.android.tools.r8.utils.ClassReferenceUtils; +import java.util.function.Consumer; +import java.util.function.Function; + +public class SyntheticStartupMethod extends StartupItem { + + private final DexType syntheticContextType; + + SyntheticStartupMethod(DexType syntheticContextType) { + this.syntheticContextType = syntheticContextType; + } + + public static Builder builder() { + return new Builder(); + } + + public static Builder builder(DexItemFactory dexItemFactory) { + return new Builder(dexItemFactory); + } + + @Override + public void accept( + Consumer<StartupClass> classConsumer, + Consumer<StartupMethod> methodConsumer, + Consumer<SyntheticStartupMethod> syntheticMethodConsumer) { + syntheticMethodConsumer.accept(this); + } + + @Override + public <T> T apply( + Function<StartupClass, T> classFunction, + Function<StartupMethod, T> methodFunction, + Function<SyntheticStartupMethod, T> syntheticMethodFunction) { + return syntheticMethodFunction.apply(this); + } + + public DexType getSyntheticContextType() { + return syntheticContextType; + } + + @Override + public boolean isSyntheticStartupMethod() { + return true; + } + + @Override + public SyntheticStartupMethod asSyntheticStartupMethod() { + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SyntheticStartupMethod that = (SyntheticStartupMethod) o; + return syntheticContextType == that.syntheticContextType; + } + + @Override + public int hashCode() { + return syntheticContextType.hashCode(); + } + + public static class Builder implements SyntheticStartupMethodBuilder { + + private final DexItemFactory dexItemFactory; + + private DexType syntheticContextReference; + + Builder() { + this(null); + } + + Builder(DexItemFactory dexItemFactory) { + this.dexItemFactory = dexItemFactory; + } + + @Override + public Builder setSyntheticContextReference(ClassReference syntheticContextReference) { + assert dexItemFactory != null; + return setSyntheticContextReference( + ClassReferenceUtils.toDexType(syntheticContextReference, dexItemFactory)); + } + + public Builder setSyntheticContextReference(DexType syntheticContextReference) { + this.syntheticContextReference = syntheticContextReference; + return this; + } + + public SyntheticStartupMethod build() { + return new SyntheticStartupMethod(syntheticContextReference); + } + } +}
diff --git a/src/main/java/com/android/tools/r8/startup/StartupProfileProvider.java b/src/main/java/com/android/tools/r8/startup/StartupProfileProvider.java index 4d98373..39ad8fc 100644 --- a/src/main/java/com/android/tools/r8/startup/StartupProfileProvider.java +++ b/src/main/java/com/android/tools/r8/startup/StartupProfileProvider.java
@@ -11,10 +11,6 @@ @Keep public interface StartupProfileProvider extends Resource { - // TODO(b/238173796): Change the implementation to use the new API below. - /** Return the startup profile. */ - String get(); - /** Provides the startup profile by callbacks to the given {@param startupProfileBuilder}. */ void getStartupProfile(StartupProfileBuilder startupProfileBuilder); }
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 f02405c..78c17ec 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -816,7 +816,7 @@ new KotlinOptimizationOptions(); private final ApiModelTestingOptions apiModelTestingOptions = new ApiModelTestingOptions(); private final DesugarSpecificOptions desugarSpecificOptions = new DesugarSpecificOptions(); - private final StartupOptions startupOptions = new StartupOptions(); + private final StartupOptions startupOptions = new StartupOptions(this); private final StartupInstrumentationOptions startupInstrumentationOptions = new StartupInstrumentationOptions(); public final TestingOptions testing = new TestingOptions();
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java index 9ab1f03..f9b2f74 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java
@@ -7,11 +7,9 @@ import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.errors.Unimplemented; -import com.android.tools.r8.experimental.startup.profile.StartupClass; -import com.android.tools.r8.experimental.startup.profile.StartupProfile; -import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.references.ClassReference; +import com.android.tools.r8.references.Reference; import com.android.tools.r8.startup.StartupProfileBuilder; import com.android.tools.r8.startup.StartupProfileProvider; import com.android.tools.r8.utils.BooleanUtils; @@ -52,30 +50,18 @@ .addKeepClassAndMembersRules(Main.class) .addOptionsModification( options -> { - DexItemFactory dexItemFactory = options.dexItemFactory(); - StartupProfile startupProfile = - StartupProfile.builder() - .apply( - builder -> - getStartupClasses() - .forEach( - startupClass -> - builder.addStartupClass( - StartupClass.dexBuilder() - .setClassReference( - toDexType(startupClass, dexItemFactory)) - .build()))) - .build(); StartupProfileProvider startupProfileProvider = new StartupProfileProvider() { - @Override - public String get() { - return startupProfile.serializeToString(); - } @Override public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) { - throw new Unimplemented(); + for (Class<?> startupClass : getStartupClasses()) { + ClassReference startupClassReference = + Reference.classFromClass(startupClass); + startupProfileBuilder.addStartupClass( + startupClassBuilder -> + startupClassBuilder.setClassReference(startupClassReference)); + } } @Override @@ -83,7 +69,9 @@ return Origin.unknown(); } }; - options.getStartupOptions().setStartupProfileProvider(startupProfileProvider); + options + .getStartupOptions() + .setStartupProfileProviders(Collections.singleton(startupProfileProvider)); }) .addHorizontallyMergedClassesInspector( inspector ->
diff --git a/src/test/java/com/android/tools/r8/compilerapi/startupprofile/StartupProfileApiTest.java b/src/test/java/com/android/tools/r8/compilerapi/startupprofile/StartupProfileApiTest.java index f8bc404..b6572fc 100644 --- a/src/test/java/com/android/tools/r8/compilerapi/startupprofile/StartupProfileApiTest.java +++ b/src/test/java/com/android/tools/r8/compilerapi/startupprofile/StartupProfileApiTest.java
@@ -82,9 +82,8 @@ testRunner.accept(new DexIndexedConsumer.DirectoryConsumer(output)); assertThat( new CodeInspector(output.resolve("classes.dex")).clazz(test.getMockClass()), isPresent()); - // TODO(b/238173796): The PostStartupMockClass should be in classes2.dex. assertThat( - new CodeInspector(output.resolve("classes.dex")).clazz(test.getPostStartupMockClass()), + new CodeInspector(output.resolve("classes2.dex")).clazz(test.getPostStartupMockClass()), isPresent()); } @@ -96,11 +95,6 @@ private StartupProfileProvider getStartupProfileProvider() { return new StartupProfileProvider() { - @Override - public String get() { - // Intentionally empty. All uses of this API should be rewritten to use getStartupProfile. - return ""; - } @Override public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) {
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java index a44f221..35ef96e 100644 --- a/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java +++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java
@@ -38,6 +38,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import java.util.concurrent.ExecutionException; import org.junit.After; import org.junit.Test; @@ -149,7 +150,8 @@ if (startupProfileProvider != null) { options .getStartupOptions() - .setStartupProfileProvider(startupProfileProvider) + .setStartupProfileProviders( + Collections.singleton(startupProfileProvider)) .setEnableMinimalStartupDex(enableMinimalStartupDex) .setEnableStartupBoundaryOptimizations( enableStartupBoundaryOptimizations);
diff --git a/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java b/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java index c7211db..0af6a45 100644 --- a/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java +++ b/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java
@@ -13,23 +13,22 @@ import com.android.tools.r8.ArchiveProgramResourceProvider; import com.android.tools.r8.DexIndexedConsumer; import com.android.tools.r8.R8FullTestBuilder; -import com.android.tools.r8.StringResource; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ThrowableConsumer; import com.android.tools.r8.ToolHelper; -import com.android.tools.r8.errors.Unimplemented; -import com.android.tools.r8.origin.Origin; -import com.android.tools.r8.startup.StartupProfileBuilder; +import com.android.tools.r8.experimental.startup.StartupProfileProviderUtils; import com.android.tools.r8.startup.StartupProfileProvider; import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.Reporter; import com.android.tools.r8.utils.ZipUtils; import com.android.tools.r8.utils.codeinspector.CodeInspector; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -238,25 +237,10 @@ boolean enableStartupBoundaryOptimizations, Path outDirectory) throws Exception { + Reporter reporter = new Reporter(); StartupProfileProvider startupProfileProvider = - new StartupProfileProvider() { - @Override - public String get() { - return StringResource.fromFile(chromeDirectory.resolve("startup.txt")) - .getStringWithRuntimeException(); - } - - @Override - public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) { - throw new Unimplemented(); - } - - @Override - public Origin getOrigin() { - return Origin.unknown(); - } - }; - + StartupProfileProviderUtils.createFromFile( + chromeDirectory.resolve("startup.txt"), reporter); buildR8( testBuilder -> testBuilder.addOptionsModification( @@ -265,7 +249,7 @@ .getStartupOptions() .setEnableMinimalStartupDex(enableMinimalStartupDex) .setEnableStartupBoundaryOptimizations(enableStartupBoundaryOptimizations) - .setStartupProfileProvider(startupProfileProvider)), + .setStartupProfileProviders(Collections.singleton(startupProfileProvider))), outDirectory); }
diff --git a/src/test/java/com/android/tools/r8/startup/InliningOutOfStartupPartitionTest.java b/src/test/java/com/android/tools/r8/startup/InliningOutOfStartupPartitionTest.java index b26ff87..b171421 100644 --- a/src/test/java/com/android/tools/r8/startup/InliningOutOfStartupPartitionTest.java +++ b/src/test/java/com/android/tools/r8/startup/InliningOutOfStartupPartitionTest.java
@@ -11,12 +11,10 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; -import com.android.tools.r8.experimental.startup.profile.StartupClass; -import com.android.tools.r8.experimental.startup.profile.StartupItem; -import com.android.tools.r8.experimental.startup.profile.StartupMethod; -import com.android.tools.r8.references.ClassReference; -import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; +import com.android.tools.r8.startup.profile.ExternalStartupClass; +import com.android.tools.r8.startup.profile.ExternalStartupItem; +import com.android.tools.r8.startup.profile.ExternalStartupMethod; import com.android.tools.r8.startup.utils.StartupTestingUtils; import com.android.tools.r8.utils.MethodReferenceUtils; import com.android.tools.r8.utils.codeinspector.ClassSubject; @@ -41,12 +39,12 @@ @Test public void test() throws Exception { - List<StartupItem<ClassReference, MethodReference, ?>> startupItems = + List<ExternalStartupItem> startupItems = ImmutableList.of( - StartupClass.referenceBuilder() + ExternalStartupClass.builder() .setClassReference(Reference.classFromClass(Main.class)) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference(MethodReferenceUtils.mainMethod(Main.class)) .build()); testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java index eda0c51..d6d12a8 100644 --- a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java +++ b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java
@@ -12,9 +12,7 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; -import com.android.tools.r8.experimental.startup.profile.StartupItem; -import com.android.tools.r8.references.ClassReference; -import com.android.tools.r8.references.MethodReference; +import com.android.tools.r8.startup.profile.ExternalStartupItem; import com.android.tools.r8.startup.utils.StartupTestingUtils; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.codeinspector.ClassSubject; @@ -45,7 +43,7 @@ @Test public void test() throws Exception { - List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); + List<ExternalStartupItem> startupList = new ArrayList<>(); testForD8(parameters.getBackend()) .addInnerClasses(getClass()) .apply(
diff --git a/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java b/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java index 13257e1..faa893b 100644 --- a/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java +++ b/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java
@@ -9,12 +9,10 @@ import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.experimental.startup.profile.StartupClass; -import com.android.tools.r8.experimental.startup.profile.StartupItem; -import com.android.tools.r8.experimental.startup.profile.StartupMethod; -import com.android.tools.r8.references.ClassReference; -import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; +import com.android.tools.r8.startup.profile.ExternalStartupClass; +import com.android.tools.r8.startup.profile.ExternalStartupItem; +import com.android.tools.r8.startup.profile.ExternalStartupMethod; import com.android.tools.r8.startup.utils.StartupTestingUtils; import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.MethodReferenceUtils; @@ -48,7 +46,7 @@ @Test public void test() throws Exception { Path out = temp.newFolder().toPath().resolve("out.txt").toAbsolutePath(); - List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); + List<ExternalStartupItem> startupList = new ArrayList<>(); testForD8(parameters.getBackend()) .addInnerClasses(getClass()) .applyIf( @@ -75,19 +73,18 @@ return ImmutableList.of("foo"); } - private List<StartupItem<ClassReference, MethodReference, ?>> getExpectedStartupList() - throws NoSuchMethodException { + private List<ExternalStartupItem> getExpectedStartupList() throws NoSuchMethodException { return ImmutableList.of( - StartupClass.referenceBuilder() + ExternalStartupClass.builder() .setClassReference(Reference.classFromClass(Main.class)) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference(MethodReferenceUtils.mainMethod(Main.class)) .build(), - StartupClass.referenceBuilder() + ExternalStartupClass.builder() .setClassReference(Reference.classFromClass(AStartupClass.class)) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference( Reference.methodFromMethod(AStartupClass.class.getDeclaredMethod("foo"))) .build());
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java index 64c4c56..e9c4224 100644 --- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java +++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
@@ -16,14 +16,14 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestCompilerBuilder; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.experimental.startup.profile.StartupClass; -import com.android.tools.r8.experimental.startup.profile.StartupItem; -import com.android.tools.r8.experimental.startup.profile.StartupMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.ir.desugar.LambdaClass; import com.android.tools.r8.references.ClassReference; -import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; +import com.android.tools.r8.startup.profile.ExternalStartupClass; +import com.android.tools.r8.startup.profile.ExternalStartupItem; +import com.android.tools.r8.startup.profile.ExternalStartupMethod; +import com.android.tools.r8.startup.profile.ExternalSyntheticStartupMethod; import com.android.tools.r8.startup.utils.MixedSectionLayoutInspector; import com.android.tools.r8.startup.utils.StartupTestingUtils; import com.android.tools.r8.synthesis.SyntheticItemsTestUtils; @@ -90,7 +90,7 @@ Path optimizedApp = r8CompileResult.writeToZip(); // Then instrument the app to generate a startup list for the minified app. - List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); + List<ExternalStartupItem> startupList = new ArrayList<>(); testForD8(parameters.getBackend()) .addProgramFiles(optimizedApp) .apply( @@ -125,7 +125,7 @@ @Test public void testLayoutUsingR8() throws Exception { // First generate a startup list for the original app. - List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); + List<ExternalStartupItem> startupList = new ArrayList<>(); D8TestCompileResult instrumentationCompileResult = testForD8(parameters.getBackend()) .addInnerClasses(getClass()) @@ -167,7 +167,7 @@ private void configureStartupOptions( TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, CodeInspector inspector, - List<StartupItem<ClassReference, MethodReference, ?>> startupList) { + List<ExternalStartupItem> startupList) { testBuilder .addOptionsModification( options -> { @@ -188,36 +188,30 @@ } @SuppressWarnings("unchecked") - private List<StartupItem<ClassReference, MethodReference, ?>> getExpectedStartupList( + private List<ExternalStartupItem> getExpectedStartupList( CodeInspector inspector, boolean isStartupListForOriginalApp) throws NoSuchMethodException { - ImmutableList.Builder<StartupItem<ClassReference, MethodReference, ?>> builder = - ImmutableList.builder(); + ImmutableList.Builder<ExternalStartupItem> builder = ImmutableList.builder(); builder.add( - StartupClass.referenceBuilder() + ExternalStartupClass.builder() .setClassReference(Reference.classFromClass(Main.class)) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference(MethodReferenceUtils.mainMethod(Main.class)) .build(), - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(A.class)) - .build(), - StartupMethod.referenceBuilder() + ExternalStartupClass.builder().setClassReference(Reference.classFromClass(A.class)).build(), + ExternalStartupMethod.builder() .setMethodReference(Reference.methodFromMethod(A.class.getDeclaredMethod("a"))) .build(), - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(B.class)) - .build(), - StartupMethod.referenceBuilder() + ExternalStartupClass.builder().setClassReference(Reference.classFromClass(B.class)).build(), + ExternalStartupMethod.builder() .setMethodReference( Reference.methodFromMethod(B.class.getDeclaredMethod("b", boolean.class))) .build()); if (useLambda) { if (isStartupListForOriginalApp) { builder.add( - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(B.class)) - .setSynthetic() + ExternalSyntheticStartupMethod.builder() + .setSyntheticContextReference(Reference.classFromClass(B.class)) .build()); } else { ClassSubject bClassSubject = inspector.clazz(B.class); @@ -238,14 +232,14 @@ externalSyntheticLambdaClassSubject.getFinalReference(); builder.add( - StartupClass.referenceBuilder() + ExternalStartupClass.builder() .setClassReference(externalSyntheticLambdaClassReference) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference( MethodReferenceUtils.instanceConstructor(externalSyntheticLambdaClassReference)) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference( Reference.method( externalSyntheticLambdaClassReference, @@ -253,7 +247,7 @@ ImmutableList.of(Reference.classFromClass(Object.class)), null)) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference( Reference.method( Reference.classFromClass(B.class), @@ -263,16 +257,14 @@ .build()); } builder.add( - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference( Reference.methodFromMethod(B.class.getDeclaredMethod("lambda$b$0", Object.class))) .build()); } builder.add( - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(C.class)) - .build(), - StartupMethod.referenceBuilder() + ExternalStartupClass.builder().setClassReference(Reference.classFromClass(C.class)).build(), + ExternalStartupMethod.builder() .setMethodReference(Reference.methodFromMethod(C.class.getDeclaredMethod("c"))) .build()); return builder.build();
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java index 5b30a0a..a824cc4 100644 --- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java +++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
@@ -14,13 +14,13 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.experimental.startup.profile.StartupClass; -import com.android.tools.r8.experimental.startup.profile.StartupItem; -import com.android.tools.r8.experimental.startup.profile.StartupMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.references.ClassReference; -import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; +import com.android.tools.r8.startup.profile.ExternalStartupClass; +import com.android.tools.r8.startup.profile.ExternalStartupItem; +import com.android.tools.r8.startup.profile.ExternalStartupMethod; +import com.android.tools.r8.startup.profile.ExternalSyntheticStartupMethod; import com.android.tools.r8.startup.utils.MixedSectionLayoutInspector; import com.android.tools.r8.startup.utils.StartupTestingUtils; import com.android.tools.r8.synthesis.SyntheticItemsTestUtils; @@ -61,7 +61,7 @@ @Test public void test() throws Exception { - List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); + List<ExternalStartupItem> startupList = new ArrayList<>(); testForD8(parameters.getBackend()) .addInnerClasses(getClass()) .apply( @@ -101,38 +101,30 @@ return ImmutableList.of("A", "B", "C"); } - private List<StartupItem<ClassReference, MethodReference, ?>> getExpectedStartupList() - throws NoSuchMethodException { + private List<ExternalStartupItem> getExpectedStartupList() throws NoSuchMethodException { return ImmutableList.of( - StartupClass.referenceBuilder() + ExternalStartupClass.builder() .setClassReference(Reference.classFromClass(Main.class)) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference(MethodReferenceUtils.mainMethod(Main.class)) .build(), - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(A.class)) - .build(), - StartupMethod.referenceBuilder() + ExternalStartupClass.builder().setClassReference(Reference.classFromClass(A.class)).build(), + ExternalStartupMethod.builder() .setMethodReference(Reference.methodFromMethod(A.class.getDeclaredMethod("a"))) .build(), - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(B.class)) - .build(), - StartupMethod.referenceBuilder() + ExternalStartupClass.builder().setClassReference(Reference.classFromClass(B.class)).build(), + ExternalStartupMethod.builder() .setMethodReference(Reference.methodFromMethod(B.class.getDeclaredMethod("b"))) .build(), - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(B.class)) - .setSynthetic() + ExternalSyntheticStartupMethod.builder() + .setSyntheticContextReference(Reference.classFromClass(B.class)) .build(), - StartupMethod.referenceBuilder() + ExternalStartupMethod.builder() .setMethodReference(Reference.methodFromMethod(B.class.getDeclaredMethod("lambda$b$0"))) .build(), - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(C.class)) - .build(), - StartupMethod.referenceBuilder() + ExternalStartupClass.builder().setClassReference(Reference.classFromClass(C.class)).build(), + ExternalStartupMethod.builder() .setMethodReference(Reference.methodFromMethod(C.class.getDeclaredMethod("c"))) .build()); }
diff --git a/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupClass.java b/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupClass.java new file mode 100644 index 0000000..c6caccf --- /dev/null +++ b/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupClass.java
@@ -0,0 +1,66 @@ +// Copyright (c) 2022, 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.startup.profile; + +import com.android.tools.r8.references.ClassReference; +import com.android.tools.r8.startup.StartupClassBuilder; +import java.util.function.Function; + +public class ExternalStartupClass extends ExternalStartupItem { + + private final ClassReference classReference; + + ExternalStartupClass(ClassReference classReference) { + this.classReference = classReference; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public <T> T apply( + Function<ExternalStartupClass, T> classFunction, + Function<ExternalStartupMethod, T> methodFunction, + Function<ExternalSyntheticStartupMethod, T> syntheticMethodFunction) { + return classFunction.apply(this); + } + + public ClassReference getReference() { + return classReference; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ExternalStartupClass that = (ExternalStartupClass) o; + return classReference.equals(that.classReference); + } + + @Override + public int hashCode() { + return classReference.hashCode(); + } + + public static class Builder implements StartupClassBuilder { + + private ClassReference classReference; + + @Override + public Builder setClassReference(ClassReference classReference) { + this.classReference = classReference; + return this; + } + + public ExternalStartupClass build() { + return new ExternalStartupClass(classReference); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupItem.java b/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupItem.java new file mode 100644 index 0000000..e3aa745 --- /dev/null +++ b/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupItem.java
@@ -0,0 +1,15 @@ +// Copyright (c) 2022, 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.startup.profile; + +import java.util.function.Function; + +public abstract class ExternalStartupItem { + + public abstract <T> T apply( + Function<ExternalStartupClass, T> classFunction, + Function<ExternalStartupMethod, T> methodFunction, + Function<ExternalSyntheticStartupMethod, T> syntheticMethodFunction); +}
diff --git a/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupMethod.java b/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupMethod.java new file mode 100644 index 0000000..0d73a7a --- /dev/null +++ b/src/test/java/com/android/tools/r8/startup/profile/ExternalStartupMethod.java
@@ -0,0 +1,67 @@ +// Copyright (c) 2022, 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.startup.profile; + +import com.android.tools.r8.references.MethodReference; +import com.android.tools.r8.startup.StartupMethodBuilder; +import com.android.tools.r8.startup.profile.ExternalStartupClass.Builder; +import java.util.function.Function; + +public class ExternalStartupMethod extends ExternalStartupItem { + + private final MethodReference methodReference; + + ExternalStartupMethod(MethodReference methodReference) { + this.methodReference = methodReference; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public <T> T apply( + Function<ExternalStartupClass, T> classFunction, + Function<ExternalStartupMethod, T> methodFunction, + Function<ExternalSyntheticStartupMethod, T> syntheticMethodFunction) { + return methodFunction.apply(this); + } + + public MethodReference getReference() { + return methodReference; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ExternalStartupMethod that = (ExternalStartupMethod) o; + return methodReference.equals(that.methodReference); + } + + @Override + public int hashCode() { + return methodReference.hashCode(); + } + + public static class Builder implements StartupMethodBuilder { + + private MethodReference methodReference; + + @Override + public Builder setMethodReference(MethodReference methodReference) { + this.methodReference = methodReference; + return this; + } + + public ExternalStartupMethod build() { + return new ExternalStartupMethod(methodReference); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/startup/profile/ExternalSyntheticStartupMethod.java b/src/test/java/com/android/tools/r8/startup/profile/ExternalSyntheticStartupMethod.java new file mode 100644 index 0000000..628cdec --- /dev/null +++ b/src/test/java/com/android/tools/r8/startup/profile/ExternalSyntheticStartupMethod.java
@@ -0,0 +1,66 @@ +// Copyright (c) 2022, 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.startup.profile; + +import com.android.tools.r8.references.ClassReference; +import com.android.tools.r8.startup.SyntheticStartupMethodBuilder; +import java.util.function.Function; + +public class ExternalSyntheticStartupMethod extends ExternalStartupItem { + + private final ClassReference syntheticContextReference; + + ExternalSyntheticStartupMethod(ClassReference syntheticContextReference) { + this.syntheticContextReference = syntheticContextReference; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public <T> T apply( + Function<ExternalStartupClass, T> classFunction, + Function<ExternalStartupMethod, T> methodFunction, + Function<ExternalSyntheticStartupMethod, T> syntheticMethodFunction) { + return syntheticMethodFunction.apply(this); + } + + public ClassReference getSyntheticContextReference() { + return syntheticContextReference; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ExternalSyntheticStartupMethod that = (ExternalSyntheticStartupMethod) o; + return syntheticContextReference.equals(that.syntheticContextReference); + } + + @Override + public int hashCode() { + return syntheticContextReference.hashCode(); + } + + public static class Builder implements SyntheticStartupMethodBuilder { + + private ClassReference syntheticContextReference; + + @Override + public Builder setSyntheticContextReference(ClassReference syntheticContextReference) { + this.syntheticContextReference = syntheticContextReference; + return this; + } + + public ExternalSyntheticStartupMethod build() { + return new ExternalSyntheticStartupMethod(syntheticContextReference); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java index 2011ff1..a9ca8c5 100644 --- a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java +++ b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
@@ -14,28 +14,25 @@ import com.android.tools.r8.TestCompilerBuilder; import com.android.tools.r8.TestParameters; import com.android.tools.r8.ThrowableConsumer; -import com.android.tools.r8.errors.Unimplemented; import com.android.tools.r8.experimental.startup.instrumentation.StartupInstrumentationOptions; -import com.android.tools.r8.experimental.startup.profile.StartupItem; -import com.android.tools.r8.experimental.startup.profile.StartupProfile; import com.android.tools.r8.experimental.startup.profile.StartupProfileParser; -import com.android.tools.r8.graph.DexItemFactory; -import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.DexType; import com.android.tools.r8.origin.Origin; -import com.android.tools.r8.references.ClassReference; -import com.android.tools.r8.references.MethodReference; -import com.android.tools.r8.references.TypeReference; +import com.android.tools.r8.startup.StartupClassBuilder; +import com.android.tools.r8.startup.StartupMethodBuilder; import com.android.tools.r8.startup.StartupProfileBuilder; import com.android.tools.r8.startup.StartupProfileProvider; +import com.android.tools.r8.startup.SyntheticStartupMethodBuilder; +import com.android.tools.r8.startup.profile.ExternalStartupClass; +import com.android.tools.r8.startup.profile.ExternalStartupItem; +import com.android.tools.r8.startup.profile.ExternalStartupMethod; +import com.android.tools.r8.startup.profile.ExternalSyntheticStartupMethod; import com.android.tools.r8.utils.AndroidApiLevel; -import com.android.tools.r8.utils.ClassReferenceUtils; -import com.android.tools.r8.utils.MethodReferenceUtils; import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.ThrowingConsumer; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; import org.junit.rules.TemporaryFolder; @@ -53,6 +50,39 @@ } } + private static StartupProfileBuilder createStartupItemFactory( + Consumer<ExternalStartupItem> startupItemConsumer) { + return new StartupProfileBuilder() { + @Override + public StartupProfileBuilder addStartupClass( + Consumer<StartupClassBuilder> startupClassBuilderConsumer) { + ExternalStartupClass.Builder startupClassBuilder = ExternalStartupClass.builder(); + startupClassBuilderConsumer.accept(startupClassBuilder); + startupItemConsumer.accept(startupClassBuilder.build()); + return this; + } + + @Override + public StartupProfileBuilder addStartupMethod( + Consumer<StartupMethodBuilder> startupMethodBuilderConsumer) { + ExternalStartupMethod.Builder startupMethodBuilder = ExternalStartupMethod.builder(); + startupMethodBuilderConsumer.accept(startupMethodBuilder); + startupItemConsumer.accept(startupMethodBuilder.build()); + return this; + } + + @Override + public StartupProfileBuilder addSyntheticStartupMethod( + Consumer<SyntheticStartupMethodBuilder> syntheticStartupMethodBuilderConsumer) { + ExternalSyntheticStartupMethod.Builder syntheticStartupMethodBuilder = + ExternalSyntheticStartupMethod.builder(); + syntheticStartupMethodBuilderConsumer.accept(syntheticStartupMethodBuilder); + startupItemConsumer.accept(syntheticStartupMethodBuilder.build()); + return this; + } + }; + } + public static ThrowableConsumer<D8TestBuilder> enableStartupInstrumentationForOriginalAppUsingFile(TestParameters parameters) { return testBuilder -> @@ -66,12 +96,6 @@ } public static ThrowableConsumer<D8TestBuilder> - enableStartupInstrumentationForOptimizedAppUsingFile(TestParameters parameters) { - return testBuilder -> - enableStartupInstrumentation(testBuilder, parameters, AppVariant.OPTIMIZED, false); - } - - public static ThrowableConsumer<D8TestBuilder> enableStartupInstrumentationForOptimizedAppUsingLogcat(TestParameters parameters) { return testBuilder -> enableStartupInstrumentation(testBuilder, parameters, AppVariant.OPTIMIZED, true); @@ -108,26 +132,22 @@ } public static void readStartupListFromFile( - Path path, Consumer<StartupItem<ClassReference, MethodReference, ?>> startupItemConsumer) - throws IOException { - StartupProfileParser.createReferenceParser() + Path path, Consumer<ExternalStartupItem> startupItemConsumer) throws IOException { + StartupProfileParser.create() .parseLines( - Files.readAllLines(path), - startupItemConsumer, - startupItemConsumer, + Files.readAllLines(path).stream(), + createStartupItemFactory(startupItemConsumer), error -> fail("Unexpected parse error: " + error)); } public static ThrowingConsumer<D8TestRunResult, RuntimeException> removeStartupListFromStdout( - Consumer<StartupItem<ClassReference, MethodReference, ?>> startupItemConsumer) { + Consumer<ExternalStartupItem> startupItemConsumer) { return runResult -> removeStartupListFromStdout(runResult, startupItemConsumer); } public static void removeStartupListFromStdout( - D8TestRunResult runResult, - Consumer<StartupItem<ClassReference, MethodReference, ?>> startupItemConsumer) { - StartupProfileParser<ClassReference, MethodReference, TypeReference> parser = - StartupProfileParser.createReferenceParser(); + D8TestRunResult runResult, Consumer<ExternalStartupItem> startupItemConsumer) { + StartupProfileParser parser = StartupProfileParser.create(); StringBuilder stdoutBuilder = new StringBuilder(); String startupDescriptorPrefix = "[" + startupInstrumentationTag + "] "; for (String line : StringUtils.splitLines(runResult.getStdOut(), true)) { @@ -135,8 +155,7 @@ String message = line.substring(startupDescriptorPrefix.length()); parser.parseLine( message, - startupItemConsumer, - startupItemConsumer, + createStartupItemFactory(startupItemConsumer), error -> fail("Unexpected parse error: " + error)); } else { stdoutBuilder.append(line).append(System.lineSeparator()); @@ -146,30 +165,31 @@ } public static void setStartupConfiguration( - TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, - List<StartupItem<ClassReference, MethodReference, ?>> startupItems) { + TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, List<ExternalStartupItem> startupItems) { testBuilder.addOptionsModification( options -> { - DexItemFactory dexItemFactory = options.dexItemFactory(); - StartupProfile startupProfile = - StartupProfile.builder() - .apply( - builder -> - startupItems.forEach( - startupItem -> - builder.addStartupItem( - convertStartupItemToDex(startupItem, dexItemFactory)))) - .build(); StartupProfileProvider startupProfileProvider = new StartupProfileProvider() { @Override - public String get() { - return startupProfile.serializeToString(); - } - - @Override public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) { - throw new Unimplemented(); + for (ExternalStartupItem startupItem : startupItems) { + startupItem.apply( + startupClass -> + startupProfileBuilder.addStartupClass( + startupClassBuilder -> + startupClassBuilder.setClassReference( + startupClass.getReference())), + startupMethod -> + startupProfileBuilder.addStartupMethod( + startupMethodBuilder -> + startupMethodBuilder.setMethodReference( + startupMethod.getReference())), + syntheticStartupMethod -> + startupProfileBuilder.addSyntheticStartupMethod( + syntheticStartupMethodBuilder -> + syntheticStartupMethodBuilder.setSyntheticContextReference( + syntheticStartupMethod.getSyntheticContextReference()))); + } } @Override @@ -177,27 +197,12 @@ return Origin.unknown(); } }; - options.getStartupOptions().setStartupProfileProvider(startupProfileProvider); + options + .getStartupOptions() + .setStartupProfileProviders(Collections.singleton(startupProfileProvider)); }); } - private static StartupItem<DexType, DexMethod, ?> convertStartupItemToDex( - StartupItem<ClassReference, MethodReference, ?> startupItem, DexItemFactory dexItemFactory) { - return StartupItem.dexBuilder() - .applyIf( - startupItem.isStartupClass(), - builder -> - builder.setClassReference( - ClassReferenceUtils.toDexType( - startupItem.asStartupClass().getReference(), dexItemFactory)), - builder -> - builder.setMethodReference( - MethodReferenceUtils.toDexMethod( - startupItem.asStartupMethod().getReference(), dexItemFactory))) - .setFlags(startupItem.getFlags()) - .build(); - } - private static byte[] getTransformedAndroidUtilLog() throws IOException { return transformer(Log.class).setClassDescriptor("Landroid/util/Log;").transform(); }
diff --git a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 index 040d696..4753c76 100644 --- a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 +++ b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
@@ -1 +1 @@ -98dc48c246bd0855133e138c2cd2b5835cf862cf \ No newline at end of file +46ac3bedbdba8732e48d13fcc94967f43ae1d91b \ No newline at end of file