changeset 55677:987508afad96 lworld

8220788: [lworld] C1 support for LW2 Arrays Reviewed-by: thartmann
author iklam
date Sun, 26 May 2019 17:25:43 -0700
parents 09703273eccf
children abe6635f08d1
files src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp src/hotspot/cpu/x86/c1_Runtime1_x86.cpp src/hotspot/share/c1/c1_GraphBuilder.cpp src/hotspot/share/c1/c1_Instruction.cpp src/hotspot/share/c1/c1_Instruction.hpp src/hotspot/share/c1/c1_LIR.cpp src/hotspot/share/c1/c1_LIR.hpp src/hotspot/share/c1/c1_LIRAssembler.hpp src/hotspot/share/c1/c1_LIRGenerator.cpp src/hotspot/share/c1/c1_LIRGenerator.hpp src/hotspot/share/c1/c1_Runtime1.cpp src/hotspot/share/c1/c1_Runtime1.hpp test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeArray.java test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java
diffstat 17 files changed, 292 insertions(+), 197 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Sun May 26 17:25:43 2019 -0700
@@ -1383,6 +1383,7 @@
   } else if (type == T_ADDRESS && addr->disp() == oopDesc::klass_offset_in_bytes()) {
 #ifdef _LP64
     if (UseCompressedClassPointers) {
+      __ andl(dest->as_register(), oopDesc::compressed_klass_mask());
       __ decode_klass_not_null(dest->as_register());
     }
 #endif
@@ -1930,25 +1931,33 @@
 
 }
 
-void LIR_Assembler::emit_opFlattenedStoreCheck(LIR_OpFlattenedStoreCheck* op) {
-  Klass* k = (Klass*)(op->element_klass()->constant_encoding());
-  assert(k->is_klass(), "must be a loaded klass");
-  add_debug_info_for_null_check_here(op->info_for_exception());
-
-#ifdef _LP64
-  if (UseCompressedClassPointers) {
-    __ movl(op->tmp1()->as_register(), Address(op->object()->as_register(), oopDesc::klass_offset_in_bytes()));
-    __ cmp_narrow_klass(op->tmp1()->as_register(), k);
-  } else {
-    __ movq(op->tmp1()->as_register(), Address(op->object()->as_register(), oopDesc::klass_offset_in_bytes()));
-    __ cmpq(op->tmp1()->as_register(), op->tmp2()->as_register());
+void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) {
+  // We are loading/storing an array that *may* be a flattened array (the declared type
+  // Object[], interface[], or VT?[]). If this array is flattened, take slow path.
+
+  __ load_storage_props(op->tmp()->as_register(), op->array()->as_register());
+  __ testb(op->tmp()->as_register(), ArrayStorageProperties::flattened_value);
+  __ jcc(Assembler::notZero, *op->stub()->entry());
+  if (!op->value()->is_illegal()) {
+    // We are storing into the array.
+    Label skip;
+    __ testb(op->tmp()->as_register(), ArrayStorageProperties::null_free_value);
+    __ jcc(Assembler::zero, skip);
+    // The array is not flattened, but it is null_free. If we are storing
+    // a null, take the slow path (which will throw NPE).
+    __ cmpptr(op->value()->as_register(), (int32_t)NULL_WORD);
+    __ jcc(Assembler::zero, *op->stub()->entry());
+    __ bind(skip);
   }
-#else
-  Unimplemented(); // FIXME
-#endif
-
-  __ jcc(Assembler::notEqual, *op->stub()->entry());
-  __ bind(*op->stub()->continuation());
+}
+
+void LIR_Assembler::emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op) {
+  // This is called when we use aastore into a an array declared as "[LVT;",
+  // where we know VT is not flattenable (due to ValueArrayElemMaxFlatOops, etc).
+  // However, we need to do a NULL check if the actual array is a "[QVT;".
+
+  __ load_storage_props(op->tmp()->as_register(), op->array()->as_register());
+  __ testb(op->tmp()->as_register(), ArrayStorageProperties::null_free_value);
 }
 
 void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
@@ -3070,18 +3079,16 @@
 }
 
 
-void LIR_Assembler::arraycopy_flat_check(Register obj, Register tmp, CodeStub* slow_path) {
-  Address klass_addr = Address(obj, oopDesc::klass_offset_in_bytes());
-  if (UseCompressedClassPointers) {
-    __ movl(tmp, klass_addr);
-    LP64_ONLY(__ decode_klass_not_null(tmp));
+void LIR_Assembler::arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest) {
+  __ load_storage_props(tmp, obj);
+  if (is_dest) {
+    // We also take slow path if it's a null_free destination array, just in case the source array
+    // contains NULLs.
+    __ testb(tmp, ArrayStorageProperties::flattened_value | ArrayStorageProperties::null_free_value);
   } else {
-    __ movptr(tmp, klass_addr);
+    __ testb(tmp, ArrayStorageProperties::flattened_value);
   }
-  __ movl(tmp, Address(tmp, Klass::layout_helper_offset()));
-  __ sarl(tmp, Klass::_lh_array_tag_shift);
-  __ cmpl(tmp, Klass::_lh_array_tag_vt_value);
-  __ jcc(Assembler::equal, *slow_path->entry());
+  __ jcc(Assembler::notEqual, *slow_path->entry());
 }
 
 
@@ -3103,7 +3110,7 @@
   CodeStub* stub = op->stub();
   int flags = op->flags();
   BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
-  if (basic_type == T_ARRAY) basic_type = T_OBJECT;
+  if (basic_type == T_ARRAY || basic_type == T_VALUETYPE) basic_type = T_OBJECT;
 
   if (flags & LIR_OpArrayCopy::always_slow_path) {
     __ jmp(*stub->entry());
@@ -3111,22 +3118,12 @@
     return;
   }
 
-  if (flags & LIR_OpArrayCopy::src_flat_check) {
-    arraycopy_flat_check(src, tmp, stub);
+  if (flags & LIR_OpArrayCopy::src_valuetype_check) {
+    arraycopy_valuetype_check(src, tmp, stub, false);
   }
 
-  if (flags & LIR_OpArrayCopy::dst_flat_check) {
-    arraycopy_flat_check(dst, tmp, stub);
-  }
-
-  if (basic_type == T_VALUETYPE) {
-    assert(flags & (LIR_OpArrayCopy::always_slow_path |
-                    LIR_OpArrayCopy::src_flat_check |
-                    LIR_OpArrayCopy::dst_flat_check), "must have checked");
-    // If either src or dst is (or maybe) a flattened array, one of the 3 checks
-    // above would have caught it, and taken the slow path. So when we come here,
-    // the array must be a (non-flat) object array.
-    basic_type = T_OBJECT;
+  if (flags & LIR_OpArrayCopy::dst_valuetype_check) {
+    arraycopy_valuetype_check(dst, tmp, stub, true);
   }
 
   // if we don't know anything, just go through the generic arraycopy
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp	Sun May 26 17:25:43 2019 -0700
@@ -55,7 +55,7 @@
     _deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
   };
 
-  void arraycopy_flat_check(Register obj, Register tmp, CodeStub* slow_path);
+void arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest);
 
 public:
 
--- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Sun May 26 17:25:43 2019 -0700
@@ -271,20 +271,6 @@
   __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci);
 }
 
