Refactor @CovariantReturnType logic to own package
Change-Id: I998beb87a7c811c4477f29de2c1e62816da06e7f
diff --git a/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeAnnotationTransformer.java
index 6bc1e23..47357cd 100644
--- a/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeAnnotationTransformer.java
+++ b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeAnnotationTransformer.java
@@ -76,24 +76,31 @@
this.references = new CovariantReturnTypeReferences(factory);
}
+ public CovariantReturnTypeReferences getReferences() {
+ return references;
+ }
+
public static void runIfNecessary(
AppView<?> appView,
IRConverter converter,
CovariantReturnTypeAnnotationTransformerEventConsumer eventConsumer,
ExecutorService executorService)
throws ExecutionException {
+ if (shouldRun(appView)) {
+ new CovariantReturnTypeAnnotationTransformer(appView, converter)
+ .run(eventConsumer, executorService);
+ }
+ }
+
+ public static boolean shouldRun(AppView<?> appView) {
if (!appView.options().processCovariantReturnTypeAnnotations) {
- return;
+ return false;
}
assert !appView.options().isDesugaredLibraryCompilation();
DexItemFactory factory = appView.dexItemFactory();
DexString covariantReturnTypeDescriptor =
factory.createString(CovariantReturnTypeReferences.COVARIANT_RETURN_TYPE_DESCRIPTOR);
- if (factory.lookupType(covariantReturnTypeDescriptor) == null) {
- return;
- }
- new CovariantReturnTypeAnnotationTransformer(appView, converter)
- .run(eventConsumer, executorService);
+ return factory.lookupType(covariantReturnTypeDescriptor) != null;
}
private void run(
@@ -234,14 +241,6 @@
return covariantReturnTypes;
}
- public boolean hasCovariantReturnTypeAnnotation(ProgramMethod method) {
- return method
- .getAnnotations()
- .hasAnnotation(
- annotation ->
- references.isOneOfCovariantReturnTypeAnnotations(annotation.getAnnotationType()));
- }
-
private void getCovariantReturnTypesFromAnnotation(
ProgramMethod method, DexEncodedAnnotation annotation, Set<DexType> covariantReturnTypes) {
boolean hasPresentAfterElement = false;
diff --git a/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeEnqueuerExtension.java b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeEnqueuerExtension.java
new file mode 100644
index 0000000..4e8573f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeEnqueuerExtension.java
@@ -0,0 +1,116 @@
+// Copyright (c) 2024, 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.desugar.covariantreturntype;
+
+import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.errors.NonKeptMethodWithCovariantReturnTypeAnnotationDiagnostic;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
+import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+import com.android.tools.r8.shaking.KeepInfo;
+import com.android.tools.r8.shaking.KeepMethodInfo;
+import com.android.tools.r8.shaking.MinimumKeepInfoCollection;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.ProgramMethodMap;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public class CovariantReturnTypeEnqueuerExtension extends EnqueuerAnalysis {
+
+ private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final CovariantReturnTypeAnnotationTransformer transformer;
+
+ private final Map<DexProgramClass, List<ProgramMethod>> pendingCovariantReturnTypeDesugaring =
+ new IdentityHashMap<>();
+
+ public CovariantReturnTypeEnqueuerExtension(
+ AppView<? extends AppInfoWithClassHierarchy> appView) {
+ this.appView = appView;
+ this.transformer = new CovariantReturnTypeAnnotationTransformer(appView);
+ }
+
+ public static void register(
+ AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ if (enqueuer.getMode().isInitialTreeShaking()
+ && CovariantReturnTypeAnnotationTransformer.shouldRun(appView)) {
+ enqueuer.registerAnalysis(new CovariantReturnTypeEnqueuerExtension(appView));
+ }
+ }
+
+ @Override
+ public void processNewlyLiveMethod(
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {
+ if (hasCovariantReturnTypeAnnotation(method)) {
+ pendingCovariantReturnTypeDesugaring
+ .computeIfAbsent(method.getHolder(), ignoreKey(ArrayList::new))
+ .add(method);
+ }
+ }
+
+ private boolean hasCovariantReturnTypeAnnotation(ProgramMethod method) {
+ CovariantReturnTypeReferences references = transformer.getReferences();
+ DexAnnotationSet annotations = method.getAnnotations();
+ return annotations.hasAnnotation(
+ annotation ->
+ references.isOneOfCovariantReturnTypeAnnotations(annotation.getAnnotationType()));
+ }
+
+ @Override
+ public void notifyFixpoint(
+ Enqueuer enqueuer, EnqueuerWorklist worklist, ExecutorService executorService, Timing timing)
+ throws ExecutionException {
+ if (pendingCovariantReturnTypeDesugaring.isEmpty()) {
+ return;
+ }
+ ProgramMethodMap<Diagnostic> errors = ProgramMethodMap.createConcurrent();
+ transformer.processMethods(
+ pendingCovariantReturnTypeDesugaring,
+ (bridge, target) -> {
+ KeepMethodInfo.Joiner bridgeKeepInfo =
+ getKeepInfoForCovariantReturnTypeBridge(target, errors);
+ enqueuer.getKeepInfo().registerCompilerSynthesizedMethod(bridge);
+ enqueuer.applyMinimumKeepInfoWhenLiveOrTargeted(bridge, bridgeKeepInfo);
+ enqueuer.getProfileCollectionAdditions().addMethodIfContextIsInProfile(bridge, target);
+ },
+ executorService);
+ errors.forEachValue(appView.reporter()::error);
+ pendingCovariantReturnTypeDesugaring.clear();
+ }
+
+ private KeepMethodInfo.Joiner getKeepInfoForCovariantReturnTypeBridge(
+ ProgramMethod target, ProgramMethodMap<Diagnostic> errors) {
+ KeepInfo.Joiner<?, ?, ?> targetKeepInfo =
+ appView
+ .rootSet()
+ .getDependentMinimumKeepInfo()
+ .getUnconditionalMinimumKeepInfoOrDefault(MinimumKeepInfoCollection.empty())
+ .getOrDefault(target.getReference(), null);
+ if (targetKeepInfo == null) {
+ targetKeepInfo = KeepMethodInfo.newEmptyJoiner();
+ }
+ InternalOptions options = appView.options();
+ if ((options.isMinifying() && targetKeepInfo.isMinificationAllowed())
+ || (options.isOptimizing() && targetKeepInfo.isOptimizationAllowed())
+ || (options.isShrinking() && targetKeepInfo.isShrinkingAllowed())) {
+ errors.computeIfAbsent(target, NonKeptMethodWithCovariantReturnTypeAnnotationDiagnostic::new);
+ }
+ return targetKeepInfo.asMethodJoiner();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index d587b61..791b3b4 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -15,6 +15,8 @@
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.utils.Timing;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
public abstract class EnqueuerAnalysis {
@@ -57,7 +59,9 @@
* Called when the Enqueuer reaches a fixpoint. This may happen multiple times, since each
* analysis may enqueue items into the worklist upon the fixpoint using {@param worklist}.
*/
- public void notifyFixpoint(Enqueuer enqueuer, EnqueuerWorklist worklist, Timing timing) {}
+ public void notifyFixpoint(
+ Enqueuer enqueuer, EnqueuerWorklist worklist, ExecutorService executorService, Timing timing)
+ throws ExecutionException {}
/**
* Called when the Enqueuer has reached the final fixpoint. Each analysis may use this callback to
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index 04c491e..f3299a3 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -135,7 +135,11 @@
return new EnqueuerAnalysis() {
@Override
@SuppressWarnings("ReferenceEquality")
- public void notifyFixpoint(Enqueuer enqueuer, EnqueuerWorklist worklist, Timing timing) {
+ public void notifyFixpoint(
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist,
+ ExecutorService executorService,
+ Timing timing) {
builders.forEach(
(builder, dynamicMethod) -> {
if (seen.add(builder)) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
index c9a6021..0ce0317 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -54,6 +54,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutorService;
import java.util.function.Predicate;
// TODO(b/112437944): Handle cycles in the graph + add a test that fails with the current
@@ -179,7 +180,11 @@
}
@Override
- public void notifyFixpoint(Enqueuer enqueuer, EnqueuerWorklist worklist, Timing timing) {
+ public void notifyFixpoint(
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist,
+ ExecutorService executorService,
+ Timing timing) {
timing.begin("[Proto] Extend fixpoint");
populateExtensionGraph(enqueuer);
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 8850e03..1781300 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -22,11 +22,10 @@
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
-import com.android.tools.r8.desugar.covariantreturntype.CovariantReturnTypeAnnotationTransformer;
+import com.android.tools.r8.desugar.covariantreturntype.CovariantReturnTypeEnqueuerExtension;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.code.CfOrDexInstruction;
import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
-import com.android.tools.r8.errors.NonKeptMethodWithCovariantReturnTypeAnnotationDiagnostic;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.features.IsolatedFeatureSplitsChecker;
@@ -480,10 +479,6 @@
private final CfInstructionDesugaringCollection desugaring;
private final ProgramMethodSet pendingCodeDesugaring = ProgramMethodSet.create();
- private final CovariantReturnTypeAnnotationTransformer covariantReturnTypeAnnotationTransformer;
- private final Map<DexProgramClass, List<ProgramMethod>> pendingCovariantReturnTypeDesugaring =
- new IdentityHashMap<>();
-
// Collections for tracing progress on interface method desugaring.
// The pending method move set is all the methods that need to be moved to companions.
@@ -543,6 +538,7 @@
shrinker -> registerAnalysis(shrinker.createEnqueuerAnalysis()));
IsolatedFeatureSplitsChecker.register(appView, this);
ResourceAccessAnalysis.register(appView, this);
+ CovariantReturnTypeEnqueuerExtension.register(appView, this);
}
targetedMethods = new LiveMethodsSet(graphReporter::registerMethod);
@@ -557,12 +553,9 @@
if (mode.isInitialTreeShaking()) {
desugaring = CfInstructionDesugaringCollection.create(appView, appView.apiLevelCompute());
interfaceProcessor = InterfaceProcessor.create(appView);
- covariantReturnTypeAnnotationTransformer =
- new CovariantReturnTypeAnnotationTransformer(appView);
} else {
desugaring = CfInstructionDesugaringCollection.empty();
interfaceProcessor = null;
- covariantReturnTypeAnnotationTransformer = null;
}
objectAllocationInfoCollection =
@@ -4312,7 +4305,6 @@
// registered first and no dependencies may exist among them.
SyntheticAdditions additions = new SyntheticAdditions(appView.createProcessorContext());
desugar(additions);
- processCovariantReturnTypeAnnotations();
synthesizeInterfaceMethodBridges();
if (additions.isEmpty()) {
return;
@@ -4335,11 +4327,6 @@
}
private boolean addToPendingDesugaring(ProgramMethod method) {
- if (covariantReturnTypeAnnotationTransformer.hasCovariantReturnTypeAnnotation(method)) {
- pendingCovariantReturnTypeDesugaring
- .computeIfAbsent(method.getHolder(), ignoreKey(ArrayList::new))
- .add(method);
- }
if (options.isInterfaceMethodDesugaringEnabled()) {
if (mustMoveToInterfaceCompanionMethod(method)) {
// TODO(b/199043500): Once "live moved methods" are tracked this can avoid the code check.
@@ -4474,44 +4461,6 @@
}
}
- private void processCovariantReturnTypeAnnotations() throws ExecutionException {
- if (pendingCovariantReturnTypeDesugaring.isEmpty()) {
- return;
- }
- ProgramMethodMap<Diagnostic> errors = ProgramMethodMap.createConcurrent();
- covariantReturnTypeAnnotationTransformer.processMethods(
- pendingCovariantReturnTypeDesugaring,
- (bridge, target) -> {
- KeepMethodInfo.Joiner bridgeKeepInfo =
- getKeepInfoForCovariantReturnTypeBridge(target, errors);
- keepInfo.registerCompilerSynthesizedMethod(bridge);
- applyMinimumKeepInfoWhenLiveOrTargeted(bridge, bridgeKeepInfo);
- profileCollectionAdditions.addMethodIfContextIsInProfile(bridge, target);
- },
- executorService);
- errors.forEachValue(appView.reporter()::error);
- pendingCovariantReturnTypeDesugaring.clear();
- }
-
- private KeepMethodInfo.Joiner getKeepInfoForCovariantReturnTypeBridge(
- ProgramMethod target, ProgramMethodMap<Diagnostic> errors) {
- KeepInfo.Joiner<?, ?, ?> targetKeepInfo =
- appView
- .rootSet()
- .getDependentMinimumKeepInfo()
- .getUnconditionalMinimumKeepInfoOrDefault(MinimumKeepInfoCollection.empty())
- .getOrDefault(target.getReference(), null);
- if (targetKeepInfo == null) {
- targetKeepInfo = KeepMethodInfo.newEmptyJoiner();
- }
- if ((options.isMinifying() && targetKeepInfo.isMinificationAllowed())
- || (options.isOptimizing() && targetKeepInfo.isOptimizationAllowed())
- || (options.isShrinking() && targetKeepInfo.isShrinkingAllowed())) {
- errors.computeIfAbsent(target, NonKeptMethodWithCovariantReturnTypeAnnotationDiagnostic::new);
- }
- return targetKeepInfo.asMethodJoiner();
- }
-
private void synthesizeInterfaceMethodBridges() {
for (InterfaceMethodSyntheticBridgeAction action : syntheticInterfaceMethodBridges.values()) {
ProgramMethod bridge = action.getMethodToKeep();
@@ -4860,7 +4809,9 @@
// Notify each analysis that a fixpoint has been reached, and give each analysis an
// opportunity to add items to the worklist.
- analyses.forEach(analysis -> analysis.notifyFixpoint(this, worklist, timing));
+ for (EnqueuerAnalysis analysis : analyses) {
+ analysis.notifyFixpoint(this, worklist, executorService, timing);
+ }
if (!worklist.isEmpty()) {
continue;
}