Remove chains of CheckCast on subtypes.
Bug:
Change-Id: Ib87ca85780375258f6b172dfeb18c51255ab1c6b
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 6a4777d..d43dc36 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -454,6 +454,7 @@
assert !options.debug;
inliner.performInlining(method, code, callGraph);
}
+ codeRewriter.removeCastChains(code);
codeRewriter.rewriteLongCompareAndRequireNonNull(code, options);
codeRewriter.commonSubexpressionElimination(code);
codeRewriter.simplifyArrayConstruction(code);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index ddc83f8..981f673 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.Binop;
import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.Cmp;
import com.android.tools.r8.ir.code.Cmp.Bias;
import com.android.tools.r8.ir.code.ConstNumber;
@@ -541,42 +542,45 @@
assert code.isConsistentGraph();
}
- // For supporting assert javac adds the static field $assertionsDisabled to all classes which
- // have methods with assertions. This is used to support the Java VM -ea flag.
- //
- // The class:
- //
- // class A {
- // void m() {
- // assert xxx;
- // }
- // }
- //
- // Is compiled into:
- //
- // class A {
- // static boolean $assertionsDisabled;
- // static {
- // $assertionsDisabled = A.class.desiredAssertionStatus();
- // }
- //
- // // method with "assert xxx";
- // void m() {
- // if (!$assertionsDisabled) {
- // if (xxx) {
- // throw new AssertionError(...);
- // }
- // }
- // }
- // }
- //
- // With the rewriting below (and other rewritings) the resulting code is:
- //
- // class A {
- // void m() {
- // }
- // }
- //
+
+ /**
+ * For supporting assert javac adds the static field $assertionsDisabled to all classes which
+ * have methods with assertions. This is used to support the Java VM -ea flag.
+ *
+ * The class:
+ * <pre>
+ * class A {
+ * void m() {
+ * assert xxx;
+ * }
+ * }
+ * </pre>
+ * Is compiled into:
+ * <pre>
+ * class A {
+ * static boolean $assertionsDisabled;
+ * static {
+ * $assertionsDisabled = A.class.desiredAssertionStatus();
+ * }
+ *
+ * // method with "assert xxx";
+ * void m() {
+ * if (!$assertionsDisabled) {
+ * if (xxx) {
+ * throw new AssertionError(...);
+ * }
+ * }
+ * }
+ * }
+ * </pre>
+ * With the rewriting below (and other rewritings) the resulting code is:
+ * <pre>
+ * class A {
+ * void m() {
+ * }
+ * }
+ * </pre>
+ */
public void disableAssertions(IRCode code) {
InstructionIterator iterator = code.instructionIterator();
while (iterator.hasNext()) {
@@ -600,6 +604,28 @@
}
}
+ /**
+ * Due to inlining, we might see chains of casts on subtypes. It suffices to cast to the lowest
+ * subtype, as that will fail if a cast on a supertype would have failed.
+ */
+ public void removeCastChains(IRCode code) {
+ InstructionIterator it = code.instructionIterator();
+ while (it.hasNext()) {
+ Instruction current = it.next();
+ if (current.isCheckCast()
+ && current.outValue() != null && current.outValue().isUsed()
+ && current.outValue().numberOfPhiUsers() == 0) {
+ CheckCast checkCast = current.asCheckCast();
+ if (checkCast.outValue().uniqueUsers().stream().allMatch(
+ user -> user.isCheckCast()
+ && user.asCheckCast().getType().isSubtypeOf(checkCast.getType(), appInfo))) {
+ checkCast.outValue().replaceUsers(checkCast.inValues().get(0));
+ it.remove();
+ }
+ }
+ }
+ }
+
private boolean canBeFolded(Instruction instruction) {
return (instruction.isBinop() && instruction.asBinop().canBeFolded()) ||
(instruction.isUnop() && instruction.asUnop().canBeFolded());
@@ -1240,7 +1266,7 @@
}
private Value addConstString(IRCode code, InstructionListIterator iterator, String s) {
- Value value = code.createValue(MoveType.OBJECT);;
+ Value value = code.createValue(MoveType.OBJECT);
iterator.add(new ConstString(value, dexItemFactory.createString(s)));
return value;
}
@@ -1279,7 +1305,7 @@
iterator.add(new ConstString(value, dexItemFactory.createString("INVOKE ")));
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
- value = code.createValue(MoveType.OBJECT);;
+ value = code.createValue(MoveType.OBJECT);
iterator.add(
new ConstString(value, dexItemFactory.createString(method.method.qualifiedName())));
iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));