-void LIRGenerator::flattened_array_store_check(LIR_Opr value, ciKlass* element_klass, CodeEmitInfo* store_check_info) {
-  LIR_Opr tmp1 = new_register(T_METADATA);
-  LIR_Opr tmp2 = LIR_OprFact::illegalOpr;
-
-#ifdef _LP64
-  if (!UseCompressedClassPointers) {
-    tmp2 = new_register(T_METADATA);
-    __ metadata2reg(element_klass->constant_encoding(), tmp2);
-  }
-#endif
-
-  __ flattened_store_check(value, element_klass, tmp1, tmp2, store_check_info);
-}
-
 //----------------------------------------------------------------------
 //             visitor functions
 //----------------------------------------------------------------------
--- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp	Sun May 26 17:25:43 2019 -0700
@@ -1131,16 +1131,17 @@
             __ stop("assert(is a type array klass)");
             break;
           case new_object_array_id:
-          case new_value_array_id: // <-- needs to be renamed to new_non_null_array_id!
-            // FIXME:
-            // The VM currently does not distinguish between anewarray of
-            // "[QV;" (elements are non-nullable) vs "[LV;" (elements may be null).
-            // Instead, both are treated essentially as "[QV;". This code needs
-            // to be reimplemented after proper support of "[LV;" is implemented in the VM.
-            //
-            __ cmpl(t0, Klass::_lh_array_tag_obj_value);
+            __ cmpl(t0, Klass::_lh_array_tag_obj_value); // new "[Ljava/lang/Object;"
             __ jcc(Assembler::equal, ok);
-            __ cmpl(t0, Klass::_lh_array_tag_vt_value);
+            __ cmpl(t0, Klass::_lh_array_tag_vt_value);  // new "[LVT;"
+            __ jcc(Assembler::equal, ok);
+            __ stop("assert(is an object or value array klass)");
+            break;
+          case new_value_array_id:
+            // new "[QVT;"
+            __ cmpl(t0, Klass::_lh_array_tag_vt_value);  // the array can be flattened.
+            __ jcc(Assembler::equal, ok);
+            __ cmpl(t0, Klass::_lh_array_tag_obj_value); // the array cannot be flattened (due to ValueArrayElemMaxFlatSize, etc)
             __ jcc(Assembler::equal, ok);
             __ stop("assert(is an object or value array klass)");
             break;
@@ -1197,10 +1198,11 @@
         int call_offset;
         if (id == new_type_array_id) {
           call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
+        } else if (id == new_object_array_id) {
+          call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
         } else {
-          // Runtime1::new_object_array handles both object and value arrays.
-          // See comments in the ASSERT block above.
-          call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
+          assert(id == new_value_array_id, "must be");
+          call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_value_array), klass, length);
         }
 
         oop_maps = new OopMapSet();
--- a/src/hotspot/share/c1/c1_GraphBuilder.cpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp	Sun May 26 17:25:43 2019 -0700
@@ -2321,11 +2321,9 @@
 void GraphBuilder::new_object_array() {
   bool will_link;
   ciKlass* klass = stream()->get_klass(will_link);
+  bool never_null = stream()->is_klass_never_null();
   ValueStack* state_before = !klass->is_loaded() || PatchALot ? copy_state_before() : copy_state_exhandling();
-  NewArray* n = new NewObjectArray(klass, ipop(), state_before);
-  if (stream()->is_klass_never_null()) {
-    n->set_never_null(true);
-  }
+  NewArray* n = new NewObjectArray(klass, ipop(), state_before, never_null);
   apush(append_split(n));
 }
 
--- a/src/hotspot/share/c1/c1_Instruction.cpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_Instruction.cpp	Sun May 26 17:25:43 2019 -0700
@@ -146,11 +146,9 @@
   if (ValueArrayFlatten) {
     ciType* type = declared_type();
     if (type != NULL && type->is_value_array_klass()) {
-      ciValueKlass* element_klass = type->as_value_array_klass()->element_klass()->as_value_klass();
-      assert(element_klass->is_loaded(), "ciValueKlasses are always loaded");
-      if (element_klass->flatten_array()) {
-        return true;
-      }
+      ciValueArrayKlass* vak = type->as_value_array_klass();
+      ArrayStorageProperties props = vak->storage_properties();
+      return (!props.is_empty() && props.is_null_free() && props.is_flattened());
     }
   }
 
