Leverage field access info for determining if field is only written in clinit
Change-Id: Ica16c5d5fd2b480403c170bf1978b0fc69ee2ca5
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index 6308a16..f8aaa42 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -19,7 +19,7 @@
import java.util.List;
import java.util.Map;
-public class DirectMappedDexApplication extends DexApplication {
+public class DirectMappedDexApplication extends DexApplication implements DexDefinitionSupplier {
// Mapping from code objects to their encoded-method owner. Used for asserting unique ownership
// and debugging purposes.
@@ -70,12 +70,46 @@
}
@Override
+ public DexDefinition definitionFor(DexReference reference) {
+ if (reference.isDexType()) {
+ return definitionFor(reference.asDexType());
+ }
+ if (reference.isDexMethod()) {
+ return definitionFor(reference.asDexMethod());
+ }
+ assert reference.isDexField();
+ return definitionFor(reference.asDexField());
+ }
+
+ @Override
+ public DexEncodedField definitionFor(DexField field) {
+ DexClass clazz = definitionFor(field.holder);
+ return clazz != null ? clazz.lookupField(field) : null;
+ }
+
+ @Override
+ public DexEncodedMethod definitionFor(DexMethod method) {
+ DexClass clazz = definitionFor(method.holder);
+ return clazz != null ? clazz.lookupMethod(method) : null;
+ }
+
+ @Override
public DexClass definitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup definition for type: " + type;
return allClasses.get(type);
}
@Override
+ public DexProgramClass definitionForProgramType(DexType type) {
+ return programDefinitionFor(type);
+ }
+
+ @Override
+ public DexItemFactory dexItemFactory() {
+ return dexItemFactory;
+ }
+
+ @Override
public DexProgramClass programDefinitionFor(DexType type) {
DexClass clazz = definitionFor(type);
return clazz instanceof DexProgramClass ? clazz.asProgramClass() : null;
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
index 1478f2d..3a307cf 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
@@ -36,11 +36,13 @@
infos.entrySet().removeIf(entry -> predicate.test(entry.getKey(), entry.getValue()));
}
- public FieldAccessInfoCollectionImpl rewrittenWithLens(GraphLense lens) {
+ public FieldAccessInfoCollectionImpl rewrittenWithLens(
+ DexDefinitionSupplier definitions, GraphLense lens) {
FieldAccessInfoCollectionImpl collection = new FieldAccessInfoCollectionImpl();
infos.forEach(
(field, info) ->
- collection.infos.put(lens.lookupField(field), info.rewrittenWithLens(lens)));
+ collection.infos.put(
+ lens.lookupField(field), info.rewrittenWithLens(definitions, lens)));
return collection;
}
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 fcd4f5c..a263cb6 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -189,25 +189,31 @@
writesWithContexts = null;
}
- public FieldAccessInfoImpl rewrittenWithLens(GraphLense lens) {
+ public FieldAccessInfoImpl rewrittenWithLens(DexDefinitionSupplier definitions, GraphLense lens) {
FieldAccessInfoImpl rewritten = new FieldAccessInfoImpl(lens.lookupField(field));
if (readsWithContexts != null) {
rewritten.readsWithContexts = new IdentityHashMap<>();
readsWithContexts.forEach(
- (access, contexts) ->
- rewritten
- .readsWithContexts
- .computeIfAbsent(lens.lookupField(access), ignore -> Sets.newIdentityHashSet())
- .addAll(contexts));
+ (access, contexts) -> {
+ Set<DexEncodedMethod> newContexts =
+ rewritten.readsWithContexts.computeIfAbsent(
+ lens.lookupField(access), ignore -> Sets.newIdentityHashSet());
+ for (DexEncodedMethod context : contexts) {
+ newContexts.add(lens.mapDexEncodedMethod(context, definitions));
+ }
+ });
}
if (writesWithContexts != null) {
rewritten.writesWithContexts = new IdentityHashMap<>();
writesWithContexts.forEach(
- (access, contexts) ->
- rewritten
- .writesWithContexts
- .computeIfAbsent(lens.lookupField(access), ignore -> Sets.newIdentityHashSet())
- .addAll(contexts));
+ (access, contexts) -> {
+ Set<DexEncodedMethod> newContexts =
+ rewritten.writesWithContexts.computeIfAbsent(
+ lens.lookupField(access), ignore -> Sets.newIdentityHashSet());
+ for (DexEncodedMethod context : contexts) {
+ newContexts.add(lens.mapDexEncodedMethod(context, definitions));
+ }
+ });
}
return rewritten;
}
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 16dab7e..8c5dd71 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -420,6 +420,10 @@
public DexEncodedMethod mapDexEncodedMethod(
DexEncodedMethod originalEncodedMethod, DexDefinitionSupplier definitions) {
+ assert originalEncodedMethod != DexEncodedMethod.SENTINEL;
+ if (originalEncodedMethod == DexEncodedMethod.ANNOTATION_REFERENCE) {
+ return DexEncodedMethod.ANNOTATION_REFERENCE;
+ }
DexMethod newMethod = getRenamedMethodSignature(originalEncodedMethod.method);
// Note that:
// * Even if `newMethod` is the same as `originalEncodedMethod.method`, we still need to look it
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index f89e220..80ca84e 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -468,7 +468,8 @@
this.virtualMethodsTargetedByInvokeDirect =
lense.rewriteMethodsConservatively(previous.virtualMethodsTargetedByInvokeDirect);
this.liveMethods = lense.rewriteMethodsConservatively(previous.liveMethods);
- this.fieldAccessInfoCollection = previous.fieldAccessInfoCollection.rewrittenWithLens(lense);
+ this.fieldAccessInfoCollection =
+ previous.fieldAccessInfoCollection.rewrittenWithLens(application, lense);
this.instanceFieldsWrittenOnlyInEnclosingInstanceInitializers =
rewriteItems(
previous.instanceFieldsWrittenOnlyInEnclosingInstanceInitializers, lense::lookupField);
@@ -791,10 +792,28 @@
return instanceFieldsWrittenOnlyInEnclosingInstanceInitializers.contains(field.field);
}
+ public boolean isStaticFieldWrittenOnlyInEnclosingStaticInitializerNew(DexEncodedField field) {
+ assert checkIfObsolete();
+ assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written";
+ if (!isPinned(field.field)) {
+ DexEncodedMethod staticInitializer =
+ definitionFor(field.field.holder).asProgramClass().getClassInitializer();
+ if (staticInitializer != null) {
+ FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.field);
+ return fieldAccessInfo != null
+ && fieldAccessInfo.isWritten()
+ && !fieldAccessInfo.isWrittenOutside(staticInitializer);
+ }
+ }
+ return false;
+ }
+
public boolean isStaticFieldWrittenOnlyInEnclosingStaticInitializer(DexEncodedField field) {
assert checkIfObsolete();
assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written";
- return staticFieldsWrittenOnlyInEnclosingStaticInitializer.contains(field.field);
+ boolean result = staticFieldsWrittenOnlyInEnclosingStaticInitializer.contains(field.field);
+ assert result == isStaticFieldWrittenOnlyInEnclosingStaticInitializerNew(field);
+ return result;
}
public boolean mayPropagateValueFor(DexReference reference) {