8238812: assert(false) failed: bad AD file

Reviewed-by: thartmann, chagedorn, roland
diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp
index 3d2f0b5..785877e 100644
--- a/src/hotspot/share/opto/compile.cpp
+++ b/src/hotspot/share/opto/compile.cpp
@@ -4371,10 +4371,10 @@
 }
 
 // Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
-Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl) {
+Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl, bool carry_dependency) {
   if (ctrl != NULL) {
     // Express control dependency by a CastII node with a narrow type.
-    value = new CastIINode(value, itype, false, true /* range check dependency */);
+    value = new CastIINode(value, itype, carry_dependency, true /* range check dependency */);
     // Make the CastII node dependent on the control input to prevent the narrowed ConvI2L
     // node from floating above the range check during loop optimizations. Otherwise, the
     // ConvI2L node may be eliminated independently of the range check, causing the data path
diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp
index 1633786..cfbe8da 100644
--- a/src/hotspot/share/opto/compile.hpp
+++ b/src/hotspot/share/opto/compile.hpp
@@ -1367,7 +1367,7 @@
                               Node* ctrl = NULL);
 
   // Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
-  static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl);
+  static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl, bool carry_dependency = false);
 
   // Auxiliary method for randomized fuzzing/stressing
   static bool randomized_select(int count);
diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp
index 64cef9a..ef21224 100644
--- a/src/hotspot/share/opto/parse2.cpp
+++ b/src/hotspot/share/opto/parse2.cpp
@@ -877,10 +877,16 @@
 
   // Clean the 32-bit int into a real 64-bit offset.
   // Otherwise, the jint value 0 might turn into an offset of 0x0800000000.
-  const TypeInt* ikeytype = TypeInt::make(0, num_cases, Type::WidenMin);
   // Make I2L conversion control dependent to prevent it from
   // floating above the range check during loop optimizations.
-  key_val = C->conv_I2X_index(&_gvn, key_val, ikeytype, control());
+  // Do not use a narrow int type here to prevent the data path from dying
+  // while the control path is not removed. This can happen if the type of key_val
+  // is later known to be out of bounds of [0, num_cases] and therefore a narrow cast
+  // would be replaced by TOP while C2 is not able to fold the corresponding range checks.
+  // Set _carry_dependency for the cast to avoid being removed by IGVN.
+#ifdef _LP64
+  key_val = C->constrained_convI2L(&_gvn, key_val, TypeInt::INT, control(), true /* carry_dependency */);
+#endif
 
   // Shift the value by wordsize so we have an index into the table, rather
   // than a switch value
diff --git a/test/hotspot/jtreg/compiler/c2/TestJumpTable.java b/test/hotspot/jtreg/compiler/c2/TestJumpTable.java
index eac1bb5..e70bfbc 100644
--- a/test/hotspot/jtreg/compiler/c2/TestJumpTable.java
+++ b/test/hotspot/jtreg/compiler/c2/TestJumpTable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,18 +23,24 @@
 
 /**
  * @test
- * @bug 8229855
+ * @bug 8229855 8238812
  * @summary Test jump table with key value that gets out of bounds after loop unrolling.
  * @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
+ *                   compiler.c2.TestJumpTable
  */
 
 package compiler.c2;
 
 public class TestJumpTable {
 
-    public static int test() {
+    public static int test0() {
         int res = 0;
         for (int i = 10; i < 50; ++i) {
             switch (i * 5) {
@@ -53,9 +59,195 @@
         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 < 20_000; ++i) {
-            test();
+        for (int i = 0; i < 50_000; ++i) {
+            test0();
+            test1();
+            test2();
+            test3();
+            test4();
+            test5();
+            test6();
         }
     }
 }