RewrittenProto: use Int2RefMap
- RemovedArguments has now Int2Ref Map
over a list of elements where each item
has the index.
- RemovedArguments empty has now an empty map
instead of null (1 extra instance), removed
corresponding null checks
- Made sure empty RemovedArguments use the
empty instance
- Fixed a bug where arg 0 of static method was
never considered as unused.
Bug: 148271981
Change-Id: I2ee0e2c20c1c670a0079ab4f12c563e075bf7da1
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index cbc8303..5c8de46 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -469,7 +469,7 @@
} else {
continue;
}
- if (index >= 0) {
+ if (index >= 0 && indexToNumber.containsKey(index)) {
registry.register(indexToNumber.get(index));
}
}
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 5c22878..a58aace 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -8,11 +8,9 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.IteratorUtils;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
+import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
import java.util.function.Consumer;
public class RewrittenPrototypeDescription {
@@ -21,15 +19,9 @@
public static class Builder {
- private int argumentIndex = -1;
private boolean isAlwaysNull = false;
private DexType type = null;
- public Builder setArgumentIndex(int argumentIndex) {
- this.argumentIndex = argumentIndex;
- return this;
- }
-
public Builder setIsAlwaysNull() {
this.isAlwaysNull = true;
return this;
@@ -41,18 +33,15 @@
}
public RemovedArgumentInfo build() {
- assert argumentIndex >= 0;
assert type != null;
- return new RemovedArgumentInfo(argumentIndex, isAlwaysNull, type);
+ return new RemovedArgumentInfo(isAlwaysNull, type);
}
}
- private final int argumentIndex;
private final boolean isAlwaysNull;
private final DexType type;
- private RemovedArgumentInfo(int argumentIndex, boolean isAlwaysNull, DexType type) {
- this.argumentIndex = argumentIndex;
+ private RemovedArgumentInfo(boolean isAlwaysNull, DexType type) {
this.isAlwaysNull = isAlwaysNull;
this.type = type;
}
@@ -61,10 +50,6 @@
return new Builder();
}
- public int getArgumentIndex() {
- return argumentIndex;
- }
-
public DexType getType() {
return type;
}
@@ -76,61 +61,48 @@
public boolean isNeverUsed() {
return !isAlwaysNull;
}
-
- RemovedArgumentInfo withArgumentIndex(int argumentIndex) {
- return this.argumentIndex != argumentIndex
- ? new RemovedArgumentInfo(argumentIndex, isAlwaysNull, type)
- : this;
- }
}
- public static class RemovedArgumentsInfo {
+ public static class RemovedArgumentInfoCollection {
- private static final RemovedArgumentsInfo empty = new RemovedArgumentsInfo(null);
+ private static final RemovedArgumentInfoCollection EMPTY = new RemovedArgumentInfoCollection();
- private final List<RemovedArgumentInfo> removedArguments;
+ private final Int2ReferenceSortedMap<RemovedArgumentInfo> removedArguments;
- public RemovedArgumentsInfo(List<RemovedArgumentInfo> removedArguments) {
- assert verifyRemovedArguments(removedArguments);
+ // Specific constructor for empty.
+ private RemovedArgumentInfoCollection() {
+ this.removedArguments = new Int2ReferenceLinkedOpenHashMap<>();
+ }
+
+ private RemovedArgumentInfoCollection(
+ Int2ReferenceSortedMap<RemovedArgumentInfo> removedArguments) {
+ assert removedArguments != null : "should use empty.";
+ assert !removedArguments.isEmpty() : "should use empty.";
this.removedArguments = removedArguments;
}
- private static boolean verifyRemovedArguments(List<RemovedArgumentInfo> removedArguments) {
- if (removedArguments != null && !removedArguments.isEmpty()) {
- // Check that list is sorted by argument indices.
- int lastArgumentIndex = removedArguments.get(0).getArgumentIndex();
- for (int i = 1; i < removedArguments.size(); ++i) {
- int currentArgumentIndex = removedArguments.get(i).getArgumentIndex();
- assert lastArgumentIndex < currentArgumentIndex;
- lastArgumentIndex = currentArgumentIndex;
- }
+ public static RemovedArgumentInfoCollection create(
+ Int2ReferenceSortedMap<RemovedArgumentInfo> removedArguments) {
+ if (removedArguments == null || removedArguments.isEmpty()) {
+ return EMPTY;
}
- return true;
+ return new RemovedArgumentInfoCollection(removedArguments);
}
- public static RemovedArgumentsInfo empty() {
- return empty;
+ public static RemovedArgumentInfoCollection empty() {
+ return EMPTY;
}
- public ListIterator<RemovedArgumentInfo> iterator() {
- return removedArguments == null
- ? Collections.emptyListIterator()
- : removedArguments.listIterator();
+ public RemovedArgumentInfo getArgumentInfo(int argIndex) {
+ return removedArguments.get(argIndex);
}
public boolean hasRemovedArguments() {
- return removedArguments != null && !removedArguments.isEmpty();
+ return !removedArguments.isEmpty();
}
public boolean isArgumentRemoved(int argumentIndex) {
- if (removedArguments != null) {
- for (RemovedArgumentInfo info : removedArguments) {
- if (info.getArgumentIndex() == argumentIndex) {
- return true;
- }
- }
- }
- return false;
+ return removedArguments.containsKey(argumentIndex);
}
public DexType[] rewriteParameters(DexEncodedMethod encodedMethod) {
@@ -156,8 +128,7 @@
return removedArguments != null ? removedArguments.size() : 0;
}
- public RemovedArgumentsInfo combine(RemovedArgumentsInfo info) {
- assert info != null;
+ public RemovedArgumentInfoCollection combine(RemovedArgumentInfoCollection info) {
if (hasRemovedArguments()) {
if (!info.hasRemovedArguments()) {
return this;
@@ -166,19 +137,32 @@
return info;
}
- List<RemovedArgumentInfo> newRemovedArguments = new LinkedList<>(removedArguments);
- ListIterator<RemovedArgumentInfo> iterator = newRemovedArguments.listIterator();
+ Int2ReferenceSortedMap<RemovedArgumentInfo> newRemovedArguments =
+ new Int2ReferenceLinkedOpenHashMap<>();
+ newRemovedArguments.putAll(removedArguments);
+ IntBidirectionalIterator iterator = removedArguments.keySet().iterator();
int offset = 0;
- for (RemovedArgumentInfo pending : info.removedArguments) {
- RemovedArgumentInfo next = IteratorUtils.peekNext(iterator);
- while (next != null && next.getArgumentIndex() <= pending.getArgumentIndex() + offset) {
- iterator.next();
- next = IteratorUtils.peekNext(iterator);
+ for (int pendingArgIndex : info.removedArguments.keySet()) {
+ int nextArgindex = peekNextOrMax(iterator);
+ while (nextArgindex <= pendingArgIndex + offset) {
+ iterator.nextInt();
+ nextArgindex = peekNextOrMax(iterator);
offset++;
}
- iterator.add(pending.withArgumentIndex(pending.getArgumentIndex() + offset));
+ assert !newRemovedArguments.containsKey(pendingArgIndex + offset);
+ newRemovedArguments.put(
+ pendingArgIndex + offset, info.removedArguments.get(pendingArgIndex));
}
- return new RemovedArgumentsInfo(newRemovedArguments);
+ 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(
@@ -198,16 +182,16 @@
private final boolean hasBeenChangedToReturnVoid;
private final boolean extraNullParameter;
- private final RemovedArgumentsInfo removedArgumentsInfo;
+ private final RemovedArgumentInfoCollection removedArgumentsInfo;
private RewrittenPrototypeDescription() {
- this(false, false, RemovedArgumentsInfo.empty());
+ this(false, false, RemovedArgumentInfoCollection.empty());
}
private RewrittenPrototypeDescription(
boolean hasBeenChangedToReturnVoid,
boolean extraNullParameter,
- RemovedArgumentsInfo removedArgumentsInfo) {
+ RemovedArgumentInfoCollection removedArgumentsInfo) {
assert removedArgumentsInfo != null;
this.extraNullParameter = extraNullParameter;
this.hasBeenChangedToReturnVoid = hasBeenChangedToReturnVoid;
@@ -215,7 +199,7 @@
}
public static RewrittenPrototypeDescription createForUninstantiatedTypes(
- boolean hasBeenChangedToReturnVoid, RemovedArgumentsInfo removedArgumentsInfo) {
+ boolean hasBeenChangedToReturnVoid, RemovedArgumentInfoCollection removedArgumentsInfo) {
return new RewrittenPrototypeDescription(
hasBeenChangedToReturnVoid, false, removedArgumentsInfo);
}
@@ -227,7 +211,7 @@
public boolean isEmpty() {
return !extraNullParameter
&& !hasBeenChangedToReturnVoid
- && !getRemovedArgumentsInfo().hasRemovedArguments();
+ && !getRemovedArgumentInfoCollection().hasRemovedArguments();
}
public boolean hasExtraNullParameter() {
@@ -238,7 +222,7 @@
return hasBeenChangedToReturnVoid;
}
- public RemovedArgumentsInfo getRemovedArgumentsInfo() {
+ public RemovedArgumentInfoCollection getRemovedArgumentInfoCollection() {
return removedArgumentsInfo;
}
@@ -276,7 +260,7 @@
: this;
}
- public RewrittenPrototypeDescription withRemovedArguments(RemovedArgumentsInfo other) {
+ public RewrittenPrototypeDescription withRemovedArguments(RemovedArgumentInfoCollection other) {
return new RewrittenPrototypeDescription(
hasBeenChangedToReturnVoid, extraNullParameter, removedArgumentsInfo.combine(other));
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 01dcf5d..a16e20e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -41,7 +41,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentsInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.CanonicalPositions;
@@ -51,7 +51,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -158,11 +157,8 @@
int register,
DexEncodedMethod method,
BiConsumer<Integer, DexType> writeCallback) {
- RemovedArgumentsInfo removedArgumentsInfo =
- builder.getPrototypeChanges().getRemovedArgumentsInfo();
- ListIterator<RemovedArgumentInfo> removedArgumentIterator = removedArgumentsInfo.iterator();
- RemovedArgumentInfo nextRemovedArgument =
- removedArgumentIterator.hasNext() ? removedArgumentIterator.next() : null;
+ RemovedArgumentInfoCollection removedArgumentsInfo =
+ builder.getPrototypeChanges().getRemovedArgumentInfoCollection();
// Fill in the Argument instructions (incomingRegisterSize last registers) in the argument
// block.
@@ -182,14 +178,13 @@
for (int usedArgumentIndex = 0; argumentIndex < numberOfArguments; ++argumentIndex) {
TypeLatticeElement type;
- if (nextRemovedArgument != null && nextRemovedArgument.getArgumentIndex() == argumentIndex) {
- writeCallback.accept(register, nextRemovedArgument.getType());
+ if (removedArgumentsInfo.isArgumentRemoved(argumentIndex)) {
+ RemovedArgumentInfo argumentInfo = removedArgumentsInfo.getArgumentInfo(argumentIndex);
+ writeCallback.accept(register, argumentInfo.getType());
type =
TypeLatticeElement.fromDexType(
- nextRemovedArgument.getType(), Nullability.maybeNull(), builder.appView);
- builder.addConstantOrUnusedArgument(register, nextRemovedArgument);
- nextRemovedArgument =
- removedArgumentIterator.hasNext() ? removedArgumentIterator.next() : null;
+ argumentInfo.getType(), Nullability.maybeNull(), builder.appView);
+ builder.addConstantOrUnusedArgument(register, argumentInfo);
} else {
DexType dexType = method.method.proto.parameters.values[usedArgumentIndex++];
writeCallback.accept(register, dexType);
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 a39a66b..d60b1e7 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
@@ -448,11 +448,12 @@
} else {
this.prototypeChanges = appView.graphLense().lookupPrototypeChanges(method.method);
- if (Log.ENABLED && prototypeChanges.getRemovedArgumentsInfo().hasRemovedArguments()) {
+ if (Log.ENABLED
+ && prototypeChanges.getRemovedArgumentInfoCollection().hasRemovedArguments()) {
Log.info(
getClass(),
"Removed "
- + prototypeChanges.getRemovedArgumentsInfo().numberOfRemovedArguments()
+ + prototypeChanges.getRemovedArgumentInfoCollection().numberOfRemovedArguments()
+ " arguments from "
+ method.toSourceString());
}
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 246d865..7226924 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
@@ -29,7 +29,7 @@
import com.android.tools.r8.graph.GraphLense.GraphLenseLookupResult;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentsInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfoCollection;
import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.ir.analysis.type.DestructivePhiTypeUpdater;
@@ -177,7 +177,8 @@
if (actualTarget != invokedMethod || invoke.getType() != actualInvokeType) {
RewrittenPrototypeDescription prototypeChanges =
graphLense.lookupPrototypeChanges(actualTarget);
- RemovedArgumentsInfo removedArgumentsInfo = prototypeChanges.getRemovedArgumentsInfo();
+ RemovedArgumentInfoCollection removedArgumentsInfo =
+ prototypeChanges.getRemovedArgumentInfoCollection();
ConstInstruction constantReturnMaterializingInstruction = null;
if (prototypeChanges.hasBeenChangedToReturnVoid() && invoke.outValue() != null) {
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 c234bc3..2cba82b 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
@@ -20,7 +20,7 @@
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentsInfo;
+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;
@@ -43,7 +43,8 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
-import java.util.ArrayList;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
@@ -63,11 +64,11 @@
public static class UninstantiatedTypeOptimizationGraphLense extends NestedGraphLense {
- private final Map<DexMethod, RemovedArgumentsInfo> removedArgumentsInfoPerMethod;
+ private final Map<DexMethod, RemovedArgumentInfoCollection> removedArgumentsInfoPerMethod;
UninstantiatedTypeOptimizationGraphLense(
BiMap<DexMethod, DexMethod> methodMap,
- Map<DexMethod, RemovedArgumentsInfo> removedArgumentsInfoPerMethod,
+ Map<DexMethod, RemovedArgumentInfoCollection> removedArgumentsInfoPerMethod,
AppView<?> appView) {
super(
ImmutableMap.of(),
@@ -88,7 +89,8 @@
if (method.proto.returnType.isVoidType() && !originalMethod.proto.returnType.isVoidType()) {
result = result.withConstantReturn();
}
- RemovedArgumentsInfo removedArgumentsInfo = removedArgumentsInfoPerMethod.get(method);
+ RemovedArgumentInfoCollection removedArgumentsInfo =
+ removedArgumentsInfoPerMethod.get(method);
if (removedArgumentsInfo != null) {
result = result.withRemovedArguments(removedArgumentsInfo);
}
@@ -125,7 +127,8 @@
Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods = new HashMap<>();
BiMap<DexMethod, DexMethod> methodMapping = HashBiMap.create();
- Map<DexMethod, RemovedArgumentsInfo> removedArgumentsInfoPerMethod = new IdentityHashMap<>();
+ Map<DexMethod, RemovedArgumentInfoCollection> removedArgumentsInfoPerMethod =
+ new IdentityHashMap<>();
TopDownClassHierarchyTraversal.forProgramClasses(appView)
.visit(
@@ -150,7 +153,7 @@
Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods,
BiMap<DexMethod, DexMethod> methodMapping,
MethodPoolCollection methodPoolCollection,
- Map<DexMethod, RemovedArgumentsInfo> removedArgumentsInfoPerMethod) {
+ Map<DexMethod, RemovedArgumentInfoCollection> removedArgumentsInfoPerMethod) {
MemberPool<DexMethod> methodPool = methodPoolCollection.get(clazz);
if (clazz.isInterface()) {
@@ -198,7 +201,8 @@
RewrittenPrototypeDescription prototypeChanges =
prototypeChangesPerMethod.getOrDefault(
encodedMethod, RewrittenPrototypeDescription.none());
- RemovedArgumentsInfo removedArgumentsInfo = prototypeChanges.getRemovedArgumentsInfo();
+ RemovedArgumentInfoCollection removedArgumentsInfo =
+ prototypeChanges.getRemovedArgumentInfoCollection();
DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
if (newMethod != method) {
Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
@@ -231,7 +235,8 @@
DexMethod method = encodedMethod.method;
RewrittenPrototypeDescription prototypeChanges =
getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
- RemovedArgumentsInfo removedArgumentsInfo = prototypeChanges.getRemovedArgumentsInfo();
+ RemovedArgumentInfoCollection removedArgumentsInfo =
+ prototypeChanges.getRemovedArgumentInfoCollection();
DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
if (newMethod != method) {
Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
@@ -259,7 +264,8 @@
DexMethod method = encodedMethod.method;
RewrittenPrototypeDescription prototypeChanges =
getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
- RemovedArgumentsInfo removedArgumentsInfo = prototypeChanges.getRemovedArgumentsInfo();
+ RemovedArgumentInfoCollection removedArgumentsInfo =
+ prototypeChanges.getRemovedArgumentInfoCollection();
DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
if (newMethod != method) {
Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
@@ -298,32 +304,26 @@
getRemovedArgumentsInfo(encodedMethod, strategy));
}
- private RemovedArgumentsInfo getRemovedArgumentsInfo(
+ private RemovedArgumentInfoCollection getRemovedArgumentsInfo(
DexEncodedMethod encodedMethod, Strategy strategy) {
if (strategy == DISALLOW_ARGUMENT_REMOVAL) {
- return RemovedArgumentsInfo.empty();
+ return RemovedArgumentInfoCollection.empty();
}
- List<RemovedArgumentInfo> removedArgumentsInfo = null;
+ Int2ReferenceSortedMap<RemovedArgumentInfo> removedArgumentsInfo = null;
DexProto proto = encodedMethod.method.proto;
int offset = encodedMethod.isStatic() ? 0 : 1;
for (int i = 0; i < proto.parameters.size(); ++i) {
DexType type = proto.parameters.values[i];
if (type.isAlwaysNull(appView)) {
if (removedArgumentsInfo == null) {
- removedArgumentsInfo = new ArrayList<>();
+ removedArgumentsInfo = new Int2ReferenceLinkedOpenHashMap<>();
}
- removedArgumentsInfo.add(
- RemovedArgumentInfo.builder()
- .setArgumentIndex(i + offset)
- .setIsAlwaysNull()
- .setType(type)
- .build());
+ removedArgumentsInfo.put(
+ i + offset, RemovedArgumentInfo.builder().setIsAlwaysNull().setType(type).build());
}
}
- return removedArgumentsInfo != null
- ? new RemovedArgumentsInfo(removedArgumentsInfo)
- : RemovedArgumentsInfo.empty();
+ return RemovedArgumentInfoCollection.create(removedArgumentsInfo);
}
private DexMethod getNewMethodSignature(
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 d8568d5..f50f7fc 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
@@ -18,7 +18,7 @@
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentsInfo;
+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;
@@ -32,7 +32,8 @@
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Streams;
-import java.util.ArrayList;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import java.util.BitSet;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -51,11 +52,12 @@
private final MethodPoolCollection methodPoolCollection;
private final BiMap<DexMethod, DexMethod> methodMapping = HashBiMap.create();
- private final Map<DexMethod, RemovedArgumentsInfo> removedArguments = new IdentityHashMap<>();
+ private final Map<DexMethod, RemovedArgumentInfoCollection> removedArguments =
+ new IdentityHashMap<>();
public static class UnusedArgumentsGraphLense extends NestedGraphLense {
- private final Map<DexMethod, RemovedArgumentsInfo> removedArguments;
+ private final Map<DexMethod, RemovedArgumentInfoCollection> removedArguments;
UnusedArgumentsGraphLense(
Map<DexType, DexType> typeMap,
@@ -65,7 +67,7 @@
BiMap<DexMethod, DexMethod> originalMethodSignatures,
GraphLense previousLense,
DexItemFactory dexItemFactory,
- Map<DexMethod, RemovedArgumentsInfo> removedArguments) {
+ Map<DexMethod, RemovedArgumentInfoCollection> removedArguments) {
super(
typeMap,
methodMap,
@@ -84,7 +86,7 @@
? originalMethodSignatures.getOrDefault(method, method)
: method;
RewrittenPrototypeDescription result = previousLense.lookupPrototypeChanges(originalMethod);
- RemovedArgumentsInfo removedArguments = this.removedArguments.get(method);
+ RemovedArgumentInfoCollection removedArguments = this.removedArguments.get(method);
return removedArguments != null ? result.withRemovedArguments(removedArguments) : result;
}
}
@@ -167,7 +169,7 @@
}
DexEncodedMethod removeArguments(
- DexEncodedMethod method, DexMethod newSignature, RemovedArgumentsInfo unused) {
+ DexEncodedMethod method, DexMethod newSignature, RemovedArgumentInfoCollection unused) {
boolean removed = usedSignatures.remove(equivalence.wrap(method.method));
assert removed;
@@ -208,7 +210,7 @@
}
DexEncodedMethod removeArguments(
- DexEncodedMethod method, DexMethod newSignature, RemovedArgumentsInfo unused) {
+ DexEncodedMethod method, DexMethod newSignature, RemovedArgumentInfoCollection unused) {
methodPool.seen(equivalence.wrap(newSignature));
return method.toTypeSubstitutedMethod(
newSignature, unused.createParameterAnnotationsRemover(method));
@@ -234,7 +236,7 @@
continue;
}
- RemovedArgumentsInfo unused = collectUnusedArguments(method);
+ RemovedArgumentInfoCollection unused = collectUnusedArguments(method);
if (unused != null && unused.hasRemovedArguments()) {
DexProto newProto = createProtoWithRemovedArguments(method, unused);
DexMethod newSignature = signatures.getNewSignature(method, newProto);
@@ -259,7 +261,7 @@
List<DexEncodedMethod> virtualMethods = clazz.virtualMethods();
for (int i = 0; i < virtualMethods.size(); i++) {
DexEncodedMethod method = virtualMethods.get(i);
- RemovedArgumentsInfo unused = collectUnusedArguments(method, methodPool);
+ RemovedArgumentInfoCollection unused = collectUnusedArguments(method, methodPool);
if (unused != null && unused.hasRemovedArguments()) {
DexProto newProto = createProtoWithRemovedArguments(method, unused);
DexMethod newSignature = signatures.getNewSignature(method, newProto);
@@ -279,11 +281,11 @@
}
}
- private RemovedArgumentsInfo collectUnusedArguments(DexEncodedMethod method) {
+ private RemovedArgumentInfoCollection collectUnusedArguments(DexEncodedMethod method) {
return collectUnusedArguments(method, null);
}
- private RemovedArgumentsInfo collectUnusedArguments(
+ private RemovedArgumentInfoCollection collectUnusedArguments(
DexEncodedMethod method, MemberPool<DexMethod> methodPool) {
if (ArgumentRemovalUtils.isPinned(method, appView)
|| appView.appInfo().keepUnusedArguments.contains(method.method)) {
@@ -314,23 +316,23 @@
method.getCode().registerArgumentReferences(method, collector);
BitSet used = collector.getUsedArguments();
if (used.cardinality() < argumentCount) {
- List<RemovedArgumentInfo> unused = new ArrayList<>();
+ Int2ReferenceSortedMap<RemovedArgumentInfo> unused = new Int2ReferenceLinkedOpenHashMap<>();
for (int argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) {
if (!used.get(argumentIndex)) {
- unused.add(
+ unused.put(
+ argumentIndex,
RemovedArgumentInfo.builder()
- .setArgumentIndex(argumentIndex)
.setType(method.method.proto.parameters.values[argumentIndex - offset])
.build());
}
}
- return new RemovedArgumentsInfo(unused);
+ return RemovedArgumentInfoCollection.create(unused);
}
return null;
}
private DexProto createProtoWithRemovedArguments(
- DexEncodedMethod encodedMethod, RemovedArgumentsInfo unused) {
+ DexEncodedMethod encodedMethod, RemovedArgumentInfoCollection unused) {
DexType[] parameters = unused.rewriteParameters(encodedMethod);
return appView.dexItemFactory().createProto(encodedMethod.method.proto.returnType, parameters);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
new file mode 100644
index 0000000..af6296b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
@@ -0,0 +1,172 @@
+// 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.ir.optimize.unusedarguments;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+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.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class UnusedAndUninstantiatedTypesTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public UnusedAndUninstantiatedTypesTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testUnusedAndUninstantiatedTypes() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(UnusedAndUninstantiatedTypesTest.class)
+ .addKeepMainRule(Main.class)
+ .noMinification()
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::assertMethodsAreThere)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(
+ "nothing",
+ "uninstantiatedThenUnused null",
+ "unusedThenUninstantiated null",
+ "doubleUninstantiatedThenUnused null and null",
+ "doubleUnusedThenUninstantiated null and null",
+ "tripleUninstantiatedThenUnused null and null and null",
+ "tripleUnusedThenUninstantiated null and null and null",
+ "withWideParameters null and null and null");
+ }
+
+ private void assertMethodsAreThere(CodeInspector i) {
+ List<FoundMethodSubject> methods = i.clazz(Main.class).allMethods();
+ assertEquals(9, methods.size());
+ for (FoundMethodSubject method : methods) {
+ if (!method.getMethod().method.name.toString().equals("main")) {
+ assertEquals(0, method.getMethod().method.getArity());
+ }
+ }
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ static class Main {
+
+ public static void main(String[] args) {
+ uninstantiatedAndUnused(null);
+ uninstantiatedThenUnused(null, new Unused());
+ unusedThenUninstantiated(new Unused(), null);
+ doubleUninstantiatedThenUnused(null, new Unused(), null, new Unused());
+ doubleUnusedThenUninstantiated(new Unused(), null, new Unused(), null);
+ tripleUninstantiatedThenUnused(null, new Unused(), new Unused(), null, null, new Unused());
+ tripleUnusedThenUninstantiated(new Unused(), null, null, new Unused(), new Unused(), null);
+ withWideParameters(0L, 1L, null, null, 2L, 3L, null);
+ }
+
+ @NeverInline
+ static void uninstantiatedAndUnused(UnInstantiated uninstantiated) {
+ System.out.println("nothing");
+ }
+
+ @NeverInline
+ static void uninstantiatedThenUnused(UnInstantiated uninstantiated, Unused unused) {
+ System.out.println("uninstantiatedThenUnused " + uninstantiated);
+ }
+
+ @NeverInline
+ static void unusedThenUninstantiated(Unused unused, UnInstantiated uninstantiated) {
+ System.out.println("unusedThenUninstantiated " + uninstantiated);
+ }
+
+ @NeverInline
+ static void doubleUninstantiatedThenUnused(
+ UnInstantiated uninstantiated1,
+ Unused unused1,
+ UnInstantiated uninstantiated2,
+ Unused unused2) {
+ System.out.println(
+ "doubleUninstantiatedThenUnused " + uninstantiated1 + " and " + uninstantiated2);
+ }
+
+ @NeverInline
+ static void doubleUnusedThenUninstantiated(
+ Unused unused1,
+ UnInstantiated uninstantiated1,
+ Unused unused2,
+ UnInstantiated uninstantiated2) {
+ System.out.println(
+ "doubleUnusedThenUninstantiated " + uninstantiated1 + " and " + uninstantiated2);
+ }
+
+ @NeverInline
+ static void tripleUninstantiatedThenUnused(
+ UnInstantiated uninstantiated1,
+ Unused unused0,
+ Unused unused1,
+ UnInstantiated uninstantiated0,
+ UnInstantiated uninstantiated2,
+ Unused unused2) {
+ System.out.println(
+ "tripleUninstantiatedThenUnused "
+ + uninstantiated1
+ + " and "
+ + uninstantiated2
+ + " and "
+ + uninstantiated0);
+ }
+
+ @NeverInline
+ static void tripleUnusedThenUninstantiated(
+ Unused unused1,
+ UnInstantiated uninstantiated0,
+ UnInstantiated uninstantiated1,
+ Unused unused0,
+ Unused unused2,
+ UnInstantiated uninstantiated2) {
+ System.out.println(
+ "tripleUnusedThenUninstantiated "
+ + uninstantiated1
+ + " and "
+ + uninstantiated2
+ + " and "
+ + uninstantiated0);
+ }
+
+ @NeverInline
+ static void withWideParameters(
+ long longUnused0,
+ long longUnused1,
+ UnInstantiated uninstantiated0,
+ UnInstantiated uninstantiated1,
+ long longUnused2,
+ long longUnused3,
+ UnInstantiated uninstantiated2) {
+ System.out.println(
+ "withWideParameters "
+ + uninstantiated1
+ + " and "
+ + uninstantiated2
+ + " and "
+ + uninstantiated0);
+ }
+ }
+
+ private static class UnInstantiated {}
+
+ private static class Unused {}
+}