@@ -161,18 +159,13 @@
   if (ValueArrayFlatten) {
     ciType* type = declared_type();
     if (type != NULL) {
-      if (type->is_value_array_klass()) {
-        ciValueKlass* element_klass = type->as_value_array_klass()->element_klass()->as_value_klass();
-        assert(element_klass->is_loaded(), "ciValueKlasses are always loaded");
-        if (element_klass->flatten_array()) {
-          return true;
-        }
-      } else if (type->is_obj_array_klass()) {
+      if (type->is_obj_array_klass()) {
+        // Check for array covariance. One of the following declared types may be a flattened array:
         ciKlass* element_klass = type->as_obj_array_klass()->element_klass();
-        if (!element_klass->is_loaded() || element_klass->is_java_lang_Object() || element_klass->is_interface()) {
-          // Array covariance:
-          //    (ValueType[] <: Object[])
-          //    (ValueType[] <: <any interface>[])
+        if (!element_klass->is_loaded() ||
+            element_klass->is_java_lang_Object() ||                                                // (ValueType[] <: Object[])
+            element_klass->is_interface() ||                                                       // (ValueType[] <: <any interface>[])
+            (element_klass->is_valuetype() && element_klass->as_value_klass()->flatten_array())) { // (ValueType[] <: ValueType?[])
           // We will add a runtime check for flat-ness.
           return true;
         }
@@ -180,8 +173,8 @@
         // This can happen as a parameter to System.arraycopy()
         return true;
       }
-    } else if (as_Phi() != NULL) {
-      // Type info gets lost during Phi merging, but we might be storing into a
+    } else {
+      // Type info gets lost during Phi merging (Phi, IfOp, etc), but we might be storing into a
       // flattened array, so we should do a runtime check.
       return true;
     }
@@ -190,6 +183,29 @@
   return false;
 }
 
+bool Instruction::maybe_null_free_array() {
+  ciType* type = declared_type();
+  if (type != NULL) {
+    if (type->is_obj_array_klass()) {
+      // Check for array covariance. One of the following declared types may be a null-free array:
+      ciKlass* element_klass = type->as_obj_array_klass()->element_klass();
+      if (!element_klass->is_loaded() ||
+          element_klass->is_java_lang_Object() ||   // (ValueType[] <: Object[])
+          element_klass->is_interface() ||          // (ValueType[] <: <any interface>[])
+          element_klass->is_valuetype()) {          // (ValueType[] <: ValueType?[])
+          // We will add a runtime check for flat-ness.
+          return true;
+      }
+    }
+  } else {
+    // Type info gets lost during Phi merging (Phi, IfOp, etc), but we might be storing into a
+    // flattened array, so we should do a runtime check.
+    return true;
+  }
+
+  return false;
+}
+
 #ifndef PRODUCT
 void Instruction::check_state(ValueStack* state) {
   if (state != NULL) {
@@ -278,6 +294,10 @@
   if (array()->is_loaded_flattened_array() && value()->as_Constant() == NULL) {
     ciKlass* element_klass = array()->declared_type()->as_value_array_klass()->element_klass();
     ciKlass* actual_klass = value()->declared_type()->as_klass();
+
+    // The following check can fail with inlining:
+    //     void test45_inline(Object[] oa, Object o, int index) { oa[index] = o; }
+    //     void test45(MyValue1[] va, int index, MyValue2 v) { test45_inline(va, v, index); }
     if (element_klass == actual_klass) {
       return true;
     }
@@ -296,7 +316,7 @@
 
 ciType* NewObjectArray::exact_type() const {
   ciKlass* element_klass = klass();
-  if (element_klass->is_valuetype()) {
+  if (is_never_null() && element_klass->is_valuetype()) {
     return ciValueArrayKlass::make(element_klass);
   } else {
     return ciObjArrayKlass::make(element_klass);
--- a/src/hotspot/share/c1/c1_Instruction.hpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_Instruction.hpp	Sun May 26 17:25:43 2019 -0700
@@ -513,6 +513,7 @@
 
   bool is_loaded_flattened_array() const;
   bool maybe_flattened_array();
+  bool maybe_null_free_array();
 
   Instruction *insert_after_same_bci(Instruction *i) {
 #ifndef PRODUCT
@@ -1436,7 +1437,10 @@
 
  public:
   // creation
-  NewObjectArray(ciKlass* klass, Value length, ValueStack* state_before) : NewArray(length, state_before), _klass(klass) {}
+  NewObjectArray(ciKlass* klass, Value length, ValueStack* state_before, bool never_null)
+  : NewArray(length, state_before), _klass(klass) {
+    set_never_null(never_null);
+  }
 
   // accessors
   ciKlass* klass() const                         { return _klass; }
--- a/src/hotspot/share/c1/c1_LIR.cpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIR.cpp	Sun May 26 17:25:43 2019 -0700
@@ -367,18 +367,19 @@
   }
 }
 
-LIR_OpFlattenedStoreCheck::LIR_OpFlattenedStoreCheck(LIR_Opr object, ciKlass* element_klass,
-                                                     LIR_Opr tmp1, LIR_Opr tmp2,
-                                                     CodeEmitInfo* info_for_exception)
-  : LIR_Op(lir_flattened_store_check, LIR_OprFact::illegalOpr, NULL)
-  , _object(object)
-  , _element_klass(element_klass)
-  , _tmp1(tmp1)
-  , _tmp2(tmp2)
-  , _info_for_exception(info_for_exception)
-{
-  _stub = new ArrayStoreExceptionStub(object, info_for_exception);
-}
+LIR_OpFlattenedArrayCheck::LIR_OpFlattenedArrayCheck(LIR_Opr array, LIR_Opr value, LIR_Opr tmp, CodeStub* stub)
+  : LIR_Op(lir_flattened_array_check, LIR_OprFact::illegalOpr, NULL)
+  , _array(array)
+  , _value(value)
+  , _tmp(tmp)
+  , _stub(stub) {}
+
+
+LIR_OpNullFreeArrayCheck::LIR_OpNullFreeArrayCheck(LIR_Opr array, LIR_Opr tmp)
+  : LIR_Op(lir_null_free_array_check, LIR_OprFact::illegalOpr, NULL)
+  , _array(array)
+  , _tmp(tmp) {}
+
 
 LIR_OpArrayCopy::LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_Opr dst_pos, LIR_Opr length,
                                  LIR_Opr tmp, ciArrayKlass* expected_type, int flags, CodeEmitInfo* info)
@@ -870,16 +871,26 @@
       break;
     }
 
-// LIR_OpFlattenedStoreCheck
-    case lir_flattened_store_check: {
-      assert(op->as_OpFlattenedStoreCheck() != NULL, "must be");
-      LIR_OpFlattenedStoreCheck* opFlattenedStoreCheck = (LIR_OpFlattenedStoreCheck*)op;
+// LIR_OpFlattenedArrayCheck
+    case lir_flattened_array_check: {
+      assert(op->as_OpFlattenedArrayCheck() != NULL, "must be");
+      LIR_OpFlattenedArrayCheck* opFlattenedArrayCheck = (LIR_OpFlattenedArrayCheck*)op;
 
-      if (opFlattenedStoreCheck->_info_for_exception)   do_info(opFlattenedStoreCheck->_info_for_exception);
-      if (opFlattenedStoreCheck->_object->is_valid())   do_temp(opFlattenedStoreCheck->_object);
-      if (opFlattenedStoreCheck->_tmp1->is_valid())     do_temp(opFlattenedStoreCheck->_tmp1);
-      if (opFlattenedStoreCheck->_tmp2->is_valid())     do_temp(opFlattenedStoreCheck->_tmp2);
-                                                        do_stub(opFlattenedStoreCheck->_stub);
+      if (opFlattenedArrayCheck->_array->is_valid()) do_input(opFlattenedArrayCheck->_array);
+      if (opFlattenedArrayCheck->_value->is_valid()) do_input(opFlattenedArrayCheck->_value);
+      if (opFlattenedArrayCheck->_tmp->is_valid())   do_temp(opFlattenedArrayCheck->_tmp);
+                                                     do_stub(opFlattenedArrayCheck->_stub);
+
+      break;
+    }
+
+// LIR_OpNullFreeArrayCheck
+    case lir_null_free_array_check: {
+      assert(op->as_OpNullFreeArrayCheck() != NULL, "must be");
+      LIR_OpNullFreeArrayCheck* opNullFreeArrayCheck = (LIR_OpNullFreeArrayCheck*)op;
+
+      if (opNullFreeArrayCheck->_array->is_valid()) do_input(opNullFreeArrayCheck->_array);
+      if (opNullFreeArrayCheck->_tmp->is_valid())   do_temp(opNullFreeArrayCheck->_tmp);
       break;
     }
 
@@ -1070,13 +1081,17 @@
   }
 }
 
-void LIR_OpFlattenedStoreCheck::emit_code(LIR_Assembler* masm) {
-  masm->emit_opFlattenedStoreCheck(this);
-  if (stub()) {
+void LIR_OpFlattenedArrayCheck::emit_code(LIR_Assembler* masm) {
+  masm->emit_opFlattenedArrayCheck(this);
+  if (stub() != NULL) {
     masm->append_code_stub(stub());
   }
 }
 
+void LIR_OpNullFreeArrayCheck::emit_code(LIR_Assembler* masm) {
+  masm->emit_opNullFreeArrayCheck(this);
+}
+
 void LIR_OpCompareAndSwap::emit_code(LIR_Assembler* masm) {
   masm->emit_compare_and_swap(this);
 }
@@ -1456,6 +1471,7 @@
 
 void LIR_List::store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3,
                            CodeEmitInfo* info_for_exception, ciMethod* profiled_method, int profiled_bci) {
+  // FIXME -- if the types of the array and/or the object are known statically, we can avoid loading the klass
   LIR_OpTypeCheck* c = new LIR_OpTypeCheck(lir_store_check, object, array, tmp1, tmp2, tmp3, info_for_exception);
   if (profiled_method != NULL) {
     c->set_profiled_method(profiled_method);
@@ -1477,10 +1493,13 @@
   }
 }
 
-void LIR_List::flattened_store_check(LIR_Opr object, ciKlass* element_klass,
-                                     LIR_Opr tmp1, LIR_Opr tmp2,
-                                     CodeEmitInfo* info_for_exception) {
-  LIR_OpFlattenedStoreCheck* c = new LIR_OpFlattenedStoreCheck(object, element_klass, tmp1, tmp2, info_for_exception);
+void LIR_List::check_flattened_array(LIR_Opr array, LIR_Opr value, LIR_Opr tmp, CodeStub* stub) {
+  LIR_OpFlattenedArrayCheck* c = new LIR_OpFlattenedArrayCheck(array, value, tmp, stub);
+  append(c);
+}
+
+void LIR_List::check_null_free_array(LIR_Opr array, LIR_Opr tmp) {
+  LIR_OpNullFreeArrayCheck* c = new LIR_OpNullFreeArrayCheck(array, tmp);
   append(c);
 }
 
@@ -1776,8 +1795,10 @@
      case lir_instanceof:            s = "instanceof";    break;
      case lir_checkcast:             s = "checkcast";     break;
      case lir_store_check:           s = "store_check";   break;
-     // LIR_OpFlattenedStoreCheck
-     case lir_flattened_store_check: s = "flattened_store_check"; break;
+     // LIR_OpFlattenedArrayCheck
+     case lir_flattened_array_check: s = "flattened_array_check"; break;
+     // LIR_OpNullFreeArrayCheck
+     case lir_null_free_array_check: s = "null_free_array_check"; break;
      // LIR_OpCompareAndSwap
      case lir_cas_long:              s = "cas_long";      break;
      case lir_cas_obj:               s = "cas_obj";      break;
@@ -2023,14 +2044,19 @@
   if (info_for_exception() != NULL) out->print(" [bci:%d]", info_for_exception()->stack()->bci());
 }
 
-void LIR_OpFlattenedStoreCheck::print_instr(outputStream* out) const {
-  object()->print(out);                  out->print(" ");
-  element_klass()->print_name_on(out);   out->print(" ");
-  tmp1()->print(out);                    out->print(" ");
-  tmp2()->print(out);                    out->print(" ");
-  if (info_for_exception() != NULL) out->print(" [bci:%d]", info_for_exception()->stack()->bci());
+void LIR_OpFlattenedArrayCheck::print_instr(outputStream* out) const {
+  array()->print(out);                   out->print(" ");
+  value()->print(out);                   out->print(" ");
+  tmp()->print(out);                     out->print(" ");
+  if (stub() != NULL) {
+    out->print("[label:" INTPTR_FORMAT "]", p2i(stub()->entry()));
+  }
 }
 
+void LIR_OpNullFreeArrayCheck::print_instr(outputStream* out) const {
+  array()->print(out);                   out->print(" ");
+  tmp()->print(out);                     out->print(" ");
+}
 
 // LIR_Op3
 void LIR_Op3::print_instr(outputStream* out) const {
--- a/src/hotspot/share/c1/c1_LIR.hpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIR.hpp	Sun May 26 17:25:43 2019 -0700
@@ -873,7 +873,8 @@
 class    LIR_OpUpdateCRC32;
 class    LIR_OpLock;
 class    LIR_OpTypeCheck;
-class    LIR_OpFlattenedStoreCheck;
+class    LIR_OpFlattenedArrayCheck;
+class    LIR_OpNullFreeArrayCheck;
 class    LIR_OpCompareAndSwap;
 class    LIR_OpProfileCall;
 class    LIR_OpProfileType;
@@ -988,9 +989,12 @@
     , lir_checkcast
     , lir_store_check
   , end_opTypeCheck
-  , begin_opFlattenedStoreCheck
-    , lir_flattened_store_check
-  , end_opFlattenedStoreCheck
+  , begin_opFlattenedArrayCheck
+    , lir_flattened_array_check
+  , end_opFlattenedArrayCheck
+  , begin_opNullFreeArrayCheck
+    , lir_null_free_array_check
+  , end_opNullFreeArrayCheck
   , begin_opCompareAndSwap
     , lir_cas_long
     , lir_cas_obj
@@ -1141,7 +1145,8 @@
   virtual LIR_OpArrayCopy* as_OpArrayCopy() { return NULL; }
   virtual LIR_OpUpdateCRC32* as_OpUpdateCRC32() { return NULL; }
   virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; }
-  virtual LIR_OpFlattenedStoreCheck* as_OpFlattenedStoreCheck() { return NULL; }
+  virtual LIR_OpFlattenedArrayCheck* as_OpFlattenedArrayCheck() { return NULL; }
+  virtual LIR_OpNullFreeArrayCheck* as_OpNullFreeArrayCheck() { return NULL; }
   virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; }
   virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; }
   virtual LIR_OpProfileType* as_OpProfileType() { return NULL; }
@@ -1274,8 +1279,8 @@
     src_objarray           = 1 << 10,
     dst_objarray           = 1 << 11,
     always_slow_path       = 1 << 12,
-    src_flat_check         = 1 << 13,
-    dst_flat_check         = 1 << 14,
+    src_valuetype_check    = 1 << 13,
+    dst_valuetype_check    = 1 << 14,
     all_flags              = (1 << 15) - 1
   };
 
@@ -1603,31 +1608,41 @@
   void print_instr(outputStream* out) const PRODUCT_RETURN;
 };
 
-// LIR_OpFlattenedStoreCheck
-class LIR_OpFlattenedStoreCheck: public LIR_Op {
+// LIR_OpFlattenedArrayCheck
+class LIR_OpFlattenedArrayCheck: public LIR_Op {
  friend class LIR_OpVisitState;
 
  private:
-  LIR_Opr       _object;
-  ciKlass*      _element_klass;
-  LIR_Opr       _tmp1;
-  LIR_Opr       _tmp2;
-  CodeEmitInfo* _info_for_exception;
+  LIR_Opr       _array;
+  LIR_Opr       _value;
+  LIR_Opr       _tmp;
   CodeStub*     _stub;
-
 public:
-  LIR_OpFlattenedStoreCheck(LIR_Opr object, ciKlass* element_klass, LIR_Opr tmp1, LIR_Opr tmp2,
-                            CodeEmitInfo* info_for_exception);
-
-  LIR_Opr object() const                         { return _object;         }
-  LIR_Opr tmp1() const                           { return _tmp1;           }
-  LIR_Opr tmp2() const                           { return _tmp2;           }
-  ciKlass* element_klass() const                 { return _element_klass;  }
-  CodeEmitInfo* info_for_exception() const       { return _info_for_exception; }
-  CodeStub* stub() const                         { return _stub;           }
+  LIR_OpFlattenedArrayCheck(LIR_Opr array, LIR_Opr value, LIR_Opr tmp, CodeStub* stub);
+  LIR_Opr array() const                          { return _array;         }
+  LIR_Opr value() const                          { return _value;         }
+  LIR_Opr tmp() const                            { return _tmp;           }
+  CodeStub* stub() const                         { return _stub;          }
 
   virtual void emit_code(LIR_Assembler* masm);
-  virtual LIR_OpFlattenedStoreCheck* as_OpFlattenedStoreCheck() { return this; }
+  virtual LIR_OpFlattenedArrayCheck* as_OpFlattenedArrayCheck() { return this; }
+  virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
+};
+
+// LIR_OpNullFreeArrayCheck
+class LIR_OpNullFreeArrayCheck: public LIR_Op {
+ friend class LIR_OpVisitState;
+
+ private:
+  LIR_Opr       _array;
+  LIR_Opr       _tmp;
+public:
+  LIR_OpNullFreeArrayCheck(LIR_Opr array, LIR_Opr tmp);
+  LIR_Opr array() const                          { return _array;         }
+  LIR_Opr tmp() const                            { return _tmp;           }
+
+  virtual void emit_code(LIR_Assembler* masm);
+  virtual LIR_OpNullFreeArrayCheck* as_OpNullFreeArrayCheck() { return this; }
   virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
 };
 
@@ -2288,7 +2303,8 @@
 
   void instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch, ciMethod* profiled_method, int profiled_bci);
   void store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception, ciMethod* profiled_method, int profiled_bci);
-  void flattened_store_check(LIR_Opr object, ciKlass* element_klass, LIR_Opr tmp1, LIR_Opr tmp2, CodeEmitInfo* info_for_exception);
+  void check_flattened_array(LIR_Opr array, LIR_Opr value, LIR_Opr tmp, CodeStub* stub);
+  void check_null_free_array(LIR_Opr array, LIR_Opr tmp);
 
   void checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass,
                   LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check,
--- a/src/hotspot/share/c1/c1_LIRAssembler.hpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp	Sun May 26 17:25:43 2019 -0700
@@ -204,7 +204,8 @@
   void emit_alloc_obj(LIR_OpAllocObj* op);
   void emit_alloc_array(LIR_OpAllocArray* op);
   void emit_opTypeCheck(LIR_OpTypeCheck* op);
-  void emit_opFlattenedStoreCheck(LIR_OpFlattenedStoreCheck* op);
+  void emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op);
+  void emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op);
   void emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null);
   void emit_compare_and_swap(LIR_OpCompareAndSwap* op);
   void emit_lock(LIR_OpLock* op);
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp	Sun May 26 17:25:43 2019 -0700
@@ -791,10 +791,10 @@
     flags &= ~LIR_OpArrayCopy::always_slow_path;
   }
   if (!src->maybe_flattened_array()) {
-    flags &= ~LIR_OpArrayCopy::src_flat_check;
+    flags &= ~LIR_OpArrayCopy::src_valuetype_check;
   }
