Minor updates and helpers for method staticizing
Change-Id: I3b0dc9fac89ff57cd9306a411a1126126ee7e8dc
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index 68921ca..cdf0ad1 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -230,8 +230,9 @@
promote(Constants.ACC_FINAL);
}
- public void demoteFromFinal() {
+ public T demoteFromFinal() {
demote(Constants.ACC_FINAL);
+ return self();
}
public boolean isPromotedToPublic() {
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 f399895..f07c38e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -64,7 +64,7 @@
}
public DexTypeList keepIf(Predicate<DexType> predicate) {
- DexType[] filtered = ArrayUtils.filter(DexType[].class, values, predicate);
+ DexType[] filtered = ArrayUtils.filter(values, predicate, DexType.EMPTY_ARRAY);
if (filtered != values) {
return DexTypeList.create(filtered);
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
index 6930912..545645e 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -13,6 +13,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -337,33 +338,75 @@
@Override
public void replaceMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
- replaceDirectMethods(replacement);
- replaceVirtualMethods(replacement);
+ List<DexEncodedMethod> newVirtualMethods = internalReplaceDirectMethods(replacement);
+ List<DexEncodedMethod> newDirectMethods = internalReplaceVirtualMethods(replacement);
+ addDirectMethods(newDirectMethods);
+ addVirtualMethods(newVirtualMethods);
}
@Override
public void replaceDirectMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
+ List<DexEncodedMethod> newVirtualMethods = internalReplaceDirectMethods(replacement);
+ addVirtualMethods(newVirtualMethods);
+ }
+
+ private List<DexEncodedMethod> internalReplaceDirectMethods(
+ Function<DexEncodedMethod, DexEncodedMethod> replacement) {
+ List<DexEncodedMethod> newVirtualMethods = new ArrayList<>();
for (int i = 0; i < directMethods.length; i++) {
DexEncodedMethod method = directMethods[i];
DexEncodedMethod newMethod = replacement.apply(method);
assert newMethod != null;
if (method != newMethod) {
- assert belongsToDirectPool(newMethod);
- directMethods[i] = newMethod;
+ if (belongsToDirectPool(newMethod)) {
+ directMethods[i] = newMethod;
+ } else {
+ directMethods[i] = null;
+ newVirtualMethods.add(newMethod);
+ }
}
}
+ if (!newVirtualMethods.isEmpty()) {
+ directMethods =
+ ArrayUtils.filter(
+ directMethods,
+ Objects::nonNull,
+ DexEncodedMethod.EMPTY_ARRAY,
+ directMethods.length - newVirtualMethods.size());
+ }
+ return newVirtualMethods;
}
@Override
public void replaceVirtualMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
+ List<DexEncodedMethod> newDirectMethods = internalReplaceVirtualMethods(replacement);
+ addDirectMethods(newDirectMethods);
+ }
+
+ private List<DexEncodedMethod> internalReplaceVirtualMethods(
+ Function<DexEncodedMethod, DexEncodedMethod> replacement) {
+ List<DexEncodedMethod> newDirectMethods = new ArrayList<>();
for (int i = 0; i < virtualMethods.length; i++) {
DexEncodedMethod method = virtualMethods[i];
DexEncodedMethod newMethod = replacement.apply(method);
if (method != newMethod) {
- assert belongsToVirtualPool(newMethod);
- virtualMethods[i] = newMethod;
+ if (belongsToVirtualPool(newMethod)) {
+ virtualMethods[i] = newMethod;
+ } else {
+ virtualMethods[i] = null;
+ newDirectMethods.add(newMethod);
+ }
}
}
+ if (!newDirectMethods.isEmpty()) {
+ virtualMethods =
+ ArrayUtils.filter(
+ virtualMethods,
+ Objects::nonNull,
+ DexEncodedMethod.EMPTY_ARRAY,
+ virtualMethods.length - newDirectMethods.size());
+ }
+ return newDirectMethods;
}
@Override
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 dda7746..bf3849c 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.IntObjConsumer;
import com.android.tools.r8.utils.IteratorUtils;
@@ -450,6 +451,11 @@
return removed;
}
+ public int numberOfRemovedNonReceiverArguments(DexEncodedMethod method) {
+ return numberOfRemovedArguments()
+ - BooleanUtils.intValue(method.isInstance() && isArgumentRemoved(0));
+ }
+
public boolean hasArgumentInfo(int argumentIndex) {
return argumentInfos.containsKey(argumentIndex);
}
@@ -542,14 +548,12 @@
}
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.getReference().proto.parameters.values;
+ DexType[] params = encodedMethod.getParameters().values;
if (isEmpty()) {
return params;
}
- DexType[] newParams = new DexType[params.length - numberOfRemovedArguments()];
+ DexType[] newParams =
+ new DexType[params.length - numberOfRemovedNonReceiverArguments(encodedMethod)];
int offset = encodedMethod.getFirstNonReceiverArgumentIndex();
int newParamIndex = 0;
for (int oldParamIndex = 0; oldParamIndex < params.length; oldParamIndex++) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
index 62cbb04..2ad1f65 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
@@ -275,6 +275,40 @@
}
@Override
+ public InvokeMethod insertNullCheckInstruction(
+ AppView<?> appView,
+ IRCode code,
+ BasicBlockIterator blockIterator,
+ Value value,
+ Position position) {
+ InternalOptions options = appView.options();
+
+ InvokeMethod invoke;
+ if (appView.options().canUseJavaUtilObjectsRequireNonNull()) {
+ DexMethod requireNonNullMethod = appView.dexItemFactory().objectsMethods.requireNonNull;
+ invoke =
+ InvokeStatic.builder()
+ .setMethod(requireNonNullMethod)
+ .setSingleArgument(value)
+ .setPosition(position)
+ .build();
+ } else {
+ DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
+ invoke =
+ InvokeVirtual.builder()
+ .setMethod(getClassMethod)
+ .setSingleArgument(value)
+ .setPosition(position)
+ .build();
+ }
+ add(invoke);
+ if (block.hasCatchHandlers()) {
+ splitCopyCatchHandlers(code, blockIterator, options);
+ }
+ return invoke;
+ }
+
+ @Override
public boolean replaceCurrentInstructionByNullCheckIfPossible(
AppView<?> appView, ProgramMethod context) {
Instruction toBeReplaced = current;
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
index f9bbcc8..a68da1a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
@@ -45,6 +45,17 @@
}
@Override
+ public InvokeMethod insertNullCheckInstruction(
+ AppView<?> appView,
+ IRCode code,
+ BasicBlockIterator blockIterator,
+ Value value,
+ Position position) {
+ return instructionIterator.insertNullCheckInstruction(
+ appView, code, blockIterator, value, position);
+ }
+
+ @Override
public boolean replaceCurrentInstructionByNullCheckIfPossible(
AppView<?> appView, ProgramMethod context) {
return instructionIterator.replaceCurrentInstructionByNullCheckIfPossible(appView, context);
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index d08413d..bc6bec6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -100,6 +100,13 @@
Value insertConstStringInstruction(AppView<?> appView, IRCode code, DexString value);
+ InvokeMethod insertNullCheckInstruction(
+ AppView<?> appView,
+ IRCode code,
+ BasicBlockIterator blockIterator,
+ Value value,
+ Position position);
+
boolean replaceCurrentInstructionByNullCheckIfPossible(AppView<?> appView, ProgramMethod context);
boolean replaceCurrentInstructionByInitClassIfPossible(
diff --git a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
index cb20fd4..37d45df 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
@@ -69,6 +69,17 @@
}
@Override
+ public InvokeMethod insertNullCheckInstruction(
+ AppView<?> appView,
+ IRCode code,
+ BasicBlockIterator blockIterator,
+ Value value,
+ Position position) {
+ return currentBlockIterator.insertNullCheckInstruction(
+ appView, code, blockIterator, value, position);
+ }
+
+ @Override
public boolean replaceCurrentInstructionByNullCheckIfPossible(
AppView<?> appView, ProgramMethod context) {
return currentBlockIterator.replaceCurrentInstructionByNullCheckIfPossible(appView, context);
diff --git a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
index 06fdc4c..13f630e 100644
--- a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
@@ -47,39 +47,6 @@
return results;
}
- /**
- * Filters the input array based on the given predicate.
- *
- * @param clazz target type's Class to cast
- * @param original an array of original elements
- * @param filter a predicate that tells us what to keep
- * @param <T> target type
- * @return a partial copy of the original array
- */
- public static <T> T[] filter(Class<T[]> clazz, T[] original, Predicate<T> filter) {
- ArrayList<T> filtered = null;
- for (int i = 0; i < original.length; i++) {
- T elt = original[i];
- if (filter.test(elt)) {
- if (filtered != null) {
- filtered.add(elt);
- }
- } else {
- if (filtered == null) {
- filtered = new ArrayList<>(original.length);
- for (int j = 0; j < i; j++) {
- filtered.add(original[j]);
- }
- }
- }
- }
- if (filtered == null) {
- return original;
- }
- return filtered.toArray(
- clazz.cast(Array.newInstance(clazz.getComponentType(), filtered.size())));
- }
-
public static <T> boolean isEmpty(T[] array) {
return array.length == 0;
}
@@ -131,8 +98,23 @@
return results != null ? results.toArray(emptyArray) : original;
}
- public static <T> T[] filter(T[] original, Predicate<T> test, T[] emptyArray) {
- return map(original, e -> test.test(e) ? e : null, emptyArray);
+ public static <T> T[] filter(T[] original, Predicate<T> predicate, T[] emptyArray) {
+ return map(original, e -> predicate.test(e) ? e : null, emptyArray);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T[] filter(T[] original, Predicate<T> predicate, T[] emptyArray, int newSize) {
+ T[] result = (T[]) Array.newInstance(emptyArray.getClass().getComponentType(), newSize);
+ int newIndex = 0;
+ for (int originalIndex = 0; originalIndex < original.length; originalIndex++) {
+ T element = original[originalIndex];
+ if (predicate.test(element)) {
+ result[newIndex] = element;
+ newIndex++;
+ }
+ }
+ assert newIndex == newSize;
+ return result;
}
public static int[] createIdentityArray(int size) {
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index f3db67c..b05928d 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -19,10 +19,13 @@
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Move;
+import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -65,6 +68,16 @@
}
@Override
+ public InvokeMethod insertNullCheckInstruction(
+ AppView<?> appView,
+ IRCode code,
+ BasicBlockIterator blockIterator,
+ Value value,
+ Position position) {
+ throw new Unimplemented();
+ }
+
+ @Override
public boolean replaceCurrentInstructionByNullCheckIfPossible(
AppView<?> appView, ProgramMethod context) {
throw new Unimplemented();
diff --git a/src/test/java/com/android/tools/r8/utils/ArrayUtilsTest.java b/src/test/java/com/android/tools/r8/utils/ArrayUtilsTest.java
index b97fd41..93cc98f 100644
--- a/src/test/java/com/android/tools/r8/utils/ArrayUtilsTest.java
+++ b/src/test/java/com/android/tools/r8/utils/ArrayUtilsTest.java
@@ -113,7 +113,7 @@
public void testFilter_identity() {
int size = 3;
Integer[] input = createInputData(size);
- Integer[] output = ArrayUtils.filter(Integer[].class, input, x -> true);
+ Integer[] output = ArrayUtils.filter(input, x -> true, new Integer[0]);
assertEquals(input, output);
}
@@ -121,7 +121,7 @@
public void testFilter_dropOdd() {
int size = 3;
Integer[] input = createInputData(size);
- Integer[] output = ArrayUtils.filter(Integer[].class, input, x -> x % 2 == 0);
+ Integer[] output = ArrayUtils.filter(input, x -> x % 2 == 0, new Integer[0]);
assertNotEquals(input, output);
assertEquals(2, output.length);
assertEquals(0, (int) output[0]);
@@ -132,7 +132,7 @@
public void testFilter_dropAll() {
int size = 3;
Integer[] input = createInputData(size);
- Integer[] output = ArrayUtils.filter(Integer[].class, input, x -> false);
+ Integer[] output = ArrayUtils.filter(input, x -> false, new Integer[0]);
assertNotEquals(input, output);
assertEquals(0, output.length);
}