/* * Copyright (c) 2020, 2021, 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 * @key stress randomness * @bug 8229855 8238812 * @summary Test jump table with key value that gets out of bounds after loop unrolling. * @requires vm.compiler2.enabled * * @run main/othervm -XX:CompileCommand=dontinline,compiler.c2.TestJumpTable::test* * -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:-UseSwitchProfiling * compiler.c2.TestJumpTable * @run main/othervm -XX:CompileCommand=dontinline,compiler.c2.TestJumpTable::test* * -Xbatch -XX:-TieredCompilation -XX:-UseOnStackReplacement * compiler.c2.TestJumpTable * @run main/othervm -XX:CompileCommand=dontinline,compiler.c2.TestJumpTable::test* * -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+StressIGVN * compiler.c2.TestJumpTable */ package compiler.c2; public class TestJumpTable { public static int test0() { int res = 0; for (int i = 10; i < 50; ++i) { switch (i * 5) { case 15: case 25: case 40: case 101: return 42; case 45: case 51: case 60: res++; break; } } return res; } static int field; // Original (slightly simplified) fuzzer generated test public static void test1() { int i4, i5 = 99, i6, i9 = 89; for (i4 = 12; i4 < 365; i4++) { for (i6 = 5; i6 > 1; i6--) { switch ((i6 * 5) + 11) { case 13: case 19: case 26: case 31: case 35: case 41: case 43: case 61: case 71: case 83: case 314: i9 = i5; break; } } } } // This generates the following subgraph: /* // i: -10..4 if ((i+min_jint) u<= max_jint) { <- This is always true but not folded by C2 ... } else { ... CastII(i-5, 0..45) <- Replaced by TOP because i-5 range is -15..-1 but still considered reachable by C2 although it is dead code ... } */ public static void test2() { for (int i = 5; i > -10; i--) { switch (i) { case 0: case 4: case 10: case 20: case 30: case 40: case 50: case 100: field = 42; break; } } } // This generates the following subgraph: /* // i: -20..0 if (i != 0) { // i: -20..-1 if (i < 0) { <- This is always true but not folded by C2 // Fall through } else { ... CastII(i-1, 0..4) <- Replaced by TOP because i-1 range is -21..-1 but still considered reachable by C2 although it is dead code ... } } else { StoreI <- Due to this additional store on, IfNode::has_shared_region returns false and the fold compares optimization does not kick in } */ public static void test3() { for (int i = 5; i > -20; i -= 5) { switch (i) { case 0: case 10: case 20: case 30: case 40: case 50: case 60: case 100: field = 42; break; } } } // This generates the following subgraph: /* // i: -20..0 if (i != 0) { // i: -20..-1 if (i u< 101) { <- This is always false but not folded by C2 because CmpU is not handled CastII(i-1, 0..49) <- Replaced by TOP because i-1 range is -21..-1 but still considered reachable by C2 although it is dead code } else { ... } } else { ... } */ public static void test4() { int local = 0; for (int i = 5; i > -20; i -= 5) { switch (i) { case 0: case 10: case 20: case 30: case 40: case 50: case 100: local = 42; break; } } } // This generates the following subgraph: /* // i: 0..20 if (i != 20) { // i: 0..19 if ((i-20) u< 281) { <- This is always false but not folded by C2 because the two ifs compare different values CastII(i-21, 0..49) <- Replaced by TOP because i-21 range is -21..-1 but still considered reachable by C2 although it is dead code } else { ... } } else { ... } */ public static void test5() { int local; for (int i = 25; i > 0; i -= 5) { switch (i) { case 20: case 30: case 40: case 50: case 60: case 70: case 300: local = 42; break; } } } // This generates the following subgraph: /* // i: 0..20 if ((i+10) != 30) { // i: 0..19 if ((i-20) u< 271) { <- This is always false but not folded by C2 because the two ifs compare different values CastII(i-21, 0..4) <- Replaced by TOP because i-21 range is -21..-1 but still considered reachable by C2 although it is dead code } else { ... } } else { ... } */ public static void test6() { int local; for (int i = 25; i > 0; i -= 5) { switch (i + 10) { case 30: case 40: case 50: case 60: case 70: case 80: case 300: local = 42; break; } } } public static void main(String[] args) { for (int i = 0; i < 50_000; ++i) { test0(); test1(); test2(); test3(); test4(); test5(); test6(); } } }