Account for deferred tracing in proto enqueuer extension
Bug: 205810841
Change-Id: Ic9bd167c73c36dc02113e539e09b47e619d3f2ce
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 9584e69..1c8ba99 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -406,6 +406,11 @@
GenericSignatureCorrectnessHelper.createForInitialCheck(appView, genericContextBuilder)
.run(appView.appInfo().classes());
+ // TODO(b/226539525): Implement enum lite proto shrinking as deferred tracing.
+ if (appView.options().protoShrinking().isEnumLiteProtoShrinkingEnabled()) {
+ appView.protoShrinker().enumLiteProtoShrinker.clearDeadEnumLiteMaps();
+ }
+
TreePruner pruner = new TreePruner(appViewWithLiveness);
DirectMappedDexApplication prunedApp = pruner.run(executorService);
@@ -422,10 +427,6 @@
appViewWithLiveness, appViewWithLiveness.appInfo().computeSubtypingInfo())
.run();
- if (appView.options().protoShrinking().isEnumLiteProtoShrinkingEnabled()) {
- appView.protoShrinker().enumLiteProtoShrinker.clearDeadEnumLiteMaps();
- }
-
AnnotationRemover annotationRemover =
annotationRemoverBuilder
.build(appViewWithLiveness, removedClasses);
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
index c5e19b9..34b3f2b 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
@@ -42,6 +42,10 @@
boolean hasReflectiveAccess();
+ boolean hasReflectiveRead();
+
+ boolean hasReflectiveWrite();
+
default boolean isAccessedFromMethodHandle() {
return isReadFromMethodHandle() || isWrittenFromMethodHandle();
}
@@ -54,6 +58,8 @@
boolean isReadFromMethodHandle();
+ boolean isReadOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate);
+
boolean isWritten();
boolean isWrittenFromMethodHandle();
@@ -62,7 +68,5 @@
boolean isWrittenOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate);
- boolean isReadOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate);
-
boolean isWrittenOutside(DexEncodedMethod method);
}
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 bdec9c0..8779817 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -27,8 +27,9 @@
public static int FLAG_IS_READ_FROM_ANNOTATION = 1 << 0;
public static int FLAG_IS_READ_FROM_METHOD_HANDLE = 1 << 1;
public static int FLAG_IS_WRITTEN_FROM_METHOD_HANDLE = 1 << 2;
- public static int FLAG_HAS_REFLECTIVE_ACCESS = 1 << 3;
- public static int FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC = 1 << 4;
+ public static int FLAG_HAS_REFLECTIVE_READ = 1 << 3;
+ public static int FLAG_HAS_REFLECTIVE_WRITE = 1 << 4;
+ public static int FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC = 1 << 5;
// A direct reference to the definition of the field.
private DexField field;
@@ -197,17 +198,39 @@
@Override
public boolean hasReflectiveAccess() {
- return (flags & FLAG_HAS_REFLECTIVE_ACCESS) != 0;
+ return hasReflectiveRead() || hasReflectiveWrite();
}
- public void setHasReflectiveAccess() {
- flags |= FLAG_HAS_REFLECTIVE_ACCESS;
+ @Override
+ public boolean hasReflectiveRead() {
+ return (flags & FLAG_HAS_REFLECTIVE_READ) != 0;
+ }
+
+ public void setHasReflectiveRead() {
+ flags |= FLAG_HAS_REFLECTIVE_READ;
+ }
+
+ @Override
+ public boolean hasReflectiveWrite() {
+ return (flags & FLAG_HAS_REFLECTIVE_WRITE) != 0;
+ }
+
+ public void setHasReflectiveWrite() {
+ flags |= FLAG_HAS_REFLECTIVE_WRITE;
}
/** Returns true if this field is read by the program. */
@Override
public boolean isRead() {
- return !readsWithContexts.isEmpty()
+ return isReadDirectly() || isReadIndirectly();
+ }
+
+ private boolean isReadDirectly() {
+ return !readsWithContexts.isEmpty();
+ }
+
+ private boolean isReadIndirectly() {
+ return hasReflectiveRead()
|| isReadFromAnnotation()
|| isReadFromMethodHandle()
|| isReadFromRecordInvokeDynamic();
@@ -227,15 +250,15 @@
return (flags & FLAG_IS_READ_FROM_METHOD_HANDLE) != 0;
}
+ public void setReadFromMethodHandle() {
+ flags |= FLAG_IS_READ_FROM_METHOD_HANDLE;
+ }
+
@Override
public boolean isReadFromRecordInvokeDynamic() {
return (flags & FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC) != 0;
}
- public void setReadFromMethodHandle() {
- flags |= FLAG_IS_READ_FROM_METHOD_HANDLE;
- }
-
public void setReadFromRecordInvokeDynamic() {
flags |= FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC;
}
@@ -244,12 +267,28 @@
flags &= ~FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC;
}
+ /**
+ * Returns true if this field is only read by methods for which {@param predicate} returns true.
+ */
+ @Override
+ public boolean isReadOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
+ return readsWithContexts.isAccessedOnlyInMethodSatisfying(predicate) && !isReadIndirectly();
+ }
+
/** Returns true if this field is written by the program. */
@Override
public boolean isWritten() {
+ return isWrittenDirectly() || isWrittenIndirectly();
+ }
+
+ private boolean isWrittenDirectly() {
return !writesWithContexts.isEmpty();
}
+ private boolean isWrittenIndirectly() {
+ return hasReflectiveWrite() || isWrittenFromMethodHandle();
+ }
+
@Override
public boolean isWrittenFromMethodHandle() {
return (flags & FLAG_IS_WRITTEN_FROM_METHOD_HANDLE) != 0;
@@ -273,15 +312,7 @@
*/
@Override
public boolean isWrittenOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
- return writesWithContexts.isAccessedOnlyInMethodSatisfying(predicate);
- }
-
- /**
- * Returns true if this field is only read by methods for which {@param predicate} returns true.
- */
- @Override
- public boolean isReadOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
- return readsWithContexts.isAccessedOnlyInMethodSatisfying(predicate);
+ return writesWithContexts.isAccessedOnlyInMethodSatisfying(predicate) && !isWrittenIndirectly();
}
/**
@@ -289,7 +320,7 @@
*/
@Override
public boolean isWrittenOutside(DexEncodedMethod method) {
- return writesWithContexts.isAccessedOutside(method);
+ return writesWithContexts.isAccessedOutside(method) || isWrittenIndirectly();
}
public boolean recordRead(DexField access, ProgramMethod context) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java
index 6accb73..e527832 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java
@@ -86,9 +86,14 @@
if (enumLite != null) {
DexEncodedField field =
enumLite.lookupField(createInternalValueMapField(enumLite.getType()));
- return field != null
- && appView.appInfo().isStaticFieldWrittenOnlyInEnclosingStaticInitializer(field)
- && !appView.appInfo().isFieldRead(field);
+ if (field == null) {
+ return false;
+ }
+ if (appView.appInfo().isFieldRead(field)) {
+ return false;
+ }
+ return !appView.appInfo().isFieldWritten(field)
+ || appView.appInfo().isStaticFieldWrittenOnlyInEnclosingStaticInitializer(field);
}
}
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
index 88d1c47..66d04da 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
+import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
@@ -231,10 +232,18 @@
public boolean isDeadProtoExtensionField(DexField fieldReference) {
AppInfoWithLiveness appInfo = appView.appInfo();
- ProgramField field = appInfo.resolveField(fieldReference).getSingleProgramField();
- return field != null
- && isDeadProtoExtensionField(
- field, appInfo.getFieldAccessInfoCollection(), appInfo.getKeepInfo());
+ return isDeadProtoExtensionField(
+ appInfo.resolveField(fieldReference),
+ appInfo.getFieldAccessInfoCollection(),
+ appInfo.getKeepInfo());
+ }
+
+ public boolean isDeadProtoExtensionField(
+ FieldResolutionResult resolutionResult,
+ FieldAccessInfoCollection<?> fieldAccessInfoCollection,
+ KeepInfoCollection keepInfo) {
+ ProgramField field = resolutionResult.getSingleProgramField();
+ return field != null && isDeadProtoExtensionField(field, fieldAccessInfoCollection, keepInfo);
}
public boolean isDeadProtoExtensionField(
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 b3976c7..e84fc5a 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
@@ -384,7 +384,7 @@
}
boolean valueStorageIsLive;
- if (enqueuer.isFieldLive(valueStorage)) {
+ if (enqueuer.isFieldReferenced(valueStorage)) {
if (enqueuer.isFieldRead(valueStorage)
|| enqueuer.isFieldWrittenOutsideDefaultConstructor(valueStorage)
|| reachesMapOrRequiredField(protoFieldInfo)) {
@@ -392,15 +392,13 @@
// (i) optimize field reads into loading the default value of the field or (ii) remove
// field writes to proto fields that could be read using reflection by the proto
// library.
- enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod);
+ worklist.enqueueTraceReflectiveFieldAccessAction(valueStorage, dynamicMethod);
}
valueStorageIsLive = true;
} else if (reachesMapOrRequiredField(protoFieldInfo)) {
// Map/required fields cannot be removed. Therefore, we mark such fields as both read and
// written such that we cannot optimize any field reads or writes.
- enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod);
- worklist.enqueueMarkFieldAsReachableAction(
- valueStorage, dynamicMethod, KeepReason.reflectiveUseIn(dynamicMethod));
+ worklist.enqueueTraceReflectiveFieldAccessAction(valueStorage, dynamicMethod);
valueStorageIsLive = true;
} else {
valueStorageIsLive = false;
@@ -414,7 +412,7 @@
newlyLiveField = protoFieldInfo.getOneOfCaseField(appView, protoMessageInfo);
} else if (protoFieldInfo.hasHazzerBitField(protoMessageInfo)) {
newlyLiveField = protoFieldInfo.getHazzerBitField(appView, protoMessageInfo);
- enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod);
+ worklist.enqueueTraceReflectiveFieldAccessAction(valueStorage, dynamicMethod);
}
} else {
// For one-of fields, mark the one-of field as live if the one-of-case field is live, and
@@ -423,13 +421,13 @@
if (protoFieldInfo.getType().isOneOf()) {
ProgramField oneOfCaseField =
protoFieldInfo.getOneOfCaseField(appView, protoMessageInfo);
- if (oneOfCaseField != null && enqueuer.isFieldLive(oneOfCaseField)) {
+ if (oneOfCaseField != null && enqueuer.isFieldReferenced(oneOfCaseField)) {
newlyLiveField = valueStorage;
}
} else if (protoFieldInfo.hasHazzerBitField(protoMessageInfo)) {
ProgramField hazzerBitField =
protoFieldInfo.getHazzerBitField(appView, protoMessageInfo);
- if (hazzerBitField == null || !enqueuer.isFieldLive(hazzerBitField)) {
+ if (hazzerBitField == null || !enqueuer.isFieldReferenced(hazzerBitField)) {
continue;
}
@@ -458,15 +456,12 @@
&& !writer.isStructurallyEqualTo(dynamicMethod);
if (enqueuer.isFieldWrittenInMethodSatisfying(
newlyLiveField, neitherDefaultConstructorNorDynamicMethod)) {
- enqueuer.registerReflectiveFieldRead(newlyLiveField.getReference(), dynamicMethod);
+ worklist.enqueueTraceReflectiveFieldReadAction(newlyLiveField, dynamicMethod);
}
// Unconditionally register the hazzer and one-of proto fields as written from
// dynamicMethod().
- if (enqueuer.registerReflectiveFieldWrite(newlyLiveField.getReference(), dynamicMethod)) {
- worklist.enqueueMarkFieldAsReachableAction(
- newlyLiveField, dynamicMethod, KeepReason.reflectiveUseIn(dynamicMethod));
- }
+ worklist.enqueueTraceReflectiveFieldWriteAction(newlyLiveField, dynamicMethod);
}
}
@@ -497,7 +492,7 @@
// schema, and therefore we do need to trace the const-class instructions that will be
// emitted for it.
ProgramField valueStorage = protoFieldInfo.getValueStorage(appView, protoMessageInfo);
- if (valueStorage != null && enqueuer.isFieldLive(valueStorage)) {
+ if (valueStorage != null && enqueuer.isFieldReferenced(valueStorage)) {
for (ProtoObject object : objects) {
if (object.isProtoObjectFromStaticGet()) {
worklist.enqueueTraceStaticFieldRead(
@@ -554,7 +549,7 @@
return;
}
- if (!enqueuer.isFieldLive(oneOfCaseField)) {
+ if (!enqueuer.isFieldReferenced(oneOfCaseField)) {
return;
}
@@ -578,10 +573,7 @@
return;
}
- if (enqueuer.registerReflectiveFieldWrite(oneOfField.getReference(), dynamicMethod)) {
- worklist.enqueueMarkFieldAsReachableAction(
- oneOfField, dynamicMethod, KeepReason.reflectiveUseIn(dynamicMethod));
- }
+ worklist.enqueueTraceReflectiveFieldWriteAction(oneOfField, dynamicMethod);
}
/**
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 ee61cc7..c7917ce 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -974,22 +974,39 @@
return registerFieldAccess(field, context, true, false);
}
- public boolean registerReflectiveFieldRead(DexField field, ProgramMethod context) {
- return registerFieldAccess(field, context, true, true);
+ public boolean registerReflectiveFieldRead(ProgramField field, ProgramMethod context) {
+ return registerFieldAccess(field.getReference(), context, true, true);
}
public boolean registerFieldWrite(DexField field, ProgramMethod context) {
return registerFieldAccess(field, context, false, false);
}
- public boolean registerReflectiveFieldWrite(DexField field, ProgramMethod context) {
- return registerFieldAccess(field, context, false, true);
+ public boolean registerReflectiveFieldWrite(ProgramField field, ProgramMethod context) {
+ return registerFieldAccess(field.getReference(), context, false, true);
}
- public boolean registerReflectiveFieldAccess(DexField field, ProgramMethod context) {
- boolean changed = registerFieldAccess(field, context, true, true);
- changed |= registerFieldAccess(field, context, false, true);
- return changed;
+ public void traceReflectiveFieldAccess(ProgramField field, ProgramMethod context) {
+ deferredTracing.notifyReflectiveFieldAccess(field, context);
+ boolean changed = registerReflectiveFieldRead(field, context);
+ changed |= registerReflectiveFieldWrite(field, context);
+ if (changed) {
+ markFieldAsReachable(field, context, KeepReason.reflectiveUseIn(context));
+ }
+ }
+
+ public void traceReflectiveFieldRead(ProgramField field, ProgramMethod context) {
+ deferredTracing.notifyReflectiveFieldAccess(field, context);
+ if (registerReflectiveFieldRead(field, context)) {
+ markFieldAsReachable(field, context, KeepReason.reflectiveUseIn(context));
+ }
+ }
+
+ public void traceReflectiveFieldWrite(ProgramField field, ProgramMethod context) {
+ deferredTracing.notifyReflectiveFieldAccess(field, context);
+ if (registerReflectiveFieldWrite(field, context)) {
+ markFieldAsReachable(field, context, KeepReason.reflectiveUseIn(context));
+ }
}
private boolean registerFieldAccess(
@@ -1023,7 +1040,18 @@
return false;
}
if (isReflective) {
- info.setHasReflectiveAccess();
+ if (isRead) {
+ if (!info.hasReflectiveRead()) {
+ info.setHasReflectiveRead();
+ return true;
+ }
+ } else {
+ if (!info.hasReflectiveWrite()) {
+ info.setHasReflectiveWrite();
+ return true;
+ }
+ }
+ return false;
}
return isRead ? info.recordRead(field, context) : info.recordWrite(field, context);
}
@@ -1718,6 +1746,21 @@
}
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_READ, metadata)) {
assert !metadata.isDeferred();
@@ -1751,18 +1794,6 @@
Log.verbose(getClass(), "Register Sget `%s`.", fieldReference);
}
- // If it is a dead proto extension field, don't trace onwards.
- boolean skipTracing =
- appView.withGeneratedExtensionRegistryShrinker(
- shrinker ->
- shrinker.isDeadProtoExtensionField(
- field, fieldAccessInfoCollection, keepInfo),
- false);
- if (skipTracing) {
- addDeadProtoTypeCandidate(field.getHolder());
- return;
- }
-
if (field.getReference() != fieldReference) {
// Mark the initial resolution holder as live. Note that this should only be done if
// the field
@@ -1799,6 +1830,21 @@
}
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();
@@ -1832,20 +1878,6 @@
Log.verbose(getClass(), "Register Sput `%s`.", fieldReference);
}
- if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
- // If it is a dead proto extension field, don't trace onwards.
- boolean skipTracing =
- appView.withGeneratedExtensionRegistryShrinker(
- shrinker ->
- shrinker.isDeadProtoExtensionField(
- field, fieldAccessInfoCollection, keepInfo),
- false);
- if (skipTracing) {
- addDeadProtoTypeCandidate(field.getHolder());
- return;
- }
- }
-
if (field.getReference() != fieldReference) {
// Mark the initial resolution holder as live. Note that this should only be done if
// the field
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
index 2867c62..0c5905a 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
@@ -143,6 +143,10 @@
return true;
}
+ public void notifyReflectiveFieldAccess(ProgramField field, ProgramMethod context) {
+ enqueueDeferredEnqueuerActions(field);
+ }
+
private boolean isEligibleForPruning(ProgramField field) {
FieldAccessInfo info = enqueuer.getFieldAccessInfoCollection().get(field.getReference());
if (info.hasReflectiveAccess()
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
index 1a5b588..a09efe6 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
@@ -11,9 +11,11 @@
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.FieldAccessInfo;
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.Enqueuer.FieldAccessKind;
import com.android.tools.r8.shaking.Enqueuer.FieldAccessMetadata;
import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness;
import com.android.tools.r8.utils.Action;
@@ -318,6 +320,36 @@
}
}
+ static class TraceReflectiveFieldAccessAction extends EnqueuerAction {
+ private final ProgramField field;
+ private final ProgramMethod context;
+ private final FieldAccessKind kind;
+
+ TraceReflectiveFieldAccessAction(ProgramField field, ProgramMethod context) {
+ this(field, context, null);
+ }
+
+ TraceReflectiveFieldAccessAction(
+ ProgramField field, ProgramMethod context, FieldAccessKind kind) {
+ this.field = field;
+ this.context = context;
+ this.kind = kind;
+ }
+
+ @Override
+ public void run(Enqueuer enqueuer) {
+ if (kind != null) {
+ if (kind.isRead()) {
+ enqueuer.traceReflectiveFieldRead(field, context);
+ } else {
+ enqueuer.traceReflectiveFieldWrite(field, context);
+ }
+ } else {
+ enqueuer.traceReflectiveFieldAccess(field, context);
+ }
+ }
+ }
+
static class TraceTypeReferenceAction extends EnqueuerAction {
private final DexProgramClass clazz;
private final KeepReason reason;
@@ -559,6 +591,15 @@
public abstract void enqueueTraceNewInstanceAction(DexType type, ProgramMethod context);
+ public abstract void enqueueTraceReflectiveFieldAccessAction(
+ ProgramField field, ProgramMethod context);
+
+ public abstract void enqueueTraceReflectiveFieldReadAction(
+ ProgramField field, ProgramMethod context);
+
+ public abstract void enqueueTraceReflectiveFieldWriteAction(
+ ProgramField field, ProgramMethod context);
+
public abstract void enqueueTraceStaticFieldRead(DexField field, ProgramMethod context);
public abstract void enqueueTraceTypeReferenceAction(DexProgramClass clazz, KeepReason reason);
@@ -693,6 +734,42 @@
}
@Override
+ public void enqueueTraceReflectiveFieldAccessAction(ProgramField field, ProgramMethod context) {
+ FieldAccessInfo info = enqueuer.getFieldAccessInfoCollection().get(field.getReference());
+ if (info == null || !info.hasReflectiveAccess()) {
+ queue.add(new TraceReflectiveFieldAccessAction(field, context));
+ }
+ }
+
+ @Override
+ public void enqueueTraceReflectiveFieldReadAction(ProgramField field, ProgramMethod context) {
+ FieldAccessInfo info = enqueuer.getFieldAccessInfoCollection().get(field.getReference());
+ if (info == null || !info.hasReflectiveRead()) {
+ queue.add(
+ new TraceReflectiveFieldAccessAction(
+ field,
+ context,
+ field.getAccessFlags().isStatic()
+ ? FieldAccessKind.STATIC_READ
+ : FieldAccessKind.INSTANCE_READ));
+ }
+ }
+
+ @Override
+ public void enqueueTraceReflectiveFieldWriteAction(ProgramField field, ProgramMethod context) {
+ FieldAccessInfo info = enqueuer.getFieldAccessInfoCollection().get(field.getReference());
+ if (info == null || !info.hasReflectiveWrite()) {
+ queue.add(
+ new TraceReflectiveFieldAccessAction(
+ field,
+ context,
+ field.getAccessFlags().isStatic()
+ ? FieldAccessKind.STATIC_WRITE
+ : FieldAccessKind.INSTANCE_WRITE));
+ }
+ }
+
+ @Override
public void enqueueTraceStaticFieldRead(DexField field, ProgramMethod context) {
queue.add(new TraceStaticFieldReadAction(field, context, FieldAccessMetadata.DEFAULT));
}
@@ -830,6 +907,21 @@
}
@Override
+ public void enqueueTraceReflectiveFieldAccessAction(ProgramField field, ProgramMethod context) {
+ throw attemptToEnqueue();
+ }
+
+ @Override
+ public void enqueueTraceReflectiveFieldReadAction(ProgramField field, ProgramMethod context) {
+ throw attemptToEnqueue();
+ }
+
+ @Override
+ public void enqueueTraceReflectiveFieldWriteAction(ProgramField field, ProgramMethod context) {
+ throw attemptToEnqueue();
+ }
+
+ @Override
public void enqueueTraceStaticFieldRead(DexField field, ProgramMethod context) {
throw attemptToEnqueue();
}
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
index da2236d..51acd65 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
@@ -73,7 +73,6 @@
this.parameters = parameters;
}
- @Ignore
@Test
public void test() throws Exception {
CodeInspector inputInspector = new CodeInspector(PROGRAM_FILES);
@@ -353,7 +352,6 @@
}
}
- @Ignore
@Test
public void testNoRewriting() throws Exception {
testForR8(parameters.getBackend())
@@ -380,7 +378,6 @@
assertRewrittenProtoSchemasMatch(new CodeInspector(PROGRAM_FILES), inspector));
}
- @Ignore
@Test
public void testTwoExtensionRegistrys() throws Exception {
CodeInspector inputInspector = new CodeInspector(PROGRAM_FILES);
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
index d53d170..e2b8e51 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
@@ -19,7 +19,6 @@
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.List;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -52,7 +51,6 @@
this.parameters = parameters;
}
- @Ignore
@Test
public void test() throws Exception {
CodeInspector inputInspector = new CodeInspector(PROGRAM_FILES);
@@ -99,7 +97,6 @@
}
}
- @Ignore
@Test
public void testNoRewriting() throws Exception {
testForR8(parameters.getBackend())