-  if (!dst->maybe_flattened_array()) {
-    flags &= ~LIR_OpArrayCopy::dst_flat_check;
+  if (!dst->maybe_flattened_array() && !dst->maybe_null_free_array()) {
+    flags &= ~LIR_OpArrayCopy::dst_valuetype_check;
   }
 
   if (!src_objarray)
@@ -1646,25 +1646,28 @@
                       obj_item, LIR_OprFact::intConst(obj_offset), temp,
                       NULL, NULL);
     } else {
-    access_load_at(decorators, field_type,
-                   obj_item, LIR_OprFact::intConst(obj_offset), temp,
-                   NULL, NULL);
-    access_store_at(decorators, field_type,
-                    elm_item, LIR_OprFact::intConst(elm_offset), temp,
-                    NULL, NULL);
+      access_load_at(decorators, field_type,
+                     obj_item, LIR_OprFact::intConst(obj_offset), temp,
+                     NULL, NULL);
+      access_store_at(decorators, field_type,
+                      elm_item, LIR_OprFact::intConst(elm_offset), temp,
+                      NULL, NULL);
     }
   }
 }
 
-void LIRGenerator::check_flattened_array(LIRItem& array, CodeStub* slow_path) {
-  LIR_Opr array_klass_reg = new_register(T_METADATA);
-
-  __ move(new LIR_Address(array.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), array_klass_reg);
-  LIR_Opr layout = new_register(T_INT);
-  __ move(new LIR_Address(array_klass_reg, in_bytes(Klass::layout_helper_offset()), T_INT), layout);
-  __ shift_right(layout, Klass::_lh_array_tag_shift, layout);
-  __ cmp(lir_cond_equal, layout, LIR_OprFact::intConst(Klass::_lh_array_tag_vt_value));
-  __ branch(lir_cond_equal, T_ILLEGAL, slow_path);
+void LIRGenerator::check_flattened_array(LIR_Opr array, LIR_Opr value, CodeStub* slow_path) {
+  LIR_Opr tmp = new_register(T_METADATA);
+  __ check_flattened_array(array, value, tmp, slow_path);
+}
+
+void LIRGenerator::check_null_free_array(LIRItem& array, LIRItem& value, CodeEmitInfo* info) {
+  LabelObj* L_end = new LabelObj();
+  LIR_Opr tmp = new_register(T_METADATA);
+  __ check_null_free_array(array.result(), tmp);
+  __ branch(lir_cond_equal, T_ILLEGAL, L_end->label());
+  __ null_check(value.result(), info);
+  __ branch_destination(L_end->label());
 }
 
 bool LIRGenerator::needs_flattened_array_store_check(StoreIndexed* x) {
@@ -1687,6 +1690,10 @@
   return false;
 }
 
+bool LIRGenerator::needs_null_free_array_store_check(StoreIndexed* x) {
+  return x->elt_type() == T_OBJECT && x->array()->maybe_null_free_array();
+}
+
 void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
   assert(x->is_pinned(),"");
   assert(x->elt_type() != T_ARRAY, "never used");
@@ -1694,7 +1701,7 @@
   bool needs_range_check = x->compute_needs_range_check();
   bool use_length = x->length() != NULL;
   bool obj_store = x->elt_type() == T_OBJECT;
-  bool needs_store_check = obj_store && !is_loaded_flattened_array &&
+  bool needs_store_check = obj_store && !(is_loaded_flattened_array && x->is_exact_flattened_array_store()) &&
                                         (x->value()->as_Constant() == NULL ||
                                          !get_jobject_constant(x->value())->is_null_object() ||
                                          x->should_profile());
@@ -1713,7 +1720,7 @@
   }
 
   if (needs_store_check || x->check_boolean()
-      || is_loaded_flattened_array || needs_flattened_array_store_check(x)) {
+      || is_loaded_flattened_array || needs_flattened_array_store_check(x) || needs_null_free_array_store_check(x)) {
     value.load_item();
   } else {
     value.load_for_store(x->elt_type());
@@ -1747,11 +1754,7 @@
   }
 
   if (is_loaded_flattened_array) {
-    if (!x->is_exact_flattened_array_store()) {
-      CodeEmitInfo* info = new CodeEmitInfo(range_check_info);
-      ciKlass* element_klass = x->array()->declared_type()->as_value_array_klass()->element_klass();
-      flattened_array_store_check(value.result(), element_klass, info);
-    } else if (!x->value()->is_never_null()) {
+    if (!x->value()->is_never_null()) {
       __ null_check(value.result(), new CodeEmitInfo(range_check_info));
     }
     access_flattened_array(false, array, index, value);
@@ -1762,7 +1765,10 @@
       // Check if we indeed have a flattened array
       index.load_item();
       slow_path = new StoreFlattenedArrayStub(array.result(), index.result(), value.result(), state_for(x));
-      check_flattened_array(array, slow_path);
+      check_flattened_array(array.result(), value.result(), slow_path);
+    } else if (needs_null_free_array_store_check(x)) {
+      CodeEmitInfo* info = new CodeEmitInfo(range_check_info);
+      check_null_free_array(array, value, info);
     }
 
     DecoratorSet decorators = IN_HEAP | IS_ARRAY;
@@ -2142,7 +2148,7 @@
       index.load_item();
       // if we are loading from flattened array, load it using a runtime call
       slow_path = new LoadFlattenedArrayStub(array.result(), index.result(), result, state_for(x));
-      check_flattened_array(array, slow_path);
+      check_flattened_array(array.result(), LIR_OprFact::illegalOpr, slow_path);
     }
 
     DecoratorSet decorators = IN_HEAP | IS_ARRAY;
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp	Sun May 26 17:25:43 2019 -0700
@@ -269,7 +269,9 @@
   Value flattenable_load_field_prolog(LoadField* x, CodeEmitInfo* info);
   void access_flattened_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item);
   bool needs_flattened_array_store_check(StoreIndexed* x);
