Reland "Remove all uses of definitionFor(DexField)"
This reverts commit 39673cbe5607eb29e6f86cdb15d9866d8a6a9157.
Change-Id: I4e1cb3eff48494ea43190b01da02e5e3ea40277f
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 e49f177..3706dec 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -21,9 +21,6 @@
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;
@@ -33,31 +30,28 @@
private final BooleanBox obsolete;
public AppInfo(DexApplication application) {
- this(application, new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), new BooleanBox());
+ this(application, new ConcurrentHashMap<>(), new BooleanBox());
}
// For desugaring.
protected AppInfo(AppInfo appInfo) {
- this(appInfo.app, appInfo.fieldDefinitionsCache, appInfo.synthesizedClasses, appInfo.obsolete);
+ this(appInfo.app, 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;
}
@@ -102,7 +96,6 @@
assert checkIfObsolete();
assert clazz.type.isD8R8SynthesizedClassType();
DexProgramClass previous = synthesizedClasses.put(clazz.type, clazz);
- invalidateFieldCacheFor(clazz.type);
assert previous == null || previous == clazz;
}
@@ -183,21 +176,6 @@
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 33c63dc..b4534f5 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -228,12 +228,6 @@
@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 5055cc5..214e41c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
@@ -7,9 +7,6 @@
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 31017af..84d581e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -7,6 +7,8 @@
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> {
@@ -24,7 +26,28 @@
}
@Override
- public <T> void apply(
+ 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(
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 d04808b..02fd431 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMember.java
@@ -13,6 +13,10 @@
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 89c8f05..3618578 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -12,6 +12,8 @@
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> {
@@ -30,7 +32,23 @@
}
@Override
- public <T> void apply(
+ 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(
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 900712b..0fe1d69 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -133,6 +133,10 @@
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 3735378..c37c9de 100644
--- a/src/main/java/com/android/tools/r8/graph/DexReference.java
+++ b/src/main/java/com/android/tools/r8/graph/DexReference.java
@@ -4,6 +4,7 @@
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;
@@ -13,7 +14,17 @@
*/
public abstract class DexReference extends IndexedDexItem {
- public abstract <T> void apply(
+ 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(
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 dfe07f6..fc7ae3e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -31,6 +31,8 @@
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> {
@@ -116,7 +118,23 @@
}
@Override
- public <T> void apply(
+ 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(
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 d66ef7e..3699d2e 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -75,13 +75,6 @@
@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 fbb42a9..01d86a1 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,8 +7,10 @@
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;
@@ -106,8 +108,9 @@
}
AbstractValue abstractValue = root.getAbstractValue(appView, context);
if (abstractValue.isSingleFieldValue()) {
- DexEncodedField field =
- appView.definitionFor(abstractValue.asSingleFieldValue().getField());
+ DexField fieldReference = abstractValue.asSingleFieldValue().getField();
+ DexClass holder = appView.definitionForHolder(fieldReference);
+ DexEncodedField field = fieldReference.lookupOnClass(holder);
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 a2a932c..9fe885d 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,7 +5,9 @@
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;
@@ -71,12 +73,14 @@
assert !isEmpty();
ConcreteMutableFieldSet rewrittenSet = new ConcreteMutableFieldSet();
for (DexEncodedField field : fields) {
- DexEncodedField rewrittenField = appView.definitionFor(lens.lookupField(field.field));
+ DexField rewrittenFieldReference = lens.lookupField(field.field);
+ DexClass holder = appView.definitionForHolder(rewrittenFieldReference);
+ DexEncodedField rewrittenField = rewrittenFieldReference.lookupOnClass(holder);
if (rewrittenField == null) {
assert false;
continue;
}
- rewrittenSet.add(field);
+ rewrittenSet.add(rewrittenField);
}
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 e66d342..ba49fc0 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,6 +14,7 @@
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;
@@ -84,16 +85,20 @@
}
}
} else if (instruction.isFieldInstruction()) {
- DexEncodedField encodedField =
- appView.definitionFor(instruction.asFieldInstruction().getField());
- if (encodedField != null && fieldAccessRequiresRewriting(encodedField, method)) {
+ // 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)) {
if (instruction.isInstanceGet() || instruction.isStaticGet()) {
- DexMethod bridge = ensureFieldAccessBridge(encodedField, true);
+ DexMethod bridge = ensureFieldAccessBridge(field, true);
instructions.replaceCurrentInstruction(
new InvokeStatic(bridge, instruction.outValue(), instruction.inValues()));
} else {
assert instruction.isInstancePut() || instruction.isStaticPut();
- DexMethod bridge = ensureFieldAccessBridge(encodedField, false);
+ DexMethod bridge = ensureFieldAccessBridge(field, 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 7da225c..2586141 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,14 +84,15 @@
return appView.definitionFor(appView.graphLense().lookupType(type));
}
- private DexEncodedMethod definitionFor(
+ private DexEncodedMethod lookupOnHolder(
DexMethod method, DexClassAndMethod context, Invoke.Type invokeType) {
return appView.definitionFor(
appView.graphLense().lookupMethod(method, context.getReference(), invokeType).getMethod());
}
- private DexEncodedField definitionFor(DexField field) {
- return appView.definitionFor(appView.graphLense().lookupField(field));
+ private DexEncodedField lookupOnHolder(DexField field) {
+ DexField rewritten = appView.graphLense().lookupField(field);
+ return rewritten.lookupOnClass(appView.definitionForHolder(rewritten));
}
// Extract the list of types in the programClass' nest, of host hostClass
@@ -365,7 +366,7 @@
if (!method.holder.isClassType()) {
return false;
}
- DexEncodedMethod encodedMethod = definitionFor(method, context, invokeType);
+ DexEncodedMethod encodedMethod = lookupOnHolder(method, context, invokeType);
if (encodedMethod != null && invokeRequiresRewriting(encodedMethod, context)) {
ensureInvokeBridge(encodedMethod);
return true;
@@ -374,7 +375,10 @@
}
private boolean registerFieldAccess(DexField field, boolean isGet) {
- DexEncodedField encodedField = definitionFor(field);
+ // 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);
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 f2cefad..def219f 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,10 +2537,13 @@
if (singleFieldValue.getField() == otherSingleFieldValue.getField()) {
simplifyIfWithKnownCondition(code, block, theIf, 0);
} else {
- DexEncodedField field = appView.definitionFor(singleFieldValue.getField());
+ DexClass holder = appView.definitionForHolder(singleFieldValue.getField());
+ DexEncodedField field = singleFieldValue.getField().lookupOnClass(holder);
if (field != null && field.isEnum()) {
+ DexClass otherHolder =
+ appView.definitionForHolder(otherSingleFieldValue.getField());
DexEncodedField otherField =
- appView.definitionFor(otherSingleFieldValue.getField());
+ otherSingleFieldValue.getField().lookupOnClass(otherHolder);
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 ef81097..5178020 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 appView.definitionFor(field);
+ return method.getHolder().lookupField(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 2fe8a19..fe70918 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,7 +4,9 @@
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;
@@ -32,9 +34,10 @@
BiConsumer<DexEncodedField, InstanceFieldInitializationInfo> consumer) {
infos.forEach(
(field, info) -> {
- DexEncodedField encodedField = definitions.definitionFor(field);
- if (encodedField != null) {
- consumer.accept(encodedField, info);
+ DexClass holder = definitions.definitionForHolder(field);
+ DexEncodedField definition = field.lookupOnClass(holder);
+ if (definition != null) {
+ consumer.accept(definition, 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 ad6313e..bcea380 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 = appView.definitionFor(field);
+ DexEncodedField definition = field.lookupOnClass(appView.definitionForHolder(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 f3fba2d..c326f61 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -12,9 +12,7 @@
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;
@@ -122,11 +120,6 @@
}
@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 8cffa05..b014c4f 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -3,15 +3,19 @@
// 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;
@@ -178,9 +182,7 @@
getOrCreateReservedFieldNamingState(clazz.type);
FieldNamingState state = parentState.createChildState(reservedNames);
if (clazz.isProgramClass()) {
- for (DexEncodedField field : clazz.fields()) {
- renameField(field, state);
- }
+ clazz.asProgramClass().forEachProgramField(field -> renameField(field, state));
}
assert !states.containsKey(clazz.type);
@@ -212,11 +214,14 @@
for (DexClass clazz : partition) {
if (clazz.isProgramClass()) {
assert clazz.isInterface();
- for (DexEncodedField field : clazz.fields()) {
- DexString newName = renameField(field, state);
- namesToBeReservedInImplementsSubclasses.markReservedDirectly(
- newName, field.field.name, field.field.type);
- }
+ clazz
+ .asProgramClass()
+ .forEachProgramField(
+ field -> {
+ DexString newName = renameField(field, state);
+ namesToBeReservedInImplementsSubclasses.markReservedDirectly(
+ newName, field.getReference().name, field.getReference().type);
+ });
}
}
@@ -236,11 +241,10 @@
}
}
- private DexString renameField(DexEncodedField encodedField, FieldNamingState state) {
- DexField field = encodedField.field;
+ private DexString renameField(ProgramField field, FieldNamingState state) {
DexString newName = state.getOrCreateNameFor(field);
- if (newName != field.name) {
- renaming.put(field, newName);
+ if (newName != field.getReference().name) {
+ renaming.put(field.getReference(), newName);
}
return newName;
}
@@ -256,32 +260,17 @@
}
private void renameNonReboundAccessToField(DexField field) {
- // Already renamed
+ // If the given field reference is a non-rebound reference to a program field, then assign the
+ // same name as the resolved field.
if (renaming.containsKey(field)) {
return;
}
- DexEncodedField definition = appView.definitionFor(field);
- if (definition != null) {
- assert definition.field == field;
+ DexProgramClass holder = asProgramClassOrNull(appView.definitionForHolder(field));
+ if (holder == null) {
return;
}
- // 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.
+ DexEncodedField definition = appView.appInfo().resolveFieldOn(holder, field).getResolvedField();
+ if (definition != null && definition.field != field && renaming.containsKey(definition.field)) {
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 f8d80cb..35e3d3f 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
@@ -6,11 +6,9 @@
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;
@@ -20,7 +18,7 @@
private final ReservedFieldNamingState reservedNames;
private final MemberNamingStrategy strategy;
- private final BiPredicate<DexString, DexField> isAvailable;
+ private final BiPredicate<DexString, ProgramField> isAvailable;
public FieldNamingState(
AppView<? extends AppInfoWithClassHierarchy> appView, MemberNamingStrategy strategy) {
@@ -42,7 +40,8 @@
super(appView, internalStates);
this.reservedNames = reservedNames;
this.strategy = strategy;
- this.isAvailable = (newName, field) -> !reservedNames.isReserved(newName, field.type);
+ this.isAvailable =
+ (newName, field) -> !reservedNames.isReserved(newName, field.getReference().type);
}
public FieldNamingState createChildState(ReservedFieldNamingState reservedNames) {
@@ -52,20 +51,13 @@
return childState;
}
- 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;
- }
+ public DexString getOrCreateNameFor(ProgramField field) {
+ DexString reservedName = strategy.getReservedName(field.getDefinition(), field.getHolder());
+ if (reservedName != null) {
+ return reservedName;
}
// TODO(b/133208730) If we cannot resolve the field, are we then allowed to rename it?
- return getOrCreateInternalState(field).createNewName(field);
+ return getOrCreateInternalState(field.getReference()).createNewName(field);
}
public void includeReservations(ReservedFieldNamingState reservedNames) {
@@ -100,9 +92,9 @@
this.nextNameIndex = nextNameIndex;
}
- public DexString createNewName(DexField field) {
+ public DexString createNewName(ProgramField field) {
DexString name = strategy.next(field, this, isAvailable);
- assert !reservedNames.isReserved(name, field.type);
+ assert !reservedNames.isReserved(name, field.getReference().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 bacc7e0..cddbea8 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(
- DexField field,
+ ProgramField field,
InternalNamingState internalState,
- BiPredicate<DexString, DexField> isAvailable);
+ BiPredicate<DexString, ProgramField> 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 8f1a41a..d0f0381 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(
- DexField field,
+ ProgramField field,
InternalNamingState internalState,
- BiPredicate<DexString, DexField> isAvailable) {
- assert checkAllowMemberRenaming(field.holder);
+ BiPredicate<DexString, ProgramField> isAvailable) {
+ assert checkAllowMemberRenaming(field.getHolderType());
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 3ce8e7f..e720b30 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -16,6 +16,7 @@
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;
@@ -32,7 +33,6 @@
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,8 +301,9 @@
DexField originalField = ((FieldSignature) signature).toDexField(factory, type);
addMemberNaming(
originalField, memberNaming, addToAdditionalMaps ? additionalFieldNamings : null);
- DexEncodedField encodedField = appView.definitionFor(originalField);
- if (encodedField == null || !encodedField.accessFlags.isPrivate()) {
+ DexClass holder = appView.definitionForHolder(originalField);
+ DexEncodedField field = originalField.lookupOnClass(holder);
+ if (field == null || !field.isPrivate()) {
nonPrivateMembers.put(originalField, memberNaming);
}
}
@@ -465,62 +466,46 @@
@Override
public DexString next(
- DexMethod method,
+ DexMethod reference,
InternalNamingState internalState,
BiPredicate<DexString, DexMethod> isAvailable) {
- 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();
+ 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();
return nextName;
}
@Override
public DexString next(
- DexField field,
+ ProgramField field,
InternalNamingState internalState,
- 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);
+ BiPredicate<DexString, ProgramField> isAvailable) {
+ DexField reference = field.getReference();
+ DexString reservedName =
+ getReservedName(field.getDefinition(), reference.name, field.getHolder());
if (reservedName != null) {
- if (!isAvailable.test(reservedName, reference)) {
- reportReservationError(definition.toReference(), reservedName);
+ if (!isAvailable.test(reservedName, field)) {
+ reportReservationError(reference, reservedName);
}
return reservedName;
}
assert !mappedNames.containsKey(reference);
assert appView.rootSet().mayBeMinified(reference, appView);
- return generateName.apply(reference, internalState, isAvailable);
+ return super.next(field, 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 df5a09c..9dfa92e 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -26,6 +26,7 @@
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;
@@ -975,8 +976,9 @@
// Switchmap classes should never be affected by renaming.
assert lens.assertDefinitionsNotModified(
switchMaps.keySet().stream()
- .map(this::definitionFor)
- .filter(Objects::nonNull)
+ .map(this::resolveField)
+ .filter(FieldResolutionResult::isSuccessfulResolution)
+ .map(FieldResolutionResult::getResolvedField)
.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 8329ac7..ff991cf 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -504,14 +504,6 @@
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) {
@@ -3349,7 +3341,7 @@
ProgramMethod methodToKeep = action.getMethodToKeep();
ProgramMethod singleTarget = action.getSingleTarget();
DexEncodedMethod singleTargetMethod = singleTarget.getDefinition();
- if (rootSet.noShrinking.containsKey(singleTargetMethod.method)) {
+ if (rootSet.noShrinking.containsMethod(singleTarget.getReference())) {
return;
}
if (methodToKeep != singleTarget) {
@@ -4171,12 +4163,6 @@
@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 3bbfa9b..5b3e34f 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -55,7 +55,6 @@
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;
@@ -82,7 +81,7 @@
private final SubtypingInfo subtypingInfo;
private final DirectMappedDexApplication application;
private final Iterable<? extends ProguardConfigurationRule> rules;
- private final Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking = new IdentityHashMap<>();
+ private final MutableItemsWithRules noShrinking = new MutableItemsWithRules();
private final Set<DexReference> noObfuscation = Sets.newIdentityHashSet();
private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>();
private final LinkedHashMap<DexReference, DexReference> checkDiscarded = new LinkedHashMap<>();
@@ -1100,7 +1099,7 @@
.computeIfAbsent(precondition.toReference(), x -> new MutableItemsWithRules())
.addReferenceWithRule(item.toReference(), keepRule);
} else {
- noShrinking.computeIfAbsent(item.toReference(), i -> new HashSet<>()).add(keepRule);
+ noShrinking.addReferenceWithRule(item.toReference(), keepRule);
}
context.markAsUsed();
}
@@ -1268,7 +1267,7 @@
final Set<DexMethod> neverInline;
final Set<DexType> neverClassInline;
- final Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking;
+ final MutableItemsWithRules noShrinking;
final Set<DexReference> noObfuscation;
final Map<DexReference, MutableItemsWithRules> dependentNoShrinking;
final Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule;
@@ -1277,7 +1276,7 @@
RootSetBase(
Set<DexMethod> neverInline,
Set<DexType> neverClassInline,
- Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking,
+ MutableItemsWithRules noShrinking,
Set<DexReference> noObfuscation,
Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
@@ -1403,16 +1402,45 @@
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 {
@@ -1439,48 +1467,159 @@
}
public void addAll(ItemsWithRules items) {
- items.forEachClass(classesWithRules::put);
- items.forEachField(fieldsWithRules::put);
- items.forEachMethod(methodsWithRules::put);
+ items.forEachClass(this::addClassWithRules);
+ items.forEachField(this::addFieldWithRules);
+ items.forEachMethod(this::addMethodWithRules);
}
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.apply(
+ reference.accept(
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 void putAll(ItemsWithRules items) {
+ items.forEachClass(this::putClassWithRules);
+ items.forEachField(this::putFieldWithRules);
+ items.forEachMethod(this::putMethodWithRules);
+ }
+
+ public void putClassWithRules(DexType type, Set<ProguardKeepRuleBase> rules) {
+ classesWithRules.put(type, rules);
+ }
+
+ public void putFieldWithRules(DexField field, Set<ProguardKeepRuleBase> rules) {
+ fieldsWithRules.put(field, rules);
+ }
+
+ public void putMethodWithRules(DexMethod method, Set<ProguardKeepRuleBase> rules) {
+ methodsWithRules.put(method, rules);
+ }
+
+ public void putReferenceWithRules(DexReference reference, Set<ProguardKeepRuleBase> rules) {
+ reference.accept(
+ this::putClassWithRules, this::putFieldWithRules, this::putMethodWithRules, rules);
+ }
+
+ public int size() {
+ return classesWithRules.size() + fieldsWithRules.size() + methodsWithRules.size();
+ }
}
public static class RootSet extends RootSetBase {
@@ -1505,7 +1644,7 @@
public final Set<ProguardIfRule> ifRules;
private RootSet(
- Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking,
+ MutableItemsWithRules noShrinking,
Set<DexReference> noObfuscation,
ImmutableList<DexReference> reasonAsked,
ImmutableList<DexReference> checkDiscarded,
@@ -1579,8 +1718,7 @@
neverClassInline.addAll(consequentRootSet.neverClassInline);
noObfuscation.addAll(consequentRootSet.noObfuscation);
if (addNoShrinking) {
- consequentRootSet.noShrinking.forEach(
- (type, rules) -> noShrinking.computeIfAbsent(type, k -> new HashSet<>()).addAll(rules));
+ noShrinking.addAll(consequentRootSet.noShrinking);
}
addDependentItems(consequentRootSet.dependentNoShrinking);
consequentRootSet.dependentKeepClassCompatRule.forEach(
@@ -1596,12 +1734,12 @@
(reference, dependence) ->
dependentNoShrinking
.computeIfAbsent(reference, x -> new MutableItemsWithRules())
- .addAll(dependence));
+ .putAll(dependence));
}
public void copy(DexReference original, DexReference rewritten) {
- if (noShrinking.containsKey(original)) {
- noShrinking.put(rewritten, noShrinking.get(original));
+ if (noShrinking.containsReference(original)) {
+ noShrinking.putReferenceWithRules(rewritten, noShrinking.getRulesForReference(original));
}
if (noObfuscation.contains(original)) {
noObfuscation.add(rewritten);
@@ -1615,7 +1753,7 @@
}
public void prune(DexReference reference) {
- noShrinking.remove(reference);
+ noShrinking.removeReference(reference);
noObfuscation.remove(reference);
noSideEffects.remove(reference);
assumedValues.remove(reference);
@@ -1633,30 +1771,29 @@
Enqueuer enqueuer) {
references.removeIf(
reference -> {
- 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 {
+ if (reference.isDexType()) {
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);
});
}
@@ -1688,52 +1825,49 @@
}
public boolean verifyKeptFieldsAreAccessedAndLive(AppInfoWithLiveness appInfo) {
- 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";
- }
- }
- }
+ 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";
+ }
+ });
return true;
}
public boolean verifyKeptMethodsAreTargetedAndLive(AppInfoWithLiveness appInfo) {
- 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";
- }
- }
- }
+ 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";
+ }
+ });
return true;
}
public boolean verifyKeptTypesAreLive(AppInfoWithLiveness appInfo) {
- for (DexReference reference : noShrinking.keySet()) {
- if (reference.isDexType()) {
- DexType type = reference.asDexType();
- assert appInfo.isLiveProgramType(type)
- : "Expected kept type `" + type.toSourceString() + "` to be live";
- }
- }
+ noShrinking.forEachClass(
+ type -> {
+ assert appInfo.isLiveProgramType(type)
+ : "Expected kept type `" + type.toSourceString() + "` to be live";
+ });
return true;
}
private boolean isKeptDirectlyOrIndirectly(DexType type, AppInfoWithLiveness appInfo) {
- if (noShrinking.containsKey(type)) {
+ if (noShrinking.containsClass(type)) {
return true;
}
DexClass clazz = appInfo.definitionFor(type);
@@ -1748,37 +1882,33 @@
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<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);
- }
- }
+ 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);
+ });
// Run through each class in the program and check that it has members it must have.
for (DexProgramClass clazz : application.classes()) {
- Set<DexReference> requiredReferences =
- requiredReferencesPerType.getOrDefault(clazz.type, ImmutableSet.of());
+ Set<DexMember<?, ?>> requiredMembers =
+ requiredMembersPerType.getOrDefault(clazz.type, ImmutableSet.of());
Set<DexField> fields = null;
Set<DexMethod> methods = null;
- for (DexReference requiredReference : requiredReferences) {
- if (requiredReference.isDexField()) {
- DexField requiredField = requiredReference.asDexField();
+ for (DexMember<?, ?> requiredMember : requiredMembers) {
+ if (requiredMember.isDexField()) {
+ DexField requiredField = requiredMember.asDexField();
if (fields == null) {
// Create a Set of the fields to avoid quadratic behavior.
fields =
@@ -1790,8 +1920,8 @@
: "Expected field `"
+ requiredField.toSourceString()
+ "` from the root set to be present";
- } else if (requiredReference.isDexMethod()) {
- DexMethod requiredMethod = requiredReference.asDexMethod();
+ } else {
+ DexMethod requiredMethod = requiredMember.asDexMethod();
if (methods == null) {
// Create a Set of the methods to avoid quadratic behavior.
methods =
@@ -1803,20 +1933,18 @@
: "Expected method `"
+ requiredMethod.toSourceString()
+ "` from the root set to be present";
- } else {
- assert false;
}
}
- requiredReferencesPerType.remove(clazz.type);
+ requiredMembersPerType.remove(clazz.type);
}
// If the map is non-empty, then a type in the root set was not in the application.
- if (!requiredReferencesPerType.isEmpty()) {
- DexType type = requiredReferencesPerType.keySet().iterator().next();
+ if (!requiredMembersPerType.isEmpty()) {
+ DexType type = requiredMembersPerType.keySet().iterator().next();
DexClass clazz = application.definitionFor(type);
assert clazz == null || clazz.isProgramClass()
: "Unexpected library type in root set: `" + type + "`";
- assert requiredReferencesPerType.isEmpty()
+ assert requiredMembersPerType.isEmpty()
: "Expected type `" + type.toSourceString() + "` to be present";
}
@@ -1827,7 +1955,6 @@
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());
@@ -1837,18 +1964,6 @@
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();
}
}
@@ -1860,7 +1975,7 @@
ConsequentRootSet(
Set<DexMethod> neverInline,
Set<DexType> neverClassInline,
- Map<DexReference, Set<ProguardKeepRuleBase>> noShrinking,
+ MutableItemsWithRules 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 3dd0f4f..1b69bc7 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<?> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final DexClass source;
- public IllegalAccessDetector(AppView<?> appView, DexClass source) {
+ public IllegalAccessDetector(AppView<AppInfoWithLiveness> 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.definitionFor(field);
+ DexEncodedField definition = appView.appInfo().resolveField(field).getResolvedField();
if (definition == null || !definition.accessFlags.isPublic()) {
foundIllegalAccess = true;
}