Version 1.4.39
Cherry pick: Support for argument removal in dex frontend
CL: https://r8-review.googlesource.com/c/r8/+/33386
Bug: 123317382
Change-Id: I36d6c54c6cf38c316015e628760d6e51b98b276f
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index f8b366e..eb8dbbf 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.4.38";
+ public static final String LABEL = "1.4.39";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 884df4f..bac74f6 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -79,6 +79,7 @@
private int argumentIndex = -1;
private boolean isAlwaysNull = false;
+ private DexType type = null;
public Builder setArgumentIndex(int argumentIndex) {
this.argumentIndex = argumentIndex;
@@ -90,18 +91,26 @@
return this;
}
+ public Builder setType(DexType type) {
+ this.type = type;
+ return this;
+ }
+
public RemovedArgumentInfo build() {
assert argumentIndex >= 0;
- return new RemovedArgumentInfo(argumentIndex, isAlwaysNull);
+ assert type != null;
+ return new RemovedArgumentInfo(argumentIndex, isAlwaysNull, type);
}
}
private final int argumentIndex;
private final boolean isAlwaysNull;
+ private final DexType type;
- private RemovedArgumentInfo(int argumentIndex, boolean isAlwaysNull) {
+ private RemovedArgumentInfo(int argumentIndex, boolean isAlwaysNull, DexType type) {
this.argumentIndex = argumentIndex;
this.isAlwaysNull = isAlwaysNull;
+ this.type = type;
}
public static Builder builder() {
@@ -112,6 +121,10 @@
return argumentIndex;
}
+ public DexType getType() {
+ return type;
+ }
+
public boolean isAlwaysNull() {
return isAlwaysNull;
}
@@ -122,7 +135,7 @@
public RemovedArgumentInfo withArgumentIndex(int argumentIndex) {
return this.argumentIndex != argumentIndex
- ? new RemovedArgumentInfo(argumentIndex, isAlwaysNull)
+ ? new RemovedArgumentInfo(argumentIndex, isAlwaysNull, type)
: this;
}
}
@@ -788,8 +801,8 @@
* <p>Subclasses can override the lookup methods.
*
* <p>For method mapping where invocation type can change just override {@link
- * #mapInvocationType(DexMethod, DexMethod, DexMethod, Type)} if the default name mapping applies,
- * and only invocation type might need to change.
+ * #mapInvocationType(DexMethod, DexMethod, Type)} if the default name mapping applies, and only
+ * invocation type might need to change.
*/
public static class NestedGraphLense extends GraphLense {
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 6acd9b1..9d92099 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
@@ -38,9 +38,9 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.GraphLense.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.graph.GraphLense.RewrittenPrototypeDescription.RemovedArgumentsInfo;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.CanonicalPositions;
import com.android.tools.r8.ir.code.CatchHandlers;
@@ -49,14 +49,14 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
public class DexSourceCode implements SourceCode {
private final DexCode code;
- private final MethodAccessFlags accessFlags;
- private final DexProto proto;
+ private final DexEncodedMethod method;
// Mapping from instruction offset to instruction index in the DexCode instruction array.
private final Map<Integer, Integer> offsetToInstructionIndex = new HashMap<>();
@@ -72,8 +72,6 @@
private Position currentPosition = null;
private final CanonicalPositions canonicalPositions;
- private final List<TypeLatticeElement> argumentTypes;
-
private List<DexDebugEntry> debugEntries = null;
// In case of inlining the position of the invoke in the caller.
private final DexMethod originalMethod;
@@ -85,11 +83,8 @@
Position callerPosition,
AppInfo appInfo) {
this.code = code;
- this.proto = method.method.proto;
- this.accessFlags = method.accessFlags;
+ this.method = method;
this.originalMethod = originalMethod;
-
- argumentTypes = computeArgumentTypes(appInfo);
DexDebugInfo info = code.getDebugInfo();
if (info != null) {
debugEntries = info.computeEntries(originalMethod);
@@ -148,16 +143,46 @@
if (code.incomingRegisterSize == 0) {
return;
}
+
+ RemovedArgumentsInfo removedArgumentsInfo = builder.prototypeChanges.getRemovedArgumentsInfo();
+ ListIterator<RemovedArgumentInfo> removedArgumentIterator = removedArgumentsInfo.iterator();
+ RemovedArgumentInfo nextRemovedArgument =
+ removedArgumentIterator.hasNext() ? removedArgumentIterator.next() : null;
+
// Fill in the Argument instructions (incomingRegisterSize last registers) in the argument
// block.
+ int argumentIndex = 0;
+
int register = code.registerSize - code.incomingRegisterSize;
- if (!accessFlags.isStatic()) {
+ if (!method.isStatic()) {
builder.addThisArgument(register);
+ ++argumentIndex;
++register;
}
- for (TypeLatticeElement typeLattice : argumentTypes) {
- builder.addNonThisArgument(register, typeLattice);
- register += typeLattice.requiredRegisters();
+
+ int numberOfArguments =
+ method.method.proto.parameters.values.length
+ + removedArgumentsInfo.numberOfRemovedArguments()
+ + (method.isStatic() ? 0 : 1);
+
+ for (int usedArgumentIndex = 0; argumentIndex < numberOfArguments; ++argumentIndex) {
+ TypeLatticeElement type;
+ if (nextRemovedArgument != null && nextRemovedArgument.getArgumentIndex() == argumentIndex) {
+ type =
+ TypeLatticeElement.fromDexType(
+ nextRemovedArgument.getType(), true, builder.getAppInfo());
+ builder.addConstantOrUnusedArgument(register);
+ nextRemovedArgument =
+ removedArgumentIterator.hasNext() ? removedArgumentIterator.next() : null;
+ } else {
+ type =
+ TypeLatticeElement.fromDexType(
+ method.method.proto.parameters.values[usedArgumentIndex++],
+ true,
+ builder.getAppInfo());
+ builder.addNonThisArgument(register, type);
+ }
+ register += type.requiredRegisters();
}
builder.flushArgumentInstructions();
}
@@ -309,14 +334,6 @@
arrayFilledDataPayloadResolver.getData(payloadOffset));
}
- private List<TypeLatticeElement> computeArgumentTypes(AppInfo appInfo) {
- List<TypeLatticeElement> types = new ArrayList<>(proto.parameters.size());
- for (DexType type : proto.parameters.values) {
- types.add(TypeLatticeElement.fromDexType(type, true, appInfo));
- }
- return types;
- }
-
private boolean isInvoke(Instruction dex) {
return dex instanceof InvokeDirect
|| dex instanceof InvokeDirectRange
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 4c9b15e..a49b6ac 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
@@ -392,7 +392,7 @@
private DexEncodedMethod context;
private final AppInfo appInfo;
private final Origin origin;
- private RewrittenPrototypeDescription prototypeChanges;
+ final RewrittenPrototypeDescription prototypeChanges;
private ListIterator<RemovedArgumentInfo> removedArgumentsIterator;
private int argumentCount = 0;
@@ -889,15 +889,8 @@
DebugLocalInfo local = getOutgoingLocal(register);
Value value = writeRegister(register, typeLattice, ThrowingInfo.NO_THROW, local);
addInstruction(new Argument(value));
- } else if (removedArgumentInfo.isAlwaysNull()) {
- if (pendingArgumentInstructions == null) {
- pendingArgumentInstructions = new ArrayList<>();
- }
- DebugLocalInfo local = getOutgoingLocal(register);
- Value value = writeRegister(register, TypeLatticeElement.NULL, ThrowingInfo.NO_THROW, local);
- pendingArgumentInstructions.add(new ConstNumber(value, 0));
} else {
- assert removedArgumentInfo.isNeverUsed();
+ handleConstantOrUnusedArgument(register, removedArgumentInfo);
}
}
@@ -913,6 +906,25 @@
}
}
+ public void addConstantOrUnusedArgument(int register) {
+ handleConstantOrUnusedArgument(register, getRemovedArgumentInfo());
+ }
+
+ private void handleConstantOrUnusedArgument(
+ int register, RemovedArgumentInfo removedArgumentInfo) {
+ assert removedArgumentInfo != null;
+ if (removedArgumentInfo.isAlwaysNull()) {
+ if (pendingArgumentInstructions == null) {
+ pendingArgumentInstructions = new ArrayList<>();
+ }
+ DebugLocalInfo local = getOutgoingLocal(register);
+ Value value = writeRegister(register, TypeLatticeElement.NULL, ThrowingInfo.NO_THROW, local);
+ pendingArgumentInstructions.add(new ConstNumber(value, 0));
+ } else {
+ assert removedArgumentInfo.isNeverUsed();
+ }
+ }
+
public void flushArgumentInstructions() {
if (pendingArgumentInstructions != null) {
pendingArgumentInstructions.forEach(this::addInstruction);
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 11e0e59..6bd668c 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
@@ -297,7 +297,11 @@
removedArgumentsInfo = new ArrayList<>();
}
removedArgumentsInfo.add(
- RemovedArgumentInfo.builder().setArgumentIndex(i + offset).setIsAlwaysNull().build());
+ RemovedArgumentInfo.builder()
+ .setArgumentIndex(i + offset)
+ .setIsAlwaysNull()
+ .setType(type)
+ .build());
}
}
return removedArgumentsInfo != null
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 9d2bb32..f0aa91a 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
@@ -208,8 +208,8 @@
return null;
}
assert method.getCode().getOwner() == method;
- int argumentCount =
- method.method.proto.parameters.size() + (method.accessFlags.isStatic() ? 0 : 1);
+ int offset = method.accessFlags.isStatic() ? 0 : 1;
+ int argumentCount = method.method.proto.parameters.size() + offset;
// TODO(65810338): Implement for virtual methods as well.
if (method.accessFlags.isPrivate() || method.accessFlags.isStatic()) {
CollectUsedArguments collector = new CollectUsedArguments();
@@ -222,9 +222,13 @@
BitSet used = collector.getUsedArguments();
if (used.cardinality() < argumentCount) {
List<RemovedArgumentInfo> unused = new ArrayList<>();
- for (int i = 0; i < argumentCount; i++) {
- if (!used.get(i)) {
- unused.add(RemovedArgumentInfo.builder().setArgumentIndex(i).build());
+ for (int argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) {
+ if (!used.get(argumentIndex)) {
+ unused.add(
+ RemovedArgumentInfo.builder()
+ .setArgumentIndex(argumentIndex)
+ .setType(method.method.proto.parameters.values[argumentIndex - offset])
+ .build());
}
}
return new RemovedArgumentsInfo(unused);