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 WhiteBox WB = WhiteBox.getWhiteBox(); 64 65 static volatile boolean doDeopt = false; 66 67 static { 68 try { 69 MethodType mtype = MethodType.methodType(Class.class); 70 71 virtualMH = LOOKUP.findVirtual(T.class, "f1", mtype); 72 staticMH = LOOKUP.findStatic (T.class, "f2", mtype); 73 intfMH = LOOKUP.findVirtual(I.class, "f3", mtype); 74 defaultMH = LOOKUP.findVirtual(T.class, "f3", mtype); 75 specialMH = LOOKUP.findSpecial(T.class, "f4", mtype, T.class); 76 privateMH = LOOKUP.findSpecial(I.class, "f4", mtype, I.class); 77 basicMH = NonInlinedReinvoker.make(staticMH); 78 } catch (Exception e) { 79 throw new Error(e); 80 } 81 } 82 83 static class T implements I { 84 @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return T.class; } 85 @DontInline public static Class<?> f2() { if (doDeopt) WB.deoptimizeAll(); return T.class; } 86 @DontInline private Class<?> f4() { if (doDeopt) WB.deoptimizeAll(); return T.class; } 87 } 88 89 static class P1 extends T { 90 @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return P1.class; } 91 @DontInline public Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return P1.class; } 92 } 93 94 static class P2 extends T { 95 @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return P2.class; } 96 @DontInline public Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return P2.class; } 97 } 98 99 interface I { 100 @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return I.class; } 101 @DontInline private Class<?> f4() { if (doDeopt) WB.deoptimizeAll(); return I.class; } 102 } 103 104 interface J1 extends I { 105 @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J1.class; } 106 } 107 108 interface J2 extends I { 109 @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J2.class; } 110 } 111 112 interface J3 extends I { 113 @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J3.class; } 114 } 115 116 static class Q1 extends T implements J1 {} 117 static class Q2 extends T implements J2 {} 118 static class Q3 extends T implements J3 {} 119 120 @DontInline 121 static void linkToVirtual(T recv, Class<?> expected) { 122 try { 123 Class<?> cls = (Class<?>)virtualMH.invokeExact(recv); 124 assertEquals(cls, expected); 125 } catch (Throwable e) { 126 throw new Error(e); 127 } 128 } 129 130 @DontInline 131 static void linkToVirtualDefault(T recv, Class<?> expected) { 132 try { 133 Class<?> cls = (Class<?>)defaultMH.invokeExact(recv); 134 assertEquals(cls, expected); 135 } catch (Throwable e) { 136 throw new Error(e); 137 } 138 } 139 140 @DontInline 141 static void linkToInterface(I recv, Class<?> expected) { 142 try { 143 Class<?> cls = (Class<?>)intfMH.invokeExact(recv); 144 assertEquals(cls, expected); 145 } catch (Throwable e) { 146 throw new Error(e); 147 } 148 } 149 150 @DontInline 151 static void linkToStatic() { 152 try { 153 Class<?> cls = (Class<?>)staticMH.invokeExact(); 154 assertEquals(cls, T.class); 155 } catch (Throwable e) { 156 throw new Error(e); 157 } 158 } 159 160 @DontInline 161 static void linkToSpecial(T recv, Class<?> expected) { 162 try { 163 Class<?> cls = (Class<?>)specialMH.invokeExact(recv); 164 assertEquals(cls, expected); 165 } catch (Throwable e) { 166 throw new Error(e); 167 } 168 } 169 170 @DontInline 171 static void linkToSpecialIntf(I recv, Class<?> expected) { 172 try { 173 Class<?> cls = (Class<?>)privateMH.invokeExact(recv); 174 assertEquals(cls, expected); 175 } catch (Throwable e) { 176 throw new Error(e); 177 } 178 } 179 180 181 @DontInline 182 static void invokeBasic() { 183 try { 184 Class<?> cls = (Class<?>)MethodHandleHelper.invokeBasicL(basicMH); 185 assertEquals(cls, T.class); 186 } catch (Throwable e) { 187 throw new Error(e); 188 } 189 } 190 191 static void run(Runnable r) { 192 for (int i = 0; i < 20_000; i++) { 193 r.run(); 194 } 195 196 doDeopt = true; 197 r.run(); 198 doDeopt = false; 199 200 WB.clearInlineCaches(); 201 202 for (int i = 0; i < 20_000; i++) { 203 r.run(); 204 } 205 206 doDeopt = true; 207 r.run(); 208 doDeopt = false; 209 } 210 211 static void testVirtual() { 212 System.out.println("linkToVirtual"); 213 214 // Monomorphic case (optimized virtual call) 215 run(() -> linkToVirtual(new T(), T.class)); 216 run(() -> linkToVirtualDefault(new T(), I.class)); 217 218 // Megamorphic case (optimized virtual call) 219 run(() -> { 220 linkToVirtual(new T() {}, T.class); 221 linkToVirtual(new T() {}, T.class); 222 linkToVirtual(new T() {}, T.class); 223 }); 224 225 run(() -> { 226 linkToVirtualDefault(new T(){}, I.class); 227 linkToVirtualDefault(new T(){}, I.class); 228 linkToVirtualDefault(new T(){}, I.class); 229 }); 230 231 // Megamorphic case (virtual call), multiple implementations 232 run(() -> { 233 linkToVirtual(new T(), T.class); 234 linkToVirtual(new P1(), P1.class); 235 linkToVirtual(new P2(), P2.class); 236 }); 237 238 run(() -> { 239 linkToVirtualDefault(new Q1(), J1.class); 240 linkToVirtualDefault(new Q2(), J2.class); 241 linkToVirtualDefault(new Q3(), J3.class); 242 }); 243 } 244 245 static void testInterface() { 246 System.out.println("linkToInterface"); 247 248 // Monomorphic case (optimized virtual call), concrete target method 249 run(() -> linkToInterface(new P1(), P1.class)); 250 251 // Monomorphic case (optimized virtual call), default target method 252 run(() -> linkToInterface(new T(), I.class)); 253 254 // Megamorphic case (virtual call) 255 run(() -> { 256 linkToInterface(new T(), I.class); 257 linkToInterface(new P1(), P1.class); 258 linkToInterface(new P2(), P2.class); 259 }); 260 } 261 262 static void testSpecial() { 263 System.out.println("linkToSpecial"); 264 // Monomorphic case (optimized virtual call) 265 run(() -> linkToSpecial(new T(), T.class)); 266 run(() -> linkToSpecialIntf(new T(), I.class)); 267 } 268 269 static void testStatic() { 270 System.out.println("linkToStatic"); 271 // static call 272 run(() -> linkToStatic()); 273 } 274 275 static void testBasic() { 276 System.out.println("invokeBasic"); 277 // static call 278 run(() -> invokeBasic()); 279 } 280 281 public static void main(String[] args) { 282 testVirtual(); 283 testInterface(); 284 testSpecial(); 285 testStatic(); 286 testBasic(); 287 } 288 }