changeset 55129:784781105f6b lworld

8223949: [lworld] Casting null to an unloaded value type should throw NPE
author thartmann
date Wed, 15 May 2019 14:23:01 +0200
parents ec67666497c5
children 9873d841ee27
files src/hotspot/share/ci/ciTypeFlow.cpp src/hotspot/share/opto/parseHelper.cpp test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java
diffstat 3 files changed, 36 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/ci/ciTypeFlow.cpp	Tue May 14 21:06:00 2019 -0700
+++ b/src/hotspot/share/ci/ciTypeFlow.cpp	Wed May 15 14:23:01 2019 +0200
@@ -626,16 +626,24 @@
 void ciTypeFlow::StateVector::do_checkcast(ciBytecodeStream* str) {
   bool will_link;
   ciKlass* klass = str->get_klass(will_link);
+  bool never_null = str->is_klass_never_null();
   if (!will_link) {
-    // VM's interpreter will not load 'klass' if object is NULL.
-    // Type flow after this block may still be needed in two situations:
-    // 1) C2 uses do_null_assert() and continues compilation for later blocks
-    // 2) C2 does an OSR compile in a later block (see bug 4778368).
-    pop_object();
-    do_null_assert(klass);
+    if (never_null) {
+      trap(str, klass,
+           Deoptimization::make_trap_request
+           (Deoptimization::Reason_unloaded,
+            Deoptimization::Action_reinterpret));
+    } else {
+      // VM's interpreter will not load 'klass' if object is NULL.
+      // Type flow after this block may still be needed in two situations:
+      // 1) C2 uses do_null_assert() and continues compilation for later blocks
+      // 2) C2 does an OSR compile in a later block (see bug 4778368).
+      pop_object();
+      do_null_assert(klass);
+    }
   } else {
     ciType* type = pop_value();
-    if (klass->is_valuetype() && (str->is_klass_never_null() || type->is_never_null())) {
+    if (klass->is_valuetype() && (never_null || type->is_never_null())) {
       // Casting to a Q-Type contains a NULL check
       push(outer()->mark_as_never_null(klass));
     } else {
--- a/src/hotspot/share/opto/parseHelper.cpp	Tue May 14 21:06:00 2019 -0700
+++ b/src/hotspot/share/opto/parseHelper.cpp	Wed May 15 14:23:01 2019 +0200
@@ -77,6 +77,7 @@
   // then the checkcast does nothing.
   const TypeOopPtr *tp = _gvn.type(obj)->isa_oopptr();
   if (!will_link || (tp && tp->klass() && !tp->klass()->is_loaded())) {
+    assert(!never_null, "Null-free value type should be loaded");
     if (C->log() != NULL) {
       if (!will_link) {
         C->log()->elem("assert_null reason='checkcast' klass='%d'",
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java	Tue May 14 21:06:00 2019 -0700
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java	Wed May 15 14:23:01 2019 +0200
@@ -802,4 +802,24 @@
         long result = test30();
         Asserts.assertEquals(result, 0L);
     }
+
+    // Test casting null to unloaded value type
+    final inline class Test31Value {
+        private final int i = 0;
+    }
+
+    @Test
+    public void test31(Object o) {
+        try {
+            o = (Test31Value)o;
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    @DontCompile
+    public void test31_verifier(boolean warmup) {
+        test31(null);
+    }
 }