/* * Copyright (c) 2013, 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 8024070 * @summary Test that type speculation doesn't cause incorrect execution * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 TypeSpeculation * */ public class TypeSpeculation { interface I { } static class A { int m() { return 1; } } static class B extends A implements I { int m() { return 2; } } static class C extends B { int m() { return 3; } } static int test1_invokevirtual(A a) { return a.m(); } static int test1_1(A a) { return test1_invokevirtual(a); } static boolean test1() { A a = new A(); B b = new B(); C c = new C(); // pollute profile at test1_invokevirtual to make sure the // compiler cannot rely on it for (int i = 0; i < 5000; i++) { test1_invokevirtual(a); test1_invokevirtual(b); test1_invokevirtual(c); } // profiling + speculation should make test1_invokevirtual // inline A.m() with a guard for (int i = 0; i < 20000; i++) { int res = test1_1(b); if (res != b.m()) { System.out.println("test1 failed with class B"); return false; } } // check that the guard works as expected by passing a // different type int res = test1_1(a); if (res != a.m()) { System.out.println("test1 failed with class A"); return false; } return true; } static int test2_invokevirtual(A a) { return a.m(); } static int test2_1(A a, boolean t) { A aa; if (t) { aa = (B)a; } else { aa = a; } // if a of type B is passed to test2_1, the static type of aa // here is no better than A but the profiled type is B so this // should inline return test2_invokevirtual(aa); } static boolean test2() { A a = new A(); B b = new B(); C c = new C(); // pollute profile at test2_invokevirtual to make sure the // compiler cannot rely on it for (int i = 0; i < 5000; i++) { test2_invokevirtual(a); test2_invokevirtual(b); test2_invokevirtual(c); } // profiling + speculation should make test2_invokevirtual // inline A.m() with a guard for (int i = 0; i < 20000; i++) { int res = test2_1(b, (i % 2) == 0); if (res != b.m()) { System.out.println("test2 failed with class B"); return false; } } // check that the guard works as expected by passing a // different type int res = test2_1(a, false); if (res != a.m()) { System.out.println("test2 failed with class A"); return false; } return true; } static int test3_invokevirtual(A a) { return a.m(); } static void test3_2(A a) { } static int test3_1(A a, int i) { if (i == 0) { return 0; } // If we come here and a is of type B but parameter profiling // is polluted, both branches of the if below should have // profiling that tell us and inlining of the virtual call // should happen if (i == 1) { test3_2(a); } else { test3_2(a); } return test3_invokevirtual(a); } static boolean test3() { A a = new A(); B b = new B(); C c = new C(); // pollute profile at test3_invokevirtual and test3_1 to make // sure the compiler cannot rely on it for (int i = 0; i < 3000; i++) { test3_invokevirtual(a); test3_invokevirtual(b); test3_invokevirtual(c); test3_1(a, 0); test3_1(b, 0); } // profiling + speculation should make test3_invokevirtual // inline A.m() with a guard for (int i = 0; i < 20000; i++) { int res = test3_1(b, (i % 2) + 1); if (res != b.m()) { System.out.println("test3 failed with class B"); return false; } } // check that the guard works as expected by passing a // different type int res = test3_1(a, 1); if (res != a.m()) { System.out.println("test3 failed with class A"); return false; } return true; } // Mix 2 incompatible profiled types static int test4_invokevirtual(A a) { return a.m(); } static void test4_2(A a) { } static int test4_1(A a, boolean b) { if (b) { test4_2(a); } else { test4_2(a); } // shouldn't inline return test4_invokevirtual(a); } static boolean test4() { A a = new A(); B b = new B(); C c = new C(); // pollute profile at test3_invokevirtual and test3_1 to make // sure the compiler cannot rely on it for (int i = 0; i < 3000; i++) { test4_invokevirtual(a); test4_invokevirtual(b); test4_invokevirtual(c); } for (int i = 0; i < 20000; i++) { if ((i % 2) == 0) { int res = test4_1(a, true); if (res != a.m()) { System.out.println("test4 failed with class A"); return false; } } else { int res = test4_1(b, false); if (res != b.m()) { System.out.println("test4 failed with class B"); return false; } } } return true; } // Mix one profiled type with an incompatible type static int test5_invokevirtual(A a) { return a.m(); } static void test5_2(A a) { } static int test5_1(A a, boolean b) { if (b) { test5_2(a); } else { A aa = (B)a; } // shouldn't inline return test5_invokevirtual(a); } static boolean test5() { A a = new A(); B b = new B(); C c = new C(); // pollute profile at test3_invokevirtual and test3_1 to make // sure the compiler cannot rely on it for (int i = 0; i < 3000; i++) { test5_invokevirtual(a); test5_invokevirtual(b); test5_invokevirtual(c); } for (int i = 0; i < 20000; i++) { if ((i % 2) == 0) { int res = test5_1(a, true); if (res != a.m()) { System.out.println("test5 failed with class A"); return false; } } else { int res = test5_1(b, false); if (res != b.m()) { System.out.println("test5 failed with class B"); return false; } } } return true; } // Mix incompatible profiled types static void test6_2(Object o) { } static Object test6_1(Object o, boolean b) { if (b) { test6_2(o); } else { test6_2(o); } return o; } static boolean test6() { A a = new A(); A[] aa = new A[10]; for (int i = 0; i < 20000; i++) { if ((i % 2) == 0) { test6_1(a, true); } else { test6_1(aa, false); } } return true; } // Mix a profiled type with an incompatible type static void test7_2(Object o) { } static Object test7_1(Object o, boolean b) { if (b) { test7_2(o); } else { Object oo = (A[])o; } return o; } static boolean test7() { A a = new A(); A[] aa = new A[10]; for (int i = 0; i < 20000; i++) { if ((i % 2) == 0) { test7_1(a, true); } else { test7_1(aa, false); } } return true; } // Mix a profiled type with an interface static void test8_2(Object o) { } static I test8_1(Object o) { test8_2(o); return (I)o; } static boolean test8() { A a = new A(); B b = new B(); C c = new C(); for (int i = 0; i < 20000; i++) { test8_1(b); } return true; } // Mix a profiled type with a constant static void test9_2(Object o) { } static Object test9_1(Object o, boolean b) { Object oo; if (b) { test9_2(o); oo = o; } else { oo = "some string"; } return oo; } static boolean test9() { A a = new A(); for (int i = 0; i < 20000; i++) { if ((i % 2) == 0) { test9_1(a, true); } else { test9_1(a, false); } } return true; } static public void main(String[] args) { boolean success = true; success = test1() && success; success = test2() && success; success = test3() && success; success = test4() && success; success = test5() && success; success = test6() && success; success = test7() && success; success = test8() && success; success = test9() && success; if (success) { System.out.println("TEST PASSED"); } else { throw new RuntimeException("TEST FAILED: erroneous bound check elimination"); } } }