Extend member value propagation to arrays of null
This extends member value propagation to optimize arr[i] into arr[i];null if the element type of the array is uninstantiated.
Change-Id: I6bf8e232bbdc29c2326b197cf91abcfb4998f535
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 9608eed..9e8d052 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -17,11 +17,13 @@
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.ir.code.ArrayGet;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.FieldInstruction;
import com.android.tools.r8.ir.code.IRCode;
@@ -63,6 +65,63 @@
this.reporter = appView.options().reporter;
}
+ private void rewriteArrayGet(
+ IRCode code,
+ ProgramMethod context,
+ Set<Value> affectedValues,
+ ListIterator<BasicBlock> blocks,
+ InstructionListIterator iterator,
+ ArrayGet arrayGet) {
+ TypeElement arrayType = arrayGet.array().getType();
+ if (!arrayType.isArrayType()) {
+ // Does not type check.
+ return;
+ }
+
+ TypeElement memberType = arrayType.asArrayType().getMemberType();
+ if (!memberType.isClassType()) {
+ // We don't know what the value of the element is.
+ return;
+ }
+
+ boolean isAlwaysNull = false;
+ ClassTypeElement memberClassType = memberType.asClassType();
+ if (memberClassType.getClassType().isAlwaysNull(appView)) {
+ isAlwaysNull = true;
+ } else if (memberClassType.getInterfaces().hasSingleKnownInterface()) {
+ isAlwaysNull =
+ memberClassType.getInterfaces().getSingleKnownInterface().isAlwaysNull(appView);
+ }
+
+ if (!isAlwaysNull) {
+ // We don't know what the value of the element is.
+ return;
+ }
+
+ BasicBlock block = arrayGet.getBlock();
+ Position position = arrayGet.getPosition();
+
+ // All usages are replaced by the replacement value.
+ Instruction replacement =
+ appView
+ .abstractValueFactory()
+ .createNullValue()
+ .createMaterializingInstruction(appView, code, arrayGet);
+ affectedValues.addAll(arrayGet.outValue().affectedValues());
+ arrayGet.outValue().replaceUsers(replacement.outValue());
+
+ // Insert the definition of the replacement.
+ replacement.setPosition(position);
+ if (block.hasCatchHandlers()) {
+ iterator
+ .splitCopyCatchHandlers(code, blocks, appView.options())
+ .listIterator(code)
+ .add(replacement);
+ } else {
+ iterator.add(replacement);
+ }
+ }
+
private boolean mayPropagateValueFor(DexClassAndField field) {
if (field.isProgramField()) {
return appView.appInfo().mayPropagateValueFor(field.getReference());
@@ -472,7 +531,10 @@
InstructionListIterator iterator = block.listIterator(code);
while (iterator.hasNext()) {
Instruction current = iterator.next();
- if (current.isInvokeMethod()) {
+ if (current.isArrayGet()) {
+ rewriteArrayGet(
+ code, context, affectedValues, blockIterator, iterator, current.asArrayGet());
+ } else if (current.isInvokeMethod()) {
rewriteInvokeMethodWithConstantValues(
code, context, affectedValues, blockIterator, iterator, current.asInvokeMethod());
} else if (current.isFieldGet()) {