RewrittenProto: Unify argument representation
Bug: 149681096
Change-Id: I47488dec51a84fd40024d9b135812af288f4a418
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
index f4552a5..663524d 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -11,16 +11,56 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BooleanUtils;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
+import com.google.common.collect.Ordering;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceRBTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
import java.util.function.Consumer;
public class RewrittenPrototypeDescription {
- public static class RemovedArgumentInfo {
+ public interface ArgumentInfo {
+
+ @SuppressWarnings("ConstantConditions")
+ static ArgumentInfo combine(ArgumentInfo arg1, ArgumentInfo arg2) {
+ if (arg1 == null) {
+ assert arg2 != null;
+ return arg2;
+ }
+ if (arg2 == null) {
+ assert arg1 != null;
+ return arg1;
+ }
+ return arg1.combine(arg2);
+ }
+
+ ArgumentInfo NO_INFO =
+ info -> {
+ assert false : "ArgumentInfo NO_INFO should not be combined";
+ return info;
+ };
+
+ default boolean isRemovedArgumentInfo() {
+ return false;
+ }
+
+ default RemovedArgumentInfo asRemovedArgumentInfo() {
+ return null;
+ }
+
+ default boolean isRewrittenTypeInfo() {
+ return false;
+ }
+
+ default RewrittenTypeInfo asRewrittenTypeInfo() {
+ return null;
+ }
+
+ // ArgumentInfo are combined with `this` first, and the `info` argument second.
+ ArgumentInfo combine(ArgumentInfo info);
+ }
+
+ public static class RemovedArgumentInfo implements ArgumentInfo {
public static class Builder {
@@ -66,140 +106,25 @@
public boolean isNeverUsed() {
return !isAlwaysNull;
}
- }
- public static class RemovedArgumentInfoCollection {
-
- private static final RemovedArgumentInfoCollection EMPTY = new RemovedArgumentInfoCollection();
-
- private final Int2ReferenceSortedMap<RemovedArgumentInfo> removedArguments;
-
- // Specific constructor for empty.
- private RemovedArgumentInfoCollection() {
- this.removedArguments = new Int2ReferenceLinkedOpenHashMap<>();
+ @Override
+ public boolean isRemovedArgumentInfo() {
+ return true;
}
- private RemovedArgumentInfoCollection(
- Int2ReferenceSortedMap<RemovedArgumentInfo> removedArguments) {
- assert removedArguments != null : "should use empty.";
- assert !removedArguments.isEmpty() : "should use empty.";
- this.removedArguments = removedArguments;
+ @Override
+ public RemovedArgumentInfo asRemovedArgumentInfo() {
+ return this;
}
- public static RemovedArgumentInfoCollection empty() {
- return EMPTY;
- }
-
- public RemovedArgumentInfo getArgumentInfo(int argIndex) {
- return removedArguments.get(argIndex);
- }
-
- public boolean hasRemovedArguments() {
- return !removedArguments.isEmpty();
- }
-
- public boolean isArgumentRemoved(int argumentIndex) {
- return removedArguments.containsKey(argumentIndex);
- }
-
- public DexType[] rewriteParameters(DexEncodedMethod encodedMethod) {
- // Currently not allowed to remove the receiver of an instance method. This would involve
- // changing invoke-direct/invoke-virtual into invoke-static.
- assert encodedMethod.isStatic() || !isArgumentRemoved(0);
- DexType[] params = encodedMethod.method.proto.parameters.values;
- if (!hasRemovedArguments()) {
- return params;
- }
- DexType[] newParams = new DexType[params.length - numberOfRemovedArguments()];
- int offset = encodedMethod.isStatic() ? 0 : 1;
- int newParamIndex = 0;
- for (int oldParamIndex = 0; oldParamIndex < params.length; ++oldParamIndex) {
- if (!isArgumentRemoved(oldParamIndex + offset)) {
- newParams[newParamIndex++] = params[oldParamIndex];
- }
- }
- return newParams;
- }
-
- public int numberOfRemovedArguments() {
- return removedArguments != null ? removedArguments.size() : 0;
- }
-
- public RemovedArgumentInfoCollection combine(RemovedArgumentInfoCollection info) {
- if (hasRemovedArguments()) {
- if (!info.hasRemovedArguments()) {
- return this;
- }
- } else {
- return info;
- }
-
- Int2ReferenceSortedMap<RemovedArgumentInfo> newRemovedArguments =
- new Int2ReferenceLinkedOpenHashMap<>();
- newRemovedArguments.putAll(removedArguments);
- IntBidirectionalIterator iterator = removedArguments.keySet().iterator();
- int offset = 0;
- for (int pendingArgIndex : info.removedArguments.keySet()) {
- int nextArgindex = peekNextOrMax(iterator);
- while (nextArgindex <= pendingArgIndex + offset) {
- iterator.nextInt();
- nextArgindex = peekNextOrMax(iterator);
- offset++;
- }
- assert !newRemovedArguments.containsKey(pendingArgIndex + offset);
- newRemovedArguments.put(
- pendingArgIndex + offset, info.removedArguments.get(pendingArgIndex));
- }
- return new RemovedArgumentInfoCollection(newRemovedArguments);
- }
-
- static int peekNextOrMax(IntBidirectionalIterator iterator) {
- if (iterator.hasNext()) {
- int i = iterator.nextInt();
- iterator.previousInt();
- return i;
- }
- return Integer.MAX_VALUE;
- }
-
- public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
- DexEncodedMethod method) {
- if (numberOfRemovedArguments() > 0 && !method.parameterAnnotationsList.isEmpty()) {
- return builder -> {
- int firstArgumentIndex = BooleanUtils.intValue(!method.isStatic());
- builder.removeParameterAnnotations(
- oldIndex -> isArgumentRemoved(oldIndex + firstArgumentIndex));
- };
- }
- return null;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private Int2ReferenceSortedMap<RemovedArgumentInfo> removedArguments;
-
- public Builder addRemovedArgument(int argIndex, RemovedArgumentInfo argInfo) {
- if (removedArguments == null) {
- removedArguments = new Int2ReferenceLinkedOpenHashMap<>();
- }
- assert !removedArguments.containsKey(argIndex);
- removedArguments.put(argIndex, argInfo);
- return this;
- }
-
- public RemovedArgumentInfoCollection build() {
- if (removedArguments == null || removedArguments.isEmpty()) {
- return EMPTY;
- }
- return new RemovedArgumentInfoCollection(removedArguments);
- }
+ @Override
+ public ArgumentInfo combine(ArgumentInfo info) {
+ assert false : "Once the argument is removed one cannot modify it any further.";
+ return this;
}
}
- public static class RewrittenTypeInfo {
+ public static class RewrittenTypeInfo implements ArgumentInfo {
private final DexType oldType;
private final DexType newType;
@@ -246,56 +171,75 @@
}
return TypeLatticeElement.getNull();
}
+
+ @Override
+ public boolean isRewrittenTypeInfo() {
+ return true;
+ }
+
+ @Override
+ public RewrittenTypeInfo asRewrittenTypeInfo() {
+ return this;
+ }
+
+ @Override
+ public ArgumentInfo combine(ArgumentInfo info) {
+ if (info.isRemovedArgumentInfo()) {
+ return info;
+ }
+ assert info.isRewrittenTypeInfo();
+ RewrittenTypeInfo rewrittenTypeInfo = info.asRewrittenTypeInfo();
+ assert newType == rewrittenTypeInfo.oldType;
+ return new RewrittenTypeInfo(oldType, rewrittenTypeInfo.newType);
+ }
}
- public static class RewrittenTypeArgumentInfoCollection {
+ public static class ArgumentInfoCollection {
- private static final RewrittenTypeArgumentInfoCollection EMPTY =
- new RewrittenTypeArgumentInfoCollection();
- private final Int2ReferenceMap<RewrittenTypeInfo> rewrittenArgumentsInfo;
+ private static final ArgumentInfoCollection EMPTY = new ArgumentInfoCollection();
- private RewrittenTypeArgumentInfoCollection() {
- this.rewrittenArgumentsInfo = new Int2ReferenceOpenHashMap<>(0);
+ private final Int2ReferenceSortedMap<ArgumentInfo> argumentInfos;
+
+ // Specific constructor for empty.
+ private ArgumentInfoCollection() {
+ this.argumentInfos = new Int2ReferenceRBTreeMap<>();
}
- private RewrittenTypeArgumentInfoCollection(
- Int2ReferenceMap<RewrittenTypeInfo> rewrittenArgumentsInfo) {
- this.rewrittenArgumentsInfo = rewrittenArgumentsInfo;
+ private ArgumentInfoCollection(Int2ReferenceSortedMap<ArgumentInfo> argumentInfos) {
+ assert argumentInfos != null : "should use empty.";
+ assert !argumentInfos.isEmpty() : "should use empty.";
+ this.argumentInfos = argumentInfos;
}
- public static RewrittenTypeArgumentInfoCollection empty() {
+ public static ArgumentInfoCollection empty() {
return EMPTY;
}
public boolean isEmpty() {
- return rewrittenArgumentsInfo.isEmpty();
+ return this == EMPTY;
}
- public RewrittenTypeInfo getArgumentRewrittenTypeInfo(int argIndex) {
- return rewrittenArgumentsInfo.get(argIndex);
- }
-
- public boolean isArgumentRewrittenTypeInfo(int argIndex) {
- return rewrittenArgumentsInfo.containsKey(argIndex);
- }
-
- public DexType[] rewriteParameters(DexEncodedMethod encodedMethod) {
- DexType[] params = encodedMethod.method.proto.parameters.values;
- if (isEmpty()) {
- return params;
- }
- DexType[] newParams = new DexType[params.length];
- int offset = encodedMethod.isStatic() ? 0 : 1;
- for (int index = 0; index < params.length; index++) {
- RewrittenTypeInfo argInfo = getArgumentRewrittenTypeInfo(index + offset);
- if (argInfo != null) {
- assert params[index] == argInfo.oldType;
- newParams[index] = argInfo.newType;
- } else {
- newParams[index] = params[index];
+ public boolean hasRemovedArguments() {
+ for (ArgumentInfo value : argumentInfos.values()) {
+ if (value.isRemovedArgumentInfo()) {
+ return true;
}
}
- return newParams;
+ return false;
+ }
+
+ public int numberOfRemovedArguments() {
+ int removed = 0;
+ for (ArgumentInfo value : argumentInfos.values()) {
+ if (value.isRemovedArgumentInfo()) {
+ removed++;
+ }
+ }
+ return removed;
+ }
+
+ public ArgumentInfo getArgumentInfo(int argumentIndex) {
+ return argumentInfos.getOrDefault(argumentIndex, ArgumentInfo.NO_INFO);
}
public static Builder builder() {
@@ -304,69 +248,138 @@
public static class Builder {
- private Int2ReferenceMap<RewrittenTypeInfo> rewrittenArgumentsInfo;
+ private Int2ReferenceSortedMap<ArgumentInfo> argumentInfos;
- public Builder rewriteArgument(int argIndex, DexType oldType, DexType newType) {
- if (rewrittenArgumentsInfo == null) {
- rewrittenArgumentsInfo = new Int2ReferenceOpenHashMap<>();
+ public void addArgumentInfo(int argIndex, ArgumentInfo argInfo) {
+ if (argumentInfos == null) {
+ argumentInfos = new Int2ReferenceRBTreeMap<>();
}
- rewrittenArgumentsInfo.put(argIndex, new RewrittenTypeInfo(oldType, newType));
- return this;
+ assert !argumentInfos.containsKey(argIndex);
+ argumentInfos.put(argIndex, argInfo);
}
- public RewrittenTypeArgumentInfoCollection build() {
- if (rewrittenArgumentsInfo == null) {
+ public ArgumentInfoCollection build() {
+ if (argumentInfos == null || argumentInfos.isEmpty()) {
return EMPTY;
}
- assert !rewrittenArgumentsInfo.isEmpty();
- return new RewrittenTypeArgumentInfoCollection(rewrittenArgumentsInfo);
+ return new ArgumentInfoCollection(argumentInfos);
}
}
+
+ public DexType[] rewriteParameters(DexEncodedMethod encodedMethod) {
+ // Currently not allowed to remove the receiver of an instance method. This would involve
+ // changing invoke-direct/invoke-virtual into invoke-static.
+ assert encodedMethod.isStatic() || !getArgumentInfo(0).isRemovedArgumentInfo();
+ DexType[] params = encodedMethod.method.proto.parameters.values;
+ if (isEmpty()) {
+ return params;
+ }
+ DexType[] newParams = new DexType[params.length - numberOfRemovedArguments()];
+ int offset = encodedMethod.isStatic() ? 0 : 1;
+ int newParamIndex = 0;
+ for (int oldParamIndex = 0; oldParamIndex < params.length; oldParamIndex++) {
+ ArgumentInfo argInfo = argumentInfos.get(oldParamIndex + offset);
+ if (argInfo == null) {
+ newParams[newParamIndex++] = params[oldParamIndex];
+ } else if (argInfo.isRewrittenTypeInfo()) {
+ RewrittenTypeInfo rewrittenTypeInfo = argInfo.asRewrittenTypeInfo();
+ assert params[oldParamIndex] == rewrittenTypeInfo.oldType;
+ newParams[newParamIndex++] = rewrittenTypeInfo.newType;
+ }
+ }
+ return newParams;
+ }
+
+ public ArgumentInfoCollection combine(ArgumentInfoCollection info) {
+ if (isEmpty()) {
+ return info;
+ } else {
+ if (info.isEmpty()) {
+ return this;
+ }
+ }
+
+ Int2ReferenceSortedMap<ArgumentInfo> newArgInfos = new Int2ReferenceRBTreeMap<>();
+ newArgInfos.putAll(argumentInfos);
+ IntBidirectionalIterator iterator = argumentInfos.keySet().iterator();
+ int offset = 0;
+ int nextArgIndex;
+ for (int pendingArgIndex : info.argumentInfos.keySet()) {
+ nextArgIndex = peekNextOrMax(iterator);
+ while (nextArgIndex <= pendingArgIndex + offset) {
+ iterator.nextInt();
+ ArgumentInfo argumentInfo = argumentInfos.get(nextArgIndex);
+ nextArgIndex = peekNextOrMax(iterator);
+ if (argumentInfo.isRemovedArgumentInfo()) {
+ offset++;
+ }
+ }
+ ArgumentInfo newArgInfo =
+ nextArgIndex == pendingArgIndex + offset
+ ? ArgumentInfo.combine(
+ argumentInfos.get(nextArgIndex), info.argumentInfos.get(pendingArgIndex))
+ : info.argumentInfos.get(pendingArgIndex);
+ newArgInfos.put(pendingArgIndex + offset, newArgInfo);
+ }
+ assert Ordering.natural().isOrdered(newArgInfos.keySet());
+ return new ArgumentInfoCollection(newArgInfos);
+ }
+
+ static int peekNextOrMax(IntBidirectionalIterator iterator) {
+ if (iterator.hasNext()) {
+ int i = iterator.nextInt();
+ iterator.previousInt();
+ return i;
+ }
+ return Integer.MAX_VALUE;
+ }
+
+ public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
+ DexEncodedMethod method) {
+ if (numberOfRemovedArguments() > 0 && !method.parameterAnnotationsList.isEmpty()) {
+ return builder -> {
+ int firstArgumentIndex = BooleanUtils.intValue(!method.isStatic());
+ builder.removeParameterAnnotations(
+ oldIndex -> getArgumentInfo(oldIndex + firstArgumentIndex).isRemovedArgumentInfo());
+ };
+ }
+ return null;
+ }
}
private static final RewrittenPrototypeDescription none = new RewrittenPrototypeDescription();
- // TODO(b/149681096): Unify RewrittenPrototypeDescription.
private final boolean extraNullParameter;
- private final RemovedArgumentInfoCollection removedArgumentInfoCollection;
+ private final ArgumentInfoCollection argumentInfoCollection;
private final RewrittenTypeInfo rewrittenReturnInfo;
- private final RewrittenTypeArgumentInfoCollection rewrittenTypeArgumentInfoCollection;
private RewrittenPrototypeDescription() {
- this(
- false,
- RemovedArgumentInfoCollection.empty(),
- null,
- RewrittenTypeArgumentInfoCollection.empty());
+ this(false, null, ArgumentInfoCollection.empty());
}
private RewrittenPrototypeDescription(
boolean extraNullParameter,
- RemovedArgumentInfoCollection removedArgumentsInfo,
RewrittenTypeInfo rewrittenReturnInfo,
- RewrittenTypeArgumentInfoCollection rewrittenArgumentsInfo) {
- assert removedArgumentsInfo != null;
+ ArgumentInfoCollection argumentsInfo) {
+ assert argumentsInfo != null;
this.extraNullParameter = extraNullParameter;
- this.removedArgumentInfoCollection = removedArgumentsInfo;
this.rewrittenReturnInfo = rewrittenReturnInfo;
- this.rewrittenTypeArgumentInfoCollection = rewrittenArgumentsInfo;
+ this.argumentInfoCollection = argumentsInfo;
}
public static RewrittenPrototypeDescription createForUninstantiatedTypes(
DexMethod method,
AppView<AppInfoWithLiveness> appView,
- RemovedArgumentInfoCollection removedArgumentsInfo) {
+ ArgumentInfoCollection removedArgumentsInfo) {
DexType returnType = method.proto.returnType;
RewrittenTypeInfo returnInfo =
returnType.isAlwaysNull(appView) ? RewrittenTypeInfo.toVoid(returnType, appView) : null;
- return new RewrittenPrototypeDescription(
- false, removedArgumentsInfo, returnInfo, RewrittenTypeArgumentInfoCollection.empty());
+ return new RewrittenPrototypeDescription(false, returnInfo, removedArgumentsInfo);
}
public static RewrittenPrototypeDescription createForRewrittenTypes(
- RewrittenTypeInfo returnInfo, RewrittenTypeArgumentInfoCollection rewrittenArgumentsInfo) {
- return new RewrittenPrototypeDescription(
- false, RemovedArgumentInfoCollection.empty(), returnInfo, rewrittenArgumentsInfo);
+ RewrittenTypeInfo returnInfo, ArgumentInfoCollection rewrittenArgumentsInfo) {
+ return new RewrittenPrototypeDescription(false, returnInfo, rewrittenArgumentsInfo);
}
public static RewrittenPrototypeDescription none() {
@@ -374,10 +387,7 @@
}
public boolean isEmpty() {
- return !extraNullParameter
- && !removedArgumentInfoCollection.hasRemovedArguments()
- && rewrittenReturnInfo == null
- && rewrittenTypeArgumentInfoCollection.isEmpty();
+ return !extraNullParameter && rewrittenReturnInfo == null && argumentInfoCollection.isEmpty();
}
public boolean hasExtraNullParameter() {
@@ -388,12 +398,8 @@
return rewrittenReturnInfo != null && rewrittenReturnInfo.hasBeenChangedToReturnVoid(appView);
}
- public RemovedArgumentInfoCollection getRemovedArgumentInfoCollection() {
- return removedArgumentInfoCollection;
- }
-
- public RewrittenTypeArgumentInfoCollection getRewrittenTypeArgumentInfoCollection() {
- return rewrittenTypeArgumentInfoCollection;
+ public ArgumentInfoCollection getArgumentInfoCollection() {
+ return argumentInfoCollection;
}
public boolean hasRewrittenReturnInfo() {
@@ -419,7 +425,6 @@
return instruction;
}
- @SuppressWarnings("ConstantConditions")
public DexProto rewriteProto(DexEncodedMethod encodedMethod, DexItemFactory dexItemFactory) {
if (isEmpty()) {
return encodedMethod.method.proto;
@@ -428,18 +433,8 @@
rewrittenReturnInfo != null
? rewrittenReturnInfo.newType
: encodedMethod.method.proto.returnType;
- // TODO(b/149681096): Unify RewrittenPrototypeDescription, have a single variable for return.
- if (rewrittenReturnInfo != null || !rewrittenTypeArgumentInfoCollection.isEmpty()) {
- assert !removedArgumentInfoCollection.hasRemovedArguments();
- DexType[] newParameters =
- rewrittenTypeArgumentInfoCollection.rewriteParameters(encodedMethod);
- return dexItemFactory.createProto(newReturnType, newParameters);
- } else {
- assert rewrittenReturnInfo == null;
- assert rewrittenTypeArgumentInfoCollection.isEmpty();
- DexType[] newParameters = removedArgumentInfoCollection.rewriteParameters(encodedMethod);
- return dexItemFactory.createProto(newReturnType, newParameters);
- }
+ DexType[] newParameters = argumentInfoCollection.rewriteParameters(encodedMethod);
+ return dexItemFactory.createProto(newReturnType, newParameters);
}
public RewrittenPrototypeDescription withConstantReturn(
@@ -448,27 +443,19 @@
return !hasBeenChangedToReturnVoid(appView)
? new RewrittenPrototypeDescription(
extraNullParameter,
- removedArgumentInfoCollection,
RewrittenTypeInfo.toVoid(oldReturnType, appView),
- rewrittenTypeArgumentInfoCollection)
+ argumentInfoCollection)
: this;
}
- public RewrittenPrototypeDescription withRemovedArguments(RemovedArgumentInfoCollection other) {
+ public RewrittenPrototypeDescription withRemovedArguments(ArgumentInfoCollection other) {
return new RewrittenPrototypeDescription(
- extraNullParameter,
- removedArgumentInfoCollection.combine(other),
- rewrittenReturnInfo,
- rewrittenTypeArgumentInfoCollection);
+ extraNullParameter, rewrittenReturnInfo, argumentInfoCollection.combine(other));
}
public RewrittenPrototypeDescription withExtraNullParameter() {
return !extraNullParameter
- ? new RewrittenPrototypeDescription(
- true,
- removedArgumentInfoCollection,
- rewrittenReturnInfo,
- rewrittenTypeArgumentInfoCollection)
+ ? new RewrittenPrototypeDescription(true, rewrittenReturnInfo, argumentInfoCollection)
: this;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 3246a8b..3c33035 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -34,9 +34,9 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
@@ -456,11 +456,11 @@
AppView<?> appView, DexMethod method) {
RewrittenPrototypeDescription prototypeChanges =
appView.graphLense().lookupPrototypeChanges(method);
- if (Log.ENABLED && prototypeChanges.getRemovedArgumentInfoCollection().hasRemovedArguments()) {
+ if (Log.ENABLED && prototypeChanges.getArgumentInfoCollection().hasRemovedArguments()) {
Log.info(
IRBuilder.class,
"Removed "
- + prototypeChanges.getRemovedArgumentInfoCollection().numberOfRemovedArguments()
+ + prototypeChanges.getArgumentInfoCollection().numberOfRemovedArguments()
+ " arguments from "
+ method.toSourceString());
}
@@ -522,11 +522,7 @@
public void buildArgumentsWithRewrittenPrototypeChanges(
int register, DexEncodedMethod method, BiConsumer<Integer, DexType> writeCallback) {
- RemovedArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getRemovedArgumentInfoCollection();
- RewrittenTypeArgumentInfoCollection rewrittenArgumentsInfo =
- prototypeChanges.getRewrittenTypeArgumentInfoCollection();
- assert !removedArgumentsInfo.hasRemovedArguments() || rewrittenArgumentsInfo.isEmpty();
+ ArgumentInfoCollection argumentsInfo = prototypeChanges.getArgumentInfoCollection();
// Fill in the Argument instructions (incomingRegisterSize last registers) in the argument
// block.
@@ -541,24 +537,24 @@
int numberOfArguments =
method.method.proto.parameters.values.length
- + removedArgumentsInfo.numberOfRemovedArguments()
+ + argumentsInfo.numberOfRemovedArguments()
+ (method.isStatic() ? 0 : 1);
int usedArgumentIndex = 0;
while (argumentIndex < numberOfArguments) {
TypeLatticeElement type;
- if (removedArgumentsInfo.isArgumentRemoved(argumentIndex)) {
- RemovedArgumentInfo argumentInfo = removedArgumentsInfo.getArgumentInfo(argumentIndex);
- writeCallback.accept(register, argumentInfo.getType());
+ ArgumentInfo argumentInfo = argumentsInfo.getArgumentInfo(argumentIndex);
+ if (argumentInfo.isRemovedArgumentInfo()) {
+ RemovedArgumentInfo removedArgumentInfo = argumentInfo.asRemovedArgumentInfo();
+ writeCallback.accept(register, removedArgumentInfo.getType());
type =
TypeLatticeElement.fromDexType(
- argumentInfo.getType(), Nullability.maybeNull(), appView);
- addConstantOrUnusedArgument(register, argumentInfo);
+ removedArgumentInfo.getType(), Nullability.maybeNull(), appView);
+ addConstantOrUnusedArgument(register, removedArgumentInfo);
} else {
DexType argType;
- if (rewrittenArgumentsInfo.isArgumentRewrittenTypeInfo(argumentIndex)) {
- RewrittenTypeInfo argumentRewrittenTypeInfo =
- rewrittenArgumentsInfo.getArgumentRewrittenTypeInfo(argumentIndex);
+ if (argumentInfo.isRewrittenTypeInfo()) {
+ RewrittenTypeInfo argumentRewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo();
assert method.method.proto.parameters.values[usedArgumentIndex]
== argumentRewrittenTypeInfo.getNewType();
// The old type is used to prevent that a changed value from reference to primitive
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index eb9e7dc..0266798 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -28,8 +28,8 @@
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.GraphLense.GraphLenseLookupResult;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
@@ -173,41 +173,50 @@
RewrittenPrototypeDescription prototypeChanges =
graphLense.lookupPrototypeChanges(actualTarget);
- // TODO(b/149681096): Unify RewrittenPrototypeDescription and merge rewritten type and
- // removedArgument rewriting.
- // When converting types the default value may change (for example default value of
- // a reference type is null while default value of int is 0).
List<Value> newInValues;
- RewrittenTypeArgumentInfoCollection rewrittenTypeArgumentInfoCollection =
- prototypeChanges.getRewrittenTypeArgumentInfoCollection();
- if (rewrittenTypeArgumentInfoCollection.isEmpty()) {
+ ArgumentInfoCollection argumentInfoCollection =
+ prototypeChanges.getArgumentInfoCollection();
+ if (argumentInfoCollection.isEmpty()) {
newInValues = invoke.inValues();
} else {
+ if (argumentInfoCollection.hasRemovedArguments()) {
+ if (Log.ENABLED) {
+ Log.info(
+ getClass(),
+ "Invoked method "
+ + invokedMethod.toSourceString()
+ + " with "
+ + argumentInfoCollection.numberOfRemovedArguments()
+ + " arguments removed");
+ }
+ }
newInValues = new ArrayList<>(actualTarget.proto.parameters.size());
for (int i = 0; i < invoke.inValues().size(); i++) {
- RewrittenTypeInfo argInfo =
- rewrittenTypeArgumentInfoCollection.getArgumentRewrittenTypeInfo(i);
- Value value = invoke.inValues().get(i);
- if (argInfo != null
- && argInfo.defaultValueHasChanged()
- && value.isConstNumber()
- && value.definition.asConstNumber().isZero()) {
- iterator.previous();
- // TODO(b/150188380): Add API to insert a const instruction with a type lattice.
- Value rewrittenDefaultValue =
- iterator.insertConstIntInstruction(code, appView.options(), 0);
- iterator.next();
- rewrittenDefaultValue.setTypeLattice(argInfo.defaultValueLatticeElement(appView));
- newInValues.add(rewrittenDefaultValue);
- } else {
+ ArgumentInfo argumentInfo = argumentInfoCollection.getArgumentInfo(i);
+ if (argumentInfo.isRewrittenTypeInfo()) {
+ RewrittenTypeInfo argInfo = argumentInfo.asRewrittenTypeInfo();
+ Value value = invoke.inValues().get(i);
+ // When converting types the default value may change (for example default value
+ // of a reference type is null while default value of int is 0).
+ if (argInfo.defaultValueHasChanged()
+ && value.isConstNumber()
+ && value.definition.asConstNumber().isZero()) {
+ iterator.previous();
+ // TODO(b/150188380): Add API to insert a const instruction with a type lattice.
+ Value rewrittenNull =
+ iterator.insertConstIntInstruction(code, appView.options(), 0);
+ iterator.next();
+ rewrittenNull.setTypeLattice(argInfo.defaultValueLatticeElement(appView));
+ newInValues.add(rewrittenNull);
+ } else {
+ newInValues.add(invoke.inValues().get(i));
+ }
+ } else if (!argumentInfo.isRemovedArgumentInfo()) {
newInValues.add(invoke.inValues().get(i));
}
}
}
- RemovedArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getRemovedArgumentInfoCollection();
-
ConstInstruction constantReturnMaterializingInstruction = null;
if (prototypeChanges.hasBeenChangedToReturnVoid(appView) && invoke.outValue() != null) {
constantReturnMaterializingInstruction =
@@ -229,26 +238,6 @@
? null
: makeOutValue(invoke, code);
- if (removedArgumentsInfo.hasRemovedArguments()) {
- if (Log.ENABLED) {
- Log.info(
- getClass(),
- "Invoked method "
- + invokedMethod.toSourceString()
- + " with "
- + removedArgumentsInfo.numberOfRemovedArguments()
- + " arguments removed");
- }
- // Remove removed arguments from the invoke.
- List<Value> tempNewInValues = new ArrayList<>(actualTarget.proto.parameters.size());
- for (int i = 0; i < newInValues.size(); i++) {
- if (!removedArgumentsInfo.isArgumentRemoved(i)) {
- tempNewInValues.add(newInValues.get(i));
- }
- }
- newInValues = tempNewInValues;
- }
-
if (prototypeChanges.hasExtraNullParameter()) {
iterator.previous();
Value extraNullValue = iterator.insertConstNullInstruction(code, appView.options());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index 98e5ceb..b8ca4bc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -19,8 +19,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfoCollection;
import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
import com.android.tools.r8.ir.analysis.AbstractError;
import com.android.tools.r8.ir.analysis.TypeChecker;
@@ -63,11 +63,11 @@
public static class UninstantiatedTypeOptimizationGraphLense extends NestedGraphLense {
private final AppView<?> appView;
- private final Map<DexMethod, RemovedArgumentInfoCollection> removedArgumentsInfoPerMethod;
+ private final Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod;
UninstantiatedTypeOptimizationGraphLense(
BiMap<DexMethod, DexMethod> methodMap,
- Map<DexMethod, RemovedArgumentInfoCollection> removedArgumentsInfoPerMethod,
+ Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod,
AppView<?> appView) {
super(
ImmutableMap.of(),
@@ -89,8 +89,7 @@
if (method.proto.returnType.isVoidType() && !originalMethod.proto.returnType.isVoidType()) {
result = result.withConstantReturn(originalMethod.proto.returnType, appView);
}
- RemovedArgumentInfoCollection removedArgumentsInfo =
- removedArgumentsInfoPerMethod.get(method);
+ ArgumentInfoCollection removedArgumentsInfo = removedArgumentsInfoPerMethod.get(method);
if (removedArgumentsInfo != null) {
result = result.withRemovedArguments(removedArgumentsInfo);
}
@@ -127,8 +126,7 @@
Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods = new HashMap<>();
BiMap<DexMethod, DexMethod> methodMapping = HashBiMap.create();
- Map<DexMethod, RemovedArgumentInfoCollection> removedArgumentsInfoPerMethod =
- new IdentityHashMap<>();
+ Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod = new IdentityHashMap<>();
TopDownClassHierarchyTraversal.forProgramClasses(appView)
.visit(
@@ -153,7 +151,7 @@
Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods,
BiMap<DexMethod, DexMethod> methodMapping,
MethodPoolCollection methodPoolCollection,
- Map<DexMethod, RemovedArgumentInfoCollection> removedArgumentsInfoPerMethod) {
+ Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod) {
MemberPool<DexMethod> methodPool = methodPoolCollection.get(clazz);
if (clazz.isInterface()) {
@@ -202,8 +200,7 @@
RewrittenPrototypeDescription prototypeChanges =
prototypeChangesPerMethod.getOrDefault(
encodedMethod, RewrittenPrototypeDescription.none());
- RemovedArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getRemovedArgumentInfoCollection();
+ ArgumentInfoCollection removedArgumentsInfo = prototypeChanges.getArgumentInfoCollection();
DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
if (newMethod != method) {
Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
@@ -236,8 +233,7 @@
DexMethod method = encodedMethod.method;
RewrittenPrototypeDescription prototypeChanges =
getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
- RemovedArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getRemovedArgumentInfoCollection();
+ ArgumentInfoCollection removedArgumentsInfo = prototypeChanges.getArgumentInfoCollection();
DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
if (newMethod != method) {
Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
@@ -265,8 +261,7 @@
DexMethod method = encodedMethod.method;
RewrittenPrototypeDescription prototypeChanges =
getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
- RemovedArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getRemovedArgumentInfoCollection();
+ ArgumentInfoCollection removedArgumentsInfo = prototypeChanges.getArgumentInfoCollection();
DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
if (newMethod != method) {
Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
@@ -304,13 +299,13 @@
encodedMethod.method, appView, getRemovedArgumentsInfo(encodedMethod, strategy));
}
- private RemovedArgumentInfoCollection getRemovedArgumentsInfo(
+ private ArgumentInfoCollection getRemovedArgumentsInfo(
DexEncodedMethod encodedMethod, Strategy strategy) {
if (strategy == DISALLOW_ARGUMENT_REMOVAL) {
- return RemovedArgumentInfoCollection.empty();
+ return ArgumentInfoCollection.empty();
}
- RemovedArgumentInfoCollection.Builder argInfosBuilder = RemovedArgumentInfoCollection.builder();
+ ArgumentInfoCollection.Builder argInfosBuilder = ArgumentInfoCollection.builder();
DexProto proto = encodedMethod.method.proto;
int offset = encodedMethod.isStatic() ? 0 : 1;
for (int i = 0; i < proto.parameters.size(); ++i) {
@@ -318,7 +313,7 @@
if (type.isAlwaysNull(appView)) {
RemovedArgumentInfo removedArg =
RemovedArgumentInfo.builder().setIsAlwaysNull().setType(type).build();
- argInfosBuilder.addRemovedArgument(i + offset, removedArg);
+ argInfosBuilder.addArgumentInfo(i + offset, removedArg);
}
}
return argInfosBuilder.build();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
index e99ba9a..7c71bd9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -17,8 +17,8 @@
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfoCollection;
import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
@@ -50,12 +50,11 @@
private final MethodPoolCollection methodPoolCollection;
private final BiMap<DexMethod, DexMethod> methodMapping = HashBiMap.create();
- private final Map<DexMethod, RemovedArgumentInfoCollection> removedArguments =
- new IdentityHashMap<>();
+ private final Map<DexMethod, ArgumentInfoCollection> removedArguments = new IdentityHashMap<>();
public static class UnusedArgumentsGraphLense extends NestedGraphLense {
- private final Map<DexMethod, RemovedArgumentInfoCollection> removedArguments;
+ private final Map<DexMethod, ArgumentInfoCollection> removedArguments;
UnusedArgumentsGraphLense(
Map<DexType, DexType> typeMap,
@@ -65,7 +64,7 @@
BiMap<DexMethod, DexMethod> originalMethodSignatures,
GraphLense previousLense,
DexItemFactory dexItemFactory,
- Map<DexMethod, RemovedArgumentInfoCollection> removedArguments) {
+ Map<DexMethod, ArgumentInfoCollection> removedArguments) {
super(
typeMap,
methodMap,
@@ -84,7 +83,7 @@
? originalMethodSignatures.getOrDefault(method, method)
: method;
RewrittenPrototypeDescription result = previousLense.lookupPrototypeChanges(originalMethod);
- RemovedArgumentInfoCollection removedArguments = this.removedArguments.get(method);
+ ArgumentInfoCollection removedArguments = this.removedArguments.get(method);
return removedArguments != null ? result.withRemovedArguments(removedArguments) : result;
}
}
@@ -167,7 +166,7 @@
}
DexEncodedMethod removeArguments(
- DexEncodedMethod method, DexMethod newSignature, RemovedArgumentInfoCollection unused) {
+ DexEncodedMethod method, DexMethod newSignature, ArgumentInfoCollection unused) {
boolean removed = usedSignatures.remove(equivalence.wrap(method.method));
assert removed;
@@ -208,7 +207,7 @@
}
DexEncodedMethod removeArguments(
- DexEncodedMethod method, DexMethod newSignature, RemovedArgumentInfoCollection unused) {
+ DexEncodedMethod method, DexMethod newSignature, ArgumentInfoCollection unused) {
methodPool.seen(equivalence.wrap(newSignature));
return method.toTypeSubstitutedMethod(
newSignature, unused.createParameterAnnotationsRemover(method));
@@ -234,7 +233,7 @@
continue;
}
- RemovedArgumentInfoCollection unused = collectUnusedArguments(method);
+ ArgumentInfoCollection unused = collectUnusedArguments(method);
if (unused != null && unused.hasRemovedArguments()) {
DexProto newProto = createProtoWithRemovedArguments(method, unused);
DexMethod newSignature = signatures.getNewSignature(method, newProto);
@@ -259,7 +258,7 @@
List<DexEncodedMethod> virtualMethods = clazz.virtualMethods();
for (int i = 0; i < virtualMethods.size(); i++) {
DexEncodedMethod method = virtualMethods.get(i);
- RemovedArgumentInfoCollection unused = collectUnusedArguments(method, methodPool);
+ ArgumentInfoCollection unused = collectUnusedArguments(method, methodPool);
if (unused != null && unused.hasRemovedArguments()) {
DexProto newProto = createProtoWithRemovedArguments(method, unused);
DexMethod newSignature = signatures.getNewSignature(method, newProto);
@@ -279,11 +278,11 @@
}
}
- private RemovedArgumentInfoCollection collectUnusedArguments(DexEncodedMethod method) {
+ private ArgumentInfoCollection collectUnusedArguments(DexEncodedMethod method) {
return collectUnusedArguments(method, null);
}
- private RemovedArgumentInfoCollection collectUnusedArguments(
+ private ArgumentInfoCollection collectUnusedArguments(
DexEncodedMethod method, MemberPool<DexMethod> methodPool) {
if (ArgumentRemovalUtils.isPinned(method, appView)
|| appView.appInfo().keepUnusedArguments.contains(method.method)) {
@@ -314,15 +313,14 @@
method.getCode().registerArgumentReferences(method, collector);
BitSet used = collector.getUsedArguments();
if (used.cardinality() < argumentCount) {
- RemovedArgumentInfoCollection.Builder argInfosBuilder =
- RemovedArgumentInfoCollection.builder();
+ ArgumentInfoCollection.Builder argInfosBuilder = ArgumentInfoCollection.builder();
for (int argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) {
if (!used.get(argumentIndex)) {
RemovedArgumentInfo removedArg =
RemovedArgumentInfo.builder()
.setType(method.method.proto.parameters.values[argumentIndex - offset])
.build();
- argInfosBuilder.addRemovedArgument(argumentIndex, removedArg);
+ argInfosBuilder.addArgumentInfo(argumentIndex, removedArg);
}
}
return argInfosBuilder.build();
@@ -331,7 +329,7 @@
}
private DexProto createProtoWithRemovedArguments(
- DexEncodedMethod encodedMethod, RemovedArgumentInfoCollection unused) {
+ DexEncodedMethod encodedMethod, ArgumentInfoCollection unused) {
DexType[] parameters = unused.rewriteParameters(encodedMethod);
return appView.dexItemFactory().createProto(encodedMethod.method.proto.returnType, parameters);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index 23fa539..8bbc20e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -21,7 +21,7 @@
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.type.ArrayTypeLatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
@@ -651,13 +651,12 @@
public void move(DexMethod from, DexMethod to, boolean isStatic) {
super.move(from, to);
int offset = BooleanUtils.intValue(!isStatic);
- RewrittenTypeArgumentInfoCollection.Builder builder =
- RewrittenTypeArgumentInfoCollection.builder();
+ ArgumentInfoCollection.Builder builder = ArgumentInfoCollection.builder();
for (int i = 0; i < from.proto.parameters.size(); i++) {
DexType fromType = from.proto.parameters.values[i];
DexType toType = to.proto.parameters.values[i];
if (fromType != toType) {
- builder.rewriteArgument(i + offset, fromType, toType);
+ builder.addArgumentInfo(i + offset, new RewrittenTypeInfo(fromType, toType));
}
}
RewrittenTypeInfo returnInfo =
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
new file mode 100644
index 0000000..ddef0b4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.enumunboxing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import org.junit.Test;
+
+public class ArgumentInfoCollectionTest extends TestBase {
+
+ @Test
+ public void testCombineRewritten() {
+ DexItemFactory factory = new DexItemFactory();
+ ArgumentInfoCollection.Builder builder1 = ArgumentInfoCollection.builder();
+ builder1.addArgumentInfo(1, new RewrittenTypeInfo(factory.intType, factory.longType));
+ builder1.addArgumentInfo(3, new RewrittenTypeInfo(factory.intType, factory.longType));
+ ArgumentInfoCollection arguments1 = builder1.build();
+
+ ArgumentInfoCollection.Builder builder2 = ArgumentInfoCollection.builder();
+ builder2.addArgumentInfo(2, new RewrittenTypeInfo(factory.floatType, factory.doubleType));
+ builder2.addArgumentInfo(4, new RewrittenTypeInfo(factory.floatType, factory.doubleType));
+ ArgumentInfoCollection arguments2 = builder2.build();
+
+ ArgumentInfoCollection combine = arguments1.combine(arguments2);
+
+ RewrittenTypeInfo arg1 = combine.getArgumentInfo(1).asRewrittenTypeInfo();
+ assertEquals(arg1.getOldType(), factory.intType);
+ assertEquals(arg1.getNewType(), factory.longType);
+ RewrittenTypeInfo arg2 = combine.getArgumentInfo(2).asRewrittenTypeInfo();
+ assertEquals(arg2.getOldType(), factory.floatType);
+ assertEquals(arg2.getNewType(), factory.doubleType);
+ RewrittenTypeInfo arg3 = combine.getArgumentInfo(3).asRewrittenTypeInfo();
+ assertEquals(arg3.getOldType(), factory.intType);
+ assertEquals(arg3.getNewType(), factory.longType);
+ RewrittenTypeInfo arg4 = combine.getArgumentInfo(4).asRewrittenTypeInfo();
+ assertEquals(arg4.getOldType(), factory.floatType);
+ assertEquals(arg4.getNewType(), factory.doubleType);
+ }
+
+ @Test
+ public void testCombineRemoved() {
+ DexItemFactory factory = new DexItemFactory();
+
+ // Arguments removed: 0 1 2 3 4 -> 0 2 4.
+ ArgumentInfoCollection.Builder builder1 = ArgumentInfoCollection.builder();
+ builder1.addArgumentInfo(
+ 1, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+ builder1.addArgumentInfo(
+ 3, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+ ArgumentInfoCollection arguments1 = builder1.build();
+
+ // Arguments removed: 0 2 4 -> 0. Arguments 2 and 4 are at position 1 and 2 after first removal.
+ ArgumentInfoCollection.Builder builder2 = ArgumentInfoCollection.builder();
+ builder2.addArgumentInfo(1, RemovedArgumentInfo.builder().setType(factory.doubleType).build());
+ builder2.addArgumentInfo(2, RemovedArgumentInfo.builder().setType(factory.doubleType).build());
+ ArgumentInfoCollection arguments2 = builder2.build();
+
+ // Arguments removed: 0 1 2 3 4 -> 0.
+ ArgumentInfoCollection combine = arguments1.combine(arguments2);
+
+ RemovedArgumentInfo arg1 = combine.getArgumentInfo(1).asRemovedArgumentInfo();
+ assertEquals(arg1.getType(), factory.intType);
+ assertTrue(arg1.isAlwaysNull());
+ RemovedArgumentInfo arg2 = combine.getArgumentInfo(2).asRemovedArgumentInfo();
+ assertEquals(arg2.getType(), factory.doubleType);
+ assertFalse(arg2.isAlwaysNull());
+ RemovedArgumentInfo arg3 = combine.getArgumentInfo(3).asRemovedArgumentInfo();
+ assertEquals(arg3.getType(), factory.intType);
+ assertTrue(arg3.isAlwaysNull());
+ RemovedArgumentInfo arg4 = combine.getArgumentInfo(4).asRemovedArgumentInfo();
+ assertEquals(arg4.getType(), factory.doubleType);
+ assertFalse(arg4.isAlwaysNull());
+ }
+
+ @Test
+ public void testCombineRemoveRewritten() {
+ DexItemFactory factory = new DexItemFactory();
+
+ ArgumentInfoCollection.Builder builder1 = ArgumentInfoCollection.builder();
+ builder1.addArgumentInfo(
+ 1, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+ builder1.addArgumentInfo(
+ 3, RemovedArgumentInfo.builder().setType(factory.intType).setIsAlwaysNull().build());
+ ArgumentInfoCollection arguments1 = builder1.build();
+
+ ArgumentInfoCollection.Builder builder2 = ArgumentInfoCollection.builder();
+ builder2.addArgumentInfo(1, new RewrittenTypeInfo(factory.floatType, factory.doubleType));
+ builder2.addArgumentInfo(2, new RewrittenTypeInfo(factory.floatType, factory.doubleType));
+ ArgumentInfoCollection arguments2 = builder2.build();
+
+ ArgumentInfoCollection combine = arguments1.combine(arguments2);
+
+ RemovedArgumentInfo arg1 = combine.getArgumentInfo(1).asRemovedArgumentInfo();
+ assertEquals(arg1.getType(), factory.intType);
+ assertTrue(arg1.isAlwaysNull());
+ RewrittenTypeInfo arg2 = combine.getArgumentInfo(2).asRewrittenTypeInfo();
+ assertEquals(arg2.getOldType(), factory.floatType);
+ assertEquals(arg2.getNewType(), factory.doubleType);
+ RemovedArgumentInfo arg3 = combine.getArgumentInfo(3).asRemovedArgumentInfo();
+ assertEquals(arg3.getType(), factory.intType);
+ assertTrue(arg3.isAlwaysNull());
+ RewrittenTypeInfo arg4 = combine.getArgumentInfo(4).asRewrittenTypeInfo();
+ assertEquals(arg4.getOldType(), factory.floatType);
+ assertEquals(arg4.getNewType(), factory.doubleType);
+ }
+}