-  void check_flattened_array(LIRItem& array, CodeStub* slow_path);
+  void check_flattened_array(LIR_Opr array, LIR_Opr value, CodeStub* slow_path);
+  bool needs_null_free_array_store_check(StoreIndexed* x);
+  void check_null_free_array(LIRItem& array, LIRItem& value,  CodeEmitInfo* info);
   void substitutability_check(IfOp* x, LIRItem& left, LIRItem& right, LIRItem& t_val, LIRItem& f_val);
 
  public:
@@ -320,7 +322,6 @@
 
   // specific implementations
   void array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci);
-  void flattened_array_store_check(LIR_Opr value, ciKlass* element_klass, CodeEmitInfo* store_check_info);
 
   static LIR_Opr result_register_for(ValueType* type, bool callee = false);
 
--- a/src/hotspot/share/c1/c1_Runtime1.cpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp	Sun May 26 17:25:43 2019 -0700
@@ -119,6 +119,7 @@
 int Runtime1::_arraycopy_checkcast_attempt_cnt = 0;
 int Runtime1::_new_type_array_slowcase_cnt = 0;
 int Runtime1::_new_object_array_slowcase_cnt = 0;
+int Runtime1::_new_value_array_slowcase_cnt = 0;
 int Runtime1::_new_instance_slowcase_cnt = 0;
 int Runtime1::_new_multi_array_slowcase_cnt = 0;
 int Runtime1::_load_flattened_array_slowcase_cnt = 0;
