Keep illegal invokes illegal.
BUG=
Change-Id: I7b72f0f42f5d85ceea114f54471903e471600818
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 2d5d803..1eb8707 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
@@ -96,7 +96,7 @@
continue;
}
DexMethod actualTarget = graphLense.lookupMethod(invokedMethod, method);
- Invoke.Type invokeType = getInvokeType(invoke, actualTarget);
+ Invoke.Type invokeType = getInvokeType(invoke, actualTarget, invokedMethod);
if (actualTarget != invokedMethod || invoke.getType() != invokeType) {
Invoke newInvoke = Invoke
.create(invokeType, actualTarget, null,
@@ -228,16 +228,26 @@
return methodHandle;
}
- private Type getInvokeType(InvokeMethod invoke, DexMethod actualTarget) {
+ private Type getInvokeType(InvokeMethod invoke, DexMethod actualTarget,
+ DexMethod originalTarget) {
if (invoke.isInvokeVirtual() || invoke.isInvokeInterface()) {
// Get the invoke type of the actual definition.
- DexClass clazz = appInfo.definitionFor(actualTarget.holder);
- if (clazz == null) {
+ DexClass newTargetClass = appInfo.definitionFor(actualTarget.holder);
+ if (newTargetClass == null) {
return invoke.getType();
} else {
- return clazz.accessFlags.isInterface()
- ? Type.INTERFACE
- : Type.VIRTUAL;
+ DexClass originalTargetClass = appInfo.definitionFor(originalTarget.holder);
+ if (originalTargetClass.isInterface() ^ (invoke.getType() == Type.INTERFACE)) {
+ // The invoke was wrong to start with, so we keep it wrong. This is to ensure we get
+ // the IncompatibleClassChangeError the original invoke would have triggered.
+ return newTargetClass.accessFlags.isInterface()
+ ? Type.VIRTUAL
+ : Type.INTERFACE;
+ } else {
+ return newTargetClass.accessFlags.isInterface()
+ ? Type.INTERFACE
+ : Type.VIRTUAL;
+ }
}
} else {
return invoke.getType();
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 3fe2173..8c5e094 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -78,13 +78,14 @@
"java.lang.NullPointerException: Attempt to read from field " +
"'Test Test.a' on a null object reference\n"},
{"merge-blocks-regression", "java.lang.NullPointerException: Attempt to invoke virtual"
- +" method 'Test Test.bW_()' on a null object reference\n"},
+ + " method 'Test Test.bW_()' on a null object reference\n"},
{"self-is-catch-block", "100\n-1\n"},
{"infinite-loop", ""},
{"regression/33336471",
"START\n0\n2\nLOOP\n1\n2\nLOOP\n2\n2\nDONE\n" +
"START\n0\n2\nLOOP\n1\n2\nLOOP\n2\n2\nDONE\n"},
{"regression/33846227", ""},
+ {"illegal-invokes", "ICCE\nICCE\n"},
});
}
@@ -123,7 +124,8 @@
thrown.expect(Throwable.class);
}
output =
- ToolHelper.checkArtOutputIdentical(originalDexFile.toString(), generated, mainClass, null);
+ ToolHelper
+ .checkArtOutputIdentical(originalDexFile.toString(), generated, mainClass, null);
}
assertEquals(expectedOutput, output);
}
diff --git a/src/test/smali/illegal-invokes/Iface.java b/src/test/smali/illegal-invokes/Iface.java
new file mode 100644
index 0000000..dd11626
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Iface.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, 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.
+
+public class Iface {
+
+ public void bar() {
+ }
+}
diff --git a/src/test/smali/illegal-invokes/Iface.smali b/src/test/smali/illegal-invokes/Iface.smali
new file mode 100644
index 0000000..d66777c
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Iface.smali
@@ -0,0 +1,10 @@
+# Copyright (c) 2017, 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.
+
+.class interface public LIface;
+.super Ljava/lang/Object;
+
+.method public abstract bar()V
+.end method
+
diff --git a/src/test/smali/illegal-invokes/Lowest.java b/src/test/smali/illegal-invokes/Lowest.java
new file mode 100644
index 0000000..e464313
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Lowest.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, 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.
+
+public class Lowest extends Iface implements Super {
+
+ @Override
+ public void foo() {
+
+ }
+}
diff --git a/src/test/smali/illegal-invokes/Lowest.smali b/src/test/smali/illegal-invokes/Lowest.smali
new file mode 100644
index 0000000..d6c5787
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Lowest.smali
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, 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.
+
+.class public LLowest;
+.super LSuper;
+
+.method public bar()V
+ .locals 0
+ return-void
+.end method
+
diff --git a/src/test/smali/illegal-invokes/Super.java b/src/test/smali/illegal-invokes/Super.java
new file mode 100644
index 0000000..54a8714
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Super.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, 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.
+
+public interface Super {
+
+ public void foo();
+}
diff --git a/src/test/smali/illegal-invokes/Super.smali b/src/test/smali/illegal-invokes/Super.smali
new file mode 100644
index 0000000..1ec4f0e
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Super.smali
@@ -0,0 +1,13 @@
+# Copyright (c) 2017, 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.
+
+.class public LSuper;
+.super Ljava/lang/Object;
+.implements LIface;
+
+.method public foo()V
+ .locals 0
+ return-void
+.end method
+
diff --git a/src/test/smali/illegal-invokes/Test.java b/src/test/smali/illegal-invokes/Test.java
new file mode 100644
index 0000000..8ddd18e
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Test.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2017, 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.
+
+public class Test {
+
+ int ignore;
+
+ public static void main(String... args) {
+ Lowest l = new Lowest();
+ callVirtualOnIface(l);
+ callIfaceOnVirtual(l);
+ }
+
+ private static void callVirtualOnIface(Iface i) {
+ try {
+ i.bar();
+ } catch (IncompatibleClassChangeError e) {
+ System.out.println("ICCE");
+ }
+ }
+
+ private static void callIfaceOnVirtual(Super s) {
+ try {
+ s.foo();
+ } catch (IncompatibleClassChangeError e) {
+ System.out.println("ICCE");
+ }
+ }
+}