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 { 87 @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return T.class; } 88 @DontInline public static Class<?> f2() { if (doDeopt) WB.deoptimizeAll(); return T.class; } 89 @DontInline private Class<?> f4() { if (doDeopt) WB.deoptimizeAll(); return T.class; } 90 } 91 92 static class P1 extends T { 93 @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return P1.class; } 94 @DontInline public Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return P1.class; } 95 } 96 97 static class P2 extends T { 98 @DontInline public Class<?> f1() { if (doDeopt) WB.deoptimizeAll(); return P2.class; } 99 @DontInline public Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return P2.class; } 100 } 101 102 interface I { 103 @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return I.class; } 104 @DontInline private Class<?> f4() { if (doDeopt) WB.deoptimizeAll(); return I.class; } 105 } 106 107 interface J1 extends I { 108 @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J1.class; } 109 } 110 111 interface J2 extends I { 112 @DontInline default Class<?> f3() { if (doDeopt) WB.deoptimizeAll(); return J2.class; } 113 } 114 115 interface J3 extends I { 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 { 124 public int hashCode() { return 0; } 125 } 126 127 @DontInline 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 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 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 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 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 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 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 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 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 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 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 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 287 static void testStatic() { 288 System.out.println("linkToStatic"); 289 // static call 290 run(() -> linkToStatic()); 291 } 292 293 static void testBasic() { 294 System.out.println("invokeBasic"); 295 // static call 296 run(() -> invokeBasic()); 297 } 298 299 public static void main(String[] args) { 300 testVirtual(); 301 testInterface(); 302 testSpecial(); 303 testStatic(); 304 testBasic(); 305 } 306 }