1 /*
2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8072008
27  * @library /test/lib / ../patches
28  * @modules java.base/jdk.internal.misc
29  *          java.base/jdk.internal.vm.annotation
30  *
31  * @build java.base/java.lang.invoke.MethodHandleHelper
32  *        sun.hotspot.WhiteBox
33  * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions
34  *                                 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
35  *                                 -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1
36  *                                 compiler.jsr292.NonInlinedCall.InvokeTest
37  */
38 
39 package compiler.jsr292.NonInlinedCall;
40 
41 import jdk.internal.vm.annotation.DontInline;
42 import sun.hotspot.WhiteBox;
43 
44 import java.lang.invoke.MethodHandle;
45 import java.lang.invoke.MethodHandleHelper;
46 import java.lang.invoke.MethodHandleHelper.NonInlinedReinvoker;
47 import java.lang.invoke.MethodHandles;
48 import java.lang.invoke.MethodType;
49 
50 import static jdk.test.lib.Asserts.assertEquals;
51 
52 public class InvokeTest {
53     static MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP;
54 
55     static final MethodHandle virtualMH; // invokevirtual   T.f1
56     static final MethodHandle staticMH;  // invokestatic    T.f2
57     static final MethodHandle intfMH;    // invokeinterface I.f3
58     static final MethodHandle defaultMH; // invokevirtual   T.f3
59     static final MethodHandle specialMH; // invokespecial   T.f4 T
60     static final MethodHandle privateMH; // invokespecial   I.f4 T
61     static final MethodHandle basicMH;
62 
63     static final MethodHandle intrinsicMH; // invokevirtual Object.hashCode
64 
65     static final WhiteBox WB = WhiteBox.getWhiteBox();
66 
67     static volatile boolean doDeopt = false;
68 
69     static {
70         try {
71             MethodType mtype = MethodType.methodType(Class.class);
72 
73             virtualMH  = LOOKUP.findVirtual(T.class, "f1", mtype);
74             staticMH   = LOOKUP.findStatic (T.class, "f2", mtype);
75             intfMH     = LOOKUP.findVirtual(I.class, "f3", mtype);
76             defaultMH  = LOOKUP.findVirtual(T.class, "f3", mtype);
77             specialMH  = LOOKUP.findSpecial(T.class, "f4", mtype, T.class);
78             privateMH  = LOOKUP.findSpecial(I.class, "f4", mtype, I.class);
79             basicMH    = NonInlinedReinvoker.make(staticMH);
80             intrinsicMH = LOOKUP.findVirtual(Object.class, "hashCode", MethodType.methodType(int.class));
81         } catch (Exception e) {
82             throw new Error(e);
83         }
84     }
85 
86     static class T implements I {
f1()87         @DontInline public        Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return T.class; }
f2()88         @DontInline public static Class<?> f2() { if (doDeopt) WB.deoptimizeAll(); return T.class; }
f4()89         @DontInline private       Class<?> f4() { if (doDeopt) WB.deoptimizeAll(); return T.class; }
90     }
91 
92     static class P1 extends T {
f1()93         @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return P1.class; }
f3()94         @DontInline public Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return P1.class; }
95     }
96 
97     static class P2 extends T {
f1()98         @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return P2.class; }
f3()99         @DontInline public Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return P2.class; }
100     }
101 
102     interface I {
f3()103         @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return I.class; }
f4()104         @DontInline private Class<?> f4() { if (doDeopt) WB.deoptimizeAll(); return I.class; }
105     }
106 
107     interface J1 extends I {
f3()108         @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J1.class; }
109     }
110 
111     interface J2 extends I {
f3()112         @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J2.class; }
113     }
114 
115     interface J3 extends I {
f3()116         @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J3.class; }
117     }
118 
119     static class Q1 extends T implements J1 {}
120     static class Q2 extends T implements J2 {}
121     static class Q3 extends T implements J3 {}
122 
123     static class H {
hashCode()124         public int hashCode() { return 0; }
125     }
126 
127     @DontInline
linkToVirtual(T recv, Class<?> expected)128     static void linkToVirtual(T recv, Class<?> expected) {
129         try {
130             Class<?> cls = (Class<?>)virtualMH.invokeExact(recv);
131             assertEquals(cls, expected);
132         } catch (Throwable e) {
133             throw new Error(e);
134         }
135     }
136 
137     @DontInline
linkToVirtualDefault(T recv, Class<?> expected)138     static void linkToVirtualDefault(T recv, Class<?> expected) {
139         try {
140             Class<?> cls = (Class<?>)defaultMH.invokeExact(recv);
141             assertEquals(cls, expected);
142         } catch (Throwable e) {
143             throw new Error(e);
144         }
145     }
146 
147     @DontInline
linkToVirtualIntrinsic(Object recv, int expected)148     static void linkToVirtualIntrinsic(Object recv, int expected) {
149         try {
150             int v = (int)intrinsicMH.invokeExact(recv);
151             assertEquals(v, expected);
152         } catch (Throwable e) {
153             throw new Error(e);
154         }
155     }
156 
157     @DontInline
linkToInterface(I recv, Class<?> expected)158     static void linkToInterface(I recv, Class<?> expected) {
159         try {
160             Class<?> cls = (Class<?>)intfMH.invokeExact(recv);
161             assertEquals(cls, expected);
162         } catch (Throwable e) {
163             throw new Error(e);
164         }
165     }
166 
167     @DontInline
linkToStatic()168     static void linkToStatic() {
169         try {
170             Class<?> cls = (Class<?>)staticMH.invokeExact();
171             assertEquals(cls, T.class);
172         } catch (Throwable e) {
173             throw new Error(e);
174         }
175     }
176 
177     @DontInline
linkToSpecial(T recv, Class<?> expected)178     static void linkToSpecial(T recv, Class<?> expected) {
179         try {
180             Class<?> cls = (Class<?>)specialMH.invokeExact(recv);
181             assertEquals(cls, expected);
182         } catch (Throwable e) {
183             throw new Error(e);
184         }
185     }
186 
187     @DontInline
linkToSpecialIntf(I recv, Class<?> expected)188     static void linkToSpecialIntf(I recv, Class<?> expected) {
189         try {
190             Class<?> cls = (Class<?>)privateMH.invokeExact(recv);
191             assertEquals(cls, expected);
192         } catch (Throwable e) {
193             throw new Error(e);
194         }
195     }
196 
197     @DontInline
invokeBasic()198     static void invokeBasic() {
199         try {
200             Class<?> cls = (Class<?>)MethodHandleHelper.invokeBasicL(basicMH);
201             assertEquals(cls, T.class);
202         } catch (Throwable e) {
203             throw new Error(e);
204         }
205     }
206 
run(Runnable r)207     static void run(Runnable r) {
208         for (int i = 0; i < 20_000; i++) {
209             r.run();
210         }
211 
212         doDeopt = true;
213         r.run();
214         doDeopt = false;
215 
216         WB.clearInlineCaches();
217 
218         for (int i = 0; i < 20_000; i++) {
219             r.run();
220         }
221 
222         doDeopt = true;
223         r.run();
224         doDeopt = false;
225     }
226 
testVirtual()227     static void testVirtual() {
228         System.out.println("linkToVirtual");
229 
230         // Monomorphic case (optimized virtual call)
231         run(() -> linkToVirtual(new T(), T.class));
232         run(() -> linkToVirtualDefault(new T(), I.class));
233 
234         run(() -> linkToVirtualIntrinsic(new H(), 0));
235 
236         // Megamorphic case (optimized virtual call)
237         run(() -> {
238             linkToVirtual(new T() {}, T.class);
239             linkToVirtual(new T() {}, T.class);
240             linkToVirtual(new T() {}, T.class);
241         });
242 
243         run(() -> {
244             linkToVirtualDefault(new T(){}, I.class);
245             linkToVirtualDefault(new T(){}, I.class);
246             linkToVirtualDefault(new T(){}, I.class);
247         });
248 
249         // Megamorphic case (virtual call), multiple implementations
250         run(() -> {
251             linkToVirtual(new T(),  T.class);
252             linkToVirtual(new P1(), P1.class);
253             linkToVirtual(new P2(), P2.class);
254         });
255 
256         run(() -> {
257             linkToVirtualDefault(new Q1(), J1.class);
258             linkToVirtualDefault(new Q2(), J2.class);
259             linkToVirtualDefault(new Q3(), J3.class);
260         });
261     }
262 
testInterface()263     static void testInterface() {
264         System.out.println("linkToInterface");
265 
266         // Monomorphic case (optimized virtual call), concrete target method
267         run(() -> linkToInterface(new P1(), P1.class));
268 
269         // Monomorphic case (optimized virtual call), default target method
270         run(() -> linkToInterface(new T(), I.class));
271 
272         // Megamorphic case (virtual call)
273         run(() -> {
274             linkToInterface(new T(),  I.class);
275             linkToInterface(new P1(), P1.class);
276             linkToInterface(new P2(), P2.class);
277         });
278     }
279 
testSpecial()280     static void testSpecial() {
281         System.out.println("linkToSpecial");
282         // Monomorphic case (optimized virtual call)
283         run(() -> linkToSpecial(new T(), T.class));
284         run(() -> linkToSpecialIntf(new T(), I.class));
285     }
286 
testStatic()287     static void testStatic() {
288         System.out.println("linkToStatic");
289         // static call
290         run(() -> linkToStatic());
291     }
292 
testBasic()293     static void testBasic() {
294         System.out.println("invokeBasic");
295         // static call
296         run(() -> invokeBasic());
297     }
298 
main(String[] args)299     public static void main(String[] args) {
300         testVirtual();
301         testInterface();
302         testSpecial();
303         testStatic();
304         testBasic();
305     }
306 }
307