Fix incorrect cache key for new method signature cache
Bug: b/241426917
Change-Id: I96a3e206f4fba54922a7546879b1ddc6147ce64c
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index ce22d5c..ba712ee 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -189,6 +189,10 @@
return accessFlags;
}
+ public int getArgumentIndexFromParameterIndex(int parameterIndex) {
+ return parameterIndex + getFirstNonReceiverArgumentIndex();
+ }
+
public DexType getArgumentType(int argumentIndex) {
return getReference().getArgumentType(argumentIndex, isStatic());
}
@@ -324,6 +328,11 @@
return getReference().getParameters();
}
+ public int getParameterIndexFromArgumentIndex(int argumentIndex) {
+ assert argumentIndex >= getFirstNonReceiverArgumentIndex();
+ return argumentIndex - getFirstNonReceiverArgumentIndex();
+ }
+
public DexType getReturnType() {
return getReference().getReturnType();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
index 880b51d..7be2dce 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.utils.IntObjConsumer;
import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -104,6 +105,13 @@
}
}
+ public void forEach(IntObjConsumer<DexType> consumer) {
+ for (int parameterIndex = 0; parameterIndex < values.length; parameterIndex++) {
+ DexType parameter = values[parameterIndex];
+ consumer.accept(parameterIndex, parameter);
+ }
+ }
+
public void forEachReverse(Consumer<? super DexType> consumer) {
for (int i = values.length - 1; i >= 0; i--) {
consumer.accept(values[i]);
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index f968d56..bf1afad 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -42,6 +42,7 @@
import com.android.tools.r8.utils.AccessUtils;
import com.android.tools.r8.utils.AndroidApiLevelUtils;
import com.android.tools.r8.utils.BooleanBox;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.IntBox;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions;
@@ -84,45 +85,63 @@
static class AllowedPrototypeChanges {
private static final AllowedPrototypeChanges EMPTY =
- new AllowedPrototypeChanges(null, Int2ReferenceMaps.emptyMap(), IntSets.EMPTY_SET);
+ new AllowedPrototypeChanges(false, null, Int2ReferenceMaps.emptyMap(), IntSets.EMPTY_SET);
+ boolean canBeConvertedToStaticMethod;
DexType newReturnType;
Int2ReferenceMap<DexType> newParameterTypes;
IntSet removableParameterIndices;
AllowedPrototypeChanges(
+ boolean canBeConvertedToStaticMethod,
DexType newReturnType,
Int2ReferenceMap<DexType> newParameterTypes,
IntSet removableParameterIndices) {
+ this.canBeConvertedToStaticMethod = canBeConvertedToStaticMethod;
this.newReturnType = newReturnType;
this.newParameterTypes = newParameterTypes;
this.removableParameterIndices = removableParameterIndices;
}
- public static AllowedPrototypeChanges create(RewrittenPrototypeDescription prototypeChanges) {
+ public static AllowedPrototypeChanges create(
+ ProgramMethod method, RewrittenPrototypeDescription prototypeChanges) {
if (prototypeChanges.isEmpty()) {
return empty();
}
+ ArgumentInfoCollection argumentInfoCollection = prototypeChanges.getArgumentInfoCollection();
+ boolean canBeConvertedToStaticMethod = argumentInfoCollection.isConvertedToStaticMethod();
+ assert !canBeConvertedToStaticMethod
+ || (method.getDefinition().isInstance()
+ && argumentInfoCollection.getArgumentInfo(0).isRemovedReceiverInfo());
DexType newReturnType =
prototypeChanges.hasRewrittenReturnInfo()
? prototypeChanges.getRewrittenReturnInfo().getNewType()
: null;
Int2ReferenceMap<DexType> newParameterTypes = new Int2ReferenceOpenHashMap<>();
IntSet removableParameterIndices = new IntOpenHashSet();
- prototypeChanges
- .getArgumentInfoCollection()
- .forEach(
- (argumentIndex, argumentInfo) -> {
- if (argumentInfo.isRemovedArgumentInfo()) {
- removableParameterIndices.add(argumentIndex);
- } else {
- assert argumentInfo.isRewrittenTypeInfo();
- RewrittenTypeInfo rewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo();
- newParameterTypes.put(argumentIndex, rewrittenTypeInfo.getNewType());
- }
- });
+ argumentInfoCollection.forEach(
+ (argumentIndex, argumentInfo) -> {
+ if (argumentInfo.isRemovedReceiverInfo()) {
+ // Skip as the receiver is not in the proto.
+ assert canBeConvertedToStaticMethod;
+ } else {
+ int parameterIndex =
+ method.getDefinition().getParameterIndexFromArgumentIndex(argumentIndex);
+ assert parameterIndex >= 0;
+ if (argumentInfo.isRemovedArgumentInfo()) {
+ removableParameterIndices.add(parameterIndex);
+ } else {
+ assert argumentInfo.isRewrittenTypeInfo();
+ RewrittenTypeInfo rewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo();
+ newParameterTypes.put(parameterIndex, rewrittenTypeInfo.getNewType());
+ }
+ }
+ });
return new AllowedPrototypeChanges(
- newReturnType, newParameterTypes, removableParameterIndices);
+ canBeConvertedToStaticMethod,
+ newReturnType,
+ newParameterTypes,
+ removableParameterIndices);
}
public static AllowedPrototypeChanges empty() {
@@ -131,7 +150,11 @@
@Override
public int hashCode() {
- return Objects.hash(newReturnType, newParameterTypes, removableParameterIndices);
+ return Objects.hash(
+ canBeConvertedToStaticMethod,
+ newReturnType,
+ newParameterTypes,
+ removableParameterIndices);
}
@Override
@@ -140,7 +163,8 @@
return false;
}
AllowedPrototypeChanges other = (AllowedPrototypeChanges) obj;
- return newReturnType == other.newReturnType
+ return canBeConvertedToStaticMethod == other.canBeConvertedToStaticMethod
+ && newReturnType == other.newReturnType
&& newParameterTypes.equals(other.newParameterTypes)
&& removableParameterIndices.equals(other.removableParameterIndices);
}
@@ -359,10 +383,11 @@
// Find the parameters that are either (i) the same constant, (ii) all unused, or (iii)
// all possible to strengthen to the same stronger type, in all methods.
+ boolean canBeConvertedToStaticMethod = canRemoveReceiverFromVirtualMethods(methods);
Int2ReferenceMap<DexType> newParameterTypes = new Int2ReferenceOpenHashMap<>();
IntSet removableVirtualMethodParametersInAllMethods = new IntArraySet();
for (int parameterIndex = 0;
- parameterIndex < signature.getProto().getArity() + 1;
+ parameterIndex < signature.getParameters().size();
parameterIndex++) {
if (canRemoveParameterFromVirtualMethods(methods, parameterIndex)) {
removableVirtualMethodParametersInAllMethods.add(parameterIndex);
@@ -380,12 +405,14 @@
getReturnValueForVirtualMethods(methods, signature);
DexType newReturnType =
getNewReturnTypeForVirtualMethods(methods, returnValueForVirtualMethods);
- if (newReturnType != null
+ if (canBeConvertedToStaticMethod
+ || newReturnType != null
|| !newParameterTypes.isEmpty()
|| !removableVirtualMethodParametersInAllMethods.isEmpty()) {
allowedPrototypeChangesForVirtualMethods.put(
signature,
new AllowedPrototypeChanges(
+ canBeConvertedToStaticMethod,
newReturnType,
newParameterTypes,
removableVirtualMethodParametersInAllMethods));
@@ -467,28 +494,30 @@
return false;
}
+ private boolean canRemoveReceiverFromVirtualMethods(ProgramMethodSet methods) {
+ if (methods.size() > 1) {
+ // Method staticizing would break dynamic dispatch.
+ return false;
+ }
+ ProgramMethod method = methods.getFirst();
+ return method.getOptimizationInfo().hasUnusedArguments()
+ && method.getOptimizationInfo().getUnusedArguments().get(0)
+ && ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method)
+ && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, 0);
+ }
+
private boolean canRemoveParameterFromVirtualMethods(
ProgramMethodSet methods, int parameterIndex) {
- if (parameterIndex == 0) {
- if (methods.size() > 1) {
- // Method staticizing would break dynamic dispatch.
- return false;
- }
- ProgramMethod method = methods.getFirst();
- return method.getOptimizationInfo().hasUnusedArguments()
- && method.getOptimizationInfo().getUnusedArguments().get(parameterIndex)
- && ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method)
- && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, parameterIndex);
- }
+ int argumentIndex = parameterIndex + 1;
for (ProgramMethod method : methods) {
if (method.getDefinition().isAbstract()) {
// OK, this parameter can be removed.
continue;
}
if (method.getOptimizationInfo().hasUnusedArguments()
- && method.getOptimizationInfo().getUnusedArguments().get(parameterIndex)
+ && method.getOptimizationInfo().getUnusedArguments().get(argumentIndex)
&& ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method)
- && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, parameterIndex)) {
+ && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, argumentIndex)) {
// OK, this parameter is unused.
continue;
}
@@ -497,7 +526,7 @@
ConcreteCallSiteOptimizationInfo concreteOptimizationInfo =
optimizationInfo.asConcreteCallSiteOptimizationInfo();
AbstractValue abstractValue =
- concreteOptimizationInfo.getAbstractArgumentValue(parameterIndex);
+ concreteOptimizationInfo.getAbstractArgumentValue(argumentIndex);
if (abstractValue.isSingleValue()
&& abstractValue.asSingleValue().isMaterializableInContext(appView, method)) {
// OK, this parameter has a constant value and can be removed.
@@ -544,9 +573,6 @@
private DexType getNewParameterTypeForVirtualMethods(
ProgramMethodSet methods, int parameterIndex) {
- if (parameterIndex == 0) {
- return null;
- }
DexType newParameterType = null;
for (ProgramMethod method : methods) {
if (method.getAccessFlags().isAbstract()) {
@@ -561,7 +587,7 @@
newParameterType = newParameterTypeForMethod;
}
assert newParameterType == null
- || newParameterType != methods.getFirst().getArgumentType(parameterIndex);
+ || newParameterType != methods.getFirst().getParameter(parameterIndex);
return newParameterType;
}
@@ -734,7 +760,7 @@
ProgramMethod method, RewrittenPrototypeDescription prototypeChanges) {
DexMethodSignature methodSignatureWithoutPrototypeChanges = method.getMethodSignature();
AllowedPrototypeChanges allowedPrototypeChanges =
- AllowedPrototypeChanges.create(prototypeChanges);
+ AllowedPrototypeChanges.create(method, prototypeChanges);
// Check if there is a reserved signature for this already.
DexMethodSignature reservedSignature =
@@ -742,6 +768,9 @@
.getOrDefault(methodSignatureWithoutPrototypeChanges, Collections.emptyMap())
.get(allowedPrototypeChanges);
if (reservedSignature != null) {
+ assert reservedSignature
+ .getProto()
+ .equals(prototypeChanges.rewriteMethod(method, dexItemFactory).getProto());
return reservedSignature.withHolder(method.getHolderType(), dexItemFactory);
}
@@ -882,14 +911,16 @@
removableParameterIndices);
}
+ boolean canBeConvertedToStaticMethod = allowedPrototypeChanges.canBeConvertedToStaticMethod;
RewrittenPrototypeDescription prototypeChanges =
computePrototypeChangesForMethod(
method,
+ canBeConvertedToStaticMethod,
allowedPrototypeChanges.newReturnType,
newParameterTypes::get,
removableParameterIndices::contains);
assert prototypeChanges.getArgumentInfoCollection().numberOfRemovedArguments()
- == removableParameterIndices.size();
+ == BooleanUtils.intValue(canBeConvertedToStaticMethod) + removableParameterIndices.size();
return prototypeChanges;
}
@@ -902,24 +933,26 @@
ArgumentInfoCollection.Builder argumentInfoCollectionBuilder =
ArgumentInfoCollection.builder()
.setArgumentInfosSize(method.getDefinition().getNumberOfArguments());
- for (int argumentIndex = 0;
- argumentIndex < method.getDefinition().getNumberOfArguments();
- argumentIndex++) {
- if (removableParameterIndices.contains(argumentIndex)) {
- argumentInfoCollectionBuilder.addArgumentInfo(
- argumentIndex,
- RemovedArgumentInfo.builder().setType(method.getArgumentType(argumentIndex)).build());
- } else if (newParameterTypes.containsKey(argumentIndex)) {
- DexType newParameterType = newParameterTypes.get(argumentIndex);
- argumentInfoCollectionBuilder.addArgumentInfo(
- argumentIndex,
- RewrittenTypeInfo.builder()
- .setCastType(newParameterType)
- .setOldType(method.getArgumentType(argumentIndex))
- .setNewType(newParameterType)
- .build());
- }
- }
+ method
+ .getParameters()
+ .forEach(
+ (parameterIndex, parameter) -> {
+ int argumentIndex =
+ method.getDefinition().getArgumentIndexFromParameterIndex(parameterIndex);
+ if (removableParameterIndices.contains(parameterIndex)) {
+ argumentInfoCollectionBuilder.addArgumentInfo(
+ argumentIndex, RemovedArgumentInfo.builder().setType(parameter).build());
+ } else if (newParameterTypes.containsKey(parameterIndex)) {
+ DexType newParameterType = newParameterTypes.get(parameterIndex);
+ argumentInfoCollectionBuilder.addArgumentInfo(
+ argumentIndex,
+ RewrittenTypeInfo.builder()
+ .setCastType(newParameterType)
+ .setOldType(parameter)
+ .setNewType(newParameterType)
+ .build());
+ }
+ });
return RewrittenPrototypeDescription.create(
Collections.emptyList(),
computeReturnChangesForMethod(method, newReturnType),
@@ -932,7 +965,11 @@
? parameterIndex -> getNewParameterType(method, parameterIndex)
: parameterIndex -> null;
return computePrototypeChangesForMethod(
- method, getNewReturnType(method), parameterIndexToParameterType, parameterIndex -> true);
+ method,
+ true,
+ getNewReturnType(method),
+ parameterIndexToParameterType,
+ parameterIndex -> true);
}
private DexType getNewReturnType(ProgramMethod method) {
@@ -996,7 +1033,6 @@
} else {
returnValue = method.getOptimizationInfo().getAbstractReturnValue();
}
-
return returnValue.isSingleValue()
&& returnValue.asSingleValue().isMaterializableInAllContexts(appView)
? returnValue.asSingleValue()
@@ -1007,12 +1043,13 @@
if (!appView.getKeepInfo(method).isParameterTypeStrengtheningAllowed(options)) {
return null;
}
- DexType staticType = method.getArgumentType(parameterIndex);
+ DexType staticType = method.getParameter(parameterIndex);
if (!staticType.isClassType()) {
return null;
}
+ int argumentIndex = method.getDefinition().getArgumentIndexFromParameterIndex(parameterIndex);
DynamicType dynamicType =
- method.getOptimizationInfo().getArgumentInfos().getDynamicType(parameterIndex);
+ method.getOptimizationInfo().getArgumentInfos().getDynamicType(argumentIndex);
if (dynamicType == null || dynamicType.isUnknown()) {
return null;
}
@@ -1046,24 +1083,27 @@
private RewrittenPrototypeDescription computePrototypeChangesForMethod(
ProgramMethod method,
+ boolean canBeConvertedToStaticMethod,
DexType newReturnType,
IntFunction<DexType> newParameterTypes,
IntPredicate removableParameterIndices) {
return RewrittenPrototypeDescription.create(
Collections.emptyList(),
computeReturnChangesForMethod(method, newReturnType),
- computeParameterChangesForMethod(method, newParameterTypes, removableParameterIndices));
+ computeParameterChangesForMethod(
+ method, canBeConvertedToStaticMethod, newParameterTypes, removableParameterIndices));
}
private ArgumentInfoCollection computeParameterChangesForMethod(
ProgramMethod method,
+ boolean canBeConvertedToStaticMethod,
IntFunction<DexType> newParameterTypes,
IntPredicate removableParameterIndices) {
ArgumentInfoCollection.Builder parameterChangesBuilder =
ArgumentInfoCollection.builder()
.setArgumentInfosSize(method.getDefinition().getNumberOfArguments());
if (method.getDefinition().isInstance()
- && removableParameterIndices.test(0)
+ && canBeConvertedToStaticMethod
&& method.getOptimizationInfo().hasUnusedArguments()
&& method.getOptimizationInfo().getUnusedArguments().get(0)
&& ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method)
@@ -1075,19 +1115,19 @@
}
CallSiteOptimizationInfo optimizationInfo = method.getOptimizationInfo().getArgumentInfos();
- for (int argumentIndex = method.getDefinition().getFirstNonReceiverArgumentIndex();
- argumentIndex < method.getDefinition().getNumberOfArguments();
- argumentIndex++) {
- if (removableParameterIndices.test(argumentIndex)) {
+ for (int parameterIndex = 0;
+ parameterIndex < method.getParameters().size();
+ parameterIndex++) {
+ int argumentIndex =
+ parameterIndex + method.getDefinition().getFirstNonReceiverArgumentIndex();
+ if (removableParameterIndices.test(parameterIndex)) {
if (method.getOptimizationInfo().hasUnusedArguments()
&& method.getOptimizationInfo().getUnusedArguments().get(argumentIndex)
&& ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method)
&& ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, argumentIndex)) {
parameterChangesBuilder.addArgumentInfo(
argumentIndex,
- RemovedArgumentInfo.builder()
- .setType(method.getArgumentType(argumentIndex))
- .build());
+ RemovedArgumentInfo.builder().setType(method.getParameter(parameterIndex)).build());
continue;
}
@@ -1098,15 +1138,15 @@
argumentIndex,
RemovedArgumentInfo.builder()
.setSingleValue(abstractValue.asSingleValue())
- .setType(method.getArgumentType(argumentIndex))
+ .setType(method.getParameter(parameterIndex))
.build());
continue;
}
}
- DexType dynamicType = newParameterTypes.apply(argumentIndex);
+ DexType dynamicType = newParameterTypes.apply(parameterIndex);
if (dynamicType != null) {
- DexType staticType = method.getArgumentType(argumentIndex);
+ DexType staticType = method.getParameter(parameterIndex);
assert dynamicType != staticType;
parameterChangesBuilder.addArgumentInfo(
argumentIndex,
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConsistentMethodRenamingWithArgumentRemovalAndStaticizingTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConsistentMethodRenamingWithArgumentRemovalAndStaticizingTest.java
index 0929298..e8daac4 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConsistentMethodRenamingWithArgumentRemovalAndStaticizingTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConsistentMethodRenamingWithArgumentRemovalAndStaticizingTest.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.codeinspector.AssertUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -31,17 +30,15 @@
@Test
public void test() throws Exception {
- AssertUtils.assertFailsCompilation(
- () ->
- testForR8(parameters.getBackend())
- .addInnerClasses(getClass())
- .addKeepMainRule(Main.class)
- .enableInliningAnnotations()
- .enableNeverClassInliningAnnotations()
- .enableNoHorizontalClassMergingAnnotations()
- .setMinApi(parameters.getApiLevel())
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("A.m()", "B.m()"));
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .enableNoHorizontalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A.m()", "B.m()");
}
static class Main {