/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 8072008 * @library /testlibrary /../../test/lib * @build InvokeTest NonInlinedReinvoker * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * java.lang.invoke.InvokeTest * java.lang.invoke.InvokeTest$T * java.lang.invoke.InvokeTest$P1 * java.lang.invoke.InvokeTest$P2 * java.lang.invoke.InvokeTest$I * java.lang.invoke.NonInlinedReinvoker * jdk.test.lib.Asserts * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 * java.lang.invoke.InvokeTest */ package java.lang.invoke; import sun.hotspot.WhiteBox; import static jdk.test.lib.Asserts.*; public class InvokeTest { static MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; static final MethodHandle virtualMH; // invokevirtual T.f1 static final MethodHandle staticMH; // invokestatic T.f2 static final MethodHandle intfMH; // invokeinterface I.f1 static final MethodHandle specialMH; // invokespecial T.f4 T static final MethodHandle basicMH; static final WhiteBox WB = WhiteBox.getWhiteBox(); static volatile boolean doDeopt = false; static { try { MethodType mtype = MethodType.methodType(Class.class); virtualMH = LOOKUP.findVirtual(T.class, "f1", mtype); staticMH = LOOKUP.findStatic (T.class, "f2", mtype); intfMH = LOOKUP.findVirtual(I.class, "f3", mtype); specialMH = LOOKUP.findSpecial(T.class, "f4", mtype, T.class); basicMH = NonInlinedReinvoker.make(staticMH); } catch (Exception e) { throw new Error(e); } } static class T implements I { @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return T.class; } @DontInline public static Class f2() { if (doDeopt) WB.deoptimize(); return T.class; } @DontInline private Class f4() { if (doDeopt) WB.deoptimize(); return T.class; } } static class P1 extends T { @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return P1.class; } @DontInline public Class f3() { if (doDeopt) WB.deoptimize(); return P1.class; } } static class P2 extends T { @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return P2.class; } @DontInline public Class f3() { if (doDeopt) WB.deoptimize(); return P2.class; } } static interface I { @DontInline default Class f3() { if (doDeopt) WB.deoptimize(); return I.class; } } @DontInline static void linkToVirtual(Object obj, Class extecpted) { try { Class cls = (Class)virtualMH.invokeExact((T)obj); assertEquals(cls, obj.getClass()); } catch (Throwable e) { throw new Error(e); } } @DontInline static void linkToInterface(Object obj, Class expected) { try { Class cls = (Class)intfMH.invokeExact((I)obj); assertEquals(cls, expected); } catch (Throwable e) { throw new Error(e); } } @DontInline static void linkToStatic() { try { Class cls = (Class)staticMH.invokeExact(); assertEquals(cls, T.class); } catch (Throwable e) { throw new Error(e); } } @DontInline static void linkToSpecial(Object obj, Class expected) { try { Class cls = (Class)specialMH.invokeExact((T)obj); assertEquals(cls, expected); } catch (Throwable e) { throw new Error(e); } } @DontInline static void invokeBasic() { try { Class cls = (Class)basicMH.invokeBasic(); assertEquals(cls, T.class); } catch (Throwable e) { throw new Error(e); } } static void run(Runnable r) { for (int i = 0; i < 20_000; i++) { r.run(); } doDeopt = true; r.run(); doDeopt = false; WB.clearInlineCaches(); for (int i = 0; i < 20_000; i++) { r.run(); } doDeopt = true; r.run(); doDeopt = false; } static void testVirtual() { System.out.println("linkToVirtual"); // Monomorphic case (optimized virtual call) run(() -> linkToVirtual(new T(), T.class)); // Megamorphic case (virtual call) Object[] recv = new Object[] { new T(), new P1(), new P2() }; run(() -> { for (Object r : recv) { linkToVirtual(r, r.getClass()); }}); } static void testInterface() { System.out.println("linkToInterface"); // Monomorphic case (optimized virtual call) run(() -> linkToInterface(new T(), I.class)); // Megamorphic case (virtual call) Object[][] recv = new Object[][] {{new T(), I.class}, {new P1(), P1.class}, {new P2(), P2.class}}; run(() -> { for (Object[] r : recv) { linkToInterface(r[0], (Class)r[1]); }}); } static void testSpecial() { System.out.println("linkToSpecial"); // Monomorphic case (optimized virtual call) run(() -> linkToSpecial(new T(), T.class)); } static void testStatic() { System.out.println("linkToStatic"); // static call run(() -> linkToStatic()); } static void testBasic() { System.out.println("invokeBasic"); // static call run(() -> invokeBasic()); } public static void main(String[] args) { testVirtual(); testInterface(); testSpecial(); testStatic(); testBasic(); } }