Share tracing for fields in Enqueuer
Change-Id: I01281a4b528c6bbc6b9818ffd4c01ddb78f2beee
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
index 39aa866..6e6c326 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AbstractAccessContexts.ConcreteAccessContexts;
import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.shaking.Enqueuer.FieldAccessKind;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
@@ -265,6 +266,14 @@
return (flags & FLAG_IS_READ_FROM_METHOD_HANDLE) != 0;
}
+ public void setAccessedFromMethodHandle(FieldAccessKind accessKind) {
+ if (accessKind.isRead()) {
+ setReadFromMethodHandle();
+ } else {
+ setWrittenFromMethodHandle();
+ }
+ }
+
public void setReadFromMethodHandle() {
flags |= FLAG_IS_READ_FROM_METHOD_HANDLE;
}
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
index 4873046..babfa95 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysisCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysisCollection.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph.analysis;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -18,6 +19,7 @@
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.Enqueuer.FieldAccessKind;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.Timing;
@@ -152,6 +154,30 @@
}
}
+ public void traceFieldAccess(
+ DexField field,
+ SingleFieldResolutionResult<?> resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist,
+ FieldAccessKind accessKind) {
+ switch (accessKind) {
+ case INSTANCE_READ:
+ traceInstanceFieldRead(field, resolutionResult, context, worklist);
+ break;
+ case INSTANCE_WRITE:
+ traceInstanceFieldWrite(field, resolutionResult, context, worklist);
+ break;
+ case STATIC_READ:
+ traceStaticFieldRead(field, resolutionResult, context, worklist);
+ break;
+ case STATIC_WRITE:
+ traceStaticFieldWrite(field, resolutionResult, context, worklist);
+ break;
+ default:
+ throw new Unreachable();
+ }
+ }
+
public void traceInstanceFieldRead(
DexField field,
FieldResolutionResult resolutionResult,
@@ -164,7 +190,7 @@
public void traceInstanceFieldWrite(
DexField field,
- FieldResolutionResult resolutionResult,
+ SingleFieldResolutionResult<?> resolutionResult,
ProgramMethod context,
EnqueuerWorklist worklist) {
for (TraceFieldAccessEnqueuerAnalysis analysis : fieldAccessAnalyses) {
@@ -184,7 +210,7 @@
public void traceStaticFieldWrite(
DexField field,
- FieldResolutionResult resolutionResult,
+ SingleFieldResolutionResult<?> resolutionResult,
ProgramMethod context,
EnqueuerWorklist worklist) {
for (TraceFieldAccessEnqueuerAnalysis analysis : fieldAccessAnalyses) {
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 4baf2a5..6dcfe4f 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1117,6 +1117,15 @@
// traversals.
//
+ public boolean registerFieldAccess(
+ DexField field, ProgramMethod context, FieldAccessKind accessKind) {
+ if (accessKind.isRead()) {
+ registerFieldRead(field, context);
+ } else {
+ registerFieldWrite(field, context);
+ }
+ }
+
public boolean registerFieldRead(DexField field, ProgramMethod context) {
return registerFieldAccess(field, context, true, false);
}
@@ -1758,13 +1767,13 @@
traceInstanceFieldRead(field, currentMethod, FieldAccessMetadata.FROM_RECORD_METHOD_HANDLE);
}
- enum FieldAccessKind {
+ public enum FieldAccessKind {
INSTANCE_READ,
INSTANCE_WRITE,
STATIC_READ,
STATIC_WRITE;
- boolean isRead() {
+ public boolean isRead() {
return this == INSTANCE_READ || this == STATIC_READ;
}
@@ -1855,61 +1864,10 @@
}
}
- @SuppressWarnings("ReferenceEquality")
void traceInstanceFieldRead(
DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
- if (!metadata.isDeferred() && !registerFieldRead(fieldReference, currentMethod)) {
- return;
- }
-
- FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
- if (deferredTracing.deferTracingOfFieldAccess(
- fieldReference, resolutionResult, currentMethod, FieldAccessKind.INSTANCE_READ, metadata)) {
- assert !metadata.isDeferred();
- return;
- }
-
- resolutionResult.visitFieldResolutionResults(
- singleResolutionResult -> {
- analyses.traceInstanceFieldRead(
- fieldReference, singleResolutionResult, currentMethod, worklist);
-
- DexClassAndField classField = singleResolutionResult.getResolutionPair();
- assert classField != null;
-
- DexClass initialResolutionHolder = singleResolutionResult.getInitialResolutionHolder();
- if (initialResolutionHolder != classField.getHolder()) {
- // Mark the initial resolution holder as live. Note that this should only be done if
- // the field is not a dead proto field (in which case we bail-out above).
- markTypeAsLive(initialResolutionHolder, currentMethod);
- }
-
- ProgramField field = classField.asProgramField();
- if (field == null) {
- // No need to trace into the non-program code.
- return;
- }
-
- assert !mode.isFinalTreeShaking() || !field.getDefinition().getOptimizationInfo().isDead()
- : "Unexpected reference in `"
- + currentMethod.toSourceString()
- + "` to field marked dead: "
- + field.getReference().toSourceString();
-
- if (metadata.isFromMethodHandle()) {
- fieldAccessInfoCollection.get(field.getReference()).setReadFromMethodHandle();
- } else if (metadata.isFromRecordMethodHandle()) {
- fieldAccessInfoCollection.get(field.getReference()).setReadFromRecordInvokeDynamic();
- }
-
- worklist.enqueueMarkFieldAsReachableAction(
- field, currentMethod, KeepReason.fieldReferencedIn(currentMethod));
- },
- failedResolution -> {
- // Must trace the types from the field reference even if it does not exist.
- traceFieldReference(fieldReference, currentMethod);
- noClassMerging.add(fieldReference.getHolderType());
- });
+ traceInstanceFieldAccess(
+ fieldReference, currentMethod, FieldAccessKind.INSTANCE_READ, metadata);
}
void traceInstanceFieldWrite(DexField field, ProgramMethod currentMethod) {
@@ -1920,28 +1878,32 @@
traceInstanceFieldWrite(field, currentMethod, FieldAccessMetadata.FROM_METHOD_HANDLE);
}
- @SuppressWarnings("ReferenceEquality")
void traceInstanceFieldWrite(
DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
- if (!metadata.isDeferred() && !registerFieldWrite(fieldReference, currentMethod)) {
+ traceInstanceFieldAccess(
+ fieldReference, currentMethod, FieldAccessKind.INSTANCE_WRITE, metadata);
+ }
+
+ private void traceInstanceFieldAccess(
+ DexField fieldReference,
+ ProgramMethod currentMethod,
+ FieldAccessKind accessKind,
+ FieldAccessMetadata metadata) {
+ if (!metadata.isDeferred() && !registerFieldAccess(fieldReference, currentMethod, accessKind)) {
return;
}
FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
if (deferredTracing.deferTracingOfFieldAccess(
- fieldReference,
- resolutionResult,
- currentMethod,
- FieldAccessKind.INSTANCE_WRITE,
- metadata)) {
+ fieldReference, resolutionResult, currentMethod, accessKind, metadata)) {
assert !metadata.isDeferred();
return;
}
resolutionResult.visitFieldResolutionResults(
singleResolutionResult -> {
- analyses.traceInstanceFieldWrite(
- fieldReference, singleResolutionResult, currentMethod, worklist);
+ analyses.traceFieldAccess(
+ fieldReference, singleResolutionResult, currentMethod, worklist, accessKind);
DexClassAndField classField = singleResolutionResult.getResolutionPair();
assert classField != null;
@@ -1966,7 +1928,11 @@
+ field.getReference().toSourceString();
if (metadata.isFromMethodHandle()) {
- fieldAccessInfoCollection.get(field.getReference()).setWrittenFromMethodHandle();
+ fieldAccessInfoCollection
+ .get(field.getReference())
+ .setAccessedFromMethodHandle(accessKind);
+ } else if (metadata.isFromRecordMethodHandle() && accessKind.isRead()) {
+ fieldAccessInfoCollection.get(field.getReference()).setReadFromRecordInvokeDynamic();
}
KeepReason reason = KeepReason.fieldReferencedIn(currentMethod);
@@ -1991,10 +1957,30 @@
traceStaticFieldRead(field, currentMethod, FieldAccessMetadata.FROM_SWITCH_METHOD_HANDLE);
}
- @SuppressWarnings("ReferenceEquality")
void traceStaticFieldRead(
DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
- if (!metadata.isDeferred() && !registerFieldRead(fieldReference, currentMethod)) {
+ traceStaticFieldAccess(fieldReference, currentMethod, FieldAccessKind.STATIC_READ, metadata);
+ }
+
+ void traceStaticFieldWrite(DexField field, ProgramMethod currentMethod) {
+ traceStaticFieldWrite(field, currentMethod, FieldAccessMetadata.DEFAULT);
+ }
+
+ void traceStaticFieldWriteFromMethodHandle(DexField field, ProgramMethod currentMethod) {
+ traceStaticFieldWrite(field, currentMethod, FieldAccessMetadata.FROM_METHOD_HANDLE);
+ }
+
+ void traceStaticFieldWrite(
+ DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
+ traceStaticFieldAccess(fieldReference, currentMethod, FieldAccessKind.STATIC_WRITE, metadata);
+ }
+
+ private void traceStaticFieldAccess(
+ DexField fieldReference,
+ ProgramMethod currentMethod,
+ FieldAccessKind accessKind,
+ FieldAccessMetadata metadata) {
+ if (!metadata.isDeferred() && !registerFieldAccess(fieldReference, currentMethod, accessKind)) {
return;
}
@@ -2015,15 +2001,15 @@
}
if (deferredTracing.deferTracingOfFieldAccess(
- fieldReference, resolutionResult, currentMethod, FieldAccessKind.STATIC_READ, metadata)) {
+ fieldReference, resolutionResult, currentMethod, accessKind, metadata)) {
assert !metadata.isDeferred();
return;
}
resolutionResult.visitFieldResolutionResults(
singleResolutionResult -> {
- analyses.traceStaticFieldRead(
- fieldReference, singleResolutionResult, currentMethod, worklist);
+ analyses.traceFieldAccess(
+ fieldReference, singleResolutionResult, currentMethod, worklist, accessKind);
DexClassAndField classField = singleResolutionResult.getResolutionPair();
assert classField != null;
@@ -2048,8 +2034,11 @@
+ field.getReference().toSourceString();
if (metadata.isFromMethodHandle()) {
- fieldAccessInfoCollection.get(field.getReference()).setReadFromMethodHandle();
+ fieldAccessInfoCollection
+ .get(field.getReference())
+ .setAccessedFromMethodHandle(accessKind);
} else if (metadata.isFromSwitchMethodHandle()) {
+ assert accessKind.isRead();
// TODO(b/340187630): This disables any optimization on such enum fields. We could
// support rewriting fields in switch method handles instead.
keepInfo.joinClass(
@@ -2074,83 +2063,6 @@
});
}
- void traceStaticFieldWrite(DexField field, ProgramMethod currentMethod) {
- traceStaticFieldWrite(field, currentMethod, FieldAccessMetadata.DEFAULT);
- }
-
- void traceStaticFieldWriteFromMethodHandle(DexField field, ProgramMethod currentMethod) {
- traceStaticFieldWrite(field, currentMethod, FieldAccessMetadata.FROM_METHOD_HANDLE);
- }
-
- @SuppressWarnings("ReferenceEquality")
- void traceStaticFieldWrite(
- DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
- if (!metadata.isDeferred() && !registerFieldWrite(fieldReference, currentMethod)) {
- return;
- }
-
- FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
-
- if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
- // If it is a dead proto extension field, don't trace onwards.
- boolean skipTracing =
- appView.withGeneratedExtensionRegistryShrinker(
- shrinker ->
- shrinker.isDeadProtoExtensionField(
- resolutionResult, fieldAccessInfoCollection, keepInfo),
- false);
- if (skipTracing) {
- addDeadProtoTypeCandidate(resolutionResult.getSingleProgramField().getHolder());
- return;
- }
- }
-
- if (deferredTracing.deferTracingOfFieldAccess(
- fieldReference, resolutionResult, currentMethod, FieldAccessKind.STATIC_WRITE, metadata)) {
- assert !metadata.isDeferred();
- return;
- }
-
- resolutionResult.visitFieldResolutionResults(
- singleResolutionResult -> {
- analyses.traceStaticFieldWrite(
- fieldReference, singleResolutionResult, currentMethod, worklist);
-
- DexClassAndField classField = singleResolutionResult.getResolutionPair();
- assert classField != null;
-
- DexClass initialResolutionHolder = singleResolutionResult.getInitialResolutionHolder();
- if (initialResolutionHolder != classField.getHolder()) {
- // Mark the initial resolution holder as live. Note that this should only be done if
- // the field is not a dead proto field (in which case we bail-out above).
- markTypeAsLive(initialResolutionHolder, currentMethod);
- }
-
- ProgramField field = classField.asProgramField();
- if (field == null) {
- // No need to trace into the non-program code.
- return;
- }
-
- assert !mode.isFinalTreeShaking() || !field.getDefinition().getOptimizationInfo().isDead()
- : "Unexpected reference in `"
- + currentMethod.toSourceString()
- + "` to field marked dead: "
- + field.getReference().toSourceString();
-
- if (metadata.isFromMethodHandle()) {
- fieldAccessInfoCollection.get(field.getReference()).setWrittenFromMethodHandle();
- }
-
- markFieldAsLive(field, currentMethod);
- },
- failedResolution -> {
- // Must trace the types from the field reference even if it does not exist.
- traceFieldReference(fieldReference, currentMethod);
- noClassMerging.add(fieldReference.getHolderType());
- });
- }
-
//
// Actual actions performed.
//