Specialize enqueuer analyses
Change-Id: I4b0f5f24b4144df520bb1a2ffc5f430de19e965b
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index dbae251..5586e26 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -33,7 +33,6 @@
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.conversion.IRConverter;
@@ -49,12 +48,10 @@
import com.android.tools.r8.ir.desugar.records.RecordFieldValuesRewriter;
import com.android.tools.r8.ir.desugar.records.RecordInstructionDesugaring;
import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaring;
-import com.android.tools.r8.ir.optimize.AssertionsRewriter;
import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.ir.optimize.NestReducer;
import com.android.tools.r8.ir.optimize.SwitchMapCollector;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxingCfMethods;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.ir.optimize.info.OptimizationInfoRemover;
import com.android.tools.r8.ir.optimize.templates.CfUtilityMethodsForCodeOptimizations;
import com.android.tools.r8.jar.CfApplicationWriter;
@@ -562,17 +559,17 @@
}
}
+ if (options.isClassMergingExtensionRequired()) {
+ finalRuntimeTypeCheckInfoBuilder = new RuntimeTypeCheckInfo.Builder(appView);
+ }
Enqueuer enqueuer =
EnqueuerFactory.createForFinalTreeShaking(
appView,
executorService,
SubtypingInfo.create(appView),
keptGraphConsumer,
- prunedTypes);
- if (options.isClassMergingExtensionRequired(enqueuer.getMode())) {
- finalRuntimeTypeCheckInfoBuilder = new RuntimeTypeCheckInfo.Builder(appView);
- finalRuntimeTypeCheckInfoBuilder.attach(enqueuer);
- }
+ prunedTypes,
+ finalRuntimeTypeCheckInfoBuilder);
EnqueuerResult enqueuerResult =
enqueuer.traceApplication(appView.rootSet(), executorService, timing);
appView.setAppInfo(enqueuerResult.getAppInfo());
@@ -1168,13 +1165,6 @@
appView, profileCollectionAdditions, executorService, subtypingInfo);
enqueuer.setKeepDeclarations(keepDeclarations);
enqueuer.setAnnotationRemoverBuilder(annotationRemoverBuilder);
- if (AssertionsRewriter.isEnabled(appView.options())) {
- ClassInitializerAssertionEnablingAnalysis analysis =
- new ClassInitializerAssertionEnablingAnalysis(
- appView, OptimizationFeedbackSimple.getInstance());
- enqueuer.registerAnalysis(analysis);
- enqueuer.registerFieldAccessAnalysis(analysis);
- }
timing.end();
timing.begin("Trace application");
EnqueuerResult enqueuerResult =
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
index 4e8573f..18be316 100644
--- a/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeEnqueuerExtension.java
@@ -13,7 +13,9 @@
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.graph.analysis.EnqueuerAnalysisCollection;
+import com.android.tools.r8.graph.analysis.FixpointEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyLiveMethodEnqueuerAnalysis;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.shaking.KeepInfo;
@@ -29,7 +31,8 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-public class CovariantReturnTypeEnqueuerExtension extends EnqueuerAnalysis {
+public class CovariantReturnTypeEnqueuerExtension
+ implements NewlyLiveMethodEnqueuerAnalysis, FixpointEnqueuerAnalysis {
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final CovariantReturnTypeAnnotationTransformer transformer;
@@ -44,10 +47,14 @@
}
public static void register(
- AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Enqueuer enqueuer,
+ EnqueuerAnalysisCollection.Builder builder) {
if (enqueuer.getMode().isInitialTreeShaking()
&& CovariantReturnTypeAnnotationTransformer.shouldRun(appView)) {
- enqueuer.registerAnalysis(new CovariantReturnTypeEnqueuerExtension(appView));
+ CovariantReturnTypeEnqueuerExtension analysis =
+ new CovariantReturnTypeEnqueuerExtension(appView);
+ builder.addNewlyLiveMethodAnalysis(analysis).addFixpointAnalysis(analysis);
}
}
diff --git a/src/main/java/com/android/tools/r8/features/IsolatedFeatureSplitsChecker.java b/src/main/java/com/android/tools/r8/features/IsolatedFeatureSplitsChecker.java
index 376acee..2b05cea 100644
--- a/src/main/java/com/android/tools/r8/features/IsolatedFeatureSplitsChecker.java
+++ b/src/main/java/com/android/tools/r8/features/IsolatedFeatureSplitsChecker.java
@@ -17,16 +17,18 @@
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.analysis.EnqueuerFieldAccessAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerInvokeAnalysis;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysisCollection;
import com.android.tools.r8.graph.analysis.EnqueuerTypeAccessAnalysis;
-import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.graph.analysis.TraceFieldAccessEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.TraceInvokeEnqueuerAnalysis;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.utils.InternalOptions;
// TODO(b/300247439): Also trace types referenced from new-array instructions, call sites, etc.
public class IsolatedFeatureSplitsChecker
- implements EnqueuerFieldAccessAnalysis, EnqueuerInvokeAnalysis, EnqueuerTypeAccessAnalysis {
+ implements TraceFieldAccessEnqueuerAnalysis,
+ TraceInvokeEnqueuerAnalysis,
+ EnqueuerTypeAccessAnalysis {
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final ClassToFeatureSplitMap features;
@@ -37,13 +39,18 @@
}
public static void register(
- AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ EnqueuerAnalysisCollection.Builder builder) {
if (enabled(appView)) {
IsolatedFeatureSplitsChecker checker = new IsolatedFeatureSplitsChecker(appView);
- enqueuer
- .registerFieldAccessAnalysis(checker)
- .registerInvokeAnalysis(checker)
- .registerTypeAccessAnalysis(checker);
+ builder
+ .addTraceFieldAccessAnalysis(checker)
+ .addTraceInvokeAnalysis(checker)
+ .addTraceCheckCastAnalysis(checker)
+ .addTraceConstClassAnalysis(checker)
+ .addTraceExceptionGuardAnalysis(checker)
+ .addTraceInstanceOfAnalysis(checker)
+ .addTraceNewInstanceAnalysis(checker);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
index ed13c75..5f8b573 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
@@ -4,14 +4,25 @@
package com.android.tools.r8.graph;
-import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysisCollection;
+import com.android.tools.r8.graph.analysis.NewlyLiveClassEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyLiveFieldEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyLiveMethodEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyReachableFieldEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyTargetedMethodEnqueuerAnalysis;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.Enqueuer.EnqueuerDefinitionSupplier;
import com.android.tools.r8.shaking.EnqueuerWorklist;
+import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import java.util.Set;
-public class GenericSignatureEnqueuerAnalysis extends EnqueuerAnalysis {
+public class GenericSignatureEnqueuerAnalysis
+ implements NewlyLiveClassEnqueuerAnalysis,
+ NewlyLiveFieldEnqueuerAnalysis,
+ NewlyLiveMethodEnqueuerAnalysis,
+ NewlyReachableFieldEnqueuerAnalysis,
+ NewlyTargetedMethodEnqueuerAnalysis {
private final EnqueuerDefinitionSupplier enqueuerDefinitionSupplier;
private final Set<DexReference> processedSignatures = Sets.newIdentityHashSet();
@@ -20,14 +31,30 @@
this.enqueuerDefinitionSupplier = enqueuerDefinitionSupplier;
}
- @Override
- public void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) {
- processSignature(clazz, clazz.getContext());
+ public static void register(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ EnqueuerDefinitionSupplier enqueuerDefinitionSupplier,
+ EnqueuerAnalysisCollection.Builder builder) {
+ // TODO(b/323816623): This check does not include presence of keep declarations.
+ // We should consider if we should always run the signature analysis and just not emit them
+ // in the end?
+ InternalOptions options = appView.options();
+ if (options.hasProguardConfiguration()
+ && options.getProguardConfiguration().getKeepAttributes().signature) {
+ GenericSignatureEnqueuerAnalysis analysis =
+ new GenericSignatureEnqueuerAnalysis(enqueuerDefinitionSupplier);
+ builder
+ .addNewlyLiveClassAnalysis(analysis)
+ .addNewlyLiveFieldAnalysis(analysis)
+ .addNewlyLiveMethodAnalysis(analysis)
+ .addNewlyReachableFieldAnalysis(analysis)
+ .addNewlyTargetedMethodAnalysis(analysis);
+ }
}
@Override
- public void notifyMarkFieldAsReachable(ProgramField field, EnqueuerWorklist worklist) {
- processSignature(field, field.getContext());
+ public void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) {
+ processSignature(clazz, clazz.getContext());
}
@Override
@@ -37,11 +64,6 @@
}
@Override
- public void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {
- processSignature(method, method.getContext());
- }
-
- @Override
public void processNewlyLiveMethod(
ProgramMethod method,
ProgramDefinition context,
@@ -50,6 +72,16 @@
processSignature(method, context);
}
+ @Override
+ public void processNewlyReachableField(ProgramField field, EnqueuerWorklist worklist) {
+ processSignature(field, field.getContext());
+ }
+
+ @Override
+ public void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {
+ processSignature(method, method.getContext());
+ }
+
private void processSignature(ProgramDefinition signatureHolder, ProgramDefinition context) {
if (!processedSignatures.add(signatureHolder.getReference())) {
return;
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index f16a2d8..4b6337e 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -6,11 +6,11 @@
import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
import com.android.tools.r8.androidapi.ComputedApiLevel;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.DexClassAndMember;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.LookupTarget;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
@@ -18,7 +18,14 @@
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
-public class ApiModelAnalysis extends EnqueuerAnalysis {
+public class ApiModelAnalysis
+ implements NewlyFailedMethodResolutionEnqueuerAnalysis,
+ NewlyLiveCodeEnqueuerAnalysis,
+ NewlyLiveFieldEnqueuerAnalysis,
+ NewlyLiveMethodEnqueuerAnalysis,
+ NewlyLiveNonProgramClassEnqueuerAnalysis,
+ NewlyReachableFieldEnqueuerAnalysis,
+ NewlyTargetedMethodEnqueuerAnalysis {
private final AppView<?> appView;
private final AndroidApiLevelCompute apiCompute;
@@ -30,6 +37,22 @@
this.minApiLevel = appView.computedMinApiLevel();
}
+ public static void register(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ EnqueuerAnalysisCollection.Builder builder) {
+ if (appView.options().apiModelingOptions().enableLibraryApiModeling) {
+ ApiModelAnalysis analysis = new ApiModelAnalysis(appView);
+ builder
+ .addNewlyFailedMethodResolutionAnalysis(analysis)
+ .addNewlyLiveCodeAnalysis(analysis)
+ .addNewlyLiveFieldAnalysis(analysis)
+ .addNewlyLiveMethodAnalysis(analysis)
+ .addNewlyLiveNonProgramClassAnalysis(analysis)
+ .addNewlyReachableFieldAnalysis(analysis)
+ .addNewlyTargetedMethodAnalysis(analysis);
+ }
+ }
+
@Override
public void processNewlyLiveField(
ProgramField field, ProgramDefinition context, EnqueuerWorklist worklist) {
@@ -46,7 +69,7 @@
}
@Override
- public void processTracedCode(
+ public void processNewlyLiveCode(
ProgramMethod method, DefaultEnqueuerUseRegistry registry, EnqueuerWorklist worklist) {
assert registry.getMaxApiReferenceLevel().isGreaterThanOrEqualTo(minApiLevel);
if (appView.options().apiModelingOptions().tracedMethodApiLevelCallback != null) {
@@ -66,27 +89,17 @@
}
@Override
- public void notifyMarkFieldAsReachable(ProgramField field, EnqueuerWorklist worklist) {
+ public void processNewlyReachableField(ProgramField field, EnqueuerWorklist worklist) {
computeAndSetApiLevelForDefinition(field);
}
@Override
- public void processNewLiveNonProgramType(ClasspathOrLibraryClass clazz) {
+ public void processNewlyLiveNonProgramType(ClasspathOrLibraryClass clazz) {
clazz.forEachClassMethod(this::computeAndSetApiLevelForDefinition);
}
@Override
- public void notifyMarkVirtualDispatchTargetAsLive(
- LookupTarget target, EnqueuerWorklist worklist) {
- target.accept(
- lookupMethodTarget -> computeAndSetApiLevelForDefinition(lookupMethodTarget.getTarget()),
- lookupLambdaTarget -> {
- // The implementation method will be assigned an api level when visited.
- });
- }
-
- @Override
- public void notifyFailedMethodResolutionTarget(
+ public void processNewlyFailedMethodResolutionTarget(
DexEncodedMethod method, EnqueuerWorklist worklist) {
// We may not trace into failed resolution targets.
method.setApiLevelForCode(ComputedApiLevel.unknown());
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
index e5122b3..d38b615 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.cf.code.CfLoad;
import com.android.tools.r8.cf.code.CfLogicalBinop;
import com.android.tools.r8.cf.code.CfStaticFieldWrite;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -24,7 +25,9 @@
import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.optimize.AssertionsRewriter;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
@@ -33,8 +36,8 @@
import java.util.stream.Collectors;
import org.objectweb.asm.Opcodes;
-public class ClassInitializerAssertionEnablingAnalysis extends EnqueuerAnalysis
- implements EnqueuerFieldAccessAnalysis {
+public class ClassInitializerAssertionEnablingAnalysis
+ implements TraceFieldAccessEnqueuerAnalysis, NewlyLiveMethodEnqueuerAnalysis {
private final DexItemFactory dexItemFactory;
private final OptimizationFeedback feedback;
private final DexString kotlinAssertionsEnabled;
@@ -53,17 +56,28 @@
.collect(Collectors.toList());
}
- @SuppressWarnings("ReferenceEquality")
+ public static void register(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Enqueuer enqueuer,
+ EnqueuerAnalysisCollection.Builder builder) {
+ if (enqueuer.getMode().isInitialTreeShaking()
+ && AssertionsRewriter.isEnabled(appView.options())) {
+ ClassInitializerAssertionEnablingAnalysis analysis =
+ new ClassInitializerAssertionEnablingAnalysis(
+ appView, OptimizationFeedbackSimple.getInstance());
+ builder.addTraceFieldAccessAnalysis(analysis).addNewlyLiveMethodAnalysis(analysis);
+ }
+ }
+
private boolean isUsingJavaAssertionsDisabledField(DexField field) {
// This does not check the holder, as for inner classes the field is read from the outer class
// and not the class itself.
- return field.getName() == dexItemFactory.assertionsDisabled
- && field.getType() == dexItemFactory.booleanType;
+ return field.getName().isIdenticalTo(dexItemFactory.assertionsDisabled)
+ && field.getType().isIdenticalTo(dexItemFactory.booleanType);
}
- @SuppressWarnings("ReferenceEquality")
private boolean isUsingKotlinAssertionsEnabledField(DexField field) {
- return field == dexItemFactory.kotlin.assertions.enabledField;
+ return field.isIdenticalTo(dexItemFactory.kotlin.assertions.enabledField);
}
@Override
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
deleted file mode 100644
index 8fd3ed4..0000000
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2019, 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.graph.analysis;
-
-import com.android.tools.r8.graph.ClasspathOrLibraryClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.LookupTarget;
-import com.android.tools.r8.graph.ProgramDefinition;
-import com.android.tools.r8.graph.ProgramField;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
-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 {
-
- /** Called when a class is found to be instantiated. */
- public void processNewlyInstantiatedClass(
- DexProgramClass clazz, ProgramMethod context, EnqueuerWorklist worklist) {}
-
- /** Called when a class is found to be live. */
- public void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) {}
-
- /** Called when a field is found to be live. */
- public void processNewlyLiveField(
- ProgramField field, ProgramDefinition context, EnqueuerWorklist worklist) {}
-
- public void processNewlyReferencedField(ProgramField field) {}
-
- /** Called when a method is found to be live. */
- public void processNewlyLiveMethod(
- ProgramMethod method,
- ProgramDefinition context,
- Enqueuer enqueuer,
- EnqueuerWorklist worklist) {}
-
- /** Called when a non program class is visited and marked live */
- public void processNewLiveNonProgramType(ClasspathOrLibraryClass clazz) {}
-
- /** Called when a method's code has been processed by the registry. */
- public void processTracedCode(
- ProgramMethod method, DefaultEnqueuerUseRegistry registry, EnqueuerWorklist worklist) {}
-
- public void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {}
-
- public void notifyMarkFieldAsReachable(ProgramField field, EnqueuerWorklist worklist) {}
-
- public void notifyMarkVirtualDispatchTargetAsLive(
- LookupTarget target, EnqueuerWorklist worklist) {}
-
- public void notifyFailedMethodResolutionTarget(
- DexEncodedMethod method, EnqueuerWorklist worklist) {}
-
- /**
- * 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, ExecutorService executorService, Timing timing)
- throws ExecutionException {}
-
- /**
- * Called when the Enqueuer has reached the final fixpoint. Each analysis may use this callback to
- * perform some post-processing.
- */
- public void done(Enqueuer enqueuer) {}
-}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysisCollection.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysisCollection.java
new file mode 100644
index 0000000..afacc0e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysisCollection.java
@@ -0,0 +1,496 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
+import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.utils.Timing;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public final class EnqueuerAnalysisCollection {
+
+ // Trace events.
+ private final TraceCheckCastEnqueuerAnalysis[] checkCastAnalyses;
+ private final TraceConstClassEnqueuerAnalysis[] constClassAnalyses;
+ private final TraceExceptionGuardEnqueuerAnalysis[] exceptionGuardAnalyses;
+ private final TraceFieldAccessEnqueuerAnalysis[] fieldAccessAnalyses;
+ private final TraceInstanceOfEnqueuerAnalysis[] instanceOfAnalyses;
+ private final TraceInvokeEnqueuerAnalysis[] invokeAnalyses;
+ private final TraceNewInstanceEnqueuerAnalysis[] newInstanceAnalyses;
+
+ // Reachability events.
+ private final NewlyFailedMethodResolutionEnqueuerAnalysis[] newlyFailedMethodResolutionAnalyses;
+ private final NewlyLiveClassEnqueuerAnalysis[] newlyLiveClassAnalyses;
+ private final NewlyLiveCodeEnqueuerAnalysis[] newlyLiveCodeAnalyses;
+ private final NewlyLiveFieldEnqueuerAnalysis[] newlyLiveFieldAnalyses;
+ private final NewlyLiveMethodEnqueuerAnalysis[] newlyLiveMethodAnalyses;
+ private final NewlyInstantiatedClassEnqueuerAnalysis[] newlyInstantiatedClassAnalyses;
+ private final NewlyLiveNonProgramClassEnqueuerAnalysis[] newlyLiveNonProgramClassAnalyses;
+ private final NewlyReachableFieldEnqueuerAnalysis[] newlyReachableFieldAnalyses;
+ private final NewlyReferencedFieldEnqueuerAnalysis[] newlyReferencedFieldAnalyses;
+ private final NewlyTargetedMethodEnqueuerAnalysis[] newlyTargetedMethodAnalyses;
+
+ // Tear down events.
+ private final FinishedEnqueuerAnalysis[] finishedAnalyses;
+ private final FixpointEnqueuerAnalysis[] fixpointAnalyses;
+
+ private EnqueuerAnalysisCollection(
+ // Trace events.
+ TraceCheckCastEnqueuerAnalysis[] checkCastAnalyses,
+ TraceConstClassEnqueuerAnalysis[] constClassAnalyses,
+ TraceExceptionGuardEnqueuerAnalysis[] exceptionGuardAnalyses,
+ TraceFieldAccessEnqueuerAnalysis[] fieldAccessAnalyses,
+ TraceInstanceOfEnqueuerAnalysis[] instanceOfAnalyses,
+ TraceInvokeEnqueuerAnalysis[] invokeAnalyses,
+ TraceNewInstanceEnqueuerAnalysis[] newInstanceAnalyses,
+ // Reachability events.
+ NewlyFailedMethodResolutionEnqueuerAnalysis[] newlyFailedMethodResolutionAnalyses,
+ NewlyLiveClassEnqueuerAnalysis[] newlyLiveClassAnalyses,
+ NewlyLiveCodeEnqueuerAnalysis[] newlyLiveCodeAnalyses,
+ NewlyLiveFieldEnqueuerAnalysis[] newlyLiveFieldAnalyses,
+ NewlyLiveMethodEnqueuerAnalysis[] newlyLiveMethodAnalyses,
+ NewlyInstantiatedClassEnqueuerAnalysis[] newlyInstantiatedClassAnalyses,
+ NewlyLiveNonProgramClassEnqueuerAnalysis[] newlyLiveNonProgramClassAnalyses,
+ NewlyReachableFieldEnqueuerAnalysis[] newlyReachableFieldAnalyses,
+ NewlyReferencedFieldEnqueuerAnalysis[] newlyReferencedFieldAnalyses,
+ NewlyTargetedMethodEnqueuerAnalysis[] newlyTargetedMethodAnalyses,
+ // Tear down events.
+ FinishedEnqueuerAnalysis[] finishedAnalyses,
+ FixpointEnqueuerAnalysis[] fixpointAnalyses) {
+ // Trace events.
+ this.checkCastAnalyses = checkCastAnalyses;
+ this.constClassAnalyses = constClassAnalyses;
+ this.exceptionGuardAnalyses = exceptionGuardAnalyses;
+ this.fieldAccessAnalyses = fieldAccessAnalyses;
+ this.instanceOfAnalyses = instanceOfAnalyses;
+ this.invokeAnalyses = invokeAnalyses;
+ this.newInstanceAnalyses = newInstanceAnalyses;
+ // Reachability events.
+ this.newlyFailedMethodResolutionAnalyses = newlyFailedMethodResolutionAnalyses;
+ this.newlyLiveClassAnalyses = newlyLiveClassAnalyses;
+ this.newlyLiveCodeAnalyses = newlyLiveCodeAnalyses;
+ this.newlyLiveFieldAnalyses = newlyLiveFieldAnalyses;
+ this.newlyLiveMethodAnalyses = newlyLiveMethodAnalyses;
+ this.newlyInstantiatedClassAnalyses = newlyInstantiatedClassAnalyses;
+ this.newlyLiveNonProgramClassAnalyses = newlyLiveNonProgramClassAnalyses;
+ this.newlyReachableFieldAnalyses = newlyReachableFieldAnalyses;
+ this.newlyReferencedFieldAnalyses = newlyReferencedFieldAnalyses;
+ this.newlyTargetedMethodAnalyses = newlyTargetedMethodAnalyses;
+ // Tear down events.
+ this.finishedAnalyses = finishedAnalyses;
+ this.fixpointAnalyses = fixpointAnalyses;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public boolean isEmpty() {
+ return ArrayUtils.isEmpty(checkCastAnalyses)
+ && ArrayUtils.isEmpty(constClassAnalyses)
+ && ArrayUtils.isEmpty(exceptionGuardAnalyses)
+ && ArrayUtils.isEmpty(fieldAccessAnalyses)
+ && ArrayUtils.isEmpty(instanceOfAnalyses)
+ && ArrayUtils.isEmpty(invokeAnalyses)
+ && ArrayUtils.isEmpty(newInstanceAnalyses)
+ && ArrayUtils.isEmpty(newlyFailedMethodResolutionAnalyses)
+ && ArrayUtils.isEmpty(newlyLiveClassAnalyses)
+ && ArrayUtils.isEmpty(newlyLiveCodeAnalyses)
+ && ArrayUtils.isEmpty(newlyLiveFieldAnalyses)
+ && ArrayUtils.isEmpty(newlyLiveMethodAnalyses)
+ && ArrayUtils.isEmpty(newlyInstantiatedClassAnalyses)
+ && ArrayUtils.isEmpty(newlyLiveNonProgramClassAnalyses)
+ && ArrayUtils.isEmpty(newlyReachableFieldAnalyses)
+ && ArrayUtils.isEmpty(newlyReferencedFieldAnalyses)
+ && ArrayUtils.isEmpty(newlyTargetedMethodAnalyses)
+ && ArrayUtils.isEmpty(finishedAnalyses)
+ && ArrayUtils.isEmpty(fixpointAnalyses);
+ }
+
+ // Trace events.
+
+ public void traceCheckCast(DexType type, DexClass clazz, ProgramMethod context) {
+ for (TraceCheckCastEnqueuerAnalysis analysis : checkCastAnalyses) {
+ analysis.traceCheckCast(type, clazz, context);
+ }
+ }
+
+ public void traceSafeCheckCast(DexType type, DexClass clazz, ProgramMethod context) {
+ for (TraceCheckCastEnqueuerAnalysis analysis : checkCastAnalyses) {
+ analysis.traceSafeCheckCast(type, clazz, context);
+ }
+ }
+
+ public void traceConstClass(DexType type, DexClass clazz, ProgramMethod context) {
+ for (TraceConstClassEnqueuerAnalysis analysis : constClassAnalyses) {
+ analysis.traceConstClass(type, clazz, context);
+ }
+ }
+
+ public void traceExceptionGuard(DexType guard, DexClass clazz, ProgramMethod context) {
+ for (TraceExceptionGuardEnqueuerAnalysis analysis : exceptionGuardAnalyses) {
+ analysis.traceExceptionGuard(guard, clazz, context);
+ }
+ }
+
+ public void traceInstanceFieldRead(
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
+ for (TraceFieldAccessEnqueuerAnalysis analysis : fieldAccessAnalyses) {
+ analysis.traceInstanceFieldRead(field, resolutionResult, context, worklist);
+ }
+ }
+
+ public void traceInstanceFieldWrite(
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
+ for (TraceFieldAccessEnqueuerAnalysis analysis : fieldAccessAnalyses) {
+ analysis.traceInstanceFieldWrite(field, resolutionResult, context, worklist);
+ }
+ }
+
+ public void traceStaticFieldRead(
+ DexField field,
+ SingleFieldResolutionResult<?> resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
+ for (TraceFieldAccessEnqueuerAnalysis analysis : fieldAccessAnalyses) {
+ analysis.traceStaticFieldRead(field, resolutionResult, context, worklist);
+ }
+ }
+
+ public void traceStaticFieldWrite(
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
+ for (TraceFieldAccessEnqueuerAnalysis analysis : fieldAccessAnalyses) {
+ analysis.traceStaticFieldWrite(field, resolutionResult, context, worklist);
+ }
+ }
+
+ public void traceInstanceOf(DexType type, DexClass clazz, ProgramMethod context) {
+ for (TraceInstanceOfEnqueuerAnalysis analysis : instanceOfAnalyses) {
+ analysis.traceInstanceOf(type, clazz, context);
+ }
+ }
+
+ public void traceInvokeStatic(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
+ for (TraceInvokeEnqueuerAnalysis analysis : invokeAnalyses) {
+ analysis.traceInvokeStatic(invokedMethod, resolutionResult, context);
+ }
+ }
+
+ public void traceInvokeDirect(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
+ for (TraceInvokeEnqueuerAnalysis analysis : invokeAnalyses) {
+ analysis.traceInvokeDirect(invokedMethod, resolutionResult, context);
+ }
+ }
+
+ public void traceInvokeInterface(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
+ for (TraceInvokeEnqueuerAnalysis analysis : invokeAnalyses) {
+ analysis.traceInvokeInterface(invokedMethod, resolutionResult, context);
+ }
+ }
+
+ public void traceInvokeSuper(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
+ for (TraceInvokeEnqueuerAnalysis analysis : invokeAnalyses) {
+ analysis.traceInvokeSuper(invokedMethod, resolutionResult, context);
+ }
+ }
+
+ public void traceInvokeVirtual(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
+ for (TraceInvokeEnqueuerAnalysis analysis : invokeAnalyses) {
+ analysis.traceInvokeVirtual(invokedMethod, resolutionResult, context);
+ }
+ }
+
+ public void traceNewInstance(DexType type, DexClass clazz, ProgramMethod context) {
+ for (TraceNewInstanceEnqueuerAnalysis analysis : newInstanceAnalyses) {
+ analysis.traceNewInstance(type, clazz, context);
+ }
+ }
+
+ // Reachability events.
+
+ public void processNewlyFailedMethodResolutionTarget(
+ DexEncodedMethod method, EnqueuerWorklist worklist) {
+ for (NewlyFailedMethodResolutionEnqueuerAnalysis analysis :
+ newlyFailedMethodResolutionAnalyses) {
+ analysis.processNewlyFailedMethodResolutionTarget(method, worklist);
+ }
+ }
+
+ public void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) {
+ for (NewlyLiveClassEnqueuerAnalysis analysis : newlyLiveClassAnalyses) {
+ analysis.processNewlyLiveClass(clazz, worklist);
+ }
+ }
+
+ public void processNewlyLiveCode(
+ ProgramMethod method, DefaultEnqueuerUseRegistry registry, EnqueuerWorklist worklist) {
+ for (NewlyLiveCodeEnqueuerAnalysis analysis : newlyLiveCodeAnalyses) {
+ analysis.processNewlyLiveCode(method, registry, worklist);
+ }
+ }
+
+ public void processNewlyLiveField(
+ ProgramField field, ProgramDefinition context, EnqueuerWorklist worklist) {
+ for (NewlyLiveFieldEnqueuerAnalysis analysis : newlyLiveFieldAnalyses) {
+ analysis.processNewlyLiveField(field, context, worklist);
+ }
+ }
+
+ public void processNewlyLiveMethod(
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {
+ for (NewlyLiveMethodEnqueuerAnalysis analysis : newlyLiveMethodAnalyses) {
+ analysis.processNewlyLiveMethod(method, context, enqueuer, worklist);
+ }
+ }
+
+ public void processNewlyInstantiatedClass(
+ DexProgramClass clazz, ProgramMethod context, EnqueuerWorklist worklist) {
+ for (NewlyInstantiatedClassEnqueuerAnalysis analysis : newlyInstantiatedClassAnalyses) {
+ analysis.processNewlyInstantiatedClass(clazz, context, worklist);
+ }
+ }
+
+ public void processNewlyLiveNonProgramType(ClasspathOrLibraryClass clazz) {
+ for (NewlyLiveNonProgramClassEnqueuerAnalysis analysis : newlyLiveNonProgramClassAnalyses) {
+ analysis.processNewlyLiveNonProgramType(clazz);
+ }
+ }
+
+ public void processNewlyReachableField(ProgramField field, EnqueuerWorklist worklist) {
+ for (NewlyReachableFieldEnqueuerAnalysis analysis : newlyReachableFieldAnalyses) {
+ analysis.processNewlyReachableField(field, worklist);
+ }
+ }
+
+ public void processNewlyReferencedField(ProgramField field) {
+ for (NewlyReferencedFieldEnqueuerAnalysis analysis : newlyReferencedFieldAnalyses) {
+ analysis.processNewlyReferencedField(field);
+ }
+ }
+
+ public void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {
+ for (NewlyTargetedMethodEnqueuerAnalysis analysis : newlyTargetedMethodAnalyses) {
+ analysis.processNewlyTargetedMethod(method, worklist);
+ }
+ }
+
+ // Tear down events.
+
+ public void done(Enqueuer enqueuer) {
+ for (FinishedEnqueuerAnalysis analysis : finishedAnalyses) {
+ analysis.done(enqueuer);
+ }
+ }
+
+ public void notifyFixpoint(
+ Enqueuer enqueuer, EnqueuerWorklist worklist, ExecutorService executorService, Timing timing)
+ throws ExecutionException {
+ for (FixpointEnqueuerAnalysis analysis : fixpointAnalyses) {
+ analysis.notifyFixpoint(enqueuer, worklist, executorService, timing);
+ }
+ }
+
+ public static class Builder {
+
+ // Trace events.
+ private final List<TraceCheckCastEnqueuerAnalysis> checkCastAnalyses = new ArrayList<>();
+ private final List<TraceConstClassEnqueuerAnalysis> constClassAnalyses = new ArrayList<>();
+ private final List<TraceExceptionGuardEnqueuerAnalysis> exceptionGuardAnalyses =
+ new ArrayList<>();
+ private final List<TraceFieldAccessEnqueuerAnalysis> fieldAccessAnalyses = new ArrayList<>();
+ private final List<TraceInstanceOfEnqueuerAnalysis> instanceOfAnalyses = new ArrayList<>();
+ private final List<TraceInvokeEnqueuerAnalysis> invokeAnalyses = new ArrayList<>();
+ private final List<TraceNewInstanceEnqueuerAnalysis> newInstanceAnalyses = new ArrayList<>();
+
+ // Reachability events.
+ private final List<NewlyFailedMethodResolutionEnqueuerAnalysis>
+ newlyFailedMethodResolutionAnalyses = new ArrayList<>();
+ private final List<NewlyLiveClassEnqueuerAnalysis> newlyLiveClassAnalyses = new ArrayList<>();
+ private final List<NewlyLiveCodeEnqueuerAnalysis> newlyLiveCodeAnalyses = new ArrayList<>();
+ private final List<NewlyLiveFieldEnqueuerAnalysis> newlyLiveFieldAnalyses = new ArrayList<>();
+ private final List<NewlyLiveMethodEnqueuerAnalysis> newlyLiveMethodAnalyses = new ArrayList<>();
+ private final List<NewlyInstantiatedClassEnqueuerAnalysis> newlyInstantiatedClassAnalyses =
+ new ArrayList<>();
+ private final List<NewlyLiveNonProgramClassEnqueuerAnalysis> newlyLiveNonProgramClassAnalyses =
+ new ArrayList<>();
+ private final List<NewlyReachableFieldEnqueuerAnalysis> newlyReachableFieldAnalyses =
+ new ArrayList<>();
+ private final List<NewlyReferencedFieldEnqueuerAnalysis> newlyReferencedFieldAnalyses =
+ new ArrayList<>();
+ private final List<NewlyTargetedMethodEnqueuerAnalysis> newlyTargetedMethodAnalyses =
+ new ArrayList<>();
+
+ // Tear down events.
+ private final List<FinishedEnqueuerAnalysis> finishedAnalyses = new ArrayList<>();
+ private final List<FixpointEnqueuerAnalysis> fixpointAnalyses = new ArrayList<>();
+
+ private Builder() {}
+
+ // Trace events.
+
+ public Builder addTraceCheckCastAnalysis(TraceCheckCastEnqueuerAnalysis analysis) {
+ checkCastAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addTraceConstClassAnalysis(TraceConstClassEnqueuerAnalysis analysis) {
+ constClassAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addTraceExceptionGuardAnalysis(TraceExceptionGuardEnqueuerAnalysis analysis) {
+ exceptionGuardAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addTraceFieldAccessAnalysis(TraceFieldAccessEnqueuerAnalysis analysis) {
+ fieldAccessAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addTraceInstanceOfAnalysis(TraceInstanceOfEnqueuerAnalysis analysis) {
+ instanceOfAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addTraceInvokeAnalysis(TraceInvokeEnqueuerAnalysis analysis) {
+ invokeAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addTraceNewInstanceAnalysis(TraceNewInstanceEnqueuerAnalysis analysis) {
+ newInstanceAnalyses.add(analysis);
+ return this;
+ }
+
+ // Reachability events.
+
+ public Builder addNewlyFailedMethodResolutionAnalysis(
+ NewlyFailedMethodResolutionEnqueuerAnalysis analysis) {
+ newlyFailedMethodResolutionAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyLiveClassAnalysis(NewlyLiveClassEnqueuerAnalysis analysis) {
+ newlyLiveClassAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyLiveCodeAnalysis(NewlyLiveCodeEnqueuerAnalysis analysis) {
+ newlyLiveCodeAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyLiveFieldAnalysis(NewlyLiveFieldEnqueuerAnalysis analysis) {
+ newlyLiveFieldAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyLiveMethodAnalysis(NewlyLiveMethodEnqueuerAnalysis analysis) {
+ newlyLiveMethodAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyInstantiatedClassAnalysis(
+ NewlyInstantiatedClassEnqueuerAnalysis analysis) {
+ newlyInstantiatedClassAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyLiveNonProgramClassAnalysis(
+ NewlyLiveNonProgramClassEnqueuerAnalysis analysis) {
+ newlyLiveNonProgramClassAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyReachableFieldAnalysis(NewlyReachableFieldEnqueuerAnalysis analysis) {
+ newlyReachableFieldAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyReferencedFieldAnalysis(NewlyReferencedFieldEnqueuerAnalysis analysis) {
+ newlyReferencedFieldAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addNewlyTargetedMethodAnalysis(NewlyTargetedMethodEnqueuerAnalysis analysis) {
+ newlyTargetedMethodAnalyses.add(analysis);
+ return this;
+ }
+
+ // Tear down events.
+
+ public Builder addFinishedAnalysis(FinishedEnqueuerAnalysis analysis) {
+ finishedAnalyses.add(analysis);
+ return this;
+ }
+
+ public Builder addFixpointAnalysis(FixpointEnqueuerAnalysis analysis) {
+ fixpointAnalyses.add(analysis);
+ return this;
+ }
+
+ public EnqueuerAnalysisCollection build() {
+ return new EnqueuerAnalysisCollection(
+ // Trace events.
+ checkCastAnalyses.toArray(TraceCheckCastEnqueuerAnalysis[]::new),
+ constClassAnalyses.toArray(TraceConstClassEnqueuerAnalysis[]::new),
+ exceptionGuardAnalyses.toArray(TraceExceptionGuardEnqueuerAnalysis[]::new),
+ fieldAccessAnalyses.toArray(TraceFieldAccessEnqueuerAnalysis[]::new),
+ instanceOfAnalyses.toArray(TraceInstanceOfEnqueuerAnalysis[]::new),
+ invokeAnalyses.toArray(TraceInvokeEnqueuerAnalysis[]::new),
+ newInstanceAnalyses.toArray(TraceNewInstanceEnqueuerAnalysis[]::new),
+ // Reachability events.
+ newlyFailedMethodResolutionAnalyses.toArray(
+ NewlyFailedMethodResolutionEnqueuerAnalysis[]::new),
+ newlyLiveClassAnalyses.toArray(NewlyLiveClassEnqueuerAnalysis[]::new),
+ newlyLiveCodeAnalyses.toArray(NewlyLiveCodeEnqueuerAnalysis[]::new),
+ newlyLiveFieldAnalyses.toArray(NewlyLiveFieldEnqueuerAnalysis[]::new),
+ newlyLiveMethodAnalyses.toArray(NewlyLiveMethodEnqueuerAnalysis[]::new),
+ newlyInstantiatedClassAnalyses.toArray(NewlyInstantiatedClassEnqueuerAnalysis[]::new),
+ newlyLiveNonProgramClassAnalyses.toArray(NewlyLiveNonProgramClassEnqueuerAnalysis[]::new),
+ newlyReachableFieldAnalyses.toArray(NewlyReachableFieldEnqueuerAnalysis[]::new),
+ newlyReferencedFieldAnalyses.toArray(NewlyReferencedFieldEnqueuerAnalysis[]::new),
+ newlyTargetedMethodAnalyses.toArray(NewlyTargetedMethodEnqueuerAnalysis[]::new),
+ // Tear down events.
+ finishedAnalyses.toArray(FinishedEnqueuerAnalysis[]::new),
+ fixpointAnalyses.toArray(FixpointEnqueuerAnalysis[]::new));
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerTypeAccessAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerTypeAccessAnalysis.java
index 3d44ef1..cb76002 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerTypeAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerTypeAccessAnalysis.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.graph.analysis;
public interface EnqueuerTypeAccessAnalysis
- extends EnqueuerCheckCastAnalysis,
- EnqueuerConstClassAnalysis,
- EnqueuerExceptionGuardAnalysis,
- EnqueuerInstanceOfAnalysis,
- EnqueuerNewInstanceAnalysis {}
+ extends TraceCheckCastEnqueuerAnalysis,
+ TraceConstClassEnqueuerAnalysis,
+ TraceExceptionGuardEnqueuerAnalysis,
+ TraceInstanceOfEnqueuerAnalysis,
+ TraceNewInstanceEnqueuerAnalysis {}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/FinishedEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/FinishedEnqueuerAnalysis.java
new file mode 100644
index 0000000..54cabca
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/FinishedEnqueuerAnalysis.java
@@ -0,0 +1,15 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.shaking.Enqueuer;
+
+public interface FinishedEnqueuerAnalysis {
+
+ /**
+ * Called when the Enqueuer has reached the final fixpoint. Each analysis may use this callback to
+ * perform some post-processing.
+ */
+ default void done(Enqueuer enqueuer) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/FixpointEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/FixpointEnqueuerAnalysis.java
new file mode 100644
index 0000000..9f67337
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/FixpointEnqueuerAnalysis.java
@@ -0,0 +1,21 @@
+// 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.graph.analysis;
+
+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 interface FixpointEnqueuerAnalysis {
+
+ /**
+ * 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}.
+ */
+ default void notifyFixpoint(
+ Enqueuer enqueuer, EnqueuerWorklist worklist, ExecutorService executorService, Timing timing)
+ throws ExecutionException {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java b/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
index ed49777..bace0d4 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
@@ -34,7 +34,8 @@
* or class merging), and thereby causes new classes to no longer verify on Dalvik, we soft-pin
* methods that reads such fields.
*/
-public class GetArrayOfMissingTypeVerifyErrorWorkaround implements EnqueuerFieldAccessAnalysis {
+public class GetArrayOfMissingTypeVerifyErrorWorkaround
+ implements TraceFieldAccessEnqueuerAnalysis {
private final DexItemFactory dexItemFactory;
private final Enqueuer enqueuer;
@@ -48,9 +49,11 @@
}
public static void register(
- AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Enqueuer enqueuer,
+ EnqueuerAnalysisCollection.Builder builder) {
if (!isNoop(appView)) {
- enqueuer.registerFieldAccessAnalysis(
+ builder.addTraceFieldAccessAnalysis(
new GetArrayOfMissingTypeVerifyErrorWorkaround(appView, enqueuer));
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
index ddb64d7..2a84623 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
@@ -17,7 +17,8 @@
import java.util.IdentityHashMap;
import java.util.Map;
-public class InitializedClassesInInstanceMethodsAnalysis extends EnqueuerAnalysis {
+public class InitializedClassesInInstanceMethodsAnalysis
+ implements FinishedEnqueuerAnalysis, NewlyInstantiatedClassEnqueuerAnalysis {
// A simple structure that stores the result of the analysis.
public static class InitializedClassesInInstanceMethods {
@@ -86,10 +87,14 @@
}
public static void register(
- AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Enqueuer enqueuer,
+ EnqueuerAnalysisCollection.Builder builder) {
if (appView.options().enableInitializedClassesInInstanceMethodsAnalysis
&& enqueuer.getMode().isInitialTreeShaking()) {
- enqueuer.registerAnalysis(new InitializedClassesInInstanceMethodsAnalysis(appView));
+ InitializedClassesInInstanceMethodsAnalysis analysis =
+ new InitializedClassesInInstanceMethodsAnalysis(appView);
+ builder.addNewlyInstantiatedClassAnalysis(analysis).addFinishedAnalysis(analysis);
} else {
appView.setInitializedClassesInInstanceMethods(null);
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/InvokeVirtualToInterfaceVerifyErrorWorkaround.java b/src/main/java/com/android/tools/r8/graph/analysis/InvokeVirtualToInterfaceVerifyErrorWorkaround.java
index 70fca76..b5bf374 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/InvokeVirtualToInterfaceVerifyErrorWorkaround.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/InvokeVirtualToInterfaceVerifyErrorWorkaround.java
@@ -27,7 +27,7 @@
// TODO(b/206891715): This only mitigates the issue. The user may still need to manually outline
// virtual invokes to classes that was once an interface. To avoid this in general (including D8)
// the compiler should outline the problematic invokes.
-public class InvokeVirtualToInterfaceVerifyErrorWorkaround implements EnqueuerInvokeAnalysis {
+public class InvokeVirtualToInterfaceVerifyErrorWorkaround implements TraceInvokeEnqueuerAnalysis {
private final DexType androidHardwareCamera2CameraDeviceType;
private final Enqueuer enqueuer;
@@ -42,9 +42,11 @@
}
public static void register(
- AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Enqueuer enqueuer,
+ EnqueuerAnalysisCollection.Builder builder) {
if (!isNoop(appView)) {
- enqueuer.registerInvokeAnalysis(
+ builder.addTraceInvokeAnalysis(
new InvokeVirtualToInterfaceVerifyErrorWorkaround(appView, enqueuer));
}
}
@@ -61,36 +63,11 @@
}
}
- @SuppressWarnings("ReferenceEquality")
private boolean isInterfaceInSomeApiLevel(DexType type) {
// CameraDevice was added as a class in API 21 (L), but was defined as an interface in the
// framework before then.
- return type == androidHardwareCamera2CameraDeviceType
+ return type.isIdenticalTo(androidHardwareCamera2CameraDeviceType)
&& (options.isGeneratingClassFiles()
|| options.getMinApiLevel().isLessThan(AndroidApiLevel.L));
}
-
- @Override
- public void traceInvokeDirect(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
- // Intentionally empty.
- }
-
- @Override
- public void traceInvokeInterface(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
- // Intentionally empty.
- }
-
- @Override
- public void traceInvokeStatic(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
- // Intentionally empty.
- }
-
- @Override
- public void traceInvokeSuper(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {
- // Intentionally empty.
- }
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyFailedMethodResolutionEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyFailedMethodResolutionEnqueuerAnalysis.java
new file mode 100644
index 0000000..4d6fc73
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyFailedMethodResolutionEnqueuerAnalysis.java
@@ -0,0 +1,13 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+
+public interface NewlyFailedMethodResolutionEnqueuerAnalysis {
+
+ default void processNewlyFailedMethodResolutionTarget(
+ DexEncodedMethod method, EnqueuerWorklist worklist) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyInstantiatedClassEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyInstantiatedClassEnqueuerAnalysis.java
new file mode 100644
index 0000000..c3eb799
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyInstantiatedClassEnqueuerAnalysis.java
@@ -0,0 +1,15 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+
+public interface NewlyInstantiatedClassEnqueuerAnalysis {
+
+ /** Called when a class is found to be instantiated. */
+ default void processNewlyInstantiatedClass(
+ DexProgramClass clazz, ProgramMethod context, EnqueuerWorklist worklist) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveClassEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveClassEnqueuerAnalysis.java
new file mode 100644
index 0000000..e681269
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveClassEnqueuerAnalysis.java
@@ -0,0 +1,13 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+
+public interface NewlyLiveClassEnqueuerAnalysis {
+
+ /** Called when a class is found to be live. */
+ default void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveCodeEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveCodeEnqueuerAnalysis.java
new file mode 100644
index 0000000..50f934f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveCodeEnqueuerAnalysis.java
@@ -0,0 +1,15 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+
+public interface NewlyLiveCodeEnqueuerAnalysis {
+
+ /** Called when a method's code has been processed by the registry. */
+ default void processNewlyLiveCode(
+ ProgramMethod method, DefaultEnqueuerUseRegistry registry, EnqueuerWorklist worklist) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveFieldEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveFieldEnqueuerAnalysis.java
new file mode 100644
index 0000000..22c0d70
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveFieldEnqueuerAnalysis.java
@@ -0,0 +1,15 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+
+public interface NewlyLiveFieldEnqueuerAnalysis {
+
+ /** Called when a field is found to be live. */
+ default void processNewlyLiveField(
+ ProgramField field, ProgramDefinition context, EnqueuerWorklist worklist) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveMethodEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveMethodEnqueuerAnalysis.java
new file mode 100644
index 0000000..6c6df87
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveMethodEnqueuerAnalysis.java
@@ -0,0 +1,19 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+
+public interface NewlyLiveMethodEnqueuerAnalysis {
+
+ /** Called when a method is found to be live. */
+ default void processNewlyLiveMethod(
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveNonProgramClassEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveNonProgramClassEnqueuerAnalysis.java
new file mode 100644
index 0000000..dbf980a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyLiveNonProgramClassEnqueuerAnalysis.java
@@ -0,0 +1,12 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
+
+public interface NewlyLiveNonProgramClassEnqueuerAnalysis {
+
+ /** Called when a non program class is visited and marked live */
+ default void processNewlyLiveNonProgramType(ClasspathOrLibraryClass clazz) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyReachableFieldEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyReachableFieldEnqueuerAnalysis.java
new file mode 100644
index 0000000..bfa942a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyReachableFieldEnqueuerAnalysis.java
@@ -0,0 +1,12 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+
+public interface NewlyReachableFieldEnqueuerAnalysis {
+
+ default void processNewlyReachableField(ProgramField field, EnqueuerWorklist worklist) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyReferencedFieldEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyReferencedFieldEnqueuerAnalysis.java
new file mode 100644
index 0000000..96c15fc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyReferencedFieldEnqueuerAnalysis.java
@@ -0,0 +1,11 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.ProgramField;
+
+public interface NewlyReferencedFieldEnqueuerAnalysis {
+
+ default void processNewlyReferencedField(ProgramField field) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/NewlyTargetedMethodEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/NewlyTargetedMethodEnqueuerAnalysis.java
new file mode 100644
index 0000000..5bd7789
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/analysis/NewlyTargetedMethodEnqueuerAnalysis.java
@@ -0,0 +1,12 @@
+// 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.graph.analysis;
+
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
+
+public interface NewlyTargetedMethodEnqueuerAnalysis {
+
+ default void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {}
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
index 3d1cb69..14aa18a 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
@@ -31,7 +31,7 @@
import java.util.IdentityHashMap;
import java.util.Map;
-public class ResourceAccessAnalysis implements EnqueuerFieldAccessAnalysis {
+public class ResourceAccessAnalysis implements TraceFieldAccessEnqueuerAnalysis {
private final R8ResourceShrinkerState resourceShrinkerState;
private final Map<DexType, RClassFieldToValueStore> fieldToValueMapping = new IdentityHashMap<>();
@@ -46,13 +46,15 @@
}
public static void register(
- AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Enqueuer enqueuer,
+ EnqueuerAnalysisCollection.Builder builder) {
if (fieldAccessAnalysisEnabled(appView, enqueuer)) {
- enqueuer.registerFieldAccessAnalysis(new ResourceAccessAnalysis(appView, enqueuer));
+ builder.addTraceFieldAccessAnalysis(new ResourceAccessAnalysis(appView, enqueuer));
}
if (liveFieldAnalysisEnabled(appView, enqueuer)) {
- enqueuer.registerAnalysis(
- new EnqueuerAnalysis() {
+ builder.addNewlyLiveFieldAnalysis(
+ new NewlyLiveFieldEnqueuerAnalysis() {
@Override
public void processNewlyLiveField(
ProgramField field, ProgramDefinition context, EnqueuerWorklist worklist) {
@@ -69,11 +71,6 @@
}
}
- @Override
- public void done(Enqueuer enqueuer) {
- EnqueuerFieldAccessAnalysis.super.done(enqueuer);
- }
-
private static boolean liveFieldAnalysisEnabled(
AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
return appView.options().androidResourceProvider != null
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerCheckCastAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/TraceCheckCastEnqueuerAnalysis.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/graph/analysis/EnqueuerCheckCastAnalysis.java
rename to src/main/java/com/android/tools/r8/graph/analysis/TraceCheckCastEnqueuerAnalysis.java
index 1ff19a6..a6362a2 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerCheckCastAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/TraceCheckCastEnqueuerAnalysis.java
@@ -1,14 +1,13 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// 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.graph.analysis;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-public interface EnqueuerCheckCastAnalysis {
+public interface TraceCheckCastEnqueuerAnalysis {
void traceCheckCast(DexType type, DexClass clazz, ProgramMethod context);
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerConstClassAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/TraceConstClassEnqueuerAnalysis.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/graph/analysis/EnqueuerConstClassAnalysis.java
rename to src/main/java/com/android/tools/r8/graph/analysis/TraceConstClassEnqueuerAnalysis.java
index 61f127a..259fe33 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerConstClassAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/TraceConstClassEnqueuerAnalysis.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// 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.graph.analysis;
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-public interface EnqueuerConstClassAnalysis {
+public interface TraceConstClassEnqueuerAnalysis {
void traceConstClass(DexType type, DexClass clazz, ProgramMethod context);
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerExceptionGuardAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/TraceExceptionGuardEnqueuerAnalysis.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/graph/analysis/EnqueuerExceptionGuardAnalysis.java
rename to src/main/java/com/android/tools/r8/graph/analysis/TraceExceptionGuardEnqueuerAnalysis.java
index 752e4a5..94c5a50 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerExceptionGuardAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/TraceExceptionGuardEnqueuerAnalysis.java
@@ -1,13 +1,12 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// 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.graph.analysis;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-public interface EnqueuerExceptionGuardAnalysis {
+public interface TraceExceptionGuardEnqueuerAnalysis {
void traceExceptionGuard(DexType guard, DexClass clazz, ProgramMethod context);
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerFieldAccessAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/TraceFieldAccessEnqueuerAnalysis.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/graph/analysis/EnqueuerFieldAccessAnalysis.java
rename to src/main/java/com/android/tools/r8/graph/analysis/TraceFieldAccessEnqueuerAnalysis.java
index 69eb560..316df40 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerFieldAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/TraceFieldAccessEnqueuerAnalysis.java
@@ -1,17 +1,15 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// 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.graph.analysis;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
-public interface EnqueuerFieldAccessAnalysis {
+public interface TraceFieldAccessEnqueuerAnalysis {
default void traceInstanceFieldRead(
DexField field,
@@ -36,10 +34,4 @@
FieldResolutionResult resolutionResult,
ProgramMethod context,
EnqueuerWorklist worklist) {}
-
- /**
- * Called when the Enqueuer has reached the final fixpoint. Each analysis may use this callback to
- * perform some post-processing.
- */
- default void done(Enqueuer enqueuer) {}
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerInstanceOfAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/TraceInstanceOfEnqueuerAnalysis.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/graph/analysis/EnqueuerInstanceOfAnalysis.java
rename to src/main/java/com/android/tools/r8/graph/analysis/TraceInstanceOfEnqueuerAnalysis.java
index 485a311..3a7bcc8 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerInstanceOfAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/TraceInstanceOfEnqueuerAnalysis.java
@@ -1,13 +1,12 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// 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.graph.analysis;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-public interface EnqueuerInstanceOfAnalysis {
+public interface TraceInstanceOfEnqueuerAnalysis {
void traceInstanceOf(DexType type, DexClass clazz, ProgramMethod context);
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerInvokeAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/TraceInvokeEnqueuerAnalysis.java
similarity index 63%
rename from src/main/java/com/android/tools/r8/graph/analysis/EnqueuerInvokeAnalysis.java
rename to src/main/java/com/android/tools/r8/graph/analysis/TraceInvokeEnqueuerAnalysis.java
index d2ca27d..d5b1568 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerInvokeAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/TraceInvokeEnqueuerAnalysis.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// 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.graph.analysis;
@@ -7,24 +7,24 @@
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
-public interface EnqueuerInvokeAnalysis {
+public interface TraceInvokeEnqueuerAnalysis {
/**
* Each traceInvokeXX method is called when a corresponding invoke is found while tracing a live
* method.
*/
- void traceInvokeStatic(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context);
+ default void traceInvokeStatic(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {}
- void traceInvokeDirect(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context);
+ default void traceInvokeDirect(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {}
- void traceInvokeInterface(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context);
+ default void traceInvokeInterface(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {}
- void traceInvokeSuper(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context);
+ default void traceInvokeSuper(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {}
- void traceInvokeVirtual(
- DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context);
+ default void traceInvokeVirtual(
+ DexMethod invokedMethod, MethodResolutionResult resolutionResult, ProgramMethod context) {}
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerNewInstanceAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/TraceNewInstanceEnqueuerAnalysis.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/graph/analysis/EnqueuerNewInstanceAnalysis.java
rename to src/main/java/com/android/tools/r8/graph/analysis/TraceNewInstanceEnqueuerAnalysis.java
index 880c91a..41bb477 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerNewInstanceAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/TraceNewInstanceEnqueuerAnalysis.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// 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.graph.analysis;
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-public interface EnqueuerNewInstanceAnalysis {
+public interface TraceNewInstanceEnqueuerAnalysis {
void traceNewInstance(DexType type, DexClass clazz, ProgramMethod context);
}
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 e66ee34..f925f86 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
@@ -20,7 +20,8 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysisCollection;
+import com.android.tools.r8.graph.analysis.FixpointEnqueuerAnalysis;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.IRCode;
@@ -82,6 +83,13 @@
assert enableAggressiveBuilderOptimization;
}
+ public static void register(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ EnqueuerAnalysisCollection.Builder builder) {
+ appView.withGeneratedMessageLiteBuilderShrinker(
+ shrinker -> builder.addFixpointAnalysis(shrinker.createEnqueuerAnalysis()));
+ }
+
private boolean computeEnableAggressiveBuilderOptimization() {
DexClass generatedMessageLiteBuilderClass =
appView
@@ -131,11 +139,11 @@
return true;
}
- public EnqueuerAnalysis createEnqueuerAnalysis() {
+ public FixpointEnqueuerAnalysis createEnqueuerAnalysis() {
Set<DexProgramClass> seen = Sets.newIdentityHashSet();
- return new EnqueuerAnalysis() {
+ return new FixpointEnqueuerAnalysis() {
+
@Override
- @SuppressWarnings("ReferenceEquality")
public void notifyFixpoint(
Enqueuer enqueuer,
EnqueuerWorklist worklist,
@@ -171,7 +179,9 @@
}
superClass.accessFlags.demoteFromAbstract();
- if (superClass.type == references.generatedMessageLiteBuilderType) {
+ if (superClass
+ .getType()
+ .isIdenticalTo(references.generatedMessageLiteBuilderType)) {
// Manually trace `new GeneratedMessageLite.Builder(DEFAULT_INSTANCE)` since we
// haven't rewritten the code yet.
worklist.enqueueTraceNewInstanceAction(
@@ -181,7 +191,9 @@
dynamicMethod,
null);
} else {
- assert superClass.type == references.generatedMessageLiteExtendableBuilderType;
+ assert superClass
+ .getType()
+ .isIdenticalTo(references.generatedMessageLiteExtendableBuilderType);
// Manually trace `new GeneratedMessageLite.ExtendableBuilder(DEFAULT_INSTANCE)`
// since we haven't rewritten the code yet.
worklist.enqueueTraceNewInstanceAction(
@@ -200,7 +212,6 @@
}
/** Returns true if an action was deferred. */
- @SuppressWarnings("ReferenceEquality")
public boolean deferDeadProtoBuilders(
DexProgramClass clazz, ProgramMethod method, BooleanSupplier register) {
if (!enableAggressiveBuilderOptimization) {
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 0ce0317..b2b08f0 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
@@ -19,7 +19,10 @@
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysisCollection;
+import com.android.tools.r8.graph.analysis.FixpointEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyLiveClassEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyLiveMethodEnqueuerAnalysis;
import com.android.tools.r8.ir.analysis.proto.GeneratedMessageLiteShrinker;
import com.android.tools.r8.ir.analysis.proto.ProtoEnqueuerUseRegistry;
import com.android.tools.r8.ir.analysis.proto.ProtoReferences;
@@ -64,7 +67,10 @@
// TODO(b/112437944): Handle incomplete information about extensions + add a test that fails with
// the current implementation. If there are some extensions that cannot be resolved, then we should
// keep fields that could reach extensions to be conservative.
-public class ProtoEnqueuerExtension extends EnqueuerAnalysis {
+public class ProtoEnqueuerExtension
+ implements NewlyLiveClassEnqueuerAnalysis,
+ NewlyLiveMethodEnqueuerAnalysis,
+ FixpointEnqueuerAnalysis {
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final RawMessageInfoDecoder decoder;
@@ -103,6 +109,18 @@
this.references = protoShrinker.references;
}
+ public static void register(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ EnqueuerAnalysisCollection.Builder builder) {
+ if (appView.options().protoShrinking().enableGeneratedMessageLiteShrinking) {
+ ProtoEnqueuerExtension analysis = new ProtoEnqueuerExtension(appView);
+ builder
+ .addNewlyLiveClassAnalysis(analysis)
+ .addNewlyLiveMethodAnalysis(analysis)
+ .addFixpointAnalysis(analysis);
+ }
+ }
+
@Override
public void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) {
assert appView.appInfo().hasClassHierarchy();
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
index e583aea..26a1258 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -8,6 +8,7 @@
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassResolutionResult;
import com.android.tools.r8.graph.DexClass;
@@ -20,17 +21,19 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.ProgramDefinition;
-import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysisCollection;
+import com.android.tools.r8.graph.analysis.FinishedEnqueuerAnalysis;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.Enqueuer.EnqueuerDefinitionSupplier;
import com.android.tools.r8.shaking.KeepClassInfo;
+import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
-public class KotlinMetadataEnqueuerExtension extends EnqueuerAnalysis {
+public class KotlinMetadataEnqueuerExtension implements FinishedEnqueuerAnalysis {
private static final OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
@@ -48,6 +51,23 @@
this.prunedTypes = prunedTypes;
}
+ public static void register(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ EnqueuerDefinitionSupplier enqueuerDefinitionSupplier,
+ Set<DexType> initialPrunedTypes,
+ EnqueuerAnalysisCollection.Builder builder) {
+ // TODO(b/323816623): This check does not include presence of keep declarations.
+ // The non-presense of PG config seems like a exeedingly rare corner case so maybe just
+ // make this conditional on tree shaking and the specific option flag.
+ InternalOptions options = appView.options();
+ if (options.hasProguardConfiguration()
+ && !options.kotlinOptimizationOptions().disableKotlinSpecificOptimizations) {
+ builder.addFinishedAnalysis(
+ new KotlinMetadataEnqueuerExtension(
+ appView, enqueuerDefinitionSupplier, initialPrunedTypes));
+ }
+ }
+
private KotlinMetadataDefinitionSupplier definitionsForContext(ProgramDefinition context) {
return new KotlinMetadataDefinitionSupplier(context, enqueuerDefinitionSupplier, prunedTypes);
}
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 96be3c1..be7b139 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -90,19 +90,13 @@
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
import com.android.tools.r8.graph.analysis.ApiModelAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerCheckCastAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerConstClassAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerExceptionGuardAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerFieldAccessAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerInstanceOfAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerInvokeAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerNewInstanceAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerTypeAccessAnalysis;
+import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysisCollection;
import com.android.tools.r8.graph.analysis.GetArrayOfMissingTypeVerifyErrorWorkaround;
import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis;
import com.android.tools.r8.graph.analysis.InvokeVirtualToInterfaceVerifyErrorWorkaround;
import com.android.tools.r8.graph.analysis.ResourceAccessAnalysis;
+import com.android.tools.r8.ir.analysis.proto.GeneratedMessageLiteBuilderShrinker;
import com.android.tools.r8.ir.analysis.proto.ProtoEnqueuerUseRegistry;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoEnqueuerExtension;
import com.android.tools.r8.ir.code.ArrayPut;
@@ -187,7 +181,6 @@
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -259,14 +252,7 @@
private final boolean forceProguardCompatibility;
private final Mode mode;
- private final Set<EnqueuerAnalysis> analyses = new LinkedHashSet<>();
- private final Set<EnqueuerFieldAccessAnalysis> fieldAccessAnalyses = new LinkedHashSet<>();
- private final Set<EnqueuerInvokeAnalysis> invokeAnalyses = new LinkedHashSet<>();
- private final Set<EnqueuerInstanceOfAnalysis> instanceOfAnalyses = new LinkedHashSet<>();
- private final Set<EnqueuerExceptionGuardAnalysis> exceptionGuardAnalyses = new LinkedHashSet<>();
- private final Set<EnqueuerCheckCastAnalysis> checkCastAnalyses = new LinkedHashSet<>();
- private final Set<EnqueuerConstClassAnalysis> constClassAnalyses = new LinkedHashSet<>();
- private final Set<EnqueuerNewInstanceAnalysis> newInstanceAnalyses = new LinkedHashSet<>();
+ private final EnqueuerAnalysisCollection analyses;
private final Map<DexProgramClass, Boolean> rClassLookupCache = new IdentityHashMap<>();
@@ -280,8 +266,6 @@
private RootSet rootSet;
private final EnqueuerUseRegistryFactory useRegistryFactory;
private AnnotationRemover.Builder annotationRemoverBuilder;
- private final EnqueuerDefinitionSupplier enqueuerDefinitionSupplier =
- new EnqueuerDefinitionSupplier(this);
private final FieldAccessInfoCollectionImpl fieldAccessInfoCollection =
new FieldAccessInfoCollectionImpl();
@@ -361,7 +345,7 @@
private Set<DexType> initialDeadProtoTypes = Sets.newIdentityHashSet();
/** Set of types that was pruned during the first round of tree shaking. */
- private Set<DexType> initialPrunedTypes;
+ private final Set<DexType> initialPrunedTypes;
private final Set<DexType> noClassMerging = Sets.newIdentityHashSet();
@@ -498,6 +482,26 @@
SubtypingInfo subtypingInfo,
GraphConsumer keptGraphConsumer,
Mode mode) {
+ this(
+ appView,
+ profileCollectionAdditions,
+ executorService,
+ subtypingInfo,
+ keptGraphConsumer,
+ mode,
+ null,
+ null);
+ }
+
+ Enqueuer(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ProfileCollectionAdditions profileCollectionAdditions,
+ ExecutorService executorService,
+ SubtypingInfo subtypingInfo,
+ GraphConsumer keptGraphConsumer,
+ Mode mode,
+ Set<DexType> initialPrunedTypes,
+ RuntimeTypeCheckInfo.Builder runtimeTypeCheckInfoBuilder) {
assert appView.appServices() != null;
InternalOptions options = appView.options();
this.appInfo = appView.appInfo();
@@ -517,25 +521,33 @@
mode.isInitialTreeShaking() && options.forceProguardCompatibility
? ProguardCompatibilityActions.builder()
: null;
+ this.initialPrunedTypes = initialPrunedTypes;
if (options.isOptimizedResourceShrinking()) {
appView.getResourceShrinkerState().setEnqueuerCallback(this::recordReferenceFromResources);
}
+
+ EnqueuerAnalysisCollection.Builder analysesBuilder = EnqueuerAnalysisCollection.builder();
if (mode.isTreeShaking()) {
- InitializedClassesInInstanceMethodsAnalysis.register(appView, this);
- GetArrayOfMissingTypeVerifyErrorWorkaround.register(appView, this);
- InitializedClassesInInstanceMethodsAnalysis.register(appView, this);
- InvokeVirtualToInterfaceVerifyErrorWorkaround.register(appView, this);
- if (options.protoShrinking().enableGeneratedMessageLiteShrinking) {
- registerAnalysis(new ProtoEnqueuerExtension(appView));
- }
- appView.withGeneratedMessageLiteBuilderShrinker(
- shrinker -> registerAnalysis(shrinker.createEnqueuerAnalysis()));
- IsolatedFeatureSplitsChecker.register(appView, this);
- ResourceAccessAnalysis.register(appView, this);
- CovariantReturnTypeEnqueuerExtension.register(appView, this);
+ EnqueuerDefinitionSupplier enqueuerDefinitionSupplier = new EnqueuerDefinitionSupplier(this);
+ ApiModelAnalysis.register(appView, analysesBuilder);
+ ClassInitializerAssertionEnablingAnalysis.register(appView, this, analysesBuilder);
+ CovariantReturnTypeEnqueuerExtension.register(appView, this, analysesBuilder);
+ GeneratedMessageLiteBuilderShrinker.register(appView, analysesBuilder);
+ GenericSignatureEnqueuerAnalysis.register(
+ appView, enqueuerDefinitionSupplier, analysesBuilder);
+ GetArrayOfMissingTypeVerifyErrorWorkaround.register(appView, this, analysesBuilder);
+ IfRuleEvaluatorFactory.register(appView, this, analysesBuilder, executorService);
+ InitializedClassesInInstanceMethodsAnalysis.register(appView, this, analysesBuilder);
+ InvokeVirtualToInterfaceVerifyErrorWorkaround.register(appView, this, analysesBuilder);
+ IsolatedFeatureSplitsChecker.register(appView, analysesBuilder);
+ KotlinMetadataEnqueuerExtension.register(
+ appView, enqueuerDefinitionSupplier, initialPrunedTypes, analysesBuilder);
+ ProtoEnqueuerExtension.register(appView, analysesBuilder);
+ ResourceAccessAnalysis.register(appView, this, analysesBuilder);
+ RuntimeTypeCheckInfo.register(runtimeTypeCheckInfoBuilder, analysesBuilder);
}
- IfRuleEvaluatorFactory.register(appView, this, executorService);
+ analyses = analysesBuilder.build();
targetedMethods = new LiveMethodsSet(graphReporter::registerMethod);
failedClassResolutionTargets = SetUtils.newIdentityHashSet(0);
@@ -586,54 +598,6 @@
return useRegistryFactory;
}
- public Enqueuer registerAnalysis(EnqueuerAnalysis analysis) {
- analyses.add(analysis);
- return this;
- }
-
- public Enqueuer registerFieldAccessAnalysis(EnqueuerFieldAccessAnalysis analysis) {
- fieldAccessAnalyses.add(analysis);
- return this;
- }
-
- public Enqueuer registerInvokeAnalysis(EnqueuerInvokeAnalysis analysis) {
- invokeAnalyses.add(analysis);
- return this;
- }
-
- public Enqueuer registerInstanceOfAnalysis(EnqueuerInstanceOfAnalysis analysis) {
- instanceOfAnalyses.add(analysis);
- return this;
- }
-
- public Enqueuer registerCheckCastAnalysis(EnqueuerCheckCastAnalysis analysis) {
- checkCastAnalyses.add(analysis);
- return this;
- }
-
- public Enqueuer registerConstClassAnalysis(EnqueuerConstClassAnalysis analysis) {
- constClassAnalyses.add(analysis);
- return this;
- }
-
- public Enqueuer registerExceptionGuardAnalysis(EnqueuerExceptionGuardAnalysis analysis) {
- exceptionGuardAnalyses.add(analysis);
- return this;
- }
-
- public Enqueuer registerNewInstanceAnalysis(EnqueuerNewInstanceAnalysis analysis) {
- newInstanceAnalyses.add(analysis);
- return this;
- }
-
- public Enqueuer registerTypeAccessAnalysis(EnqueuerTypeAccessAnalysis analysis) {
- return registerCheckCastAnalysis(analysis)
- .registerConstClassAnalysis(analysis)
- .registerExceptionGuardAnalysis(analysis)
- .registerInstanceOfAnalysis(analysis)
- .registerNewInstanceAnalysis(analysis);
- }
-
public void setKeepDeclarations(List<KeepDeclaration> keepDeclarations) {
// Keep declarations are used during initial tree shaking. Re-runs use the rule instance sets.
assert mode.isInitialTreeShaking();
@@ -650,11 +614,6 @@
this.initialDeadProtoTypes = initialDeadProtoTypes;
}
- public void setInitialPrunedTypes(Set<DexType> initialPrunedTypes) {
- assert mode.isFinalTreeShaking();
- this.initialPrunedTypes = initialPrunedTypes;
- }
-
public void addDeadProtoTypeCandidate(DexType type) {
DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type));
if (clazz != null) {
@@ -897,7 +856,7 @@
// rules.
handleLibraryTypeInheritingFromProgramType(clazz.asLibraryClass());
}
- analyses.forEach(analysis -> analysis.processNewLiveNonProgramType(clazz));
+ analyses.processNewlyLiveNonProgramType(clazz);
clazz.forEachClassField(
field ->
addNonProgramClassToWorklist(
@@ -1191,8 +1150,7 @@
// Notify analyses.
if (field.isProgramField()) {
- ProgramField programField = field.asProgramField();
- analyses.forEach(analysis -> analysis.processNewlyReferencedField(programField));
+ analyses.processNewlyReferencedField(field.asProgramField());
}
}
@@ -1326,12 +1284,12 @@
void traceCheckCast(DexType type, ProgramMethod currentMethod, boolean ignoreCompatRules) {
DexClass clazz = internalTraceConstClassOrCheckCast(type, currentMethod, ignoreCompatRules);
- checkCastAnalyses.forEach(analysis -> analysis.traceCheckCast(type, clazz, currentMethod));
+ analyses.traceCheckCast(type, clazz, currentMethod);
}
void traceSafeCheckCast(DexType type, ProgramMethod currentMethod) {
DexClass clazz = internalTraceConstClassOrCheckCast(type, currentMethod, true);
- checkCastAnalyses.forEach(analysis -> analysis.traceSafeCheckCast(type, clazz, currentMethod));
+ analyses.traceSafeCheckCast(type, clazz, currentMethod);
}
void traceConstClass(
@@ -1341,7 +1299,7 @@
boolean ignoreCompatRules) {
handleLockCandidate(type, currentMethod, iterator);
DexClass clazz = internalTraceConstClassOrCheckCast(type, currentMethod, ignoreCompatRules);
- constClassAnalyses.forEach(analysis -> analysis.traceConstClass(type, clazz, currentMethod));
+ analyses.traceConstClass(type, clazz, currentMethod);
}
private void handleLockCandidate(
@@ -1504,14 +1462,13 @@
void traceInstanceOf(DexType type, ProgramMethod currentMethod) {
DexClass clazz = resolveBaseType(type, currentMethod);
traceTypeReference(type, currentMethod);
- instanceOfAnalyses.forEach(analysis -> analysis.traceInstanceOf(type, clazz, currentMethod));
+ analyses.traceInstanceOf(type, clazz, currentMethod);
}
void traceExceptionGuard(DexType type, ProgramMethod currentMethod) {
DexClass clazz = resolveBaseType(type, currentMethod);
traceTypeReference(type, currentMethod);
- exceptionGuardAnalyses.forEach(
- analysis -> analysis.traceExceptionGuard(type, clazz, currentMethod));
+ analyses.traceExceptionGuard(type, clazz, currentMethod);
}
void traceInvokeDirect(
@@ -1560,8 +1517,7 @@
markTypeAsLive(invokedMethod.getHolderType(), context);
MethodResolutionResult resolutionResult =
handleInvokeOfDirectTarget(invokedMethod, context, reason);
- invokeAnalyses.forEach(
- analysis -> analysis.traceInvokeDirect(invokedMethod, resolutionResult, context));
+ analyses.traceInvokeDirect(invokedMethod, resolutionResult, context);
}
void traceInvokeInterface(
@@ -1586,8 +1542,7 @@
markTypeAsLive(invokedMethod.getHolderType(), context);
MethodResolutionResult result =
markVirtualMethodAsReachable(invokedMethod, true, context, keepReason);
- invokeAnalyses.forEach(
- analysis -> analysis.traceInvokeInterface(invokedMethod, result, context));
+ analyses.traceInvokeInterface(invokedMethod, result, context);
}
void traceInvokeStatic(
@@ -1632,8 +1587,7 @@
markTypeAsLive(invokedMethod.getHolderType(), context);
MethodResolutionResult resolutionResult =
handleInvokeOfStaticTarget(invokedMethod, context, reason);
- invokeAnalyses.forEach(
- analysis -> analysis.traceInvokeStatic(invokedMethod, resolutionResult, context));
+ analyses.traceInvokeStatic(invokedMethod, resolutionResult, context);
}
void traceInvokeSuper(
@@ -1679,8 +1633,7 @@
markTypeAsLive(invokedMethod.getHolderType(), context);
MethodResolutionResult resolutionResult =
markVirtualMethodAsReachable(invokedMethod, false, context, reason);
- invokeAnalyses.forEach(
- analysis -> analysis.traceInvokeVirtual(invokedMethod, resolutionResult, context));
+ analyses.traceInvokeVirtual(invokedMethod, resolutionResult, context);
}
void traceMethodPosition(com.android.tools.r8.ir.code.Position position, ProgramMethod context) {
@@ -1729,7 +1682,7 @@
context,
InstantiationReason.NEW_INSTANCE_INSTRUCTION,
KeepReason.instantiatedIn(context));
- newInstanceAnalyses.forEach(analysis -> analysis.traceNewInstance(type, clazz, context));
+ analyses.traceNewInstance(type, clazz, context);
}
void traceNewInstanceFromLambda(DexType type, ProgramMethod context) {
@@ -1880,10 +1833,8 @@
resolutionResult.visitFieldResolutionResults(
singleResolutionResult -> {
- fieldAccessAnalyses.forEach(
- analysis ->
- analysis.traceInstanceFieldRead(
- fieldReference, singleResolutionResult, currentMethod, worklist));
+ analyses.traceInstanceFieldRead(
+ fieldReference, singleResolutionResult, currentMethod, worklist);
ProgramField field = singleResolutionResult.getProgramField();
if (field == null) {
@@ -1946,10 +1897,8 @@
resolutionResult.visitFieldResolutionResults(
singleResolutionResult -> {
- fieldAccessAnalyses.forEach(
- analysis ->
- analysis.traceInstanceFieldWrite(
- fieldReference, singleResolutionResult, currentMethod, worklist));
+ analyses.traceInstanceFieldWrite(
+ fieldReference, singleResolutionResult, currentMethod, worklist);
ProgramField field = singleResolutionResult.getProgramField();
if (field == null) {
@@ -2025,10 +1974,8 @@
resolutionResult.visitFieldResolutionResults(
singleResolutionResult -> {
- fieldAccessAnalyses.forEach(
- analysis ->
- analysis.traceStaticFieldRead(
- fieldReference, singleResolutionResult, currentMethod, worklist));
+ analyses.traceStaticFieldRead(
+ fieldReference, singleResolutionResult, currentMethod, worklist);
ProgramField field = singleResolutionResult.getProgramField();
if (field == null) {
@@ -2115,10 +2062,8 @@
resolutionResult.visitFieldResolutionResults(
singleResolutionResult -> {
- fieldAccessAnalyses.forEach(
- analysis ->
- analysis.traceStaticFieldWrite(
- fieldReference, singleResolutionResult, currentMethod, worklist));
+ analyses.traceStaticFieldWrite(
+ fieldReference, singleResolutionResult, currentMethod, worklist);
ProgramField field = singleResolutionResult.getProgramField();
if (field == null) {
@@ -2362,7 +2307,7 @@
compatEnqueueHolderIfDependentNonStaticMember(
clazz, rootSet.getDependentKeepClassCompatRule(clazz.getType()));
- analyses.forEach(analysis -> analysis.processNewlyLiveClass(clazz, worklist));
+ analyses.processNewlyLiveClass(clazz, worklist);
}
private void processDeferredAnnotations(
@@ -2950,9 +2895,7 @@
// Notify analyses. This is done even if `clazz` has already been marked as instantiated,
// because each analysis may depend on seeing all the (clazz, reason) pairs. Thus, not doing so
// could lead to nondeterminism.
- analyses.forEach(
- analysis ->
- analysis.processNewlyInstantiatedClass(clazz.asProgramClass(), context, worklist));
+ analyses.processNewlyInstantiatedClass(clazz.asProgramClass(), context, worklist);
if (!markInstantiatedClass(clazz, context, instantiationReason, keepReason)) {
return;
@@ -3363,7 +3306,7 @@
}
// Notify analyses.
- analyses.forEach(analysis -> analysis.processNewlyLiveField(field, context, worklist));
+ analyses.processNewlyLiveField(field, context, worklist);
}
// Package protected due to entry point from worklist.
@@ -3391,7 +3334,7 @@
addEffectivelyLiveOriginalField(field);
traceFieldDefinition(field);
- analyses.forEach(analysis -> analysis.notifyMarkFieldAsReachable(field, worklist));
+ analyses.processNewlyReachableField(field, worklist);
}
private void handleFieldAccessWithInaccessibleFieldType(
@@ -3672,7 +3615,6 @@
target.accept(
method -> markVirtualDispatchMethodTargetAsLive(method, reason),
lambda -> markVirtualDispatchLambdaTargetAsLive(lambda, reason));
- analyses.forEach(analysis -> analysis.notifyMarkVirtualDispatchTargetAsLive(target, worklist));
}
private void markVirtualDispatchMethodTargetAsLive(
@@ -3804,10 +3746,8 @@
resolution.lookupInvokeSuperTarget(context.getHolder(), appView);
if (target == null) {
failedMethodResolutionTargets.add(resolution.getResolvedMethod().getReference());
- analyses.forEach(
- analyses ->
- analyses.notifyFailedMethodResolutionTarget(
- resolution.getResolvedMethod(), worklist));
+ analyses.processNewlyFailedMethodResolutionTarget(
+ resolution.getResolvedMethod(), worklist);
return;
}
@@ -3829,8 +3769,7 @@
}
}
});
- invokeAnalyses.forEach(
- analysis -> analysis.traceInvokeSuper(reference, resolutionResults, context));
+ analyses.traceInvokeSuper(reference, resolutionResults, context);
}
public boolean isRClass(DexProgramClass dexProgramClass) {
@@ -3867,29 +3806,6 @@
RootSet rootSet, ExecutorService executorService, Timing timing) throws ExecutionException {
this.rootSet = rootSet;
rootSet.pendingMethodMoveInverse.forEach(pendingMethodMoveInverse::put);
- // Translate the result of root-set computation into enqueuer actions.
- timing.begin("Register analysis");
- // TODO(b/323816623): This check does not include presence of keep declarations.
- // The non-presense of PG config seems like a exeedingly rare corner case so maybe just
- // make this conditional on tree shaking and the specific option flag.
- if (mode.isTreeShaking()
- && appView.options().hasProguardConfiguration()
- && !options.kotlinOptimizationOptions().disableKotlinSpecificOptimizations) {
- registerAnalysis(
- new KotlinMetadataEnqueuerExtension(
- appView, enqueuerDefinitionSupplier, initialPrunedTypes));
- }
- // TODO(b/323816623): This check does not include presence of keep declarations.
- // We should consider if we should always run the signature analysis and just not emit them
- // in the end?
- if (appView.options().getProguardConfiguration() != null
- && appView.options().getProguardConfiguration().getKeepAttributes().signature) {
- registerAnalysis(new GenericSignatureEnqueuerAnalysis(enqueuerDefinitionSupplier));
- }
- if (options.apiModelingOptions().enableLibraryApiModeling) {
- registerAnalysis(new ApiModelAnalysis(appView));
- }
- timing.end();
// Transfer the minimum keep info from the root set into the Enqueuer state.
timing.begin("Transfer minimum keep info");
@@ -3935,8 +3851,7 @@
finalizeLibraryMethodOverrideInformation();
timing.end();
timing.begin("Finish analysis");
- analyses.forEach(analyses -> analyses.done(this));
- fieldAccessAnalyses.forEach(fieldAccessAnalyses -> fieldAccessAnalyses.done(this));
+ analyses.done(this);
if (appView.options().isOptimizedResourceShrinking()) {
appView.getResourceShrinkerState().enqueuerDone(this.mode.isFinalTreeShaking());
}
@@ -4770,9 +4685,7 @@
// Notify each analysis that a fixpoint has been reached, and give each analysis an
// opportunity to add items to the worklist.
- for (EnqueuerAnalysis analysis : analyses) {
- analysis.notifyFixpoint(this, worklist, executorService, timing);
- }
+ analyses.notifyFixpoint(this, worklist, executorService, timing);
if (!worklist.isEmpty()) {
continue;
}
@@ -5069,8 +4982,7 @@
}
}
- // Notify analyses.
- analyses.forEach(analysis -> analysis.processNewlyLiveMethod(method, context, this, worklist));
+ analyses.processNewlyLiveMethod(method, context, this, worklist);
}
private void markMethodAsTargeted(ProgramMethod method, KeepReason reason) {
@@ -5090,7 +5002,7 @@
markMethodAsLiveWithCompatRule(method);
}
}
- analyses.forEach(analysis -> analysis.processNewlyTargetedMethod(method, worklist));
+ analyses.processNewlyTargetedMethod(method, worklist);
}
void traceMethodDefinitionExcludingCode(ProgramMethod method) {
@@ -5124,8 +5036,7 @@
DefaultEnqueuerUseRegistry registry =
useRegistryFactory.create(appView, method, this, appView.apiLevelCompute());
method.registerCodeReferences(registry);
- // Notify analyses.
- analyses.forEach(analysis -> analysis.processTracedCode(method, registry, worklist));
+ analyses.processNewlyLiveCode(method, registry, worklist);
}
private void markReferencedTypesAsLive(ProgramMethod method) {
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerFactory.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerFactory.java
index e5f90c2..09ea894 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerFactory.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerFactory.java
@@ -35,7 +35,8 @@
ExecutorService executorService,
SubtypingInfo subtypingInfo,
GraphConsumer keptGraphConsumer,
- Set<DexType> initialPrunedTypes) {
+ Set<DexType> initialPrunedTypes,
+ RuntimeTypeCheckInfo.Builder runtimeTypeCheckInfoBuilder) {
ProfileCollectionAdditions profileCollectionAdditions =
ProfileCollectionAdditions.create(appView);
Enqueuer enqueuer =
@@ -45,10 +46,11 @@
executorService,
subtypingInfo,
keptGraphConsumer,
- Mode.FINAL_TREE_SHAKING);
+ Mode.FINAL_TREE_SHAKING,
+ initialPrunedTypes,
+ runtimeTypeCheckInfoBuilder);
appView.withProtoShrinker(
shrinker -> enqueuer.setInitialDeadProtoTypes(shrinker.getDeadProtoTypes()));
- enqueuer.setInitialPrunedTypes(initialPrunedTypes);
return enqueuer;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
index 9fe386a..497f691 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
@@ -14,7 +14,13 @@
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysisCollection;
+import com.android.tools.r8.graph.analysis.FixpointEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyLiveClassEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyLiveFieldEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyLiveMethodEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyReferencedFieldEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.NewlyTargetedMethodEnqueuerAnalysis;
import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSet;
import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSetBuilder;
import com.android.tools.r8.threading.TaskCollection;
@@ -30,7 +36,13 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-public class IfRuleEvaluatorFactory extends EnqueuerAnalysis {
+public class IfRuleEvaluatorFactory
+ implements NewlyLiveClassEnqueuerAnalysis,
+ NewlyLiveFieldEnqueuerAnalysis,
+ NewlyLiveMethodEnqueuerAnalysis,
+ NewlyReferencedFieldEnqueuerAnalysis,
+ NewlyTargetedMethodEnqueuerAnalysis,
+ FixpointEnqueuerAnalysis {
private final AppView<? extends AppInfoWithClassHierarchy> appView;
@@ -61,11 +73,20 @@
public static void register(
AppView<? extends AppInfoWithClassHierarchy> appView,
Enqueuer enqueuer,
+ EnqueuerAnalysisCollection.Builder builder,
ExecutorService executorService) {
Set<ProguardIfRule> ifRules =
appView.hasRootSet() ? appView.rootSet().ifRules : Collections.emptySet();
if (ifRules != null && !ifRules.isEmpty()) {
- enqueuer.registerAnalysis(new IfRuleEvaluatorFactory(appView, enqueuer, executorService));
+ IfRuleEvaluatorFactory factory =
+ new IfRuleEvaluatorFactory(appView, enqueuer, executorService);
+ builder
+ .addNewlyLiveClassAnalysis(factory)
+ .addNewlyLiveFieldAnalysis(factory)
+ .addNewlyLiveMethodAnalysis(factory)
+ .addNewlyReferencedFieldAnalysis(factory)
+ .addNewlyTargetedMethodAnalysis(factory)
+ .addFixpointAnalysis(factory);
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RuntimeTypeCheckInfo.java b/src/main/java/com/android/tools/r8/shaking/RuntimeTypeCheckInfo.java
index 045227d..705edd8 100644
--- a/src/main/java/com/android/tools/r8/shaking/RuntimeTypeCheckInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/RuntimeTypeCheckInfo.java
@@ -10,9 +10,10 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.analysis.EnqueuerCheckCastAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerExceptionGuardAnalysis;
-import com.android.tools.r8.graph.analysis.EnqueuerInstanceOfAnalysis;
+import com.android.tools.r8.graph.analysis.EnqueuerAnalysisCollection;
+import com.android.tools.r8.graph.analysis.TraceCheckCastEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.TraceExceptionGuardEnqueuerAnalysis;
+import com.android.tools.r8.graph.analysis.TraceInstanceOfEnqueuerAnalysis;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
import com.android.tools.r8.utils.SetUtils;
@@ -33,6 +34,15 @@
this.exceptionGuardTypes = exceptionGuardTypes;
}
+ public static void register(Builder builder, EnqueuerAnalysisCollection.Builder analysesBuilder) {
+ if (builder != null) {
+ analysesBuilder
+ .addTraceCheckCastAnalysis(builder)
+ .addTraceExceptionGuardAnalysis(builder)
+ .addTraceInstanceOfAnalysis(builder);
+ }
+ }
+
public boolean isCheckCastType(DexProgramClass clazz) {
return checkCastTypes.contains(clazz.type);
}
@@ -59,9 +69,9 @@
}
public static class Builder
- implements EnqueuerInstanceOfAnalysis,
- EnqueuerCheckCastAnalysis,
- EnqueuerExceptionGuardAnalysis {
+ implements TraceInstanceOfEnqueuerAnalysis,
+ TraceCheckCastEnqueuerAnalysis,
+ TraceExceptionGuardEnqueuerAnalysis {
private final GraphLens appliedGraphLens;
private final DexItemFactory factory;
@@ -109,12 +119,5 @@
set.add(baseType);
}
}
-
- public void attach(Enqueuer enqueuer) {
- enqueuer
- .registerInstanceOfAnalysis(this)
- .registerCheckCastAnalysis(this)
- .registerExceptionGuardAnalysis(this);
- }
}
}
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 0462ec8..29bab19 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -941,8 +941,7 @@
* If any non-static class merging is enabled, information about types referred to by instanceOf
* and check cast instructions needs to be collected.
*/
- public boolean isClassMergingExtensionRequired(Enqueuer.Mode mode) {
- assert mode.isFinalTreeShaking();
+ public boolean isClassMergingExtensionRequired() {
WholeProgramOptimizations wholeProgramOptimizations = WholeProgramOptimizations.ON;
return horizontalClassMergerOptions.isEnabled(wholeProgramOptimizations)
&& !horizontalClassMergerOptions.isRestrictedToSynthetics();