Record method handle accesses in field access info
Change-Id: Id6e0c08226f0b71aefecd63fe2873d3bc729c68e
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 2bd8acf..38d3a8e 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
@@ -32,12 +32,20 @@
boolean hasReflectiveAccess();
+ default boolean isAccessedFromMethodHandle() {
+ return isReadFromMethodHandle() || isWrittenFromMethodHandle();
+ }
+
boolean isRead();
+ boolean isReadFromMethodHandle();
+
boolean isReadOnlyIn(DexEncodedMethod method);
boolean isWritten();
+ boolean isWrittenFromMethodHandle();
+
boolean isWrittenInMethodSatisfying(Predicate<DexEncodedMethod> predicate);
boolean isWrittenOnlyInMethodSatisfying(Predicate<DexEncodedMethod> predicate);
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 4715169..b15153b 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -22,11 +22,15 @@
public static final FieldAccessInfoImpl MISSING_FIELD_ACCESS_INFO = new FieldAccessInfoImpl(null);
+ public static int FLAG_IS_READ_FROM_METHOD_HANDLE = 1 << 0;
+ public static int FLAG_IS_WRITTEN_FROM_METHOD_HANDLE = 1 << 1;
+ public static int FLAG_HAS_REFLECTIVE_ACCESS = 1 << 2;
+
// A direct reference to the definition of the field.
private DexField field;
- // If this field has a reflective access.
- private boolean hasReflectiveAccess;
+ // If this field is accessed from a method handle or has a reflective access.
+ private int flags;
// Maps every direct and indirect reference in a read-context to the set of methods in which that
// reference appears.
@@ -185,11 +189,11 @@
@Override
public boolean hasReflectiveAccess() {
- return hasReflectiveAccess;
+ return (flags & FLAG_HAS_REFLECTIVE_ACCESS) != 0;
}
public void setHasReflectiveAccess() {
- hasReflectiveAccess = true;
+ flags |= FLAG_HAS_REFLECTIVE_ACCESS;
}
/** Returns true if this field is read by the program. */
@@ -199,6 +203,15 @@
}
@Override
+ public boolean isReadFromMethodHandle() {
+ return (flags & FLAG_IS_READ_FROM_METHOD_HANDLE) != 0;
+ }
+
+ public void setReadFromMethodHandle() {
+ flags |= FLAG_IS_READ_FROM_METHOD_HANDLE;
+ }
+
+ @Override
public boolean isReadOnlyIn(DexEncodedMethod method) {
assert isRead();
assert method != null;
@@ -212,6 +225,15 @@
return writesWithContexts != null && !writesWithContexts.isEmpty();
}
+ @Override
+ public boolean isWrittenFromMethodHandle() {
+ return (flags & FLAG_IS_WRITTEN_FROM_METHOD_HANDLE) != 0;
+ }
+
+ public void setWrittenFromMethodHandle() {
+ flags |= FLAG_IS_WRITTEN_FROM_METHOD_HANDLE;
+ }
+
/**
* Returns true if this field is written by a method for which {@param predicate} returns true.
*/
@@ -292,9 +314,7 @@
public FieldAccessInfoImpl rewrittenWithLens(DexDefinitionSupplier definitions, GraphLense lens) {
FieldAccessInfoImpl rewritten = new FieldAccessInfoImpl(lens.lookupField(field));
- if (hasReflectiveAccess) {
- rewritten.setHasReflectiveAccess();
- }
+ rewritten.flags = flags;
if (readsWithContexts != null) {
rewritten.readsWithContexts = new IdentityHashMap<>();
readsWithContexts.forEach(
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 fb41239..f452556 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -35,16 +35,32 @@
public abstract boolean registerInvokeSuper(DexMethod method);
+ public abstract boolean registerInstanceFieldRead(DexField field);
+
+ public boolean registerInstanceFieldReadFromMethodHandle(DexField field) {
+ return registerInstanceFieldRead(field);
+ }
+
public abstract boolean registerInstanceFieldWrite(DexField field);
- public abstract boolean registerInstanceFieldRead(DexField field);
+ public boolean registerInstanceFieldWriteFromMethodHandle(DexField field) {
+ return registerInstanceFieldWrite(field);
+ }
public abstract boolean registerNewInstance(DexType type);
public abstract boolean registerStaticFieldRead(DexField field);
+ public boolean registerStaticFieldReadFromMethodHandle(DexField field) {
+ return registerStaticFieldRead(field);
+ }
+
public abstract boolean registerStaticFieldWrite(DexField field);
+ public boolean registerStaticFieldWriteFromMethodHandle(DexField field) {
+ return registerStaticFieldWrite(field);
+ }
+
public abstract boolean registerTypeReference(DexType type);
public boolean registerConstClass(DexType type) {
@@ -55,20 +71,19 @@
return registerTypeReference(type);
}
- public void registerMethodHandle(
- DexMethodHandle methodHandle, MethodHandleUse use) {
+ public void registerMethodHandle(DexMethodHandle methodHandle, MethodHandleUse use) {
switch (methodHandle.type) {
case INSTANCE_GET:
- registerInstanceFieldRead(methodHandle.asField());
+ registerInstanceFieldReadFromMethodHandle(methodHandle.asField());
break;
case INSTANCE_PUT:
- registerInstanceFieldWrite(methodHandle.asField());
+ registerInstanceFieldWriteFromMethodHandle(methodHandle.asField());
break;
case STATIC_GET:
- registerStaticFieldRead(methodHandle.asField());
+ registerStaticFieldReadFromMethodHandle(methodHandle.asField());
break;
case STATIC_PUT:
- registerStaticFieldWrite(methodHandle.asField());
+ registerStaticFieldWriteFromMethodHandle(methodHandle.asField());
break;
case INVOKE_INSTANCE:
registerInvokeVirtual(methodHandle.asMethod());
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index 4064d79..ef36b5b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -313,7 +313,7 @@
assert false;
return;
}
- if (!info.hasReflectiveAccess()) {
+ if (!info.hasReflectiveAccess() && !info.isWrittenFromMethodHandle()) {
info.forEachWriteContext(
context ->
fieldWrites.computeIfAbsent(context, ignore -> new ArrayList<>()).add(field));
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 dfcee69..f35fb94 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -65,13 +65,23 @@
}
@Override
+ public boolean registerInstanceFieldRead(DexField field) {
+ return enqueuer.traceInstanceFieldRead(field, context.getMethod());
+ }
+
+ @Override
+ public boolean registerInstanceFieldReadFromMethodHandle(DexField field) {
+ return enqueuer.traceInstanceFieldReadFromMethodHandle(field, context.getMethod());
+ }
+
+ @Override
public boolean registerInstanceFieldWrite(DexField field) {
return enqueuer.traceInstanceFieldWrite(field, context.getMethod());
}
@Override
- public boolean registerInstanceFieldRead(DexField field) {
- return enqueuer.traceInstanceFieldRead(field, context.getMethod());
+ public boolean registerInstanceFieldWriteFromMethodHandle(DexField field) {
+ return enqueuer.traceInstanceFieldWriteFromMethodHandle(field, context.getMethod());
}
@Override
@@ -85,11 +95,21 @@
}
@Override
+ public boolean registerStaticFieldReadFromMethodHandle(DexField field) {
+ return enqueuer.traceStaticFieldReadFromMethodHandle(field, context.getMethod());
+ }
+
+ @Override
public boolean registerStaticFieldWrite(DexField field) {
return enqueuer.traceStaticFieldWrite(field, context.getMethod());
}
@Override
+ public boolean registerStaticFieldWriteFromMethodHandle(DexField field) {
+ return enqueuer.traceStaticFieldWriteFromMethodHandle(field, context.getMethod());
+ }
+
+ @Override
public boolean registerConstClass(DexType type) {
return enqueuer.traceConstClass(type, context.getMethod());
}
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 818237c..dc426ea 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -963,6 +963,15 @@
}
boolean traceInstanceFieldRead(DexField field, DexEncodedMethod currentMethod) {
+ return traceInstanceFieldRead(field, currentMethod, false);
+ }
+
+ boolean traceInstanceFieldReadFromMethodHandle(DexField field, DexEncodedMethod currentMethod) {
+ return traceInstanceFieldRead(field, currentMethod, true);
+ }
+
+ private boolean traceInstanceFieldRead(
+ DexField field, DexEncodedMethod currentMethod, boolean fromMethodHandle) {
if (!registerFieldRead(field, currentMethod)) {
return false;
}
@@ -975,6 +984,10 @@
return false;
}
+ if (fromMethodHandle) {
+ fieldAccessInfoCollection.get(encodedField.field).setReadFromMethodHandle();
+ }
+
DexProgramClass clazz = getProgramClassOrNull(encodedField.field.holder);
if (clazz == null) {
return false;
@@ -999,6 +1012,15 @@
}
boolean traceInstanceFieldWrite(DexField field, DexEncodedMethod currentMethod) {
+ return traceInstanceFieldWrite(field, currentMethod, false);
+ }
+
+ boolean traceInstanceFieldWriteFromMethodHandle(DexField field, DexEncodedMethod currentMethod) {
+ return traceInstanceFieldWrite(field, currentMethod, true);
+ }
+
+ private boolean traceInstanceFieldWrite(
+ DexField field, DexEncodedMethod currentMethod, boolean fromMethodHandle) {
if (!registerFieldWrite(field, currentMethod)) {
return false;
}
@@ -1011,6 +1033,10 @@
return false;
}
+ if (fromMethodHandle) {
+ fieldAccessInfoCollection.get(encodedField.field).setWrittenFromMethodHandle();
+ }
+
DexProgramClass clazz = getProgramClassOrNull(encodedField.field.holder);
if (clazz == null) {
return false;
@@ -1035,6 +1061,15 @@
}
boolean traceStaticFieldRead(DexField field, DexEncodedMethod currentMethod) {
+ return traceStaticFieldRead(field, currentMethod, false);
+ }
+
+ boolean traceStaticFieldReadFromMethodHandle(DexField field, DexEncodedMethod currentMethod) {
+ return traceStaticFieldRead(field, currentMethod, true);
+ }
+
+ private boolean traceStaticFieldRead(
+ DexField field, DexEncodedMethod currentMethod, boolean fromMethodHandle) {
if (!registerFieldRead(field, currentMethod)) {
return false;
}
@@ -1046,6 +1081,10 @@
return false;
}
+ if (fromMethodHandle) {
+ fieldAccessInfoCollection.get(encodedField.field).setReadFromMethodHandle();
+ }
+
if (!isProgramClass(encodedField.field.holder)) {
// No need to trace into the non-program code.
return false;
@@ -1079,6 +1118,15 @@
}
boolean traceStaticFieldWrite(DexField field, DexEncodedMethod currentMethod) {
+ return traceStaticFieldWrite(field, currentMethod, false);
+ }
+
+ boolean traceStaticFieldWriteFromMethodHandle(DexField field, DexEncodedMethod currentMethod) {
+ return traceStaticFieldWrite(field, currentMethod, true);
+ }
+
+ private boolean traceStaticFieldWrite(
+ DexField field, DexEncodedMethod currentMethod, boolean fromMethodHandle) {
if (!registerFieldWrite(field, currentMethod)) {
return false;
}
@@ -1090,6 +1138,10 @@
return false;
}
+ if (fromMethodHandle) {
+ fieldAccessInfoCollection.get(encodedField.field).setWrittenFromMethodHandle();
+ }
+
if (!isProgramClass(encodedField.field.holder)) {
// No need to trace into the non-program code.
return false;