1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method; 18*795d594fSAndroid Build Coastguard Worker 19*795d594fSAndroid Build Coastguard Worker public class Main { main(String[] args)20*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) { 21*795d594fSAndroid Build Coastguard Worker // Check if we're running dalvik or RI. 22*795d594fSAndroid Build Coastguard Worker usingRI = false; 23*795d594fSAndroid Build Coastguard Worker try { 24*795d594fSAndroid Build Coastguard Worker Class.forName("dalvik.system.PathClassLoader"); 25*795d594fSAndroid Build Coastguard Worker } catch (ClassNotFoundException e) { 26*795d594fSAndroid Build Coastguard Worker usingRI = true; 27*795d594fSAndroid Build Coastguard Worker } 28*795d594fSAndroid Build Coastguard Worker 29*795d594fSAndroid Build Coastguard Worker try { 30*795d594fSAndroid Build Coastguard Worker test1(); 31*795d594fSAndroid Build Coastguard Worker test2(); 32*795d594fSAndroid Build Coastguard Worker test3(); 33*795d594fSAndroid Build Coastguard Worker test4(); 34*795d594fSAndroid Build Coastguard Worker test5(); 35*795d594fSAndroid Build Coastguard Worker test6(); 36*795d594fSAndroid Build Coastguard Worker test7(); 37*795d594fSAndroid Build Coastguard Worker test8(); 38*795d594fSAndroid Build Coastguard Worker test9(); 39*795d594fSAndroid Build Coastguard Worker test10(); 40*795d594fSAndroid Build Coastguard Worker test11(); 41*795d594fSAndroid Build Coastguard Worker test12(); 42*795d594fSAndroid Build Coastguard Worker 43*795d594fSAndroid Build Coastguard Worker // TODO: How to test that interface method resolution returns the unique 44*795d594fSAndroid Build Coastguard Worker // maximally-specific non-abstract superinterface method if there is one? 45*795d594fSAndroid Build Coastguard Worker // Maybe reflection? (This is not even implemented yet!) 46*795d594fSAndroid Build Coastguard Worker } catch (Throwable t) { 47*795d594fSAndroid Build Coastguard Worker t.printStackTrace(System.out); 48*795d594fSAndroid Build Coastguard Worker } 49*795d594fSAndroid Build Coastguard Worker } 50*795d594fSAndroid Build Coastguard Worker 51*795d594fSAndroid Build Coastguard Worker /* 52*795d594fSAndroid Build Coastguard Worker * Test1 53*795d594fSAndroid Build Coastguard Worker * ----- 54*795d594fSAndroid Build Coastguard Worker * Tested functions: 55*795d594fSAndroid Build Coastguard Worker * public class Test1Base { 56*795d594fSAndroid Build Coastguard Worker * public void foo() { ... } 57*795d594fSAndroid Build Coastguard Worker * } 58*795d594fSAndroid Build Coastguard Worker * public class Test1Derived extends Test1Base { 59*795d594fSAndroid Build Coastguard Worker * private void foo() { ... } 60*795d594fSAndroid Build Coastguard Worker * ... 61*795d594fSAndroid Build Coastguard Worker * } 62*795d594fSAndroid Build Coastguard Worker * Tested invokes: 63*795d594fSAndroid Build Coastguard Worker * invoke-direct Test1Derived.foo()V from Test1Derived in first dex file 64*795d594fSAndroid Build Coastguard Worker * expected: executes Test1Derived.foo()V 65*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test1Derived.foo()V from Test1User in second dex file 66*795d594fSAndroid Build Coastguard Worker * expected: throws IllegalAccessError (JLS 15.12.4.3) 67*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test1Derived.foo()V from Test1User2 in first dex file 68*795d594fSAndroid Build Coastguard Worker * expected: throws IllegalAccessError (JLS 15.12.4.3) 69*795d594fSAndroid Build Coastguard Worker * 70*795d594fSAndroid Build Coastguard Worker * Previously, the behavior was inconsistent between dex files, throwing ICCE 71*795d594fSAndroid Build Coastguard Worker * from one and invoking the method from another. This was because the lookups for 72*795d594fSAndroid Build Coastguard Worker * direct and virtual methods were independent but results were stored in a single 73*795d594fSAndroid Build Coastguard Worker * slot in the DexCache method array and then retrieved from there without checking 74*795d594fSAndroid Build Coastguard Worker * the resolution kind. Thus, the first invoke-direct stored the private 75*795d594fSAndroid Build Coastguard Worker * Test1Derived.foo() in the DexCache and the attempt to use invoke-virtual 76*795d594fSAndroid Build Coastguard Worker * from the same dex file (by Test1User2) would throw ICCE. However, the same 77*795d594fSAndroid Build Coastguard Worker * invoke-virtual from a different dex file (by Test1User) would ignore the 78*795d594fSAndroid Build Coastguard Worker * direct method Test1Derived.foo() and find the Test1Base.foo() and call it. 79*795d594fSAndroid Build Coastguard Worker * 80*795d594fSAndroid Build Coastguard Worker * The method lookup has been changed and we now consistently find the private 81*795d594fSAndroid Build Coastguard Worker * Derived.foo() and throw ICCE for both invoke-virtual calls. 82*795d594fSAndroid Build Coastguard Worker * 83*795d594fSAndroid Build Coastguard Worker * Files: 84*795d594fSAndroid Build Coastguard Worker * src/Test1Base.java - defines public foo()V. 85*795d594fSAndroid Build Coastguard Worker * jasmin/Test1Derived.j - defines private foo()V, calls it with invokespecial. 86*795d594fSAndroid Build Coastguard Worker * jasmin-multidex/Test1User.j - calls invokevirtual Test1Derived.foo(). 87*795d594fSAndroid Build Coastguard Worker * jasmin/Test1User2.j - calls invokevirtual Test1Derived.foo(). 88*795d594fSAndroid Build Coastguard Worker */ test1()89*795d594fSAndroid Build Coastguard Worker private static void test1() throws Exception { 90*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test1Derived"); 91*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test1User"); 92*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test1User2"); 93*795d594fSAndroid Build Coastguard Worker } 94*795d594fSAndroid Build Coastguard Worker 95*795d594fSAndroid Build Coastguard Worker /* 96*795d594fSAndroid Build Coastguard Worker * Test2 97*795d594fSAndroid Build Coastguard Worker * ----- 98*795d594fSAndroid Build Coastguard Worker * Tested functions: 99*795d594fSAndroid Build Coastguard Worker * public class Test2Base { 100*795d594fSAndroid Build Coastguard Worker * public static void foo() { ... } 101*795d594fSAndroid Build Coastguard Worker * } 102*795d594fSAndroid Build Coastguard Worker * public interface Test2Interface { 103*795d594fSAndroid Build Coastguard Worker * default void foo() { ... } // default: avoid subclassing Test2Derived. 104*795d594fSAndroid Build Coastguard Worker * } 105*795d594fSAndroid Build Coastguard Worker * public class Test2Derived extends Test2Base implements Test2Interface { 106*795d594fSAndroid Build Coastguard Worker * } 107*795d594fSAndroid Build Coastguard Worker * Tested invokes: 108*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test2Derived.foo()V from Test2User in first dex file 109*795d594fSAndroid Build Coastguard Worker * expected: throws IncompatibleClassChangeError 110*795d594fSAndroid Build Coastguard Worker * (JLS 13.4.19, the inherited Base.foo() changed from non-static to static) 111*795d594fSAndroid Build Coastguard Worker * invoke-static Test2Derived.foo()V from Test2User2 in first dex file 112*795d594fSAndroid Build Coastguard Worker * expected: executes Test2Base.foo()V 113*795d594fSAndroid Build Coastguard Worker * 114*795d594fSAndroid Build Coastguard Worker * Previously, due to different lookup types and multi-threaded verification, 115*795d594fSAndroid Build Coastguard Worker * it was undeterministic which method ended up in the DexCache, so this test 116*795d594fSAndroid Build Coastguard Worker * was flaky, sometimes erroneously executing the Test2Interface.foo(). 117*795d594fSAndroid Build Coastguard Worker * 118*795d594fSAndroid Build Coastguard Worker * The method lookup has been changed and we now consistently find the 119*795d594fSAndroid Build Coastguard Worker * Test2Base.foo()V over the method from the interface, in line with the RI. 120*795d594fSAndroid Build Coastguard Worker * 121*795d594fSAndroid Build Coastguard Worker * Files: 122*795d594fSAndroid Build Coastguard Worker * src/Test2Base.java - defines public static foo()V. 123*795d594fSAndroid Build Coastguard Worker * src/Test2Interface.java - defines default foo()V. 124*795d594fSAndroid Build Coastguard Worker * jasmin/Test2Derived.j - extends Test2Derived, implements Test2Interface. 125*795d594fSAndroid Build Coastguard Worker * jasmin/Test2User.j - calls invokevirtual Test2Derived.foo() 126*795d594fSAndroid Build Coastguard Worker * jasmin/Test2User2.j - calls invokestatic Test2Derived.foo() 127*795d594fSAndroid Build Coastguard Worker */ test2()128*795d594fSAndroid Build Coastguard Worker private static void test2() throws Exception { 129*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test2User"); 130*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test2User2"); 131*795d594fSAndroid Build Coastguard Worker } 132*795d594fSAndroid Build Coastguard Worker 133*795d594fSAndroid Build Coastguard Worker /* 134*795d594fSAndroid Build Coastguard Worker * Test3 135*795d594fSAndroid Build Coastguard Worker * ----- 136*795d594fSAndroid Build Coastguard Worker * Tested functions: 137*795d594fSAndroid Build Coastguard Worker * public class Test3Base { 138*795d594fSAndroid Build Coastguard Worker * public static void foo() { ... } 139*795d594fSAndroid Build Coastguard Worker * } 140*795d594fSAndroid Build Coastguard Worker * public interface Test3Interface { 141*795d594fSAndroid Build Coastguard Worker * default void foo() { ... } // default: avoid subclassing Test3Derived. 142*795d594fSAndroid Build Coastguard Worker * } 143*795d594fSAndroid Build Coastguard Worker * public class Test3Derived extends Test3Base implements Test3Interface { 144*795d594fSAndroid Build Coastguard Worker * } 145*795d594fSAndroid Build Coastguard Worker * Tested invokes: 146*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test3Derived.foo()V from Test3User in second dex file 147*795d594fSAndroid Build Coastguard Worker * expected: throws IncompatibleClassChangeError 148*795d594fSAndroid Build Coastguard Worker * (JLS 13.4.19, the inherited Base.foo() changed from non-static to static) 149*795d594fSAndroid Build Coastguard Worker * 150*795d594fSAndroid Build Coastguard Worker * This is Test2 (without the invoke-static) with a small change: the Test3User with 151*795d594fSAndroid Build Coastguard Worker * the invoke-interface is in a secondary dex file to avoid the effects of the DexCache. 152*795d594fSAndroid Build Coastguard Worker * 153*795d594fSAndroid Build Coastguard Worker * Previously the invoke-virtual would resolve to the Test3Interface.foo()V but 154*795d594fSAndroid Build Coastguard Worker * it now resolves to Test3Base.foo()V and throws ICCE in line with the RI. 155*795d594fSAndroid Build Coastguard Worker * 156*795d594fSAndroid Build Coastguard Worker * Files: 157*795d594fSAndroid Build Coastguard Worker * src/Test3Base.java - defines public static foo()V. 158*795d594fSAndroid Build Coastguard Worker * src/Test3Interface.java - defines default foo()V. 159*795d594fSAndroid Build Coastguard Worker * src/Test3Derived.java - extends Test2Derived, implements Test2Interface. 160*795d594fSAndroid Build Coastguard Worker * jasmin-multidex/Test3User.j - calls invokevirtual Test3Derived.foo() 161*795d594fSAndroid Build Coastguard Worker */ test3()162*795d594fSAndroid Build Coastguard Worker private static void test3() throws Exception { 163*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test3User"); 164*795d594fSAndroid Build Coastguard Worker } 165*795d594fSAndroid Build Coastguard Worker 166*795d594fSAndroid Build Coastguard Worker /* 167*795d594fSAndroid Build Coastguard Worker * Test4 168*795d594fSAndroid Build Coastguard Worker * ----- 169*795d594fSAndroid Build Coastguard Worker * Tested functions: 170*795d594fSAndroid Build Coastguard Worker * public interface Test4Interface { 171*795d594fSAndroid Build Coastguard Worker * // Not declaring toString(). 172*795d594fSAndroid Build Coastguard Worker * } 173*795d594fSAndroid Build Coastguard Worker * Tested invokes: 174*795d594fSAndroid Build Coastguard Worker * invoke-interface Test4Interface.toString()Ljava/lang/String; in first dex file 175*795d594fSAndroid Build Coastguard Worker * expected: executes java.lang.Object.toString()Ljava/lang/String 176*795d594fSAndroid Build Coastguard Worker * (JLS 9.2 specifies implicitly declared methods from Object). 177*795d594fSAndroid Build Coastguard Worker * 178*795d594fSAndroid Build Coastguard Worker * The RI resolves the call to java.lang.Object.toString() and executes it. 179*795d594fSAndroid Build Coastguard Worker * ART used to resolve it in a secondary resolution attempt only to distinguish 180*795d594fSAndroid Build Coastguard Worker * between ICCE and NSME and then throw ICCE. We now allow the call to proceed. 181*795d594fSAndroid Build Coastguard Worker * 182*795d594fSAndroid Build Coastguard Worker * Files: 183*795d594fSAndroid Build Coastguard Worker * src/Test4Interface.java - does not declare toString(). 184*795d594fSAndroid Build Coastguard Worker * src/Test4Derived.java - extends Test4Interface. 185*795d594fSAndroid Build Coastguard Worker * jasmin/Test4User.j - calls invokeinterface Test4Interface.toString(). 186*795d594fSAndroid Build Coastguard Worker */ test4()187*795d594fSAndroid Build Coastguard Worker private static void test4() throws Exception { 188*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test4User"); 189*795d594fSAndroid Build Coastguard Worker } 190*795d594fSAndroid Build Coastguard Worker 191*795d594fSAndroid Build Coastguard Worker /* 192*795d594fSAndroid Build Coastguard Worker * Test5 193*795d594fSAndroid Build Coastguard Worker * ----- 194*795d594fSAndroid Build Coastguard Worker * Tested functions: 195*795d594fSAndroid Build Coastguard Worker * public interface Test5Interface { 196*795d594fSAndroid Build Coastguard Worker * public void foo(); 197*795d594fSAndroid Build Coastguard Worker * } 198*795d594fSAndroid Build Coastguard Worker * public abstract class Test5Base implements Test5Interface{ 199*795d594fSAndroid Build Coastguard Worker * // Not declaring foo(). 200*795d594fSAndroid Build Coastguard Worker * } 201*795d594fSAndroid Build Coastguard Worker * public class Test5Derived extends Test5Base { 202*795d594fSAndroid Build Coastguard Worker * public void foo() { ... } 203*795d594fSAndroid Build Coastguard Worker * } 204*795d594fSAndroid Build Coastguard Worker * Tested invokes: 205*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test5Base.foo()V from Test5User in first dex file 206*795d594fSAndroid Build Coastguard Worker * expected: executes Test5Derived.foo()V 207*795d594fSAndroid Build Coastguard Worker * invoke-interface Test5Base.foo()V from Test5User2 in first dex file 208*795d594fSAndroid Build Coastguard Worker * expected: throws IncompatibleClassChangeError (JLS 13.3) 209*795d594fSAndroid Build Coastguard Worker * 210*795d594fSAndroid Build Coastguard Worker * We previously didn't check the type of the referencing class when the method 211*795d594fSAndroid Build Coastguard Worker * was found in the dex cache and the invoke-interface would only check the 212*795d594fSAndroid Build Coastguard Worker * type of the resolved method which happens to be OK; then we would fail a 213*795d594fSAndroid Build Coastguard Worker * DCHECK(!method->IsCopied()) in Class::FindVirtualMethodForInterface(). This has 214*795d594fSAndroid Build Coastguard Worker * been fixed and we consistently check the type of the referencing class as well. 215*795d594fSAndroid Build Coastguard Worker * 216*795d594fSAndroid Build Coastguard Worker * Since normal virtual method dispatch in compiled or quickened code does not 217*795d594fSAndroid Build Coastguard Worker * actually use the DexCache and we want to populate the Test5Base.foo()V entry 218*795d594fSAndroid Build Coastguard Worker * anyway, we force verification at runtime by adding a call to an arbitrary 219*795d594fSAndroid Build Coastguard Worker * unresolved method to Test5User.test(), catching and ignoring the ICCE. Files: 220*795d594fSAndroid Build Coastguard Worker * src/Test5Interface.java - interface, declares foo()V. 221*795d594fSAndroid Build Coastguard Worker * src/Test5Base.java - abstract class, implements Test5Interface. 222*795d594fSAndroid Build Coastguard Worker * src/Test5Derived.java - extends Test5Base, implements foo()V. 223*795d594fSAndroid Build Coastguard Worker * jasmin/Test5User2.j - calls invokeinterface Test5Base.foo()V. 224*795d594fSAndroid Build Coastguard Worker * jasmin/Test5User.j - calls invokevirtual Test5Base.foo()V, 225*795d594fSAndroid Build Coastguard Worker * - also calls undefined Test5Base.bar()V, supresses ICCE. 226*795d594fSAndroid Build Coastguard Worker */ test5()227*795d594fSAndroid Build Coastguard Worker private static void test5() throws Exception { 228*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test5User"); 229*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test5User2"); 230*795d594fSAndroid Build Coastguard Worker } 231*795d594fSAndroid Build Coastguard Worker 232*795d594fSAndroid Build Coastguard Worker /* 233*795d594fSAndroid Build Coastguard Worker * Test6 234*795d594fSAndroid Build Coastguard Worker * ----- 235*795d594fSAndroid Build Coastguard Worker * Tested functions: 236*795d594fSAndroid Build Coastguard Worker * public interface Test6Interface { 237*795d594fSAndroid Build Coastguard Worker * // Not declaring toString(). 238*795d594fSAndroid Build Coastguard Worker * } 239*795d594fSAndroid Build Coastguard Worker * Tested invokes: 240*795d594fSAndroid Build Coastguard Worker * invoke-interface Test6Interface.toString() from Test6User in first dex file 241*795d594fSAndroid Build Coastguard Worker * expected: executes java.lang.Object.toString()Ljava/lang/String 242*795d594fSAndroid Build Coastguard Worker * (JLS 9.2 specifies implicitly declared methods from Object). 243*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test6Interface.toString() from Test6User2 in first dex file 244*795d594fSAndroid Build Coastguard Worker * expected: throws IncompatibleClassChangeError (JLS 13.3) 245*795d594fSAndroid Build Coastguard Worker * 246*795d594fSAndroid Build Coastguard Worker * Previously, the invoke-interface would have been rejected, throwing ICCE, 247*795d594fSAndroid Build Coastguard Worker * and the invoke-virtual would have been accepted, calling Object.toString(). 248*795d594fSAndroid Build Coastguard Worker * 249*795d594fSAndroid Build Coastguard Worker * The method lookup has been changed and we now accept the invoke-interface, 250*795d594fSAndroid Build Coastguard Worker * calling Object.toString(), and reject the invoke-virtual, throwing ICCE, 251*795d594fSAndroid Build Coastguard Worker * in line with the RI. However, if the method is already in the DexCache for 252*795d594fSAndroid Build Coastguard Worker * the invoke-virtual, we need to check the referenced class in order to throw 253*795d594fSAndroid Build Coastguard Worker * the ICCE as the resolved method kind actually matches the invoke-virtual. 254*795d594fSAndroid Build Coastguard Worker * This test ensures that we do. 255*795d594fSAndroid Build Coastguard Worker * 256*795d594fSAndroid Build Coastguard Worker * Files: 257*795d594fSAndroid Build Coastguard Worker * src/Test6Interface.java - interface, does not declare toString(). 258*795d594fSAndroid Build Coastguard Worker * src/Test6Derived.java - implements Test6Interface. 259*795d594fSAndroid Build Coastguard Worker * jasmin/Test6User.j - calls invokeinterface Test6Interface.toString(). 260*795d594fSAndroid Build Coastguard Worker * jasmin/Test6User2.j - calls invokevirtual Test6Interface.toString(). 261*795d594fSAndroid Build Coastguard Worker */ test6()262*795d594fSAndroid Build Coastguard Worker private static void test6() throws Exception { 263*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test6User"); 264*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test6User2"); 265*795d594fSAndroid Build Coastguard Worker } 266*795d594fSAndroid Build Coastguard Worker 267*795d594fSAndroid Build Coastguard Worker /* 268*795d594fSAndroid Build Coastguard Worker * Test7 269*795d594fSAndroid Build Coastguard Worker * ----- 270*795d594fSAndroid Build Coastguard Worker * Tested function: 271*795d594fSAndroid Build Coastguard Worker * public class Test7Base { 272*795d594fSAndroid Build Coastguard Worker * private void foo() { ... } 273*795d594fSAndroid Build Coastguard Worker * } 274*795d594fSAndroid Build Coastguard Worker * public interface Test7Interface { 275*795d594fSAndroid Build Coastguard Worker * default void foo() { ... } 276*795d594fSAndroid Build Coastguard Worker * } 277*795d594fSAndroid Build Coastguard Worker * public class Test7Derived extends Test7Base implements Test7Interface { 278*795d594fSAndroid Build Coastguard Worker * // Not declaring foo(). 279*795d594fSAndroid Build Coastguard Worker * } 280*795d594fSAndroid Build Coastguard Worker * Tested invokes: 281*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test7Derived.foo()V from Test7User in first dex file 282*795d594fSAndroid Build Coastguard Worker * expected: executes Test7Interface.foo()V (inherited by Test7Derived, JLS 8.4.8) 283*795d594fSAndroid Build Coastguard Worker * invoke-interface Test7Interface.foo()V from Test7User in first dex file 284*795d594fSAndroid Build Coastguard Worker * expected: throws IllegalAccessError (JLS 15.12.4.4) 285*795d594fSAndroid Build Coastguard Worker * on a Test7Derived object. 286*795d594fSAndroid Build Coastguard Worker * 287*795d594fSAndroid Build Coastguard Worker * This tests a case where javac happily compiles code (in line with JLS) that 288*795d594fSAndroid Build Coastguard Worker * then throws IllegalAccessError on the RI (both invokes). 289*795d594fSAndroid Build Coastguard Worker * 290*795d594fSAndroid Build Coastguard Worker * For the invoke-virtual, the RI throws IAE as the private Test7Base.foo() is 291*795d594fSAndroid Build Coastguard Worker * found before the inherited (see JLS 8.4.8) Test7Interface.foo(). This conflicts 292*795d594fSAndroid Build Coastguard Worker * with the JLS 15.12.2.1 saying that members inherited (JLS 8.4.8) from superclasses 293*795d594fSAndroid Build Coastguard Worker * and superinterfaces are included in the search. ART follows the JLS behavior. 294*795d594fSAndroid Build Coastguard Worker * 295*795d594fSAndroid Build Coastguard Worker * The invoke-interface method resolution is trivial but the post-resolution 296*795d594fSAndroid Build Coastguard Worker * processing is non-intuitive. According to older versions of JLS 15.12.4.4, and 297*795d594fSAndroid Build Coastguard Worker * implemented by older RI, the invokeinterface ignores overriding and searches 298*795d594fSAndroid Build Coastguard Worker * class hierarchy for any method with the requested signature, finds the private 299*795d594fSAndroid Build Coastguard Worker * Test7Base.foo()V and throws IllegalAccessError. However, newer versions of JLS 300*795d594fSAndroid Build Coastguard Worker * limit the search to overriding methods, thus excluding private methods, and 301*795d594fSAndroid Build Coastguard Worker * therefore find and call Test7Interface.foo()V just like ART. Bug: 63624936. 302*795d594fSAndroid Build Coastguard Worker * 303*795d594fSAndroid Build Coastguard Worker * Files: 304*795d594fSAndroid Build Coastguard Worker * src/Test7User.java - calls invoke-virtual Test7Derived.foo()V. 305*795d594fSAndroid Build Coastguard Worker * src/Test7User2.java - calls invoke-interface Test7Interface.foo()V. 306*795d594fSAndroid Build Coastguard Worker * src/Test7Base.java - defines private foo()V. 307*795d594fSAndroid Build Coastguard Worker * src/Test7Interface.java - defines default foo()V. 308*795d594fSAndroid Build Coastguard Worker * src/Test7Derived.java - extends Test7Base, implements Test7Interface. 309*795d594fSAndroid Build Coastguard Worker */ test7()310*795d594fSAndroid Build Coastguard Worker private static void test7() throws Exception { 311*795d594fSAndroid Build Coastguard Worker if (usingRI) { 312*795d594fSAndroid Build Coastguard Worker // For RI, just print the expected output to hide the deliberate divergence. 313*795d594fSAndroid Build Coastguard Worker System.out.println("Calling Test7User.test():\n" + 314*795d594fSAndroid Build Coastguard Worker "Test7Interface.foo()"); 315*795d594fSAndroid Build Coastguard Worker } else { 316*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test7User"); 317*795d594fSAndroid Build Coastguard Worker } 318*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test7User2"); 319*795d594fSAndroid Build Coastguard Worker } 320*795d594fSAndroid Build Coastguard Worker 321*795d594fSAndroid Build Coastguard Worker /* 322*795d594fSAndroid Build Coastguard Worker * Test8 323*795d594fSAndroid Build Coastguard Worker * ----- 324*795d594fSAndroid Build Coastguard Worker * Tested function: 325*795d594fSAndroid Build Coastguard Worker * public class Test8Base { 326*795d594fSAndroid Build Coastguard Worker * public static void foo() { ... } 327*795d594fSAndroid Build Coastguard Worker * } 328*795d594fSAndroid Build Coastguard Worker * public class Test8Derived extends Test8Base { 329*795d594fSAndroid Build Coastguard Worker * public void foo() { ... } 330*795d594fSAndroid Build Coastguard Worker * } 331*795d594fSAndroid Build Coastguard Worker * Tested invokes: 332*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test8Derived.foo()V from Test8User in first dex file 333*795d594fSAndroid Build Coastguard Worker * expected: executes Test8Derived.foo()V 334*795d594fSAndroid Build Coastguard Worker * invoke-static Test8Derived.foo()V from Test8User2 in first dex file 335*795d594fSAndroid Build Coastguard Worker * expected: throws IncompatibleClassChangeError (JLS 13.4.19) 336*795d594fSAndroid Build Coastguard Worker * 337*795d594fSAndroid Build Coastguard Worker * Another test for invoke type mismatch. 338*795d594fSAndroid Build Coastguard Worker * 339*795d594fSAndroid Build Coastguard Worker * Files: 340*795d594fSAndroid Build Coastguard Worker * src/Test8Base.java - defines static foo()V. 341*795d594fSAndroid Build Coastguard Worker * jasmin/Test8Derived.j - defines non-static foo()V. 342*795d594fSAndroid Build Coastguard Worker * jasmin/Test8User.j - calls invokevirtual Test8Derived.foo()V. 343*795d594fSAndroid Build Coastguard Worker * jasmin/Test8User2.j - calls invokestatic Test8Derived.foo()V. 344*795d594fSAndroid Build Coastguard Worker */ test8()345*795d594fSAndroid Build Coastguard Worker private static void test8() throws Exception { 346*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test8User"); 347*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test8User2"); 348*795d594fSAndroid Build Coastguard Worker } 349*795d594fSAndroid Build Coastguard Worker 350*795d594fSAndroid Build Coastguard Worker /* 351*795d594fSAndroid Build Coastguard Worker * Test9 352*795d594fSAndroid Build Coastguard Worker * ----- 353*795d594fSAndroid Build Coastguard Worker * Tested function: 354*795d594fSAndroid Build Coastguard Worker * public class Test9Base { 355*795d594fSAndroid Build Coastguard Worker * public void foo() { ... } 356*795d594fSAndroid Build Coastguard Worker * } 357*795d594fSAndroid Build Coastguard Worker * public class Test9Derived extends Test9Base { 358*795d594fSAndroid Build Coastguard Worker * public static void foo() { ... } 359*795d594fSAndroid Build Coastguard Worker * } 360*795d594fSAndroid Build Coastguard Worker * Tested invokes: 361*795d594fSAndroid Build Coastguard Worker * invoke-static Test9Derived.foo()V from Test9User in first dex file 362*795d594fSAndroid Build Coastguard Worker * expected: executes Test9Derived.foo()V 363*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test9Derived.foo()V from Test9User2 in first dex file 364*795d594fSAndroid Build Coastguard Worker * expected: throws IncompatibleClassChangeError (JLS 13.4.19) 365*795d594fSAndroid Build Coastguard Worker * 366*795d594fSAndroid Build Coastguard Worker * Another test for invoke type mismatch. 367*795d594fSAndroid Build Coastguard Worker * 368*795d594fSAndroid Build Coastguard Worker * Files: 369*795d594fSAndroid Build Coastguard Worker * src/Test9Base.java - defines non-static foo()V. 370*795d594fSAndroid Build Coastguard Worker * jasmin/Test9Derived.j - defines static foo()V. 371*795d594fSAndroid Build Coastguard Worker * jasmin/Test9User.j - calls invokestatic Test8Derived.foo()V. 372*795d594fSAndroid Build Coastguard Worker * jasmin/Test9User2.j - calls invokevirtual Test8Derived.foo()V. 373*795d594fSAndroid Build Coastguard Worker */ test9()374*795d594fSAndroid Build Coastguard Worker private static void test9() throws Exception { 375*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test9User"); 376*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test9User2"); 377*795d594fSAndroid Build Coastguard Worker } 378*795d594fSAndroid Build Coastguard Worker 379*795d594fSAndroid Build Coastguard Worker /* 380*795d594fSAndroid Build Coastguard Worker * Test10 381*795d594fSAndroid Build Coastguard Worker * ------ 382*795d594fSAndroid Build Coastguard Worker * Tested function: 383*795d594fSAndroid Build Coastguard Worker * public class Test10Base implements Test10Interface { } 384*795d594fSAndroid Build Coastguard Worker * public interface Test10Interface { } 385*795d594fSAndroid Build Coastguard Worker * Tested invokes: 386*795d594fSAndroid Build Coastguard Worker * invoke-interface Test10Interface.clone()Ljava/lang/Object; from Test10User in first dex 387*795d594fSAndroid Build Coastguard Worker * RI: Throws NoSuchMethodError (JLS 13.4.12?) 388*795d594fSAndroid Build Coastguard Worker * ART: Throws IncompatibleClassChangeError. 389*795d594fSAndroid Build Coastguard Worker * 390*795d594fSAndroid Build Coastguard Worker * This test is simulating compiling Test10Interface with "public Object clone()" method, along 391*795d594fSAndroid Build Coastguard Worker * with every other class. Then we delete "clone" from Test10Interface only. As there is a 392*795d594fSAndroid Build Coastguard Worker * method with the same signature declared in `java.lang.Object`, ART throws ICCE. For some 393*795d594fSAndroid Build Coastguard Worker * reason RI throws NSME even though 13.4.12 is not applicable due to the superclass declaring 394*795d594fSAndroid Build Coastguard Worker * a method with the same signature and the applicable section 13.4.7 does not specify what 395*795d594fSAndroid Build Coastguard Worker * exception should be thrown (but ICCE is a reasonable choice). 396*795d594fSAndroid Build Coastguard Worker * 397*795d594fSAndroid Build Coastguard Worker * Files: 398*795d594fSAndroid Build Coastguard Worker * src/Test10Interface.java - defines empty interface 399*795d594fSAndroid Build Coastguard Worker * src/Test10Base.java - implements Test10Interface 400*795d594fSAndroid Build Coastguard Worker * jasmin/Test10User.j - invokeinterface Test10Interface.clone()Ljava/lang/Object; 401*795d594fSAndroid Build Coastguard Worker */ test10()402*795d594fSAndroid Build Coastguard Worker private static void test10() throws Exception { 403*795d594fSAndroid Build Coastguard Worker if (usingRI) { 404*795d594fSAndroid Build Coastguard Worker // For RI, just print the expected output to hide the divergence. 405*795d594fSAndroid Build Coastguard Worker System.out.println("Calling Test10User.test():\n" + 406*795d594fSAndroid Build Coastguard Worker "Caught java.lang.reflect.InvocationTargetException\n" + 407*795d594fSAndroid Build Coastguard Worker " caused by java.lang.IncompatibleClassChangeError"); 408*795d594fSAndroid Build Coastguard Worker } else { 409*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test10User"); 410*795d594fSAndroid Build Coastguard Worker } 411*795d594fSAndroid Build Coastguard Worker } 412*795d594fSAndroid Build Coastguard Worker 413*795d594fSAndroid Build Coastguard Worker /* 414*795d594fSAndroid Build Coastguard Worker * Test11 415*795d594fSAndroid Build Coastguard Worker * ------ 416*795d594fSAndroid Build Coastguard Worker * Tested function: 417*795d594fSAndroid Build Coastguard Worker * public class Test11Base { 418*795d594fSAndroid Build Coastguard Worker * Test11Base(String) { ... } 419*795d594fSAndroid Build Coastguard Worker * } 420*795d594fSAndroid Build Coastguard Worker * public class Test11Derived extends Test11Base { 421*795d594fSAndroid Build Coastguard Worker * Test11Derived() { Test11Base("Test"); } 422*795d594fSAndroid Build Coastguard Worker * } 423*795d594fSAndroid Build Coastguard Worker * Tested invokes: 424*795d594fSAndroid Build Coastguard Worker * invoke-direct Test11Derived.<init>(Ljava/lang/String;)V from Test11User in first dex 425*795d594fSAndroid Build Coastguard Worker * TODO b/183485797 This should throw a NSME (constructors are never inherited, JLS 8.8) 426*795d594fSAndroid Build Coastguard Worker * but actually calls the superclass constructor. 427*795d594fSAndroid Build Coastguard Worker * expected: Successful construction of a Test11Derived instance. 428*795d594fSAndroid Build Coastguard Worker * According to JLS, constructors are never inherited, so we should throw NoSuchMethodError and 429*795d594fSAndroid Build Coastguard Worker * the RI does exactly that. However, ART has been permissive and allowed calling a superclass 430*795d594fSAndroid Build Coastguard Worker * constructor directly for a long time and bytecode optimizers such as R8 are now using this 431*795d594fSAndroid Build Coastguard Worker * to significantly reduce the dex file size. It is undesirable to implement strict checks now 432*795d594fSAndroid Build Coastguard Worker * due to app compatibility issues and dex file size impact. Therefore ART deliberately 433*795d594fSAndroid Build Coastguard Worker * diverges from the RI in this case and accepts the call to the superclass constructor. 434*795d594fSAndroid Build Coastguard Worker * 435*795d594fSAndroid Build Coastguard Worker * Files: 436*795d594fSAndroid Build Coastguard Worker * src/Test11Base.java - defines Test11Base with <init>(Ljava/lang/String;)V 437*795d594fSAndroid Build Coastguard Worker * src/Test11Derived.java - defines Test11Derived with <init>()V 438*795d594fSAndroid Build Coastguard Worker * jasmin/Test11User.j - invokespecial Test11Derived.<init>(Ljava/lang/String;)V 439*795d594fSAndroid Build Coastguard Worker */ test11()440*795d594fSAndroid Build Coastguard Worker private static void test11() throws Exception { 441*795d594fSAndroid Build Coastguard Worker if (usingRI) { 442*795d594fSAndroid Build Coastguard Worker // For RI, just print the expected output to hide the deliberate divergence. 443*795d594fSAndroid Build Coastguard Worker System.out.println("Calling Test11User.test():\n" + 444*795d594fSAndroid Build Coastguard Worker "Test11Base.<init>(\"Test\")"); 445*795d594fSAndroid Build Coastguard Worker } else { 446*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test11User"); 447*795d594fSAndroid Build Coastguard Worker } 448*795d594fSAndroid Build Coastguard Worker } 449*795d594fSAndroid Build Coastguard Worker 450*795d594fSAndroid Build Coastguard Worker /* 451*795d594fSAndroid Build Coastguard Worker * Test12 452*795d594fSAndroid Build Coastguard Worker * ----- 453*795d594fSAndroid Build Coastguard Worker * Tested function: 454*795d594fSAndroid Build Coastguard Worker * public class pkg.Test12Base { 455*795d594fSAndroid Build Coastguard Worker * void foo() { ... } // package-private 456*795d594fSAndroid Build Coastguard Worker * } 457*795d594fSAndroid Build Coastguard Worker * public class Test12Derived extends pkg.Test12Base { } 458*795d594fSAndroid Build Coastguard Worker * Tested invokes: 459*795d594fSAndroid Build Coastguard Worker * invoke-virtual Test12Derived.foo()V; from Test12User in first dex 460*795d594fSAndroid Build Coastguard Worker * expected: throws IllegalAccessError (JLS 13.4.7) 461*795d594fSAndroid Build Coastguard Worker * 462*795d594fSAndroid Build Coastguard Worker * This test is simulating compiling Test12Derived with "public void foo()" method, along 463*795d594fSAndroid Build Coastguard Worker * with every other class. Then we delete "foo" from Test12Derived only. The invoke finds 464*795d594fSAndroid Build Coastguard Worker * an inaccessible method in pkg1.Test12Base and throws IAE. 465*795d594fSAndroid Build Coastguard Worker * 466*795d594fSAndroid Build Coastguard Worker * This is somewhat similar to Test10 but throws IAE instead of ICCE. 467*795d594fSAndroid Build Coastguard Worker * 468*795d594fSAndroid Build Coastguard Worker * Files: 469*795d594fSAndroid Build Coastguard Worker * src/pkg/Test12Base.java - declares package-private foo()V 470*795d594fSAndroid Build Coastguard Worker * src/Test12Derived.java - does not declare foo()V 471*795d594fSAndroid Build Coastguard Worker * jasmin/Test12User.j - invokevirtual Test12Derived.foo()V 472*795d594fSAndroid Build Coastguard Worker */ test12()473*795d594fSAndroid Build Coastguard Worker private static void test12() throws Exception { 474*795d594fSAndroid Build Coastguard Worker invokeUserTest("Test12User"); 475*795d594fSAndroid Build Coastguard Worker } 476*795d594fSAndroid Build Coastguard Worker invokeUserTest(String userName)477*795d594fSAndroid Build Coastguard Worker private static void invokeUserTest(String userName) throws Exception { 478*795d594fSAndroid Build Coastguard Worker System.out.println("Calling " + userName + ".test():"); 479*795d594fSAndroid Build Coastguard Worker try { 480*795d594fSAndroid Build Coastguard Worker Class<?> user = Class.forName(userName); 481*795d594fSAndroid Build Coastguard Worker Method utest = user.getDeclaredMethod("test"); 482*795d594fSAndroid Build Coastguard Worker utest.invoke(null); 483*795d594fSAndroid Build Coastguard Worker } catch (Throwable t) { 484*795d594fSAndroid Build Coastguard Worker System.out.println("Caught " + t.getClass().getName()); 485*795d594fSAndroid Build Coastguard Worker for (Throwable c = t.getCause(); c != null; c = c.getCause()) { 486*795d594fSAndroid Build Coastguard Worker System.out.println(" caused by " + c.getClass().getName()); 487*795d594fSAndroid Build Coastguard Worker } 488*795d594fSAndroid Build Coastguard Worker } 489*795d594fSAndroid Build Coastguard Worker } 490*795d594fSAndroid Build Coastguard Worker 491*795d594fSAndroid Build Coastguard Worker // Replace the variable part of the output of the default toString() implementation 492*795d594fSAndroid Build Coastguard Worker // so that we have a deterministic output. normalizeToString(String s)493*795d594fSAndroid Build Coastguard Worker static String normalizeToString(String s) { 494*795d594fSAndroid Build Coastguard Worker int atPos = s.indexOf("@"); 495*795d594fSAndroid Build Coastguard Worker return s.substring(0, atPos + 1) + "..."; 496*795d594fSAndroid Build Coastguard Worker } 497*795d594fSAndroid Build Coastguard Worker 498*795d594fSAndroid Build Coastguard Worker static boolean usingRI; 499*795d594fSAndroid Build Coastguard Worker } 500