xref: /aosp_15_r20/art/test/162-method-resolution/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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