[KeepAnno] Add tracing of inlining positions
Bug: b/325014359
Bug: b/323816623
Change-Id: Ica289493398558365d7322a092adc1dcddc3a067
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index d7d1b0b..6238dd5 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.utils.TraversalContinuation;
import java.util.ListIterator;
@@ -60,6 +61,10 @@
return continuation;
}
+ public void registerInliningPosition(Position position) {
+ assert position.hasCallerPosition();
+ }
+
public void registerRecordFieldValues(DexField[] fields) {
registerTypeReference(appView.dexItemFactory().objectArrayType);
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirCode.java b/src/main/java/com/android/tools/r8/lightir/LirCode.java
index 6f93b21..5090346 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirCode.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirCode.java
@@ -585,6 +585,11 @@
@Override
public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
assert registry.getTraversalContinuation().shouldContinue();
+ for (PositionEntry positionEntry : positionTable) {
+ if (positionEntry instanceof StructuredPositionEntry) {
+ registry.registerInliningPosition(((StructuredPositionEntry) positionEntry).position);
+ }
+ }
LirUseRegistryCallback<EV> registryCallbacks = new LirUseRegistryCallback<>(this, registry);
for (LirInstructionView view : this) {
if (metadataMap != null) {
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
index 736f285..dd975f7 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -19,6 +19,7 @@
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.ir.code.Position;
import java.util.ListIterator;
public class DefaultEnqueuerUseRegistry extends ComputeApiLevelUseRegistry {
@@ -45,6 +46,12 @@
}
@Override
+ public void registerInliningPosition(Position position) {
+ super.registerInliningPosition(position);
+ enqueuer.traceMethodPosition(position, getContext());
+ }
+
+ @Override
public void registerInitClass(DexType clazz) {
super.registerInitClass(clazz);
enqueuer.traceInitClass(clazz, getContext());
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 0dfda11..1d2e7b8 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -131,7 +131,6 @@
import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringLookupResult;
import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringTypeLookupResult;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.position.Position;
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.shaking.AnnotationMatchResult.MatchedAnnotation;
import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction;
@@ -315,6 +314,10 @@
*/
private final SetWithReportedReason<DexProgramClass> liveTypes = new SetWithReportedReason<>();
+ /** Set of effectively live items from the original program. */
+ // TODO(b/323816623): Add reason tracking.
+ private final Set<DexReference> effectivelyLiveOriginalReferences = SetUtils.newIdentityHashSet();
+
/** Set of interfaces that have been transitioned to being instantiated indirectly. */
private final Set<DexProgramClass> interfacesTransitionedToInstantiated =
Sets.newIdentityHashSet();
@@ -1631,6 +1634,27 @@
analysis -> analysis.traceInvokeVirtual(invokedMethod, resolutionResult, context));
}
+ void traceMethodPosition(com.android.tools.r8.ir.code.Position position, ProgramMethod context) {
+ if (!options.testing.enableExtractedKeepAnnotations) {
+ // Currently inlining is only intended for the evaluation of keep annotation edges.
+ return;
+ }
+ while (position.hasCallerPosition()) {
+ // Any inner position should not be non-synthetic user methods.
+ assert !position.isD8R8Synthesized();
+ DexMethod method = position.getMethod();
+ // TODO(b/325014359): It might be reasonable to reduce this map size by tracking which methods
+ // actually are used in preconditions.
+ if (effectivelyLiveOriginalReferences.add(method)) {
+ effectivelyLiveOriginalReferences.add(method.getHolderType());
+ }
+ position = position.getCallerPosition();
+ }
+ // The outer-most position should be equal to the context.
+ // No need to trace this as the method is already traced since it is invoked.
+ assert context.getReference().isIdenticalTo(position.getMethod());
+ }
+
void traceNewInstance(DexType type, ProgramMethod context) {
boolean skipTracing =
registerDeferredActionForDeadProtoBuilder(
@@ -3402,6 +3426,35 @@
return liveTypes.contains(clazz);
}
+ public boolean isEffectivelyLive(DexProgramClass clazz) {
+ if (isTypeLive(clazz)) {
+ return true;
+ }
+ if (mode.isInitialTreeShaking()) {
+ return false;
+ }
+ // TODO(b/325014359): Replace this by value tracking in instructions (akin to resource values).
+ for (DexEncodedField field : clazz.fields()) {
+ if (field.getOptimizationInfo().valueHasBeenPropagated()) {
+ return true;
+ }
+ }
+ // TODO(b/325014359): Replace this by value or position tracking.
+ // We need to be careful not to throw away such values/positions.
+ for (DexEncodedMethod method : clazz.methods()) {
+ if (method.getOptimizationInfo().returnValueHasBeenPropagated()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isOriginalReferenceEffectivelyLive(DexReference reference) {
+ // The effectively-live original set contains types, fields and methods witnessed by
+ // instructions, such as method inlining positions.
+ return effectivelyLiveOriginalReferences.contains(reference);
+ }
+
public boolean isNonProgramTypeLive(DexClass clazz) {
assert !clazz.isProgramClass();
return liveNonProgramTypes.contains(clazz);
@@ -4671,7 +4724,7 @@
context,
new InterfaceDesugarMissingTypeDiagnostic(
context.getOrigin(),
- Position.UNKNOWN,
+ com.android.tools.r8.position.Position.UNKNOWN,
missing.asClassReference(),
context.getType().asClassReference(),
null)));
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
index 933cc33..32ec312 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexDefinition;
import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexReference;
@@ -178,23 +177,7 @@
}
private boolean isEffectivelyLive(DexProgramClass clazz) {
- // A type is effectively live if (1) it is truly live, (2) the value of one of its fields has
- // been inlined by the member value propagation, or (3) the return value of one of its methods
- // has been forwarded by the member value propagation.
- if (enqueuer.isTypeLive(clazz)) {
- return true;
- }
- for (DexEncodedField field : clazz.fields()) {
- if (field.getOptimizationInfo().valueHasBeenPropagated()) {
- return true;
- }
- }
- for (DexEncodedMethod method : clazz.methods()) {
- if (method.getOptimizationInfo().returnValueHasBeenPropagated()) {
- return true;
- }
- }
- return false;
+ return enqueuer.isEffectivelyLive(clazz);
}
/** Determines if {@param clazz} satisfies the given if-rule class specification. */