@@ -393,13 +394,28 @@
   assert(array_klass->is_klass(), "not a class");
   Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive
   Klass* elem_klass = ArrayKlass::cast(array_klass)->element_klass();
-  if (elem_klass->is_value()) {
-    arrayOop obj = oopFactory::new_valueArray(elem_klass, length, CHECK);
-    thread->set_vm_result(obj);
-  } else {
-    objArrayOop obj = oopFactory::new_objArray(elem_klass, length, CHECK);
-    thread->set_vm_result(obj);
+  objArrayOop obj = oopFactory::new_objArray(elem_klass, length, CHECK);
+  thread->set_vm_result(obj);
+  // This is pretty rare but this runtime patch is stressful to deoptimization
+  // if we deoptimize here so force a deopt to stress the path.
+  if (DeoptimizeALot) {
+    deopt_caller();
   }
+JRT_END
+
+
+JRT_ENTRY(void, Runtime1::new_value_array(JavaThread* thread, Klass* array_klass, jint length))
+  NOT_PRODUCT(_new_value_array_slowcase_cnt++;)
+
+  // Note: no handle for klass needed since they are not used
+  //       anymore after new_objArray() and no GC can happen before.
+  //       (This may have to change if this code changes!)
+  assert(array_klass->is_klass(), "not a class");
+  Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive
+  Klass* elem_klass = ArrayKlass::cast(array_klass)->element_klass();
+  assert(elem_klass->is_value(), "must be");
+  arrayOop obj = oopFactory::new_valueArray(elem_klass, length, CHECK);
+  thread->set_vm_result(obj);
   // This is pretty rare but this runtime patch is stressful to deoptimization
   // if we deoptimize here so force a deopt to stress the path.
   if (DeoptimizeALot) {
@@ -1042,6 +1058,10 @@
       case Bytecodes::_multianewarray:
         { Bytecode_multianewarray mna(caller_method(), caller_method->bcp_from(bci));
           k = caller_method->constants()->klass_at(mna.index(), CHECK);
+          if (k->name()->is_Q_array_signature()) {
+            // Logically creates elements, ensure klass init
+            k->initialize(CHECK);
+          }
         }
         break;
       case Bytecodes::_instanceof:
@@ -1057,7 +1077,12 @@
       case Bytecodes::_anewarray:
         { Bytecode_anewarray anew(caller_method(), caller_method->bcp_from(bci));
           Klass* ek = caller_method->constants()->klass_at(anew.index(), CHECK);
-          k = ek->array_klass(CHECK);
+          if (ek->is_value() && caller_method->constants()->klass_at_noresolve(anew.index())->is_Q_signature()) {
+            k = ek->array_klass(ArrayStorageProperties::flattened_and_null_free, 1, CHECK);
+            assert(ArrayKlass::cast(k)->storage_properties().is_null_free(), "Expect a null-free array class here");
+          } else {
+            k = ek->array_klass(CHECK);
+          }
         }
         break;
       case Bytecodes::_ldc:
@@ -1563,6 +1588,7 @@
 
   tty->print_cr(" _new_type_array_slowcase_cnt:    %d", _new_type_array_slowcase_cnt);
   tty->print_cr(" _new_object_array_slowcase_cnt:  %d", _new_object_array_slowcase_cnt);
+  tty->print_cr(" _new_value_array_slowcase_cnt:   %d", _new_value_array_slowcase_cnt);
   tty->print_cr(" _new_instance_slowcase_cnt:      %d", _new_instance_slowcase_cnt);
   tty->print_cr(" _new_multi_array_slowcase_cnt:   %d", _new_multi_array_slowcase_cnt);
   tty->print_cr(" _load_flattened_array_slowcase_cnt: %d", _load_flattened_array_slowcase_cnt);
--- a/src/hotspot/share/c1/c1_Runtime1.hpp	Thu May 23 16:19:48 2019 +0200
+++ b/src/hotspot/share/c1/c1_Runtime1.hpp	Sun May 26 17:25:43 2019 -0700
@@ -110,6 +110,7 @@
   static int _arraycopy_checkcast_attempt_cnt;
   static int _new_type_array_slowcase_cnt;
   static int _new_object_array_slowcase_cnt;
+  static int _new_value_array_slowcase_cnt;
   static int _new_instance_slowcase_cnt;
   static int _new_multi_array_slowcase_cnt;
   static int _load_flattened_array_slowcase_cnt;
@@ -153,6 +154,7 @@
   static void new_instance    (JavaThread* thread, Klass* klass);
   static void new_type_array  (JavaThread* thread, Klass* klass, jint length);
   static void new_object_array(JavaThread* thread, Klass* klass, jint length);
+  static void new_value_array (JavaThread* thread, Klass* klass, jint length);
   static void new_multi_array (JavaThread* thread, Klass* klass, int rank, jint* dims);
   static void load_flattened_array(JavaThread* thread, valueArrayOopDesc* array, int index);
   static void store_flattened_array(JavaThread* thread, valueArrayOopDesc* array, int index, oopDesc* value);
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java	Thu May 23 16:19:48 2019 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java	Sun May 26 17:25:43 2019 -0700
@@ -1463,9 +1463,6 @@
             RefPoint rp1 = new RefPoint(1, 2);
             RefPoint rp2 = new RefPoint(22, 33);
             int result;
-            if (!warmup) {
-                System.out.println("Hello: " + i);
-            }
             try (ForceGCMarker m = ForceGCMarker.mark(warmup)) {
                 result = test77(rp1, rp2);
             }
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeArray.java	Thu May 23 16:19:48 2019 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeArray.java	Sun May 26 17:25:43 2019 -0700
@@ -390,6 +390,9 @@
         Asserts.assertEQ(m, 1234);
 
         MyValue7[][] arr = new MyValue7[2][2];
+        Object[] oa = arr[1];
+        Asserts.assertNE(oa[0], null);
+
         arr[0][1] = new MyValue7(5678);
         m = 9999;
         for (int i=0; i<n; i++) {
@@ -417,6 +420,9 @@
         Asserts.assertEQ(m, 1234);
 
         MyValue7Box?[][] arr = new MyValue7Box?[2][2];
+        Object[] oa = arr[1];
+        Asserts.assertEQ(oa[0], null);
+
         arr[0][1] = new MyValue7Box(5678);
         m = 9999;
         for (int i=0; i<n; i++) {
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java	Thu May 23 16:19:48 2019 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java	Sun May 26 17:25:43 2019 -0700
@@ -105,6 +105,7 @@
     // User defined settings
     protected static final boolean XCOMP = Platform.isComp();
     private static final boolean PRINT_GRAPH = true;
+    private static final boolean VERBOSE = Boolean.parseBoolean(System.getProperty("Verbose", "false"));
     private static final boolean PRINT_TIMES = Boolean.parseBoolean(System.getProperty("PrintTimes", "false"));
     private static       boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true")) && !TEST_C1 && !XCOMP;
     private static final boolean VERIFY_VM = Boolean.parseBoolean(System.getProperty("VerifyVM", "false"));
@@ -566,6 +567,9 @@
         // Execute tests
         TreeMap<Long, String> durations = PRINT_TIMES ? new TreeMap<Long, String>() : null;
         for (Method test : tests.values()) {
+            if (VERBOSE) {
+                System.out.println("Starting " + test.getName());
+            }
             long startTime = System.nanoTime();
             Method verifier = getClass().getMethod(test.getName() + "_verifier", boolean.class);
             // Warmup using verifier method
@@ -580,10 +584,13 @@
             Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
             // Check result
             verifier.invoke(this, false);
-            if (PRINT_TIMES) {
+            if (PRINT_TIMES || VERBOSE) {
                 long endTime = System.nanoTime();
                 long duration = (endTime - startTime);
                 durations.put(duration, test.getName());
+                if (VERBOSE) {
+                    System.out.println("Done " + test.getName() + ": " + duration + "ms");
+                }
             }
         }