Revert "Remove all uses of definitionFor(DexField)"
This reverts commit e987cb1c67ce17c09e7f4725dc308f92ff27d2d5.
Revert "Remove field definitions cache"
This reverts commit 76dff502470f97379464d91c5da3703d60b0f229.
Change-Id: Iff21cf096d05e50230f28a88a3d3629d05f34b25
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 3706dec..e49f177 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -21,6 +21,9 @@
private final DexApplication app;
private final DexItemFactory dexItemFactory;
+ // TODO(b/151804585): Remove this cache.
+ private final ConcurrentHashMap<DexType, Map<DexField, DexEncodedField>> fieldDefinitionsCache;
+
// For some optimizations, e.g. optimizing synthetic classes, we may need to resolve the current
// class being optimized.
private final ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses;
@@ -30,28 +33,31 @@
private final BooleanBox obsolete;
public AppInfo(DexApplication application) {
- this(application, new ConcurrentHashMap<>(), new BooleanBox());
+ this(application, new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), new BooleanBox());
}
// For desugaring.
protected AppInfo(AppInfo appInfo) {
- this(appInfo.app, appInfo.synthesizedClasses, appInfo.obsolete);
+ this(appInfo.app, appInfo.fieldDefinitionsCache, appInfo.synthesizedClasses, appInfo.obsolete);
}
// For AppInfoWithLiveness.
protected AppInfo(AppInfoWithClassHierarchy previous) {
this(
((AppInfo) previous).app,
+ new ConcurrentHashMap<>(((AppInfo) previous).fieldDefinitionsCache),
new ConcurrentHashMap<>(((AppInfo) previous).synthesizedClasses),
new BooleanBox());
}
private AppInfo(
DexApplication application,
+ ConcurrentHashMap<DexType, Map<DexField, DexEncodedField>> fieldDefinitionsCache,
ConcurrentHashMap<DexType, DexProgramClass> synthesizedClasses,
BooleanBox obsolete) {
this.app = application;
this.dexItemFactory = application.dexItemFactory;
+ this.fieldDefinitionsCache = fieldDefinitionsCache;
this.synthesizedClasses = synthesizedClasses;
this.obsolete = obsolete;
}
@@ -96,6 +102,7 @@
assert checkIfObsolete();
assert clazz.type.isD8R8SynthesizedClassType();
DexProgramClass previous = synthesizedClasses.put(clazz.type, clazz);
+ invalidateFieldCacheFor(clazz.type);
assert previous == null || previous == clazz;
}
@@ -176,6 +183,21 @@
return clazz.getMethodCollection().getMethod(method);
}
+ @Deprecated
+ @Override
+ public DexEncodedField definitionFor(DexField field) {
+ assert checkIfObsolete();
+ return getFieldDefinitions(field.holder).get(field);
+ }
+
+ private Map<DexField, DexEncodedField> getFieldDefinitions(DexType type) {
+ return fieldDefinitionsCache.computeIfAbsent(type, this::computeFieldDefinitions);
+ }
+
+ public void invalidateFieldCacheFor(DexType type) {
+ fieldDefinitionsCache.remove(type);
+ }
+
/**
* Lookup static method on the method holder, or answers null.
*
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index b4534f5..33c63dc 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -228,6 +228,12 @@
@Deprecated
@Override
+ public final DexEncodedField definitionFor(DexField field) {
+ return appInfo().definitionFor(field);
+ }
+
+ @Deprecated
+ @Override
public final DexEncodedMethod definitionFor(DexMethod method) {
return appInfo().definitionFor(method);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
index 214e41c..5055cc5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
@@ -7,6 +7,9 @@
public interface DexDefinitionSupplier {
@Deprecated
+ DexEncodedField definitionFor(DexField field);
+
+ @Deprecated
DexEncodedMethod definitionFor(DexMethod method);
DexClass definitionFor(DexType type);
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index 84d581e..31017af 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -7,8 +7,6 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.naming.NamingLens;
import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
public class DexField extends DexMember<DexEncodedField, DexField> {
@@ -26,28 +24,7 @@
}
@Override
- public DexEncodedField lookupOnClass(DexClass clazz) {
- return clazz != null ? clazz.lookupField(this) : null;
- }
-
- @Override
- public <T> T apply(
- Function<DexType, T> classConsumer,
- Function<DexField, T> fieldConsumer,
- Function<DexMethod, T> methodConsumer) {
- return fieldConsumer.apply(this);
- }
-
- @Override
- public void accept(
- Consumer<DexType> classConsumer,
- Consumer<DexField> fieldConsumer,
- Consumer<DexMethod> methodConsumer) {
- fieldConsumer.accept(this);
- }
-
- @Override
- public <T> void accept(
+ public <T> void apply(
BiConsumer<DexType, T> classConsumer,
BiConsumer<DexField, T> fieldConsumer,
BiConsumer<DexMethod, T> methodConsumer,
diff --git a/src/main/java/com/android/tools/r8/graph/DexMember.java b/src/main/java/com/android/tools/r8/graph/DexMember.java
index 02fd431..d04808b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMember.java
@@ -13,10 +13,6 @@
this.holder = holder;
}
- public DexEncodedMember<?, ?> lookupOnClass(DexClass clazz) {
- return clazz != null ? clazz.lookupMember(this) : null;
- }
-
public abstract boolean match(R entry);
public abstract boolean match(D entry);
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index 3618578..89c8f05 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -12,8 +12,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
public class DexMethod extends DexMember<DexEncodedMethod, DexMethod> {
@@ -32,23 +30,7 @@
}
@Override
- public <T> T apply(
- Function<DexType, T> classConsumer,
- Function<DexField, T> fieldConsumer,
- Function<DexMethod, T> methodConsumer) {
- return methodConsumer.apply(this);
- }
-
- @Override
- public void accept(
- Consumer<DexType> classConsumer,
- Consumer<DexField> fieldConsumer,
- Consumer<DexMethod> methodConsumer) {
- methodConsumer.accept(this);
- }
-
- @Override
- public <T> void accept(
+ public <T> void apply(
BiConsumer<DexType, T> classConsumer,
BiConsumer<DexField, T> fieldConsumer,
BiConsumer<DexMethod, T> methodConsumer,
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 0fe1d69..900712b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -133,10 +133,6 @@
synthesizedDirectlyFrom.forEach(this::addSynthesizedFrom);
}
- public void forEachProgramField(Consumer<ProgramField> consumer) {
- forEachField(field -> consumer.accept(new ProgramField(this, field)));
- }
-
public void forEachProgramMethod(Consumer<ProgramMethod> consumer) {
forEachProgramMethodMatching(alwaysTrue(), consumer);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexReference.java b/src/main/java/com/android/tools/r8/graph/DexReference.java
index c37c9de..3735378 100644
--- a/src/main/java/com/android/tools/r8/graph/DexReference.java
+++ b/src/main/java/com/android/tools/r8/graph/DexReference.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.graph;
import java.util.function.BiConsumer;
-import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -14,17 +13,7 @@
*/
public abstract class DexReference extends IndexedDexItem {
- public abstract <T> T apply(
- Function<DexType, T> classConsumer,
- Function<DexField, T> fieldConsumer,
- Function<DexMethod, T> methodConsumer);
-
- public abstract void accept(
- Consumer<DexType> classConsumer,
- Consumer<DexField> fieldConsumer,
- Consumer<DexMethod> methodConsumer);
-
- public abstract <T> void accept(
+ public abstract <T> void apply(
BiConsumer<DexType, T> classConsumer,
BiConsumer<DexField, T> fieldConsumer,
BiConsumer<DexMethod, T> methodConsumer,
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index fc7ae3e..dfe07f6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -31,8 +31,6 @@
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
import java.util.function.Predicate;
public class DexType extends DexReference implements PresortedComparable<DexType> {
@@ -118,23 +116,7 @@
}
@Override
- public <T> T apply(
- Function<DexType, T> classConsumer,
- Function<DexField, T> fieldConsumer,
- Function<DexMethod, T> methodConsumer) {
- return classConsumer.apply(this);
- }
-
- @Override
- public void accept(
- Consumer<DexType> classConsumer,
- Consumer<DexField> fieldConsumer,
- Consumer<DexMethod> methodConsumer) {
- classConsumer.accept(this);
- }
-
- @Override
- public <T> void accept(
+ public <T> void apply(
BiConsumer<DexType, T> classConsumer,
BiConsumer<DexField, T> fieldConsumer,
BiConsumer<DexMethod, T> methodConsumer,
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 3699d2e..d66ef7e 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -75,6 +75,13 @@
@Deprecated
@Override
+ public DexEncodedField definitionFor(DexField field) {
+ DexClass clazz = definitionFor(field.holder);
+ return clazz != null ? clazz.lookupField(field) : null;
+ }
+
+ @Deprecated
+ @Override
public DexEncodedMethod definitionFor(DexMethod method) {
DexClass clazz = definitionFor(method.holder);
return clazz != null ? clazz.lookupMethod(method) : null;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
index 01d86a1..fbb42a9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
@@ -7,10 +7,8 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
@@ -108,9 +106,8 @@
}
AbstractValue abstractValue = root.getAbstractValue(appView, context);
if (abstractValue.isSingleFieldValue()) {
- DexField fieldReference = abstractValue.asSingleFieldValue().getField();
- DexClass holder = appView.definitionForHolder(fieldReference);
- DexEncodedField field = fieldReference.lookupOnClass(holder);
+ DexEncodedField field =
+ appView.definitionFor(abstractValue.asSingleFieldValue().getField());
if (field != null && field.isEnum()) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
index 9fe885d..a2a932c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
@@ -5,9 +5,7 @@
package com.android.tools.r8.ir.analysis.fieldvalueanalysis;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.SetUtils;
@@ -73,14 +71,12 @@
assert !isEmpty();
ConcreteMutableFieldSet rewrittenSet = new ConcreteMutableFieldSet();
for (DexEncodedField field : fields) {
- DexField rewrittenFieldReference = lens.lookupField(field.field);
- DexClass holder = appView.definitionForHolder(rewrittenFieldReference);
- DexEncodedField rewrittenField = rewrittenFieldReference.lookupOnClass(holder);
+ DexEncodedField rewrittenField = appView.definitionFor(lens.lookupField(field.field));
if (rewrittenField == null) {
assert false;
continue;
}
- rewrittenSet.add(rewrittenField);
+ rewrittenSet.add(field);
}
return rewrittenSet;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index ba49fc0..e66d342 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
-import com.android.tools.r8.ir.code.FieldInstruction;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -85,20 +84,16 @@
}
}
} else if (instruction.isFieldInstruction()) {
- // Since we only need to desugar accesses to private fields, and all accesses to private
- // fields must be accessing the private field directly on its holder, we can lookup the
- // field on the holder instead of resolving the field.
- FieldInstruction fieldInstruction = instruction.asFieldInstruction();
- DexClass holder = appView.definitionForHolder(fieldInstruction.getField());
- DexEncodedField field = fieldInstruction.getField().lookupOnClass(holder);
- if (field != null && fieldAccessRequiresRewriting(field, method)) {
+ DexEncodedField encodedField =
+ appView.definitionFor(instruction.asFieldInstruction().getField());
+ if (encodedField != null && fieldAccessRequiresRewriting(encodedField, method)) {
if (instruction.isInstanceGet() || instruction.isStaticGet()) {
- DexMethod bridge = ensureFieldAccessBridge(field, true);
+ DexMethod bridge = ensureFieldAccessBridge(encodedField, true);
instructions.replaceCurrentInstruction(
new InvokeStatic(bridge, instruction.outValue(), instruction.inValues()));
} else {
assert instruction.isInstancePut() || instruction.isStaticPut();
- DexMethod bridge = ensureFieldAccessBridge(field, false);
+ DexMethod bridge = ensureFieldAccessBridge(encodedField, false);
instructions.replaceCurrentInstruction(
new InvokeStatic(bridge, instruction.outValue(), instruction.inValues()));
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index 2586141..7da225c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -84,15 +84,14 @@
return appView.definitionFor(appView.graphLense().lookupType(type));
}
- private DexEncodedMethod lookupOnHolder(
+ private DexEncodedMethod definitionFor(
DexMethod method, DexClassAndMethod context, Invoke.Type invokeType) {
return appView.definitionFor(
appView.graphLense().lookupMethod(method, context.getReference(), invokeType).getMethod());
}
- private DexEncodedField lookupOnHolder(DexField field) {
- DexField rewritten = appView.graphLense().lookupField(field);
- return rewritten.lookupOnClass(appView.definitionForHolder(rewritten));
+ private DexEncodedField definitionFor(DexField field) {
+ return appView.definitionFor(appView.graphLense().lookupField(field));
}
// Extract the list of types in the programClass' nest, of host hostClass
@@ -366,7 +365,7 @@
if (!method.holder.isClassType()) {
return false;
}
- DexEncodedMethod encodedMethod = lookupOnHolder(method, context, invokeType);
+ DexEncodedMethod encodedMethod = definitionFor(method, context, invokeType);
if (encodedMethod != null && invokeRequiresRewriting(encodedMethod, context)) {
ensureInvokeBridge(encodedMethod);
return true;
@@ -375,10 +374,7 @@
}
private boolean registerFieldAccess(DexField field, boolean isGet) {
- // Since we only need to desugar accesses to private fields, and all accesses to private
- // fields must be accessing the private field directly on its holder, we can lookup the field
- // on the holder instead of resolving the field.
- DexEncodedField encodedField = lookupOnHolder(field);
+ DexEncodedField encodedField = definitionFor(field);
if (encodedField != null && fieldAccessRequiresRewriting(encodedField, context)) {
ensureFieldAccessBridge(encodedField, isGet);
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index def219f..f2cefad 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -2537,13 +2537,10 @@
if (singleFieldValue.getField() == otherSingleFieldValue.getField()) {
simplifyIfWithKnownCondition(code, block, theIf, 0);
} else {
- DexClass holder = appView.definitionForHolder(singleFieldValue.getField());
- DexEncodedField field = singleFieldValue.getField().lookupOnClass(holder);
+ DexEncodedField field = appView.definitionFor(singleFieldValue.getField());
if (field != null && field.isEnum()) {
- DexClass otherHolder =
- appView.definitionForHolder(otherSingleFieldValue.getField());
DexEncodedField otherField =
- otherSingleFieldValue.getField().lookupOnClass(otherHolder);
+ appView.definitionFor(otherSingleFieldValue.getField());
if (otherField != null && otherField.isEnum()) {
simplifyIfWithKnownCondition(code, block, theIf, 1);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index 5178020..ef81097 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -155,7 +155,7 @@
return appView.appInfo().withLiveness().resolveField(field).getResolvedField();
}
if (field.holder == method.getHolderType()) {
- return method.getHolder().lookupField(field);
+ return appView.definitionFor(field);
}
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
index fe70918..2fe8a19 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
@@ -4,9 +4,7 @@
package com.android.tools.r8.ir.optimize.info.field;
-
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
@@ -34,10 +32,9 @@
BiConsumer<DexEncodedField, InstanceFieldInitializationInfo> consumer) {
infos.forEach(
(field, info) -> {
- DexClass holder = definitions.definitionForHolder(field);
- DexEncodedField definition = field.lookupOnClass(holder);
- if (definition != null) {
- consumer.accept(definition, info);
+ DexEncodedField encodedField = definitions.definitionFor(field);
+ if (encodedField != null) {
+ consumer.accept(encodedField, info);
} else {
assert false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
index bcea380..ad6313e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
@@ -65,7 +65,7 @@
for (LibraryMembers libraryMembers : appView.dexItemFactory().libraryMembersCollection) {
libraryMembers.forEachFinalField(
field -> {
- DexEncodedField definition = field.lookupOnClass(appView.definitionForHolder(field));
+ DexEncodedField definition = appView.definitionFor(field);
if (definition != null) {
if (definition.isFinal()) {
finalLibraryFields.add(definition);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
index c326f61..f3fba2d 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -12,7 +12,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -120,6 +122,11 @@
}
@Override
+ public DexEncodedField definitionFor(DexField field) {
+ throw new Unreachable("Should not be called");
+ }
+
+ @Override
public DexEncodedMethod definitionFor(DexMethod method) {
throw new Unreachable("Should not be called");
}
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
index b014c4f..8cffa05 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -3,19 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
-
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.BottomUpClassHierarchyTraversal;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
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.ProgramField;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -182,7 +178,9 @@
getOrCreateReservedFieldNamingState(clazz.type);
FieldNamingState state = parentState.createChildState(reservedNames);
if (clazz.isProgramClass()) {
- clazz.asProgramClass().forEachProgramField(field -> renameField(field, state));
+ for (DexEncodedField field : clazz.fields()) {
+ renameField(field, state);
+ }
}
assert !states.containsKey(clazz.type);
@@ -214,14 +212,11 @@
for (DexClass clazz : partition) {
if (clazz.isProgramClass()) {
assert clazz.isInterface();
- clazz
- .asProgramClass()
- .forEachProgramField(
- field -> {
- DexString newName = renameField(field, state);
- namesToBeReservedInImplementsSubclasses.markReservedDirectly(
- newName, field.getReference().name, field.getReference().type);
- });
+ for (DexEncodedField field : clazz.fields()) {
+ DexString newName = renameField(field, state);
+ namesToBeReservedInImplementsSubclasses.markReservedDirectly(
+ newName, field.field.name, field.field.type);
+ }
}
}
@@ -241,10 +236,11 @@
}
}
- private DexString renameField(ProgramField field, FieldNamingState state) {
+ private DexString renameField(DexEncodedField encodedField, FieldNamingState state) {
+ DexField field = encodedField.field;
DexString newName = state.getOrCreateNameFor(field);
- if (newName != field.getReference().name) {
- renaming.put(field.getReference(), newName);
+ if (newName != field.name) {
+ renaming.put(field, newName);
}
return newName;
}
@@ -260,17 +256,32 @@
}
private void renameNonReboundAccessToField(DexField field) {
- // If the given field reference is a non-rebound reference to a program field, then assign the
- // same name as the resolved field.
+ // Already renamed
if (renaming.containsKey(field)) {
return;
}
- DexProgramClass holder = asProgramClassOrNull(appView.definitionForHolder(field));
- if (holder == null) {
+ DexEncodedField definition = appView.definitionFor(field);
+ if (definition != null) {
+ assert definition.field == field;
return;
}
- DexEncodedField definition = appView.appInfo().resolveFieldOn(holder, field).getResolvedField();
- if (definition != null && definition.field != field && renaming.containsKey(definition.field)) {
+ // Now, `field` is reference. Find its definition and check if it's renamed.
+ DexClass holder = appView.definitionFor(field.holder);
+ // We don't care pruned types or library classes.
+ if (holder == null || holder.isNotProgramClass()) {
+ return;
+ }
+ definition = appView.appInfo().resolveField(field).getResolvedField();
+ if (definition == null) {
+ // The program is already broken in the sense that it has an unresolvable field reference.
+ // Leave it as-is.
+ return;
+ }
+ assert definition.field != field;
+ assert definition.holder() != field.holder;
+ // If the definition is renamed,
+ if (renaming.containsKey(definition.field)) {
+ // Assign the same, renamed name as the definition to the reference.
renaming.put(field, renaming.get(definition.field));
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNamingState.java b/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
index 35e3d3f..f8d80cb 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
@@ -6,9 +6,11 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.naming.FieldNamingState.InternalState;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -18,7 +20,7 @@
private final ReservedFieldNamingState reservedNames;
private final MemberNamingStrategy strategy;
- private final BiPredicate<DexString, ProgramField> isAvailable;
+ private final BiPredicate<DexString, DexField> isAvailable;
public FieldNamingState(
AppView<? extends AppInfoWithClassHierarchy> appView, MemberNamingStrategy strategy) {
@@ -40,8 +42,7 @@
super(appView, internalStates);
this.reservedNames = reservedNames;
this.strategy = strategy;
- this.isAvailable =
- (newName, field) -> !reservedNames.isReserved(newName, field.getReference().type);
+ this.isAvailable = (newName, field) -> !reservedNames.isReserved(newName, field.type);
}
public FieldNamingState createChildState(ReservedFieldNamingState reservedNames) {
@@ -51,13 +52,20 @@
return childState;
}
- public DexString getOrCreateNameFor(ProgramField field) {
- DexString reservedName = strategy.getReservedName(field.getDefinition(), field.getHolder());
- if (reservedName != null) {
- return reservedName;
+ public DexString getOrCreateNameFor(DexField field) {
+ DexEncodedField encodedField = appView.appInfo().resolveField(field).getResolvedField();
+ if (encodedField != null) {
+ DexClass clazz = appView.definitionFor(encodedField.holder());
+ if (clazz == null) {
+ return field.name;
+ }
+ DexString reservedName = strategy.getReservedName(encodedField, clazz);
+ if (reservedName != null) {
+ return reservedName;
+ }
}
// TODO(b/133208730) If we cannot resolve the field, are we then allowed to rename it?
- return getOrCreateInternalState(field.getReference()).createNewName(field);
+ return getOrCreateInternalState(field).createNewName(field);
}
public void includeReservations(ReservedFieldNamingState reservedNames) {
@@ -92,9 +100,9 @@
this.nextNameIndex = nextNameIndex;
}
- public DexString createNewName(ProgramField field) {
+ public DexString createNewName(DexField field) {
DexString name = strategy.next(field, this, isAvailable);
- assert !reservedNames.isReserved(name, field.getReference().type);
+ assert !reservedNames.isReserved(name, field.type);
return name;
}
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNamingStrategy.java b/src/main/java/com/android/tools/r8/naming/MemberNamingStrategy.java
index cddbea8..bacc7e0 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNamingStrategy.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNamingStrategy.java
@@ -7,9 +7,9 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.ProgramField;
import java.util.function.BiPredicate;
public interface MemberNamingStrategy {
@@ -20,9 +20,9 @@
BiPredicate<DexString, DexMethod> isAvailable);
DexString next(
- ProgramField field,
+ DexField field,
InternalNamingState internalState,
- BiPredicate<DexString, ProgramField> isAvailable);
+ BiPredicate<DexString, DexField> isAvailable);
DexString getReservedName(DexEncodedMethod method, DexClass holder);
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index d0f0381..8f1a41a 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -11,11 +11,11 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
import com.android.tools.r8.naming.ClassNameMinifier.ClassNamingStrategy;
@@ -240,10 +240,10 @@
@Override
public DexString next(
- ProgramField field,
+ DexField field,
InternalNamingState internalState,
- BiPredicate<DexString, ProgramField> isAvailable) {
- assert checkAllowMemberRenaming(field.getHolderType());
+ BiPredicate<DexString, DexField> isAvailable) {
+ assert checkAllowMemberRenaming(field.holder);
DexString candidate;
do {
candidate = getNextName(internalState, false);
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index e720b30..3ce8e7f 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
@@ -33,6 +32,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.TriFunction;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Maps;
@@ -301,9 +301,8 @@
DexField originalField = ((FieldSignature) signature).toDexField(factory, type);
addMemberNaming(
originalField, memberNaming, addToAdditionalMaps ? additionalFieldNamings : null);
- DexClass holder = appView.definitionForHolder(originalField);
- DexEncodedField field = originalField.lookupOnClass(holder);
- if (field == null || !field.isPrivate()) {
+ DexEncodedField encodedField = appView.definitionFor(originalField);
+ if (encodedField == null || !encodedField.accessFlags.isPrivate()) {
nonPrivateMembers.put(originalField, memberNaming);
}
}
@@ -466,46 +465,62 @@
@Override
public DexString next(
- DexMethod reference,
+ DexMethod method,
InternalNamingState internalState,
BiPredicate<DexString, DexMethod> isAvailable) {
- DexClass holder = appView.definitionForHolder(reference);
- assert holder != null;
- DexEncodedMethod method = holder.lookupMethod(reference);
- DexString reservedName = getReservedName(method, reference.name, holder);
- DexString nextName;
- if (reservedName != null) {
- if (!isAvailable.test(reservedName, reference)) {
- reportReservationError(reference, reservedName);
- }
- nextName = reservedName;
- } else {
- assert !mappedNames.containsKey(reference);
- assert appView.rootSet().mayBeMinified(reference, appView);
- nextName = super.next(reference, internalState, isAvailable);
- }
- assert nextName == reference.name || !method.isInitializer();
- assert nextName == reference.name || !holder.isAnnotation();
+ DexEncodedMethod definition = appView.definitionFor(method);
+ DexString nextName =
+ nextName(
+ method,
+ definition,
+ method.name,
+ method.holder,
+ internalState,
+ isAvailable,
+ super::next);
+ assert nextName == method.name || !definition.isClassInitializer();
+ assert nextName == method.name
+ || !appView.definitionFor(method.holder).accessFlags.isAnnotation();
return nextName;
}
@Override
public DexString next(
- ProgramField field,
+ DexField field,
InternalNamingState internalState,
- BiPredicate<DexString, ProgramField> isAvailable) {
- DexField reference = field.getReference();
- DexString reservedName =
- getReservedName(field.getDefinition(), reference.name, field.getHolder());
+ BiPredicate<DexString, DexField> isAvailable) {
+ return nextName(
+ field,
+ appView.definitionFor(field),
+ field.name,
+ field.holder,
+ internalState,
+ isAvailable,
+ super::next);
+ }
+
+ private <T extends DexReference> DexString nextName(
+ T reference,
+ DexDefinition definition,
+ DexString name,
+ DexType holderType,
+ InternalNamingState internalState,
+ BiPredicate<DexString, T> isAvailable,
+ TriFunction<T, InternalNamingState, BiPredicate<DexString, T>, DexString> generateName) {
+ assert definition.isDexEncodedMethod() || definition.isDexEncodedField();
+ assert definition.toReference() == reference;
+ DexClass holder = appView.definitionFor(holderType);
+ assert holder != null;
+ DexString reservedName = getReservedName(definition, name, holder);
if (reservedName != null) {
- if (!isAvailable.test(reservedName, field)) {
- reportReservationError(reference, reservedName);
+ if (!isAvailable.test(reservedName, reference)) {
+ reportReservationError(definition.toReference(), reservedName);
}
return reservedName;
}
assert !mappedNames.containsKey(reference);
assert appView.rootSet().mayBeMinified(reference, appView);
- return super.next(field, internalState, isAvailable);
+ return generateName.apply(reference, internalState, isAvailable);
}
@Override
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 9dfa92e..df5a09c 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -26,7 +26,6 @@
import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
import com.android.tools.r8.graph.FieldAccessInfoImpl;
-import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.InstantiatedSubTypeInfo;
@@ -976,9 +975,8 @@
// Switchmap classes should never be affected by renaming.
assert lens.assertDefinitionsNotModified(
switchMaps.keySet().stream()
- .map(this::resolveField)
- .filter(FieldResolutionResult::isSuccessfulResolution)
- .map(FieldResolutionResult::getResolvedField)
+ .map(this::definitionFor)
+ .filter(Objects::nonNull)
.collect(Collectors.toList()));
assert lens.assertDefinitionsNotModified(
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 ff991cf..8329ac7 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -504,6 +504,14 @@
recordTypeReference(field.type);
}
+ public DexEncodedField definitionFor(DexField field) {
+ DexClass clazz = definitionFor(field.holder);
+ if (clazz == null) {
+ return null;
+ }
+ return clazz.lookupField(field);
+ }
+
public DexEncodedMethod definitionFor(DexMethod method) {
DexClass clazz = definitionFor(method.holder);
if (clazz == null) {
@@ -3341,7 +3349,7 @@
ProgramMethod methodToKeep = action.getMethodToKeep();
ProgramMethod singleTarget = action.getSingleTarget();
DexEncodedMethod singleTargetMethod = singleTarget.getDefinition();
- if (rootSet.noShrinking.containsMethod(singleTarget.getReference())) {
+ if (rootSet.noShrinking.containsKey(singleTargetMethod.method)) {
return;
}
if (methodToKeep != singleTarget) {
@@ -4163,6 +4171,12 @@
@Deprecated
@Override
+ public DexEncodedField definitionFor(DexField field) {
+ return enqueuer.definitionFor(field);
+ }
+
+ @Deprecated
+ @Override
public DexEncodedMethod definitionFor(DexMethod method) {
return enqueuer.definitionFor(method);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index af14927..3bbfa9b 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -55,6 +55,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
@@ -81,7 +82,7 @@
private final SubtypingInfo subtypingInfo;
private final DirectMappedDexApplication application;
private final Iterable<? extends ProguardConfigurationRule> rules;
- private final MutableItemsWithRules noShrinking = new MutableItemsWithRules();
+ private final Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking = new IdentityHashMap<>();
private final Set<DexReference> noObfuscation = Sets.newIdentityHashSet();
private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>();
private final LinkedHashMap<DexReference, DexReference> checkDiscarded = new LinkedHashMap<>();
@@ -1099,7 +1100,7 @@
.computeIfAbsent(precondition.toReference(), x -> new MutableItemsWithRules())
.addReferenceWithRule(item.toReference(), keepRule);
} else {
- noShrinking.addReferenceWithRule(item.toReference(), keepRule);
+ noShrinking.computeIfAbsent(item.toReference(), i -> new HashSet<>()).add(keepRule);
}
context.markAsUsed();
}
@@ -1267,7 +1268,7 @@
final Set<DexMethod> neverInline;
final Set<DexType> neverClassInline;
- final MutableItemsWithRules noShrinking;
+ final Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking;
final Set<DexReference> noObfuscation;
final Map<DexReference, MutableItemsWithRules> dependentNoShrinking;
final Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule;
@@ -1276,7 +1277,7 @@
RootSetBase(
Set<DexMethod> neverInline,
Set<DexType> neverClassInline,
- MutableItemsWithRules noShrinking,
+ Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking,
Set<DexReference> noObfuscation,
Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
@@ -1402,45 +1403,16 @@
return MutableItemsWithRules.EMPTY;
}
- public abstract boolean containsClass(DexType type);
-
- public abstract boolean containsField(DexField field);
-
- public abstract boolean containsMethod(DexMethod method);
-
- public final boolean containsReference(DexReference reference) {
- return reference.apply(this::containsClass, this::containsField, this::containsMethod);
- }
-
- public abstract void forEachClass(Consumer<DexType> consumer);
-
public abstract void forEachClass(BiConsumer<DexType, Set<ProguardKeepRuleBase>> consumer);
- public abstract void forEachField(Consumer<? super DexField> consumer);
-
public abstract void forEachField(
BiConsumer<? super DexField, Set<ProguardKeepRuleBase>> consumer);
- public abstract void forEachMember(Consumer<DexMember<?, ?>> consumer);
-
public abstract void forEachMember(
BiConsumer<DexMember<?, ?>, Set<ProguardKeepRuleBase>> consumer);
- public abstract void forEachMethod(Consumer<? super DexMethod> consumer);
-
public abstract void forEachMethod(
BiConsumer<? super DexMethod, Set<ProguardKeepRuleBase>> consumer);
-
- public abstract Set<ProguardKeepRuleBase> getRulesForClass(DexType type);
-
- public abstract Set<ProguardKeepRuleBase> getRulesForField(DexField field);
-
- public abstract Set<ProguardKeepRuleBase> getRulesForMethod(DexMethod method);
-
- public final Set<ProguardKeepRuleBase> getRulesForReference(DexReference reference) {
- return reference.apply(
- this::getRulesForClass, this::getRulesForField, this::getRulesForMethod);
- }
}
static class MutableItemsWithRules extends ItemsWithRules {
@@ -1467,136 +1439,48 @@
}
public void addAll(ItemsWithRules items) {
- items.forEachClass(this::addClassWithRules);
- items.forEachField(this::addFieldWithRules);
- items.forEachMethod(this::addMethodWithRules);
+ items.forEachClass(classesWithRules::put);
+ items.forEachField(fieldsWithRules::put);
+ items.forEachMethod(methodsWithRules::put);
}
public void addClassWithRule(DexType type, ProguardKeepRuleBase rule) {
classesWithRules.computeIfAbsent(type, ignore -> new HashSet<>()).add(rule);
}
- public void addClassWithRules(DexType type, Set<ProguardKeepRuleBase> rules) {
- classesWithRules.computeIfAbsent(type, ignore -> new HashSet<>()).addAll(rules);
- }
-
public void addFieldWithRule(DexField field, ProguardKeepRuleBase rule) {
fieldsWithRules.computeIfAbsent(field, ignore -> new HashSet<>()).add(rule);
}
- public void addFieldWithRules(DexField field, Set<ProguardKeepRuleBase> rules) {
- fieldsWithRules.computeIfAbsent(field, ignore -> new HashSet<>()).addAll(rules);
- }
-
public void addMethodWithRule(DexMethod method, ProguardKeepRuleBase rule) {
methodsWithRules.computeIfAbsent(method, ignore -> new HashSet<>()).add(rule);
}
- public void addMethodWithRules(DexMethod method, Set<ProguardKeepRuleBase> rules) {
- methodsWithRules.computeIfAbsent(method, ignore -> new HashSet<>()).addAll(rules);
- }
-
public void addReferenceWithRule(DexReference reference, ProguardKeepRuleBase rule) {
- reference.accept(
+ reference.apply(
this::addClassWithRule, this::addFieldWithRule, this::addMethodWithRule, rule);
}
- public void addReferenceWithRules(DexReference reference, Set<ProguardKeepRuleBase> rules) {
- reference.accept(
- this::addClassWithRules, this::addFieldWithRules, this::addMethodWithRules, rules);
- }
-
- @Override
- public boolean containsClass(DexType type) {
- return classesWithRules.containsKey(type);
- }
-
- @Override
- public boolean containsField(DexField field) {
- return fieldsWithRules.containsKey(field);
- }
-
- @Override
- public boolean containsMethod(DexMethod method) {
- return methodsWithRules.containsKey(method);
- }
-
- @Override
- public void forEachClass(Consumer<DexType> consumer) {
- classesWithRules.keySet().forEach(consumer);
- }
-
@Override
public void forEachClass(BiConsumer<DexType, Set<ProguardKeepRuleBase>> consumer) {
classesWithRules.forEach(consumer);
}
@Override
- public void forEachField(Consumer<? super DexField> consumer) {
- fieldsWithRules.keySet().forEach(consumer);
- }
-
- @Override
public void forEachField(BiConsumer<? super DexField, Set<ProguardKeepRuleBase>> consumer) {
fieldsWithRules.forEach(consumer);
}
@Override
- public void forEachMember(Consumer<DexMember<?, ?>> consumer) {
- forEachField(consumer);
- forEachMethod(consumer);
- }
-
- @Override
public void forEachMember(BiConsumer<DexMember<?, ?>, Set<ProguardKeepRuleBase>> consumer) {
forEachField(consumer);
forEachMethod(consumer);
}
@Override
- public void forEachMethod(Consumer<? super DexMethod> consumer) {
- methodsWithRules.keySet().forEach(consumer);
- }
-
- @Override
public void forEachMethod(BiConsumer<? super DexMethod, Set<ProguardKeepRuleBase>> consumer) {
methodsWithRules.forEach(consumer);
}
-
- @Override
- public Set<ProguardKeepRuleBase> getRulesForClass(DexType type) {
- return classesWithRules.get(type);
- }
-
- @Override
- public Set<ProguardKeepRuleBase> getRulesForField(DexField field) {
- return fieldsWithRules.get(field);
- }
-
- @Override
- public Set<ProguardKeepRuleBase> getRulesForMethod(DexMethod method) {
- return methodsWithRules.get(method);
- }
-
- public void removeClass(DexType type) {
- classesWithRules.remove(type);
- }
-
- public void removeField(DexField field) {
- fieldsWithRules.remove(field);
- }
-
- public void removeMethod(DexMethod method) {
- methodsWithRules.remove(method);
- }
-
- public void removeReference(DexReference reference) {
- reference.accept(this::removeClass, this::removeField, this::removeMethod);
- }
-
- public int size() {
- return classesWithRules.size() + fieldsWithRules.size() + methodsWithRules.size();
- }
}
public static class RootSet extends RootSetBase {
@@ -1621,7 +1505,7 @@
public final Set<ProguardIfRule> ifRules;
private RootSet(
- MutableItemsWithRules noShrinking,
+ Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking,
Set<DexReference> noObfuscation,
ImmutableList<DexReference> reasonAsked,
ImmutableList<DexReference> checkDiscarded,
@@ -1695,7 +1579,8 @@
neverClassInline.addAll(consequentRootSet.neverClassInline);
noObfuscation.addAll(consequentRootSet.noObfuscation);
if (addNoShrinking) {
- noShrinking.addAll(consequentRootSet.noShrinking);
+ consequentRootSet.noShrinking.forEach(
+ (type, rules) -> noShrinking.computeIfAbsent(type, k -> new HashSet<>()).addAll(rules));
}
addDependentItems(consequentRootSet.dependentNoShrinking);
consequentRootSet.dependentKeepClassCompatRule.forEach(
@@ -1715,8 +1600,8 @@
}
public void copy(DexReference original, DexReference rewritten) {
- if (noShrinking.containsReference(original)) {
- noShrinking.addReferenceWithRules(rewritten, noShrinking.getRulesForReference(original));
+ if (noShrinking.containsKey(original)) {
+ noShrinking.put(rewritten, noShrinking.get(original));
}
if (noObfuscation.contains(original)) {
noObfuscation.add(rewritten);
@@ -1730,7 +1615,7 @@
}
public void prune(DexReference reference) {
- noShrinking.removeReference(reference);
+ noShrinking.remove(reference);
noObfuscation.remove(reference);
noSideEffects.remove(reference);
assumedValues.remove(reference);
@@ -1748,29 +1633,30 @@
Enqueuer enqueuer) {
references.removeIf(
reference -> {
- if (reference.isDexType()) {
+ if (reference.isDexField()) {
+ DexEncodedField definition = definitions.definitionFor(reference.asDexField());
+ if (definition == null) {
+ return true;
+ }
+ DexClass holder = definitions.definitionFor(definition.holder());
+ if (holder.isProgramClass()) {
+ return !enqueuer.isFieldReferenced(definition);
+ }
+ return !enqueuer.isNonProgramTypeLive(holder);
+ } else if (reference.isDexMethod()) {
+ DexEncodedMethod definition = definitions.definitionFor(reference.asDexMethod());
+ if (definition == null) {
+ return true;
+ }
+ DexClass holder = definitions.definitionFor(definition.holder());
+ if (holder.isProgramClass()) {
+ return !enqueuer.isMethodLive(definition) && !enqueuer.isMethodTargeted(definition);
+ }
+ return !enqueuer.isNonProgramTypeLive(holder);
+ } else {
DexClass definition = definitions.definitionFor(reference.asDexType());
return definition == null || !enqueuer.isTypeLive(definition);
}
-
- assert reference.isDexMember();
-
- DexMember<?, ?> member = reference.asDexMember();
- DexClass holder = definitions.definitionForHolder(member);
- DexEncodedMember<?, ?> definition = member.lookupOnClass(holder);
- if (definition == null) {
- return true;
- }
- if (holder.isProgramClass()) {
- if (definition.isDexEncodedField()) {
- DexEncodedField field = definition.asDexEncodedField();
- return !enqueuer.isFieldReferenced(field);
- }
- assert definition.isDexEncodedMethod();
- DexEncodedMethod method = definition.asDexEncodedMethod();
- return !enqueuer.isMethodLive(method) && !enqueuer.isMethodTargeted(method);
- }
- return !enqueuer.isNonProgramTypeLive(holder);
});
}
@@ -1802,49 +1688,52 @@
}
public boolean verifyKeptFieldsAreAccessedAndLive(AppInfoWithLiveness appInfo) {
- noShrinking.forEachField(
- reference -> {
- DexClass holder = appInfo.definitionForHolder(reference);
- DexEncodedField field = reference.lookupOnClass(holder);
- if (field != null
- && (field.isStatic() || isKeptDirectlyOrIndirectly(field.holder(), appInfo))) {
- assert appInfo.isFieldRead(field)
- : "Expected kept field `" + field.toSourceString() + "` to be read";
- assert appInfo.isFieldWritten(field)
- : "Expected kept field `" + field.toSourceString() + "` to be written";
- }
- });
+ for (DexReference reference : noShrinking.keySet()) {
+ if (reference.isDexField()) {
+ DexField field = reference.asDexField();
+ DexEncodedField encodedField = appInfo.definitionFor(field);
+ if (encodedField != null
+ && (encodedField.isStatic() || isKeptDirectlyOrIndirectly(field.holder, appInfo))) {
+ assert appInfo.isFieldRead(encodedField)
+ : "Expected kept field `" + field.toSourceString() + "` to be read";
+ assert appInfo.isFieldWritten(encodedField)
+ : "Expected kept field `" + field.toSourceString() + "` to be written";
+ }
+ }
+ }
return true;
}
public boolean verifyKeptMethodsAreTargetedAndLive(AppInfoWithLiveness appInfo) {
- noShrinking.forEachMethod(
- reference -> {
- assert appInfo.targetedMethods.contains(reference)
- : "Expected kept method `" + reference.toSourceString() + "` to be targeted";
- DexEncodedMethod method =
- appInfo.definitionForHolder(reference).lookupMethod(reference);
- if (!method.isAbstract() && isKeptDirectlyOrIndirectly(method.holder(), appInfo)) {
- assert appInfo.liveMethods.contains(reference)
- : "Expected non-abstract kept method `"
- + reference.toSourceString()
- + "` to be live";
- }
- });
+ for (DexReference reference : noShrinking.keySet()) {
+ if (reference.isDexMethod()) {
+ DexMethod method = reference.asDexMethod();
+ assert appInfo.targetedMethods.contains(method)
+ : "Expected kept method `" + method.toSourceString() + "` to be targeted";
+ DexEncodedMethod encodedMethod = appInfo.definitionFor(method);
+ if (!encodedMethod.accessFlags.isAbstract()
+ && isKeptDirectlyOrIndirectly(method.holder, appInfo)) {
+ assert appInfo.liveMethods.contains(method)
+ : "Expected non-abstract kept method `" + method.toSourceString() + "` to be live";
+ }
+ }
+ }
return true;
}
public boolean verifyKeptTypesAreLive(AppInfoWithLiveness appInfo) {
- noShrinking.forEachClass(
- type -> {
- assert appInfo.isLiveProgramType(type)
- : "Expected kept type `" + type.toSourceString() + "` to be live";
- });
+ for (DexReference reference : noShrinking.keySet()) {
+ if (reference.isDexType()) {
+ DexType type = reference.asDexType();
+ assert appInfo.isLiveProgramType(type)
+ : "Expected kept type `" + type.toSourceString() + "` to be live";
+ }
+ }
return true;
}
private boolean isKeptDirectlyOrIndirectly(DexType type, AppInfoWithLiveness appInfo) {
- if (noShrinking.containsClass(type)) {
+ if (noShrinking.containsKey(type)) {
return true;
}
DexClass clazz = appInfo.definitionFor(type);
@@ -1859,33 +1748,37 @@
public boolean verifyKeptItemsAreKept(DexApplication application, AppInfo appInfo) {
// Create a mapping from each required type to the set of required members on that type.
- Map<DexType, Set<DexMember<?, ?>>> requiredMembersPerType = new IdentityHashMap<>();
- noShrinking.forEachClass(
- type -> {
- assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(type)
- : "Expected reference `" + type.toSourceString() + "` to be pinned";
- requiredMembersPerType.computeIfAbsent(type, key -> Sets.newIdentityHashSet());
- });
- noShrinking.forEachMember(
- member -> {
- assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(member)
- : "Expected reference `" + member.toSourceString() + "` to be pinned";
- requiredMembersPerType
- .computeIfAbsent(member.holder, key -> Sets.newIdentityHashSet())
- .add(member);
- });
+ Map<DexType, Set<DexReference>> requiredReferencesPerType = new IdentityHashMap<>();
+ for (DexReference reference : noShrinking.keySet()) {
+ // Check that `pinnedItems` is a super set of the root set.
+ assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(reference)
+ : "Expected reference `" + reference.toSourceString() + "` to be pinned";
+ if (reference.isDexType()) {
+ DexType type = reference.asDexType();
+ requiredReferencesPerType.putIfAbsent(type, Sets.newIdentityHashSet());
+ } else {
+ assert reference.isDexField() || reference.isDexMethod();
+ DexType holder =
+ reference.isDexField()
+ ? reference.asDexField().holder
+ : reference.asDexMethod().holder;
+ requiredReferencesPerType
+ .computeIfAbsent(holder, key -> Sets.newIdentityHashSet())
+ .add(reference);
+ }
+ }
// Run through each class in the program and check that it has members it must have.
for (DexProgramClass clazz : application.classes()) {
- Set<DexMember<?, ?>> requiredMembers =
- requiredMembersPerType.getOrDefault(clazz.type, ImmutableSet.of());
+ Set<DexReference> requiredReferences =
+ requiredReferencesPerType.getOrDefault(clazz.type, ImmutableSet.of());
Set<DexField> fields = null;
Set<DexMethod> methods = null;
- for (DexMember<?, ?> requiredMember : requiredMembers) {
- if (requiredMember.isDexField()) {
- DexField requiredField = requiredMember.asDexField();
+ for (DexReference requiredReference : requiredReferences) {
+ if (requiredReference.isDexField()) {
+ DexField requiredField = requiredReference.asDexField();
if (fields == null) {
// Create a Set of the fields to avoid quadratic behavior.
fields =
@@ -1897,8 +1790,8 @@
: "Expected field `"
+ requiredField.toSourceString()
+ "` from the root set to be present";
- } else {
- DexMethod requiredMethod = requiredMember.asDexMethod();
+ } else if (requiredReference.isDexMethod()) {
+ DexMethod requiredMethod = requiredReference.asDexMethod();
if (methods == null) {
// Create a Set of the methods to avoid quadratic behavior.
methods =
@@ -1910,18 +1803,20 @@
: "Expected method `"
+ requiredMethod.toSourceString()
+ "` from the root set to be present";
+ } else {
+ assert false;
}
}
- requiredMembersPerType.remove(clazz.type);
+ requiredReferencesPerType.remove(clazz.type);
}
// If the map is non-empty, then a type in the root set was not in the application.
- if (!requiredMembersPerType.isEmpty()) {
- DexType type = requiredMembersPerType.keySet().iterator().next();
+ if (!requiredReferencesPerType.isEmpty()) {
+ DexType type = requiredReferencesPerType.keySet().iterator().next();
DexClass clazz = application.definitionFor(type);
assert clazz == null || clazz.isProgramClass()
: "Unexpected library type in root set: `" + type + "`";
- assert requiredMembersPerType.isEmpty()
+ assert requiredReferencesPerType.isEmpty()
: "Expected type `" + type.toSourceString() + "` to be present";
}
@@ -1932,6 +1827,7 @@
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("RootSet");
+
builder.append("\nnoShrinking: " + noShrinking.size());
builder.append("\nnoObfuscation: " + noObfuscation.size());
builder.append("\nreasonAsked: " + reasonAsked.size());
@@ -1941,6 +1837,18 @@
builder.append("\ndependentNoShrinking: " + dependentNoShrinking.size());
builder.append("\nidentifierNameStrings: " + identifierNameStrings.size());
builder.append("\nifRules: " + ifRules.size());
+
+ builder.append("\n\nNo Shrinking:");
+ noShrinking.keySet().stream()
+ .sorted(Comparator.comparing(DexReference::toSourceString))
+ .forEach(
+ a ->
+ builder
+ .append("\n")
+ .append(a.toSourceString())
+ .append(" ")
+ .append(noShrinking.get(a)));
+ builder.append("\n");
return builder.toString();
}
}
@@ -1952,7 +1860,7 @@
ConsequentRootSet(
Set<DexMethod> neverInline,
Set<DexType> neverClassInline,
- MutableItemsWithRules noShrinking,
+ Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking,
Set<DexReference> noObfuscation,
Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 1b69bc7..3dd0f4f 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1788,10 +1788,10 @@
private boolean foundIllegalAccess;
private ProgramMethod context;
- private final AppView<AppInfoWithLiveness> appView;
+ private final AppView<?> appView;
private final DexClass source;
- public IllegalAccessDetector(AppView<AppInfoWithLiveness> appView, DexClass source) {
+ public IllegalAccessDetector(AppView<?> appView, DexClass source) {
super(appView.dexItemFactory());
this.appView = appView;
this.source = source;
@@ -1813,7 +1813,7 @@
checkTypeReference(field.holder);
checkTypeReference(field.type);
- DexEncodedField definition = appView.appInfo().resolveField(field).getResolvedField();
+ DexEncodedField definition = appView.definitionFor(field);
if (definition == null || !definition.accessFlags.isPublic()) {
foundIllegalAccess = true;
}