changeset 53174:26f4a81bd030 lworld

8215122: [lworld] TestLWold fails with ClassCastException
author thartmann
date Tue, 11 Dec 2018 15:00:35 +0100
parents 128ccaa6d2e3
children 9f53142ee638
files src/hotspot/share/opto/graphKit.cpp test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java
diffstat 2 files changed, 79 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/opto/graphKit.cpp	Tue Dec 11 13:45:11 2018 +0100
+++ b/src/hotspot/share/opto/graphKit.cpp	Tue Dec 11 15:00:35 2018 +0100
@@ -3145,6 +3145,7 @@
   kill_dead_locals();           // Benefit all the uncommon traps
   const TypeKlassPtr* tk = _gvn.type(superklass)->is_klassptr();
   const TypeOopPtr* toop = TypeOopPtr::make_from_klass(tk->klass());
+  assert(!never_null || toop->is_valuetypeptr(), "must be a value type pointer");
   bool is_value = obj->is_ValueType();
 
   // Fast cutout:  Check the case that the cast is vacuously true.
@@ -3172,21 +3173,23 @@
         if (!is_value) {
           obj = record_profiled_receiver_for_speculation(obj);
           if (never_null) {
-            assert(toop->is_valuetypeptr(), "must be a value type pointer");
             obj = null_check(obj);
-            if (toop->value_klass()->is_scalarizable()) {
-              obj = ValueTypeNode::make_from_oop(this, obj, toop->value_klass());
-            }
+          }
+          if (toop->is_valuetypeptr() && toop->value_klass()->is_scalarizable() && !gvn().type(obj)->maybe_null()) {
+            obj = ValueTypeNode::make_from_oop(this, obj, toop->value_klass());
           }
         }
         return obj;
       case Compile::SSC_always_false:
-        // It needs a null check because a null will *pass* the cast check.
-        if (is_value || toop->is_valuetypeptr()) {
-          // Value types are never null - always throw an exception
+        if (is_value || never_null) {
+          if (!is_value) {
+            null_check(obj);
+          }
+          // Value type is never null. Always throw an exception.
           builtin_throw(Deoptimization::Reason_class_check, makecon(TypeKlassPtr::make(klass)));
           return top();
         } else {
+          // It needs a null check because a null will *pass* the cast check.
           return null_assert(obj);
         }
       }
@@ -3220,7 +3223,6 @@
   if (is_value) {
     not_null_obj = obj;
   } else if (never_null) {
-    assert(toop->is_valuetypeptr(), "must be a value type pointer");
     not_null_obj = null_check(obj);
   } else {
     not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java	Tue Dec 11 13:45:11 2018 +0100
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java	Tue Dec 11 15:00:35 2018 +0100
@@ -1903,7 +1903,7 @@
     }
 */
 
-    // Casting a null Integer to a value type should throw a NPE
+    // Casting a null Integer to a (non-nullable) value type should throw a NullPointerException
     @ForceInline
     public MyValue1 test76_helper(Object o) {
         return (MyValue1)o;
@@ -1921,6 +1921,74 @@
             throw new RuntimeException("NullPointerException expected");
         } catch (NullPointerException e) {
             // Expected
+        } catch (Exception e) {
+            throw new RuntimeException("test76 failed: unexpected exception", e);
+        }
+    }
+
+    // Casting an Integer to a (non-nullable) value type should throw a ClassCastException
+    @ForceInline
+    public MyValue1 test77_helper(Object o) {
+        return (MyValue1)o;
+    }
+
+    @Test
+    public MyValue1 test77(Integer i) throws Throwable {
+        return test77_helper(i);
+    }
+
+    @DontCompile
+    public void test77_verifier(boolean warmup) throws Throwable {
+        try {
+            test77(new Integer(42));
+            throw new RuntimeException("ClassCastException expected");
+        } catch (ClassCastException e) {
+            // Expected
+        } catch (Exception e) {
+            throw new RuntimeException("test77 failed: unexpected exception", e);
+        }
+    }
+
+    // Casting a null Integer to a nullable value type should not throw
+    @ForceInline
+    public MyValue1.box test78_helper(Object o) {
+        return (MyValue1.box)o;
+    }
+
+    @Test
+    public MyValue1.box test78(Integer i) throws Throwable {
+        return test78_helper(i);
+    }
+
+    @DontCompile
+    public void test78_verifier(boolean warmup) throws Throwable {
+        try {
+            test78(null); // Should not throw
+        } catch (Exception e) {
+            throw new RuntimeException("test78 failed: unexpected exception", e);
+        }
+    }
+
+    // Casting an Integer to a nullable value type should throw a ClassCastException
+    @ForceInline
+    public MyValue1.box test79_helper(Object o) {
+        return (MyValue1.box)o;
+    }
+
+    @Test
+    public MyValue1.box test79(Integer i) throws Throwable {
+        return test79_helper(i);
+    }
+
+    @DontCompile
+    public void test79_verifier(boolean warmup) throws Throwable {
+        try {
+            test79(new Integer(42));
+            throw new RuntimeException("ClassCastException expected");
+        } catch (ClassCastException e) {
+            // Expected
+        } catch (Exception e) {
+            throw new RuntimeException("test79 failed: unexpected exception", e);
         }
     }
 }