changeset 52596:65b5a7bf0dbc lworld

8212190: [lworld] Support for nullable value types in C2 Reviewed-by: roland
author thartmann
date Wed, 24 Oct 2018 14:25:20 +0200
parents d03e3aa668e6
children 6132641c6ff6
files src/hotspot/cpu/x86/macroAssembler_x86.cpp src/hotspot/cpu/x86/macroAssembler_x86.hpp src/hotspot/cpu/x86/methodHandles_x86.cpp src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp src/hotspot/cpu/x86/templateTable_x86.cpp src/hotspot/cpu/x86/x86_64.ad src/hotspot/share/aot/aotCompiledMethod.hpp src/hotspot/share/asm/codeBuffer.hpp src/hotspot/share/ci/ciClassList.hpp src/hotspot/share/ci/ciMetadata.hpp src/hotspot/share/ci/ciSignature.cpp src/hotspot/share/ci/ciSignature.hpp src/hotspot/share/ci/ciStreams.hpp src/hotspot/share/ci/ciType.hpp src/hotspot/share/ci/ciTypeFlow.cpp src/hotspot/share/ci/ciTypeFlow.hpp src/hotspot/share/code/compiledMethod.hpp src/hotspot/share/code/nmethod.cpp src/hotspot/share/code/nmethod.hpp src/hotspot/share/interpreter/interpreterRuntime.cpp src/hotspot/share/interpreter/interpreterRuntime.hpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/method.cpp src/hotspot/share/oops/method.hpp src/hotspot/share/opto/callGenerator.cpp src/hotspot/share/opto/castnode.cpp src/hotspot/share/opto/castnode.hpp src/hotspot/share/opto/cfgnode.cpp src/hotspot/share/opto/compile.cpp src/hotspot/share/opto/doCall.cpp src/hotspot/share/opto/graphKit.cpp src/hotspot/share/opto/graphKit.hpp src/hotspot/share/opto/library_call.cpp src/hotspot/share/opto/machnode.hpp src/hotspot/share/opto/macro.cpp src/hotspot/share/opto/node.hpp src/hotspot/share/opto/output.cpp src/hotspot/share/opto/parse1.cpp src/hotspot/share/opto/parse2.cpp src/hotspot/share/opto/parse3.cpp src/hotspot/share/opto/parseHelper.cpp src/hotspot/share/opto/type.cpp src/hotspot/share/opto/type.hpp src/hotspot/share/opto/valuetypenode.cpp src/hotspot/share/opto/valuetypenode.hpp src/hotspot/share/runtime/globals.hpp test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBasicFunctionality.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld_mismatched.jasm test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java
diffstat 54 files changed, 1352 insertions(+), 1613 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -6678,46 +6678,6 @@
 
 }
 
-// Add null checks for all value type arguments
-void MacroAssembler::null_check_value_args(Method* method) {
-  // Get registers/stack slots for arguments
-  assert(method->has_value_args(), "must have value type args");
-  Symbol* sig_ext = method->adapter()->get_sig_extended();
-  assert(sig_ext != NULL, "must have extended signature");
-  BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, 256);
-  VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, 256);
-  int num = 0;
-  for (SignatureStream ss(sig_ext); !ss.at_return_type(); ss.next()) {
-    BasicType bt = ss.type();
-    sig_bt[num++] = bt;
-    if (type2size[bt] == 2) {
-      sig_bt[num++] = T_VOID;
-    }
-  }
-  SharedRuntime::java_calling_convention(sig_bt, regs, num, false);
-
-  // Jump to c2i adapter if a value type argument is null
-  bool has_receiver = !method->is_static();
-  RuntimeAddress interpreter_entry = RuntimeAddress(method->get_c2i_entry());
-  num = 0;
-  for (SignatureStream ss(sig_ext); !ss.at_return_type(); num += type2size[ss.type()], ss.next()) {
-    if ((has_receiver && num == 0) || ss.type() != T_VALUETYPEPTR) {
-      continue; // Skip receiver and non value type args
-    }
-    VMReg r = regs[num].first();
-    if (r->is_reg()) {
-      testptr(r->as_Register(), r->as_Register());
-    } else {
-      if (!r->is_stack()) {
-        r->print();
-      }
-      int st_off = r->reg2stack() * VMRegImpl::stack_slot_size + wordSize;
-      cmpptr(Address(rsp, st_off), NULL_WORD);
-    }
-    jump_cc(Assembler::zero, interpreter_entry);
-  }
-}
-
 // clear memory of size 'cnt' qwords, starting at 'base' using XMM/YMM registers
 void MacroAssembler::xmm_clear_mem(Register base, Register cnt, Register val, XMMRegister xtmp) {
   // cnt - number of qwords (8-byte words).
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -1600,9 +1600,6 @@
   // C2 compiled method's prolog code.
   void verified_entry(int framesize, int stack_bang_size, bool fp_mode_24b);
 
-  // Add null checks for all value type arguments
-  void null_check_value_args(Method* method);
-
   // clear memory of size 'cnt' qwords, starting at 'base';
   // if 'is_large' is set, do not try to produce short loop
   void clear_mem(Register base, Register cnt, Register val, XMMRegister xtmp, bool is_large, bool word_copy_only);
--- a/src/hotspot/cpu/x86/methodHandles_x86.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -147,7 +147,7 @@
     __ BIND(run_compiled_code);
   }
 
-  const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_value_offset() :
+  const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() :
                                                      Method::from_interpreted_offset();
   __ jmp(Address(method, entry_offset));
 
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -1089,7 +1089,7 @@
 
   // Will jump to the compiled code just as if compiled code was doing it.
   // Pre-load the register-jump target early, to schedule it better.
-  __ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_value_offset())));
+  __ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_offset())));
 
 #if INCLUDE_JVMCI
   if (EnableJVMCI || UseAOT) {
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -2767,20 +2767,6 @@
     __ bind(no_safepoint);
   }
 
-  if (EnableValhalla && state == atos) {
-    Label not_returning_null_vt;
-    const Register method = rbx, tmp = rdx;
-
-    __ testl(rax, rax);
-    __ jcc(Assembler::notZero, not_returning_null_vt);
-    __ get_method(method);
-    __ load_unsigned_short(tmp, Address(rbx, Method::flags_offset()));
-    __ testl(tmp, Method::is_returning_vt_mask());
-    __ jcc(Assembler::zero, not_returning_null_vt);
-    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::deoptimize_caller_frame_for_vt), method);
-    __ bind(not_returning_null_vt);
-  }
-
   // Narrow result if state is itos but result type is smaller.
   // Need to narrow in the return bytecode rather than in generate_return_entry
   // since compiled code callers expect the result to already be narrowed.
--- a/src/hotspot/cpu/x86/x86_64.ad	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/cpu/x86/x86_64.ad	Wed Oct 24 14:25:20 2018 +0200
@@ -901,7 +901,6 @@
   int framesize = C->frame_size_in_bytes();
   int bangsize = C->bang_size_in_bytes();
 
-  __ bind(*_verified_entry);
   __ verified_entry(framesize, C->need_stack_bang(bangsize)?bangsize:0, false);
 
   C->set_frame_complete(cbuf.insts_size());
@@ -1571,28 +1570,6 @@
 
 //=============================================================================
 #ifndef PRODUCT
-void MachVVEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
-{
-  st->print_cr("MachVVEPNode");
-}
-#endif
-
-void MachVVEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
-{
-  // Add null checks for all value type args and then jump to
-  // the verified entry point (skipping the unverified entry).
-  MacroAssembler masm(&cbuf);
-  masm.null_check_value_args((Method*)ra_->C->method()->constant_encoding());
-  masm.jmp(*_verified_entry);
-}
-
-uint MachVVEPNode::size(PhaseRegAlloc* ra_) const
-{
-  return MachNode::size(ra_); // too many variables; just compute it the hard way
-}
-
-//=============================================================================
-#ifndef PRODUCT
 void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
 {
   if (UseCompressedClassPointers) {
--- a/src/hotspot/share/aot/aotCompiledMethod.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/aot/aotCompiledMethod.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -192,7 +192,6 @@
 
   virtual int comp_level() const { return CompLevel_aot; }
   virtual address verified_entry_point() const { return _code + _meta->verified_entry_offset(); }
-  virtual address verified_value_entry_point() const { return NULL; }
   virtual void log_identity(xmlStream* stream) const;
   virtual void log_state_change(oop cause = NULL) const;
   virtual bool make_entrant() NOT_TIERED({ ShouldNotReachHere(); return false; });
--- a/src/hotspot/share/asm/codeBuffer.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/asm/codeBuffer.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -42,7 +42,6 @@
 public:
   enum Entries { Entry,
                  Verified_Entry,
-                 Verified_Value_Entry,
                  Frame_Complete, // Offset in the code where the frame setup is (for forte stackwalks) is complete
                  OSR_Entry,
                  Exceptions,     // Offset where exception handler lives
@@ -63,7 +62,6 @@
   CodeOffsets() {
     _values[Entry         ] = 0;
     _values[Verified_Entry] = 0;
-    _values[Verified_Value_Entry] = -1;
     _values[Frame_Complete] = frame_never_safe;
     _values[OSR_Entry     ] = 0;
     _values[Exceptions    ] = -1;
--- a/src/hotspot/share/ci/ciClassList.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/ci/ciClassList.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -67,6 +67,7 @@
 class       ciValueArrayKlass;
 class       ciObjArrayKlass;
 class       ciTypeArrayKlass;
+class    ciWrapper;
 
 // Simulate Java Language style package-private access with
 // friend declarations.
@@ -114,6 +115,7 @@
 friend class ciTypeArray;              \
 friend class ciType;                   \
 friend class ciReturnAddress;          \
+friend class ciWrapper;                \
 friend class ciKlass;                  \
 friend class ciInstanceKlass;          \
 friend class ciValueKlass;             \
--- a/src/hotspot/share/ci/ciMetadata.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/ci/ciMetadata.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -62,6 +62,7 @@
   virtual bool is_value_array_klass() const { return false; }
   virtual bool is_obj_array_klass() const   { return false; }
   virtual bool is_type_array_klass() const  { return false; }
+  virtual bool is_wrapper() const           { return false; }
   virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
 
   ciMethod*                as_method() {
@@ -112,10 +113,14 @@
     assert(is_valuetype(), "bad cast");
     return (ciValueKlass*)this;
   }
+  ciWrapper*               as_wrapper() {
+    assert(is_wrapper(), "bad cast");
+    return (ciWrapper*)this;
+  }
 
   Metadata* constant_encoding() { return _metadata; }
 
-  bool equals(ciMetadata* obj) const { return (this == obj); }
+  virtual bool equals(ciMetadata* obj) const { return (this == obj); }
 
   int hash() { return ident() * 31; } // ???
 
--- a/src/hotspot/share/ci/ciSignature.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/ci/ciSignature.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -68,6 +68,9 @@
         ciSymbol* klass_name = env->get_symbol(name);
         type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false);
       }
+      if (type->is_valuetype() && !NullableValueTypes) {
+        type = new (arena) ciWrapper(type, /* never_null */ true);
+      }
     }
     _types->append(type);
     if (ss.at_return_type()) {
@@ -93,10 +96,19 @@
   EXCEPTION_CONTEXT;
   Arena* arena = CURRENT_ENV->arena();
   _types = new (arena) GrowableArray<ciType*>(arena, _count + 1, 0, NULL);
+  ciType* type = NULL;
   for (int i = 0; i < _count; i++) {
-    _types->append(method_type->ptype_at(i));
+    type = method_type->ptype_at(i);
+    if (type->is_valuetype() && !NullableValueTypes) {
+      type = new (arena) ciWrapper(type, /* never_null */ true);
+    }
+    _types->append(type);
   }
-  _types->append(method_type->rtype());
+  type = method_type->rtype();
+  if (type->is_valuetype() && !NullableValueTypes) {
+    type = new (arena) ciWrapper(type, /* never_null */ true);
+  }
+  _types->append(type);
 }
 
 // ------------------------------------------------------------------
@@ -104,7 +116,7 @@
 //
 // What is the return type of this signature?
 ciType* ciSignature::return_type() const {
-  return _types->at(_count);
+  return _types->at(_count)->unwrap();
 }
 
 // ------------------------------------------------------------------
@@ -115,7 +127,24 @@
 ciType* ciSignature::type_at(int index) const {
   assert(index < _count, "out of bounds");
   // The first _klasses element holds the return klass.
-  return _types->at(index);
+  return _types->at(index)->unwrap();
+}
+
+// ------------------------------------------------------------------
+// ciSignature::return_never_null
+//
+// True if we statically know that the return value is never null.
+bool ciSignature::returns_never_null() const {
+  return _types->at(_count)->is_never_null();
+}
+
+// ------------------------------------------------------------------
+// ciSignature::never_null_at
+//
+// True if we statically know that the argument at 'index' is never null.
+bool ciSignature::is_never_null_at(int index) const {
+  assert(index < _count, "out of bounds");
+  return _types->at(index)->is_never_null();
 }
 
 // ------------------------------------------------------------------
--- a/src/hotspot/share/ci/ciSignature.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/ci/ciSignature.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -60,6 +60,8 @@
 
   ciType*   return_type() const;
   ciType*   type_at(int index) const;
+  bool      returns_never_null() const;
+  bool      is_never_null_at(int index) const;
 
   int       size() const                         { return _size; }
   int       count() const                        { return _count; }
--- a/src/hotspot/share/ci/ciStreams.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/ci/ciStreams.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -305,6 +305,14 @@
     }
   }
 
+  bool is_never_null() {
+    if (at_return_type()) {
+      return _sig->returns_never_null();
+    } else {
+      return _sig->is_never_null_at(_pos);
+    }
+  }
+
   // next klass in the signature
   ciKlass* next_klass() {
     ciKlass* sig_k;
--- a/src/hotspot/share/ci/ciType.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/ci/ciType.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -35,6 +35,7 @@
   CI_PACKAGE_ACCESS
   friend class ciKlass;
   friend class ciReturnAddress;
+  friend class ciWrapper;
 
 private:
   BasicType _basic_type;
@@ -77,6 +78,9 @@
   bool is_type() const                      { return true; }
   bool is_classless() const                 { return is_primitive_type(); }
 
+  virtual ciType*     unwrap()              { return this; }
+  virtual bool is_never_null() const        { return false; }
+
   const char* name();
   virtual void print_name_on(outputStream* st);
   void print_name() {
@@ -112,4 +116,40 @@
   static ciReturnAddress* make(int bci);
 };
 
+// ciWrapper
+//
+// This class wraps another type to carry additional information like nullability.
+// Should only be instantiated and used by ciTypeFlow and ciSignature.
+class ciWrapper : public ciType {
+  CI_PACKAGE_ACCESS
+  friend class ciSignature;
+  friend class ciTypeFlow;
+
+private:
+  ciType* _type;
+  bool _never_null;
+
+  ciWrapper(ciType* type, bool never_null) : ciType(type->basic_type()) {
+    assert(type->is_valuetype(), "should only be used for value types");
+    _type = type;
+    _never_null = never_null;
+  }
+
+  const char* type_string() { return "ciWrapper"; }
+
+  void print_impl(outputStream* st) { _type->print_impl(st); }
+
+public:
+  bool equals(ciMetadata* obj) const {
+    return obj->is_wrapper() &&
+           obj->as_wrapper()->unwrap()->equals(_type) &&
+           obj->as_wrapper()->is_never_null() == _never_null;
+  }
+
+  bool    is_wrapper() const { return true; }
+
+  ciType*     unwrap()       { return _type; }
+  bool is_never_null() const { return _never_null; }
+};
+
 #endif // SHARE_VM_CI_CITYPE_HPP
--- a/src/hotspot/share/ci/ciTypeFlow.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/ci/ciTypeFlow.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -272,6 +272,13 @@
 //   different kinds is always java.lang.Object.
 ciType* ciTypeFlow::StateVector::type_meet_internal(ciType* t1, ciType* t2, ciTypeFlow* analyzer) {
   assert(t1 != t2, "checked in caller");
+
+  // Unwrap the types after gathering nullness information
+  bool never_null1 = t1->is_never_null();
+  bool never_null2 = t2->is_never_null();
+  t1 = t1->unwrap();
+  t2 = t2->unwrap();
+
   if (t1->equals(top_type())) {
     return t2;
   } else if (t2->equals(top_type())) {
@@ -339,7 +346,12 @@
       // Must be two plain old instance klasses.
       assert(k1->is_instance_klass(), "previous cases handle non-instances");
       assert(k2->is_instance_klass(), "previous cases handle non-instances");
-      return k1->least_common_ancestor(k2);
+      ciType* result = k1->least_common_ancestor(k2);
+      if (never_null1 && never_null2 && result->is_valuetype()) {
+        // Both value types are never null, mark the result as never null
+        result = analyzer->mark_as_never_null(result);
+      }
+      return result;
     }
   }
 }
@@ -402,13 +414,22 @@
   // "Push" the method signature into the first few locals.
   state->set_stack_size(-max_locals());
   if (!method()->is_static()) {
-    state->push(method()->holder());
+    ciType* holder = method()->holder();
+    if (holder->is_valuetype()) {
+      // The receiver is never null
+      holder = mark_as_never_null(holder);
+    }
+    state->push(holder);
     assert(state->tos() == state->local(0), "");
   }
   for (ciSignatureStream str(method()->signature());
        !str.at_return_type();
        str.next()) {
-    state->push_translate(str.type());
+    ciType* arg = str.type();
+    if (str.is_never_null()) {
+      arg = mark_as_never_null(arg);
+    }
+    state->push_translate(arg);
   }
   // Set the rest of the locals to bottom.
   Cell cell = state->next_cell(state->tos());
@@ -584,7 +605,12 @@
          (Deoptimization::Reason_unloaded,
           Deoptimization::Action_reinterpret));
   } else {
-    push_object(element_klass);
+    if (element_klass->is_valuetype()) {
+      // Value type array elements are never null
+      push(outer()->mark_as_never_null(element_klass));
+    } else {
+      push_object(element_klass);
+    }
   }
 }
 
@@ -603,7 +629,11 @@
     do_null_assert(klass);
   } else {
     pop_object();
-    push_object(klass);
+    if (klass->is_valuetype() && !NullableValueTypes) {
+      push(outer()->mark_as_never_null(klass));
+    } else {
+      push_object(klass);
+    }
   }
 }
 
@@ -645,6 +675,10 @@
       // (See bug 4379915.)
       do_null_assert(field_type->as_klass());
     } else {
+      if (field->is_flattenable()) {
+        // A flattenable field is never null
+        field_type = outer()->mark_as_never_null(field_type);
+      }
       push_translate(field_type);
     }
   }
@@ -712,6 +746,9 @@
         // See do_getstatic() for similar explanation, as well as bug 4684993.
         do_null_assert(return_type->as_klass());
       } else {
+        if (sigstr.is_never_null()) {
+          return_type = outer()->mark_as_never_null(return_type);
+        }
         push_translate(return_type);
       }
     }
@@ -735,13 +772,17 @@
     outer()->record_failure("ldc did not link");
     return;
   }
-  if (basic_type == T_OBJECT || basic_type == T_ARRAY) {
+  if (basic_type == T_OBJECT || basic_type == T_OBJECT || basic_type == T_ARRAY) {
     ciObject* obj = con.as_object();
     if (obj->is_null_object()) {
       push_null();
     } else {
       assert(obj->is_instance() || obj->is_array(), "must be java_mirror of klass");
-      push_object(obj->klass());
+      ciType* type = obj->klass();
+      if (type->is_valuetype()) {
+        type = outer()->mark_as_never_null(type);
+      }
+      push(type);
     }
   } else {
     push_translate(ciType::make(basic_type));
@@ -784,8 +825,8 @@
   if (!will_link) {
     trap(str, klass, str->get_klass_index());
   } else {
-    assert(klass->is_valuetype(), "should be value type");
-    push_object(klass);
+    // The default value type is never null
+    push(outer()->mark_as_never_null(klass));
   }
 }
 
@@ -795,7 +836,6 @@
   bool will_link;
   ciField* field = str->get_field(will_link);
   ciKlass* klass = field->holder();
-  assert(klass->is_valuetype(), "should be value type");
   if (!will_link) {
     trap(str, klass, str->get_field_holder_index());
   } else {
@@ -808,7 +848,8 @@
       assert(type == half_type(type2), "must be 2nd half");
     }
     pop_object();
-    push_object(klass);
+    // The newly created value type can never be null
+    push(outer()->mark_as_never_null(klass));
   }
 }
 
@@ -3043,6 +3084,11 @@
   }
 }
 
+ciType* ciTypeFlow::mark_as_never_null(ciType* type) {
+  // Wrap the type to carry the information that it is never null
+  return new (arena()) ciWrapper(type, /* never_null */ true);
+}
+
 #ifndef PRODUCT
 // ------------------------------------------------------------------
 // ciTypeFlow::print_on
--- a/src/hotspot/share/ci/ciTypeFlow.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/ci/ciTypeFlow.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -864,6 +864,8 @@
   int next_pre_order()              { return _next_pre_order; }
   int inc_next_pre_order()          { return _next_pre_order++; }
 
+  ciType* mark_as_never_null(ciType* type);
+
 private:
   // A work list used during flow analysis.
   Block* _work_list;
--- a/src/hotspot/share/code/compiledMethod.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/code/compiledMethod.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -201,7 +201,6 @@
   virtual int   compile_id() const = 0;
 
   virtual address verified_entry_point() const = 0;
-  virtual address verified_value_entry_point() const = 0;
   virtual void log_identity(xmlStream* log) const = 0;
   virtual void log_state_change(oop cause = NULL) const = 0;
   virtual bool make_not_used() = 0;
--- a/src/hotspot/share/code/nmethod.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/code/nmethod.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -588,10 +588,6 @@
     _comp_level              = CompLevel_none;
     _entry_point             = code_begin()          + offsets->value(CodeOffsets::Entry);
     _verified_entry_point    = code_begin()          + offsets->value(CodeOffsets::Verified_Entry);
-    if (method->has_value_args()) {
-      // Use the normale entry point for now
-      _verified_value_entry_point = _verified_entry_point;
-    }
     _osr_entry_point         = NULL;
     _exception_cache         = NULL;
     _pc_desc_container.reset_to(NULL);
@@ -749,11 +745,6 @@
     _nmethod_end_offset      = _nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize);
     _entry_point             = code_begin()          + offsets->value(CodeOffsets::Entry);
     _verified_entry_point    = code_begin()          + offsets->value(CodeOffsets::Verified_Entry);
-    if (method->has_value_args()) {
-      _verified_value_entry_point = code_begin()     + offsets->value(CodeOffsets::Verified_Value_Entry);
-    } else {
-      _verified_value_entry_point = NULL;
-    }
     _osr_entry_point         = code_begin()          + offsets->value(CodeOffsets::OSR_Entry);
     _exception_cache         = NULL;
 
@@ -2488,7 +2479,7 @@
 }
 
 void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) const {
-  address low = verified_value_entry_point() != NULL ? verified_value_entry_point() : entry_point();
+  address low = entry_point();
   if (block_begin == low) {
     // Print method arguments before the method entry
     methodHandle m = method();
@@ -2596,7 +2587,6 @@
 
   if (block_begin == entry_point())             stream->print_cr("[Entry Point]");
   if (block_begin == verified_entry_point())    stream->print_cr("[Verified Entry Point]");
-  if (block_begin == verified_value_entry_point()) stream->print_cr("[Verified Value Entry Point]");
   if (JVMCI_ONLY(_exception_offset >= 0 &&) block_begin == exception_begin())         stream->print_cr("[Exception Handler]");
   if (block_begin == stub_begin())              stream->print_cr("[Stub Code]");
   if (JVMCI_ONLY(_deopt_handler_begin != NULL &&) block_begin == deopt_handler_begin())     stream->print_cr("[Deopt Handler Code]");
--- a/src/hotspot/share/code/nmethod.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/code/nmethod.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -90,7 +90,6 @@
   // offsets for entry points
   address _entry_point;                      // entry point with class check
   address _verified_entry_point;             // entry point without class check
-  address _verified_value_entry_point;       // value type entry point without class check
   address _osr_entry_point;                  // entry point for on stack replacement
 
   // Offsets for different nmethod parts
@@ -315,7 +314,6 @@
   // entry points
   address entry_point() const                     { return _entry_point;             } // normal entry point
   address verified_entry_point() const            { return _verified_entry_point;    } // if klass is correct
-  address verified_value_entry_point() const      { return _verified_value_entry_point; } // pass value type args as oops
 
   // flag accessing and manipulation
   bool  is_not_installed() const                  { return _state == not_installed; }
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -1730,15 +1730,6 @@
   // preparing the same method will be sure to see non-null entry & mirror.
 IRT_END
 
-IRT_ENTRY(void, InterpreterRuntime::deoptimize_caller_frame_for_vt(JavaThread* thread, Method* callee))
-  // Called from within the owner thread, so no need for safepoint
-  assert(callee->is_returning_vt(), "must be");
-  RegisterMap reg_map(thread);
-  frame last_frame = thread->last_frame();
-  frame caller_frame = last_frame.sender(&reg_map);
-  Deoptimization::deoptimize_frame(thread, caller_frame.id());
-IRT_END
-
 #if defined(IA32) || defined(AMD64) || defined(ARM)
 IRT_LEAF(void, InterpreterRuntime::popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address))
   if (src_address == dest_address) {
--- a/src/hotspot/share/interpreter/interpreterRuntime.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -181,8 +181,6 @@
   static void    verify_mdp(Method* method, address bcp, address mdp);
 #endif // ASSERT
   static MethodCounters* build_method_counters(JavaThread* thread, Method* m);
-
-  static void deoptimize_caller_frame_for_vt(JavaThread* thread, Method* callee);
 };
 
 
--- a/src/hotspot/share/oops/instanceKlass.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -866,9 +866,6 @@
             if (!klass->is_value()) {
               THROW_(vmSymbols::java_lang_IncompatibleClassChangeError(), false);
             }
-            if (ss.at_return_type()) {
-              m->set_is_returning_vt();
-            }
           }
         }
       }
--- a/src/hotspot/share/oops/method.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/oops/method.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -1191,7 +1191,7 @@
 
   OrderAccess::storestore();
   mh->_from_compiled_entry = code->verified_entry_point();
-  mh->_from_compiled_value_entry = mh->has_value_args() ? code->verified_value_entry_point() : code->verified_entry_point();
+  mh->_from_compiled_value_entry = code->verified_entry_point();
   OrderAccess::storestore();
   // Instantly compiled code can execute.
   if (!mh->is_method_handle_intrinsic())
--- a/src/hotspot/share/oops/method.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/oops/method.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -90,8 +90,7 @@
     _has_injected_profile  = 1 << 4,
     _running_emcp          = 1 << 5,
     _intrinsic_candidate   = 1 << 6,
-    _reserved_stack_access = 1 << 7,
-    _is_returning_vt       = 1 << 8
+    _reserved_stack_access = 1 << 7
   };
   mutable u2 _flags;
 
@@ -577,6 +576,7 @@
   Symbol* klass_name() const;                    // returns the name of the method holder
   BasicType result_type() const;                 // type of the method result
   bool may_return_oop() const                    { BasicType r = result_type(); return (r == T_OBJECT || r == T_ARRAY ||  r == T_VALUETYPE); }
+  bool is_returning_vt() const                   { BasicType r = result_type(); return r == T_VALUETYPE; }
 #ifdef ASSERT
   ValueKlass* returned_value_type(Thread* thread) const;
 #endif
@@ -894,18 +894,6 @@
     _flags = x ? (_flags | _reserved_stack_access) : (_flags & ~_reserved_stack_access);
   }
 
-  static int is_returning_vt_mask() {
-    return _is_returning_vt;
-  }
-
-  bool is_returning_vt() const {
-    return (_flags & _is_returning_vt) != 0;
-  }
-
-  void set_is_returning_vt() {
-    _flags |= _is_returning_vt;
-  }
-
   JFR_ONLY(DEFINE_TRACE_FLAG_ACCESSOR;)
 
   ConstMethod::MethodType method_type() const {
--- a/src/hotspot/share/opto/callGenerator.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/callGenerator.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -923,14 +923,9 @@
     arg = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type));
     kit.set_argument(arg_nb, arg);
   }
-  if (sig_type->is_valuetypeptr() && !arg->is_ValueType()) {
-    kit.inc_sp(nargs); // restore arguments
-    if (t->as_value_klass()->is_scalarizable()) {
-      arg = ValueTypeNode::make_from_oop(&kit, arg, t->as_value_klass(), /* null2default */ false);
-    } else {
-      arg = kit.filter_null(arg);
-    }
-    kit.dec_sp(nargs);
+  if (sig_type->is_valuetypeptr() && !arg->is_ValueType() &&
+      !kit.gvn().type(arg)->maybe_null() && t->as_value_klass()->is_scalarizable()) {
+    arg = ValueTypeNode::make_from_oop(&kit, arg, t->as_value_klass());
     kit.set_argument(arg_nb, arg);
   }
 }
--- a/src/hotspot/share/opto/castnode.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/castnode.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -286,26 +286,6 @@
 //------------------------------Identity---------------------------------------
 // If input is already higher or equal to cast type, then this is an identity.
 Node* CheckCastPPNode::Identity(PhaseGVN* phase) {
-  // This is a value type, its input is a phi. That phi is also a
-  // value type of that same type and its inputs are value types of
-  // the same type: push the cast through the phi.
-  if (phase->is_IterGVN() &&
-      in(0) == NULL &&
-      type()->is_valuetypeptr() &&
-      in(1) != NULL &&
-      in(1)->is_Phi()) {
-    PhaseIterGVN* igvn = phase->is_IterGVN();
-    Node* phi = in(1);
-    const Type* vtptr = type();
-    for (uint i = 1; i < phi->req(); i++) {
-      if (phi->in(i) != NULL && !phase->type(phi->in(i))->higher_equal(vtptr)) {
-        Node* cast = phase->transform(new CheckCastPPNode(NULL, phi->in(i), vtptr));
-        igvn->replace_input_of(phi, i, cast);
-      }
-    }
-    return phi;
-  }
-
   Node* dom = dominating_cast(phase, phase);
   if (dom != NULL) {
     return dom;
@@ -405,172 +385,6 @@
   // return join;
 }
 
-Node* CheckCastPPNode::Ideal(PhaseGVN *phase, bool can_reshape) {
-  // This is a value type. Its input is the return of a call: the call
-  // returns a value type and we now know its exact type: build a
-  // ValueTypePtrNode from the call.
-  const TypeInstPtr* cast_type = type()->isa_instptr();
-  if (can_reshape &&
-      in(0) == NULL &&
-      phase->C->can_add_value_type() &&
-      cast_type && cast_type->is_valuetypeptr() &&
-      in(1) != NULL && in(1)->is_Proj() &&
-      in(1)->in(0) != NULL && in(1)->in(0)->is_CallStaticJava() &&
-      in(1)->in(0)->as_CallStaticJava()->method() != NULL &&
-      in(1)->as_Proj()->_con == TypeFunc::Parms) {
-    ciValueKlass* vk = cast_type->value_klass();
-    PhaseIterGVN* igvn = phase->is_IterGVN();
-
-    if (ValueTypeReturnedAsFields && vk->can_be_returned_as_fields()) {
-      igvn->set_delay_transform(true);
-      CallNode* call = in(1)->in(0)->as_Call();
-      igvn->C->remove_macro_node(call);
-      // We now know the return type of the call
-      const TypeTuple* range_sig = TypeTuple::make_range(vk, false);
-      const TypeTuple* range_cc = TypeTuple::make_range(vk, true);
-      assert(range_sig != call->_tf->range_sig() && range_cc != call->_tf->range_cc(), "type should change");
-      call->_tf = TypeFunc::make(call->_tf->domain_sig(), call->_tf->domain_cc(),
-                                 range_sig, range_cc);
-      igvn->set_type(call, call->Value(igvn));
-      igvn->set_type(in(1), in(1)->Value(igvn));
-
-      Node* ctl_hook = new Node(1);
-      Node* mem_hook = new Node(1);
-      Node* io_hook = new Node(1);
-      Node* res_hook = new Node(1);
-      Node* ex_ctl_hook = new Node(1);
-      Node* ex_mem_hook = new Node(1);
-      Node* ex_io_hook = new Node(1);
-
-      // Extract projections from the call and hook users to temporary nodes.
-      // We will re-attach them to newly created PhiNodes below.
-      CallProjections* projs = call->extract_projections(true, true);
-      assert(projs->nb_resproj == 1, "unexpected number of results");
-      igvn->replace_in_uses(projs->fallthrough_catchproj, ctl_hook);
-      igvn->replace_in_uses(projs->fallthrough_memproj, mem_hook);
-      igvn->replace_in_uses(projs->fallthrough_ioproj, io_hook);
-      igvn->replace_in_uses(projs->resproj[0], res_hook);
-      igvn->replace_in_uses(projs->catchall_catchproj, ex_ctl_hook);
-      igvn->replace_in_uses(projs->catchall_memproj, ex_mem_hook);
-      igvn->replace_in_uses(projs->catchall_ioproj, ex_io_hook);
-
-      // Restore IO input of the CatchNode
-      CatchNode* catchp = projs->fallthrough_catchproj->in(0)->as_Catch();
-      catchp->set_req(TypeFunc::I_O, projs->catchall_ioproj);
-      igvn->rehash_node_delayed(catchp);
-
-      // Rebuild the output JVMState from the call and use it to initialize a GraphKit
-      JVMState* new_jvms = call->jvms()->clone_shallow(igvn->C);
-      SafePointNode* new_map = new SafePointNode(call->req(), new_jvms);
-      for (uint i = TypeFunc::FramePtr; i < call->req(); i++) {
-        new_map->init_req(i, call->in(i));
-      }
-      new_map->set_control(projs->fallthrough_catchproj);
-      new_map->set_memory(MergeMemNode::make(projs->fallthrough_memproj));
-      new_map->set_i_o(projs->fallthrough_ioproj);
-      new_jvms->set_map(new_map);
-
-      GraphKit kit(new_jvms, igvn);
-
-      // Either we get a buffered value pointer and we can case use it
-      // or we get a tagged klass pointer and we need to allocate a value.
-      Node* cast = igvn->transform(new CastP2XNode(kit.control(), projs->resproj[0]));
-      Node* masked = igvn->transform(new AndXNode(cast, igvn->MakeConX(0x1)));
-      Node* cmp = igvn->transform(new CmpXNode(masked, igvn->MakeConX(0x1)));
-      Node* bol = kit.Bool(cmp, BoolTest::eq);
-      IfNode* iff = kit.create_and_map_if(kit.control(), bol, PROB_MAX, COUNT_UNKNOWN);
-      Node* iftrue = kit.IfTrue(iff);
-      Node* iffalse = kit.IfFalse(iff);
-
-      Node* region = new RegionNode(3);
-      Node* mem_phi = new PhiNode(region, Type::MEMORY, TypePtr::BOTTOM);
-      Node* io_phi = new PhiNode(region, Type::ABIO);
-      Node* res_phi = new PhiNode(region, cast_type);
-      Node* ex_region = new RegionNode(3);
-      Node* ex_mem_phi = new PhiNode(ex_region, Type::MEMORY, TypePtr::BOTTOM);
-      Node* ex_io_phi = new PhiNode(ex_region, Type::ABIO);
-
-      // True branch: result is a tagged klass pointer
-      // Allocate a value type (will add extra projections to the call)
-      kit.set_control(iftrue);
-      Node* res = igvn->transform(ValueTypePtrNode::make_from_call(&kit, vk, call));
-      res = res->isa_ValueTypePtr()->allocate(&kit);
-
-      // Get exception state
-      GraphKit ekit(kit.transfer_exceptions_into_jvms(), igvn);
-      SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states();
-      Node* ex_oop = ekit.use_exception_state(ex_map);
-
-      region->init_req(1, kit.control());
-      mem_phi->init_req(1, kit.reset_memory());
-      io_phi->init_req(1, kit.i_o());
-      res_phi->init_req(1, res);
-      ex_region->init_req(1, ekit.control());
-      ex_mem_phi->init_req(1, ekit.reset_memory());
-      ex_io_phi->init_req(1, ekit.i_o());
-
-      // False branch: result is not tagged
-      // Load buffered value type from returned oop
-      kit.set_control(iffalse);
-      kit.set_all_memory(projs->fallthrough_memproj);
-      kit.set_i_o(projs->fallthrough_ioproj);
-      // Cast oop to NotNull
-      ConstraintCastNode* res_cast = clone()->as_ConstraintCast();
-      res_cast->set_req(0, kit.control());
-      res_cast->set_req(1, projs->resproj[0]);
-      res_cast->set_type(cast_type->cast_to_ptr_type(TypePtr::NotNull));
-      Node* ctl = kit.control(); // Control may get updated below
-      res = ValueTypePtrNode::make_from_oop(&kit, igvn->transform(res_cast));
-
-      region->init_req(2, ctl);
-      mem_phi->init_req(2, kit.reset_memory());
-      io_phi->init_req(2, kit.i_o());
-      res_phi->init_req(2, res);
-      ex_region->init_req(2, projs->catchall_catchproj);
-      ex_mem_phi->init_req(2, projs->catchall_memproj);
-      ex_io_phi->init_req(2, projs->catchall_ioproj);
-
-      igvn->set_delay_transform(false);
-
-      // Re-attach users to newly created PhiNodes
-      igvn->replace_node(ctl_hook, igvn->transform(region));
-      igvn->replace_node(mem_hook, igvn->transform(mem_phi));
-      igvn->replace_node(io_hook, igvn->transform(io_phi));
-      igvn->replace_node(res_hook, igvn->transform(res_phi));
-      igvn->replace_node(ex_ctl_hook, igvn->transform(ex_region));
-      igvn->replace_node(ex_mem_hook, igvn->transform(ex_mem_phi));
-      igvn->replace_node(ex_io_hook, igvn->transform(ex_io_phi));
-      return this;
-    } else {
-      CallNode* call = in(1)->in(0)->as_Call();
-      // We now know the return type of the call
-      const TypeTuple* range = TypeTuple::make_range(vk, false);
-      if (range != call->_tf->range_sig()) {
-        // Build the ValueTypePtrNode by loading the fields
-        call->_tf = TypeFunc::make(call->_tf->domain_sig(), call->_tf->domain_cc(),
-                                   range, range);
-        phase->set_type(call, call->Value(phase));
-        phase->set_type(in(1), in(1)->Value(phase));
-        uint last = phase->C->unique();
-        CallNode* call = in(1)->in(0)->as_Call();
-        // Extract projections from the call and hook control users to temporary node
-        CallProjections* projs = call->extract_projections(true, true);
-        Node* ctl = projs->fallthrough_catchproj;
-        Node* mem = projs->fallthrough_memproj;
-        Node* ctl_hook = new Node(1);
-        igvn->replace_in_uses(ctl, ctl_hook);
-        GraphKit kit(call->jvms(), igvn);
-        kit.set_control(ctl);
-        Node* vtptr = ValueTypePtrNode::make_from_oop(&kit, in(1));
-        // Attach users to updated control
-        igvn->replace_node(ctl_hook, kit.control());
-        return vtptr;
-      }
-    }
-  }
-  return NULL;
-}
-
 //=============================================================================
 //------------------------------Value------------------------------------------
 const Type* CastX2PNode::Value(PhaseGVN* phase) const {
--- a/src/hotspot/share/opto/castnode.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/castnode.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -114,7 +114,6 @@
 
   virtual Node* Identity(PhaseGVN* phase);
   virtual const Type* Value(PhaseGVN* phase) const;
-  virtual Node* Ideal(PhaseGVN *phase, bool can_reshape);
   virtual int   Opcode() const;
   virtual uint  ideal_reg() const { return Op_RegP; }
   bool depends_only_on_test() const { return !type()->isa_rawptr() && ConstraintCastNode::depends_only_on_test(); }
--- a/src/hotspot/share/opto/cfgnode.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/cfgnode.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -1664,55 +1664,6 @@
     }
   }
 
-  if (type()->is_valuetypeptr() && can_reshape) {
-    // If the Phi merges the result from a mix of constant and non
-    // constant method handles, only some of its inputs are
-    // ValueTypePtr nodes and we can't push the ValueTypePtr node down
-    // to remove the need for allocations. This if fixed by transforming:
-    //
-    // (Phi ValueTypePtr#1 Node#2) to (Phi ValueTypePtr#1 CheckCastPP#2)
-    //
-    // Then pushing the CheckCastPP up through Phis until it reaches
-    // the non constant method handle call. The type of the return
-    // value is then known from the type of the CheckCastPP. A
-    // ValueTypePtr can be created by adding projections to the call
-    // for all values being returned. See
-    // CheckCastPPNode::Ideal(). That ValueTypePtr node can then be
-    // pushed down through Phis.
-    const TypeInstPtr* ti = NULL;
-    for (uint i = 1; i < req(); i++) {
-      if (in(i) != NULL && in(i)->is_ValueTypePtr()) {
-        const TypeInstPtr* t = phase->type(in(i))->is_instptr();
-        t = t->cast_to_ptr_type(TypePtr::BotPTR)->is_instptr();
-        if (ti == NULL) {
-          ti = t;
-        } else {
-          assert(ti == t, "Phi should merge identical value types");
-        }
-      } else {
-        assert(in(i) == NULL || ti == NULL || phase->type(in(i))->higher_equal(ti) || phase->type(in(i)) == Type::TOP, "bad type");
-      }
-    }
-    if (ti != NULL) {
-      // One input is a value type. All inputs must have the same type.
-      bool progress = false;
-      PhaseIterGVN* igvn = phase->is_IterGVN();
-      for (uint i = 1; i < req(); i++) {
-        if (in(i) != NULL && !in(i)->is_Con() && !phase->type(in(i))->higher_equal(ti)) {
-          // Can't transform because CheckCastPPNode::Identity can
-          // push the cast up through another Phi and cause this same
-          // transformation to run again, indefinitely
-          Node* cast = igvn->register_new_node_with_optimizer(new CheckCastPPNode(NULL, in(i), ti));
-          set_req(i, cast);
-          progress = true;
-        }
-      }
-      if (progress) {
-        return this;
-      }
-    }
-  }
-
   Node *top = phase->C->top();
   bool new_phi = (outcnt() == 0); // transforming new Phi
   // No change for igvn if new phi is not hooked
--- a/src/hotspot/share/opto/compile.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/compile.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -616,11 +616,6 @@
     masm.bind(fakeL);
     n->as_MachBranch()->save_label(&saveL, &save_bnum);
     n->as_MachBranch()->label_set(&fakeL, 0);
-  } else if (n->is_MachProlog()) {
-    MacroAssembler masm(&buf);
-    masm.bind(fakeL);
-    saveL = ((MachPrologNode*)n)->_verified_entry;
-    ((MachPrologNode*)n)->_verified_entry = &fakeL;
   }
   n->emit(buf, this->regalloc());
 
@@ -630,8 +625,6 @@
   // Restore label.
   if (is_branch) {
     n->as_MachBranch()->label_set(saveL, save_bnum);
-  } else if (n->is_MachProlog()) {
-    ((MachPrologNode*)n)->_verified_entry = saveL;
   }
 
   // End scratch_emit_size section.
@@ -790,7 +783,7 @@
     CallGenerator* cg = NULL;
     if (is_osr_compilation()) {
       const TypeTuple *domain = StartOSRNode::osr_domain();
-      const TypeTuple *range = TypeTuple::make_range(method());
+      const TypeTuple *range = TypeTuple::make_range(method()->signature());
       init_tf(TypeFunc::make(domain, range));
       StartNode* s = new StartOSRNode(root(), domain);
       initial_gvn()->set_type_bottom(s);
@@ -948,10 +941,6 @@
       _code_offsets.set_value(CodeOffsets::OSR_Entry, _first_block_size);
     } else {
       _code_offsets.set_value(CodeOffsets::Verified_Entry, _first_block_size);
-      if (_code_offsets.value(CodeOffsets::Entry) == -1) {
-        // We emitted a value type entry point, adjust normal entry
-        _code_offsets.set_value(CodeOffsets::Entry, _first_block_size);
-      }
       _code_offsets.set_value(CodeOffsets::OSR_Entry, 0);
     }
 
--- a/src/hotspot/share/opto/doCall.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/doCall.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -665,10 +665,8 @@
           if (ctype->is_loaded()) {
             const TypeOopPtr* arg_type = TypeOopPtr::make_from_klass(rtype->as_klass());
             const Type*       sig_type = TypeOopPtr::make_from_klass(ctype->as_klass());
-            if (ct == T_VALUETYPE && cg->method()->get_Method()->is_returning_vt()) {
-              // A NULL ValueType cannot be returned to compiled code. The 'areturn' bytecode
-              // handler will deoptimize its caller if it is about to return a NULL ValueType.
-              // (See comments inside TypeTuple::make_range).
+            if (declared_signature->returns_never_null()) {
+              assert(ct == T_VALUETYPE, "should be a value type");
               sig_type = sig_type->join_speculative(TypePtr::NOTNULL);
             }
             if (arg_type != NULL && !arg_type->higher_equal(sig_type) && !peek()->is_ValueType()) {
@@ -698,13 +696,9 @@
     }
 
     if (rtype->basic_type() == T_VALUETYPE && !peek()->is_ValueType()) {
-      // Deoptimize if the return value is null and then continue execution after the call
       Node* retnode = pop();
-      assert(!gvn().type(retnode)->maybe_null() || !cg->method()->get_Method()->is_returning_vt(), "should never be null");
-      if (rtype->as_value_klass()->is_scalarizable()) {
-        retnode = ValueTypeNode::make_from_oop(this, retnode, rtype->as_value_klass(), /* null2default */ false, iter().next_bci());
-      } else if (gvn().type(retnode)->maybe_null()) {
-        retnode = filter_null(retnode, false, NULL, iter().next_bci());
+      if (!gvn().type(retnode)->maybe_null() && rtype->as_value_klass()->is_scalarizable()) {
+        retnode = ValueTypeNode::make_from_oop(this, retnode, rtype->as_value_klass());
       }
       push_node(T_VALUETYPE, retnode);
     }
--- a/src/hotspot/share/opto/graphKit.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/graphKit.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -1394,34 +1394,18 @@
   return value;
 }
 
-Node* GraphKit::filter_null(Node* value, bool null2default, ciValueKlass* vk, int trap_bci) {
+Node* GraphKit::null2default(Node* value, ciValueKlass* vk) {
   Node* null_ctl = top();
   value = null_check_oop(value, &null_ctl);
   if (!null_ctl->is_top()) {
-    if (null2default) {
-      // Return default value if oop is null
-      Node* region = new RegionNode(3);
-      region->init_req(1, control());
-      region->init_req(2, null_ctl);
-      value = PhiNode::make(region, value, TypeInstPtr::make(TypePtr::BotPTR, vk));
-      value->set_req(2, ValueTypeNode::default_oop(gvn(), vk));
-      set_control(gvn().transform(region));
-      value = gvn().transform(value);
-    } else {
-      // Deoptimize if oop is null
-      PreserveJVMState pjvms(this);
-      set_control(null_ctl);
-      int cur_bci = bci();
-      if (trap_bci != -1) {
-        // Put trap at different bytecode
-        push(null());
-        set_bci(trap_bci);
-      }
-      uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-      if (trap_bci != -1) {
-        set_bci(cur_bci);
-      }
-    }
+    // Return default value if oop is null
+    Node* region = new RegionNode(3);
+    region->init_req(1, control());
+    region->init_req(2, null_ctl);
+    value = PhiNode::make(region, value, TypeInstPtr::make(TypePtr::BotPTR, vk));
+    value->set_req(2, ValueTypeNode::default_oop(gvn(), vk));
+    set_control(gvn().transform(region));
+    value = gvn().transform(value);
   }
   return value;
 }
@@ -1823,14 +1807,6 @@
         // Pass value type argument via oop to callee
         arg = vt->allocate(this)->get_oop();
       }
-    } else if (t->is_valuetypeptr() && !arg->is_ValueTypePtr() && gvn().type(arg)->maybe_null()) {
-      // Constant null passed for a value type argument
-      assert(arg->bottom_type()->remove_speculative() == TypePtr::NULL_PTR, "Anything other than null?");
-      ciMethod* declared_method = method()->get_method_at_bci(bci());
-      int arg_size = declared_method->signature()->arg_size_for_bc(java_bc());
-      inc_sp(arg_size); // restore arguments
-      uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-      return;
     }
     call->init_req(idx, arg);
     idx++;
@@ -2887,11 +2863,9 @@
   // recv_xtype, since now we know what the type will be.
   Node* cast = new CheckCastPPNode(control(), receiver, recv_xtype);
   Node* res = _gvn.transform(cast);
-  if (recv_xtype->is_valuetypeptr()) {
-    assert(!gvn().type(res)->maybe_null(), "should never be null");
-    if (recv_xtype->value_klass()->is_scalarizable()) {
-      res = ValueTypeNode::make_from_oop(this, res, recv_xtype->value_klass());
-    }
+  if (recv_xtype->is_valuetypeptr() && recv_xtype->value_klass()->is_scalarizable()) {
+    assert(!gvn().type(res)->maybe_null(), "receiver should never be null");
+    res = ValueTypeNode::make_from_oop(this, res, recv_xtype->value_klass());
   }
 
   (*casted_receiver) = res;
@@ -3194,12 +3168,9 @@
         // to the type system as a speculative type.
         if (!is_value) {
           obj = record_profiled_receiver_for_speculation(obj);
-          if (toop->is_valuetypeptr()) {
-            if (toop->value_klass()->is_scalarizable()) {
-              obj = ValueTypeNode::make_from_oop(this, obj, toop->value_klass(), /* null2default */ false);
-            } else {
-              obj = filter_null(obj);
-            }
+          if (toop->is_valuetypeptr() && toop->value_klass()->is_scalarizable() && !NullableValueTypes) {
+            obj = null_check(obj);
+            obj = ValueTypeNode::make_from_oop(this, obj, toop->value_klass());
           }
         }
         return obj;
@@ -3242,8 +3213,8 @@
   Node* not_null_obj = NULL;
   if (is_value) {
     not_null_obj = obj;
-  } else if (toop->is_valuetypeptr()) {
-    not_null_obj = filter_null(obj);
+  } else if (toop->is_valuetypeptr() && !NullableValueTypes) {
+    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);
   }
@@ -3339,11 +3310,8 @@
 
   if (!is_value) {
     res = record_profiled_receiver_for_speculation(res);
-    if (toop->is_valuetypeptr()) {
-      assert(!gvn().type(res)->maybe_null(), "should never be null");
-      if (toop->value_klass()->is_scalarizable()) {
-        res = ValueTypeNode::make_from_oop(this, res, toop->value_klass());
-      }
+    if (toop->is_valuetypeptr() && toop->value_klass()->is_scalarizable() && !gvn().type(res)->maybe_null()) {
+      res = ValueTypeNode::make_from_oop(this, res, toop->value_klass());
     }
   }
   return res;
@@ -4388,12 +4356,10 @@
                                                         /*is_unsigned_load=*/false);
   if (con_type != NULL) {
     Node* con = makecon(con_type);
-    if (field->layout_type() == T_VALUETYPE) {
+    if (field->layout_type() == T_VALUETYPE && field->type()->as_value_klass()->is_scalarizable()) {
       // Load value type from constant oop
       assert(!con_type->maybe_null(), "should never be null");
-      if (field->type()->as_value_klass()->is_scalarizable()) {
-        con = ValueTypeNode::make_from_oop(this, con, field->type()->as_value_klass());
-      }
+      con = ValueTypeNode::make_from_oop(this, con, field->type()->as_value_klass());
     }
     return con;
   }
--- a/src/hotspot/share/opto/graphKit.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/graphKit.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -377,7 +377,7 @@
     return null_check_common(value, type, true, NULL, _gvn.type(value)->speculative_always_null());
   }
 
-  Node* filter_null(Node* value, bool null2default = false, ciValueKlass* vk = NULL, int trap_bci = -1);
+  Node* null2default(Node* value, ciValueKlass* vk = NULL);
 
   // Check if value is null and abort if it is
   Node* must_be_not_null(Node* value, bool do_replace_in_map);
--- a/src/hotspot/share/opto/library_call.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/library_call.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -2525,13 +2525,13 @@
       p = gvn().transform(new CastP2XNode(NULL, p));
       p = ConvX2UL(p);
     }
-    if (value_type->is_valuetypeptr()) {
-      // Load a non-flattened value type from memory
+    if (field != NULL && field->is_flattenable()) {
+      // Load a non-flattened but flattenable value type from memory
       assert(!field->is_flattened(), "unsafe value type load from flattened field");
       if (value_type->value_klass()->is_scalarizable()) {
-        p = ValueTypeNode::make_from_oop(this, p, value_type->value_klass(), /* buffer_check */ false, /* null2default */ field->is_flattenable());
-      } else if (gvn().type(p)->maybe_null()) {
-        p = filter_null(p, field->is_flattenable(), value_type->value_klass());
+        p = ValueTypeNode::make_from_oop(this, p, value_type->value_klass());
+      } else {
+        p = null2default(p, value_type->value_klass());
       }
     }
     // The load node has the control of the preceding MemBarCPUOrder.  All
--- a/src/hotspot/share/opto/machnode.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/machnode.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -463,22 +463,6 @@
   int  constant_offset_unchecked() const;
 };
 
-//------------------------------MachVTEPNode-----------------------------------
-// Machine Verified Value Type Entry Point Node
-class MachVVEPNode : public MachIdealNode {
-public:
-  MachVVEPNode(Label* verified_entry) : _verified_entry(verified_entry) {}
-  virtual void emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const;
-  virtual uint size(PhaseRegAlloc* ra_) const;
-
-#ifndef PRODUCT
-  virtual const char* Name() const { return "Verified ValueType Entry-Point"; }
-  virtual void format(PhaseRegAlloc*, outputStream* st) const;
-#endif
-private:
-  Label* _verified_entry;
-};
-
 //------------------------------MachUEPNode-----------------------------------
 // Machine Unvalidated Entry Point Node
 class MachUEPNode : public MachIdealNode {
@@ -497,14 +481,11 @@
 // Machine function Prolog Node
 class MachPrologNode : public MachIdealNode {
 public:
-  MachPrologNode(Label* verified_entry) : _verified_entry(verified_entry) {
-    init_class_id(Class_MachProlog);
-  }
+  MachPrologNode( ) {}
   virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const;
   virtual uint size(PhaseRegAlloc *ra_) const;
   virtual int reloc() const;
 
-  Label* _verified_entry;
 #ifndef PRODUCT
   virtual const char *Name() const { return "Prolog"; }
   virtual void format( PhaseRegAlloc *, outputStream *st ) const;
--- a/src/hotspot/share/opto/macro.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/macro.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -607,6 +607,17 @@
         assert(UseCompressedOops, "unexpected narrow oop");
         value = transform_later(new DecodeNNode(value, value->get_ptr_type()));
       }
+      /*
+      // TODO attempt scalarization here?
+      if (vt->field_is_flattenable(i)) {
+        // Loading a non-flattened but flattenable value type from memory
+        if (field_type->as_value_klass()->is_scalarizable()) {
+          value = ValueTypeNode::make_from_oop(kit, value, ft->as_value_klass());
+        } else {
+          value = kit->filter_null(value, true, ft->as_value_klass());
+        }
+      }
+      */
     }
     if (value != NULL) {
       vt->set_field_value(i, value);
--- a/src/hotspot/share/opto/node.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/node.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -102,7 +102,6 @@
 class MachNode;
 class MachNullCheckNode;
 class MachProjNode;
-class MachPrologNode;
 class MachReturnNode;
 class MachSafePointNode;
 class MachSpillCopyNode;
@@ -665,7 +664,6 @@
         DEFINE_CLASS_ID(MachJump,       MachConstant, 0)
       DEFINE_CLASS_ID(MachMerge,        Mach, 6)
       DEFINE_CLASS_ID(MachMemBar,       Mach, 7)
-      DEFINE_CLASS_ID(MachProlog,       Mach, 8)
 
     DEFINE_CLASS_ID(Type,  Node, 2)
       DEFINE_CLASS_ID(Phi,   Type, 0)
@@ -858,7 +856,6 @@
   DEFINE_CLASS_QUERY(MachJump)
   DEFINE_CLASS_QUERY(MachNullCheck)
   DEFINE_CLASS_QUERY(MachProj)
-  DEFINE_CLASS_QUERY(MachProlog)
   DEFINE_CLASS_QUERY(MachReturn)
   DEFINE_CLASS_QUERY(MachSafePoint)
   DEFINE_CLASS_QUERY(MachSpillCopy)
--- a/src/hotspot/share/opto/output.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/output.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -71,14 +71,12 @@
   const StartNode *start = entry->head()->as_Start();
 
   // Replace StartNode with prolog
-  Label verified_entry;
-  MachPrologNode* prolog = new MachPrologNode(&verified_entry);
+  MachPrologNode *prolog = new MachPrologNode();
   entry->map_node(prolog, 0);
   _cfg->map_node_to_block(prolog, entry);
   _cfg->unmap_node_from_block(start); // start is no longer in any block
 
   // Virtual methods need an unverified entry point
-  bool has_value_args = _method != NULL && _method->get_Method()->has_value_args();
   if (is_osr_compilation()) {
     if (PoisonOSREntry) {
       // TODO: Should use a ShouldNotReachHereNode...
@@ -89,11 +87,6 @@
       // Insert unvalidated entry point
       _cfg->insert(broot, 0, new MachUEPNode());
     }
-    if (has_value_args) {
-      // Insert value type entry point
-      assert(EnableValhalla, "Value types should be enabled");
-      _cfg->insert(broot, 0, new MachVVEPNode(&verified_entry));
-    }
   }
 
   // Break before main entry point
@@ -129,18 +122,6 @@
     return;
   }
 
-  if (!is_osr_compilation() && has_value_args) {
-    // We added an entry point for value types,
-    // compute offset of "normal" entry point
-    _code_offsets.set_value(CodeOffsets::Verified_Value_Entry, 0);
-    uint entry_offset = -1; // will be patched later
-    if (!_method->flags().is_static()) {
-      MachVVEPNode* vvep = (MachVVEPNode*)broot->get_node(0);
-      entry_offset = vvep->size(_regalloc);
-    }
-    _code_offsets.set_value(CodeOffsets::Entry, entry_offset);
-  }
-
   ScheduleAndBundle();
 
 #ifndef PRODUCT
--- a/src/hotspot/share/opto/parse1.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/parse1.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -610,13 +610,10 @@
     Node* parm = map()->in(i);
     const Type* t = _gvn.type(parm);
     if (!ValueTypePassFieldsAsArgs) {
-      if (t->is_valuetypeptr()) {
+      if (t->is_valuetypeptr() && t->value_klass()->is_scalarizable() && !t->maybe_null()) {
         // Create ValueTypeNode from the oop and replace the parameter
-        assert(!t->maybe_null(), "value type arguments should never be null");
-        if (t->value_klass()->is_scalarizable()) {
-          Node* vt = ValueTypeNode::make_from_oop(this, parm, t->value_klass());
-          map()->replace_edge(parm, vt);
-        }
+        Node* vt = ValueTypeNode::make_from_oop(this, parm, t->value_klass());
+        map()->replace_edge(parm, vt);
       }
     } else {
       assert(false, "FIXME");
@@ -826,9 +823,8 @@
       ret_type = TypeOopPtr::BOTTOM;
     }
     if ((_caller->has_method() || tf()->returns_value_type_as_fields()) &&
-        ret_type->is_valuetypeptr() && ret_type->value_klass()->is_scalarizable()) {
-      // When inlining or with multiple return values: return value
-      // type as ValueTypeNode not as oop
+        ret_type->is_valuetypeptr() && ret_type->value_klass()->is_scalarizable() && !ret_type->maybe_null()) {
+      // Scalarize value type return when inlining or with multiple return values
       ret_type = TypeValueType::make(ret_type->value_klass());
     }
     int         ret_size = type2size[ret_type->basic_type()];
@@ -1744,13 +1740,7 @@
           // Allocate value type in src block to be able to merge it with oop in target block
           map()->set_req(j, ValueTypePtrNode::make_from_value_type(this, n->as_ValueType(), true));
         }
-        if ((t->isa_valuetype() || t->is_valuetypeptr()) && !n->is_ValueType() && gvn().type(n)->maybe_null()) {
-          assert(n->bottom_type()->remove_speculative() == TypePtr::NULL_PTR, "Anything other than null?");
-          uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-          assert(stopped(), "should be a dead path now");
-          set_parse_bci(old_bci);
-          return;
-        }
+        assert(!t->isa_valuetype() || n->is_ValueType(), "inconsistent typeflow info");
       }
     }
   }
@@ -2360,8 +2350,8 @@
   if (value != NULL) {
     Node* phi = _exits.argument(0);
     const TypeOopPtr* tr = phi->bottom_type()->isa_oopptr();
-    if (value->is_ValueType() && (!_caller->has_method() || (tr && tr->is_valuetypeptr()))) {
-      // Value type is returned as oop, make sure it's allocated
+    if (value->is_ValueType() && !_caller->has_method()) {
+      // Value type is returned as oop from root method, make sure it's allocated
       value = value->as_ValueType()->allocate(this)->get_oop();
     } else if (tr && tr->isa_instptr() && tr->klass()->is_loaded() && tr->klass()->is_interface()) {
       // If returning oops to an interface-return, there is a silent free
@@ -2374,13 +2364,6 @@
         }
         value = _gvn.transform(new CheckCastPPNode(0, value, tr));
       }
-    } else if ((phi->bottom_type()->isa_valuetype() || phi->bottom_type()->is_valuetypeptr())
-               && !value->is_ValueType() && gvn().type(value)->maybe_null()) {
-      assert(value->bottom_type()->remove_speculative() == TypePtr::NULL_PTR, "Anything other than null?");
-      inc_sp(1);
-      uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-      dec_sp(1);
-      return;
     } else {
       // Handle returns of oop-arrays to an arrays-of-interface return
       const TypeInstPtr* phi_tip;
--- a/src/hotspot/share/opto/parse2.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/parse2.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -184,29 +184,23 @@
     const Type* val_t = _gvn.type(val);
     if (elemtype->isa_valuetype() != NULL) {
       // Store to flattened value type array
-      val_t = _gvn.type(cast_val);
       if (!cast_val->is_ValueType()) {
-        if (val_t->maybe_null()) {
-          // Can not store null into a value type array
-          assert(val_t == TypePtr::NULL_PTR, "Anything other than null?");
-          inc_sp(3);
-          uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-          return;
-        }
-        assert(!val_t->maybe_null(), "should never be null");
+        inc_sp(3);
+        cast_val = null_check(cast_val);
+        if (stopped()) return;
+        dec_sp(3);
         cast_val = ValueTypeNode::make_from_oop(this, cast_val, elemtype->is_valuetype()->value_klass());
       }
       cast_val->as_ValueType()->store_flattened(this, ary, adr);
       return;
     } else if (elemptr->is_valuetypeptr()) {
       // Store to non-flattened value type array
-      val_t = _gvn.type(cast_val);
-      if (!cast_val->is_ValueType() && val_t->maybe_null()) {
+      if (!cast_val->is_ValueType()) {
         // Can not store null into a value type array
-        assert(val_t == TypePtr::NULL_PTR, "Anything other than null?");
         inc_sp(3);
-        uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-        return;
+        cast_val = null_check(cast_val);
+        if (stopped()) return;
+        dec_sp(3);
       }
     } else if (elemptr->can_be_value_type() && !ary_t->klass_is_exact() &&
                (val->is_ValueType() || val_t == TypePtr::NULL_PTR || val_t->is_oopptr()->can_be_value_type())) {
@@ -241,12 +235,17 @@
           } else {
             if (TypePtr::NULL_PTR->higher_equal(val_t)) {
               sync_kit(ideal);
-              inc_sp(3);
-              val = filter_null(val);
-              dec_sp(3);
+              Node* null_ctl = top();
+              val = null_check_oop(val, &null_ctl);
+              if (null_ctl != top()) {
+                PreserveJVMState pjvms(this);
+                inc_sp(3);
+                set_control(null_ctl);
+                uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
+                dec_sp(3);
+              }
               ideal.sync_kit(this);
             }
-
             if (!ideal.ctrl()->is_top()) {
               ideal.make_leaf_call(OptoRuntime::store_unknown_value_Type(),
                                    CAST_FROM_FN_PTR(address, OptoRuntime::store_unknown_value),
--- a/src/hotspot/share/opto/parse3.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/parse3.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -230,12 +230,12 @@
     DecoratorSet decorators = IN_HEAP;
     decorators |= is_vol ? MO_SEQ_CST : MO_UNORDERED;
     ld = access_load_at(obj, adr, adr_type, type, bt, decorators);
-    if (bt == T_VALUETYPE) {
-      // Load a non-flattened value type from memory
+    if (flattenable) {
+      // Load a non-flattened but flattenable value type from memory
       if (field_klass->as_value_klass()->is_scalarizable()) {
-        ld = ValueTypeNode::make_from_oop(this, ld, field_klass->as_value_klass(), /* null2default */ flattenable, iter().next_bci());
-      } else if (gvn().type(ld)->maybe_null()){
-        ld = filter_null(ld, flattenable, field_klass->as_value_klass(), iter().next_bci());
+        ld = ValueTypeNode::make_from_oop(this, ld, field_klass->as_value_klass());
+      } else {
+        ld = null2default(ld, field_klass->as_value_klass());
       }
     }
   }
@@ -296,20 +296,20 @@
       field_type = Type::BOTTOM;
     }
   }
-  if (field->is_flattenable() && !val->is_ValueType() && gvn().type(val)->maybe_null()) {
-    // We can see a null constant here
-    assert(val->bottom_type()->remove_speculative() == TypePtr::NULL_PTR, "Anything other than null?");
-    push(null());
-    uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-    assert(stopped(), "dead path");
-    return;
-  } else if (field->is_flattened()) {
+
+  if (field->is_flattenable() && !val->is_ValueType()) {
+    inc_sp(1);
+    val = null_check(val);
+    dec_sp(1);
+    if (stopped()) return;
+  }
+
+  if (field->is_flattened()) {
+    // Store flattened value type to a non-static field
     if (!val->is_ValueType()) {
       assert(!gvn().type(val)->maybe_null(), "should never be null");
       val = ValueTypeNode::make_from_oop(this, val, field->type()->as_value_klass());
     }
-    // Store flattened value type to a non-static field
-    assert(bt == T_VALUETYPE, "flattening is only supported for value type fields");
     val->as_ValueType()->store_flattened(this, obj, obj, field->holder(), offset);
   } else {
     access_store_at(control(), obj, adr, adr_type, val, field_type, bt, decorators);
--- a/src/hotspot/share/opto/parseHelper.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/parseHelper.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -355,15 +355,23 @@
   Node* holder = pop();
 
   if (!holder->is_ValueType()) {
-    assert(!gvn().type(holder)->maybe_null(), "should never be null");
+    // Null check and scalarize value type holder
     inc_sp(2);
+    holder = null_check(holder);
+    dec_sp(2);
+    if (stopped()) return;
     holder = ValueTypeNode::make_from_oop(this, holder, holder_klass);
-    if (field->is_flattenable() && !val->is_ValueType() && gvn().type(val)->maybe_null()) {
-      assert(val->bottom_type()->remove_speculative() == TypePtr::NULL_PTR, "Anything other than null?");
-      uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-      return;
-    }
+  }
+  if (!val->is_ValueType() && field->is_flattenable()) {
+    // Null check and scalarize value type field value
+    inc_sp(2);
+    val = null_check(val);
     dec_sp(2);
+    if (stopped()) return;
+    val = ValueTypeNode::make_from_oop(this, val, gvn().type(val)->value_klass());
+  } else if (val->is_ValueType() && !field->is_flattenable()) {
+    // Non-flattenable field should not be scalarized
+    val = ValueTypePtrNode::make_from_value_type(this, val->as_ValueType());
   }
 
   // Clone the value type node and set the new field value
--- a/src/hotspot/share/opto/type.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/type.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -265,13 +265,15 @@
     assert(type->is_return_address(), "");
     return TypeRawPtr::make((address)(intptr_t)type->as_return_address()->bci());
 
-  case T_VALUETYPE:
-    if (type->as_value_klass()->is_scalarizable()) {
-      return TypeValueType::make(type->as_value_klass());
+  case T_VALUETYPE: {
+    bool is_never_null = type->is_never_null();
+    ciValueKlass* vk = type->unwrap()->as_value_klass();
+    if (vk->is_scalarizable() && is_never_null) {
+      return TypeValueType::make(vk);
     } else {
-      // Value types cannot be null
-      return TypeOopPtr::make_from_klass(type->as_klass())->join_speculative(TypePtr::NOTNULL);
+      return TypeOopPtr::make_from_klass(vk)->join_speculative(is_never_null ? TypePtr::NOTNULL : TypePtr::BOTTOM);
     }
+  }
 
   default:
     // make sure we did not mix up the cases:
@@ -1940,13 +1942,12 @@
 
 //------------------------------make-------------------------------------------
 // Make a TypeTuple from the range of a method signature
-const TypeTuple *TypeTuple::make_range(ciMethod* method, bool ret_vt_fields) {
-  ciSignature* sig = method->signature();
+const TypeTuple *TypeTuple::make_range(ciSignature* sig, bool ret_vt_fields) {
   ciType* return_type = sig->return_type();
-  return make_range(method, return_type, ret_vt_fields);
-}
-
-const TypeTuple *TypeTuple::make_range(ciMethod* method, ciType* return_type, bool ret_vt_fields) {
+  return make_range(return_type, sig->returns_never_null(), ret_vt_fields);
+}
+
+const TypeTuple *TypeTuple::make_range(ciType* return_type, bool never_null, bool ret_vt_fields) {
   uint arg_cnt = 0;
   if (ret_vt_fields) {
     ret_vt_fields = return_type->is_valuetype() && ((ciValueKlass*)return_type)->can_be_returned_as_fields();
@@ -1986,15 +1987,7 @@
       pos++;
       collect_value_fields(vk, field_array, pos);
     } else {
-      if (method->get_Method()->is_returning_vt()) {
-        // A NULL ValueType cannot be returned to compiled code. The 'areturn' bytecode
-        // handler will deoptimize its caller if it is about to return a NULL ValueType.
-        field_array[TypeFunc::Parms] = get_const_type(return_type)->join_speculative(TypePtr::NOTNULL);
-      } else {
-        // We're calling a legacy class's method that is returning a VT but doesn't know about it, so
-        // it won't do the deoptimization at 'areturn'.
-        field_array[TypeFunc::Parms] = get_const_type(return_type);
-      }
+      field_array[TypeFunc::Parms] = get_const_type(return_type)->join_speculative(never_null ? TypePtr::NOTNULL : TypePtr::BOTTOM);
     }
     break;
   case T_VOID:
@@ -2074,8 +2067,7 @@
         ciValueKlass* vk = (ciValueKlass*)type;
         collect_value_fields(vk, field_array, pos);
       } else {
-        // Value type arguments cannot be NULL
-        field_array[pos++] = get_const_type(type)->join_speculative(TypePtr::NOTNULL);
+        field_array[pos++] = get_const_type(type)->join_speculative(sig->is_never_null_at(i) ? TypePtr::NOTNULL : TypePtr::BOTTOM);
       }
       break;
     }
@@ -5621,8 +5613,8 @@
     domain_sig = TypeTuple::make_domain(method->holder(), method->signature(), false);
     domain_cc = TypeTuple::make_domain(method->holder(), method->signature(), ValueTypePassFieldsAsArgs);
   }
-  const TypeTuple *range_sig = TypeTuple::make_range(method, false);
-  const TypeTuple *range_cc = TypeTuple::make_range(method, ValueTypeReturnedAsFields);
+  const TypeTuple *range_sig = TypeTuple::make_range(method->signature(), false);
+  const TypeTuple *range_cc = TypeTuple::make_range(method->signature(), ValueTypeReturnedAsFields);
   tf = TypeFunc::make(domain_sig, domain_cc, range_sig, range_cc);
   C->set_last_tf(method, tf);  // fill cache
   return tf;
--- a/src/hotspot/share/opto/type.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/type.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -690,11 +690,8 @@
   }
 
   static const TypeTuple *make( uint cnt, const Type **fields );
-  static const TypeTuple *make_range(ciMethod *method, bool ret_vt_fields = false);
-  static const TypeTuple *make_range(ciMethod *method, ciType *ret_type, bool ret_vt_fields = false);
-  static const TypeTuple *make_range(ciType *ret_type, bool ret_vt_fields = false) {
-    return make_range(NULL, ret_type, ret_vt_fields);
-  }
+  static const TypeTuple *make_range(ciSignature* sig, bool ret_vt_fields = false);
+  static const TypeTuple *make_range(ciType* return_type, bool never_null = false, bool ret_vt_fields = false);
   static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig, bool vt_fields_as_args = false);
 
   // Subroutine call type with space allocated for argument types
--- a/src/hotspot/share/opto/valuetypenode.cpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/valuetypenode.cpp	Wed Oct 24 14:25:20 2018 +0200
@@ -317,7 +317,7 @@
   return adr_type;
 }
 
-void ValueTypeBaseNode::load(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset, int trap_bci) {
+void ValueTypeBaseNode::load(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
   // Initialize the value type by loading its field values from
   // memory and adding the values as input edges to the node.
   for (uint i = 0; i < field_count(); ++i) {
@@ -353,12 +353,12 @@
         }
         value = kit->access_load_at(base, adr, adr_type, val_type, bt, decorators);
       }
-      if (ft->is_valuetype()) {
-        // Loading a non-flattened value type from memory
+      if (field_is_flattenable(i)) {
+        // Loading a non-flattened but flattenable value type from memory
         if (ft->as_value_klass()->is_scalarizable()) {
-          value = ValueTypeNode::make_from_oop(kit, value, ft->as_value_klass(), /* null2default */ field_is_flattenable(i), trap_bci);
+          value = ValueTypeNode::make_from_oop(kit, value, ft->as_value_klass());
         } else {
-          value = kit->filter_null(value, field_is_flattenable(i), ft->as_value_klass(), trap_bci);
+          value = kit->null2default(value, ft->as_value_klass());
         }
       }
     }
@@ -540,41 +540,33 @@
   return true;
 }
 
-ValueTypeNode* ValueTypeNode::make_from_oop(GraphKit* kit, Node* oop, ciValueKlass* vk, bool null2default, int trap_bci) {
+ValueTypeNode* ValueTypeNode::make_from_oop(GraphKit* kit, Node* oop, ciValueKlass* vk) {
   PhaseGVN& gvn = kit->gvn();
-  const TypePtr* oop_type = gvn.type(oop)->is_ptr();
-  bool null_check = oop_type->maybe_null();
 
   // Create and initialize a ValueTypeNode by loading all field
   // values from a heap-allocated version and also save the oop.
   ValueTypeNode* vt = new ValueTypeNode(vk, oop);
 
-  if (null_check) {
+  if (oop->isa_ValueTypePtr()) {
+    // Can happen with late inlining
+    ValueTypePtrNode* vtptr = oop->as_ValueTypePtr();
+    vt->set_oop(vtptr->get_oop());
+    for (uint i = Oop+1; i < vtptr->req(); ++i) {
+      vt->init_req(i, vtptr->in(i));
+    }
+  } else if (gvn.type(oop)->maybe_null()) {
     // Add a null check because the oop may be null
     Node* null_ctl = kit->top();
     Node* not_null_oop = kit->null_check_oop(oop, &null_ctl);
     if (kit->stopped()) {
       // Constant null
-      if (null2default) {
-        kit->set_control(null_ctl);
-        return make_default(gvn, vk);
-      } else {
-        int bci = kit->bci();
-        if (trap_bci != -1) {
-          // Put trap at different bytecode
-          kit->push(kit->null());
-          kit->set_bci(trap_bci);
-        }
-        kit->replace_in_map(oop, kit->null());
-        kit->uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-        kit->set_bci(bci);
-        return NULL;
-      }
+      kit->set_control(null_ctl);
+      return make_default(gvn, vk);
     }
     vt->set_oop(not_null_oop);
-    vt->load(kit, not_null_oop, not_null_oop, vk, /* holder_offset */ 0, trap_bci);
+    vt->load(kit, not_null_oop, not_null_oop, vk, /* holder_offset */ 0);
 
-    if (null2default && (null_ctl != kit->top())) {
+    if (null_ctl != kit->top()) {
       // Return default value type if oop is null
       ValueTypeNode* def = make_default(gvn, vk);
       Node* region = new RegionNode(3);
@@ -584,24 +576,11 @@
       vt = vt->clone_with_phis(&gvn, region)->as_ValueType();
       vt->merge_with(&gvn, def, 2, true);
       kit->set_control(gvn.transform(region));
-    } else if (null_ctl != kit->top()) {
-      // Deoptimize if oop is null
-      PreserveJVMState pjvms(kit);
-      kit->set_control(null_ctl);
-      int bci = kit->bci();
-      if (trap_bci != -1) {
-        // Put trap at different bytecode
-        kit->push(kit->null());
-        kit->set_bci(trap_bci);
-      }
-      kit->replace_in_map(oop, kit->null());
-      kit->uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none);
-      kit->set_bci(bci);
     }
   } else {
     // Oop can never be null
     Node* init_ctl = kit->control();
-    vt->load(kit, oop, oop, vk, /* holder_offset */ 0, trap_bci);
+    vt->load(kit, oop, oop, vk, /* holder_offset */ 0);
     assert(init_ctl != kit->control() || oop->is_Con() || oop->is_CheckCastPP() || oop->Opcode() == Op_ValueTypePtr ||
            vt->is_loaded(&gvn) == oop, "value type should be loaded");
   }
@@ -760,6 +739,14 @@
     // Use the pre-allocated oop for default value types
     set_oop(default_oop(*phase, value_klass()));
     return this;
+  } else if (oop->isa_ValueTypePtr()) {
+    // Can happen with late inlining
+    ValueTypePtrNode* vtptr = oop->as_ValueTypePtr();
+    set_oop(vtptr->get_oop());
+    for (uint i = Oop+1; i < vtptr->req(); ++i) {
+      set_req(i, vtptr->in(i));
+    }
+    return this;
   }
 
   if (!is_allocated(phase)) {
@@ -903,12 +890,6 @@
   return kit->gvn().transform(vtptr)->as_ValueTypePtr();
 }
 
-ValueTypePtrNode* ValueTypePtrNode::make_from_call(GraphKit* kit, ciValueKlass* vk, CallNode* call) {
-  ValueTypePtrNode* vtptr = new ValueTypePtrNode(vk, kit->zerocon(T_VALUETYPE));
-  vtptr->initialize(kit, call, vk);
-  return vtptr;
-}
-
 ValueTypePtrNode* ValueTypePtrNode::make_from_oop(GraphKit* kit, Node* oop) {
   // Create and initialize a ValueTypePtrNode by loading all field
   // values from a heap-allocated version and also save the oop.
--- a/src/hotspot/share/opto/valuetypenode.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/opto/valuetypenode.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -85,7 +85,7 @@
   // Store the field values to memory
   void store(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset = 0, bool deoptimize_on_exception = false) const;
   // Initialize the value type by loading its field values from memory
-  void load(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset = 0, int trap_bci = -1);
+  void load(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset = 0);
 
   // Allocates the value type (if not yet allocated)
   ValueTypeBaseNode* allocate(GraphKit* kit, bool deoptimize_on_exception = false);
@@ -121,7 +121,7 @@
   // Create with default field values
   static ValueTypeNode* make_default(PhaseGVN& gvn, ciValueKlass* vk);
   // Create and initialize by loading the field values from an oop
-  static ValueTypeNode* make_from_oop(GraphKit* kit, Node* oop, ciValueKlass* vk, bool null2default = true, int trap_bci = -1);
+  static ValueTypeNode* make_from_oop(GraphKit* kit, Node* oop, ciValueKlass* vk);
   // Create and initialize by loading the field values from a flattened field or array
   static ValueTypeNode* make_from_flattened(GraphKit* kit, ciValueKlass* vk, Node* obj, Node* ptr, ciInstanceKlass* holder = NULL, int holder_offset = 0);
   // Create and initialize with the inputs or outputs of a MultiNode (method entry or call)
@@ -160,8 +160,6 @@
 public:
   // Create and initialize with the values of a ValueTypeNode
   static ValueTypePtrNode* make_from_value_type(GraphKit* kit, ValueTypeNode* vt, bool deoptimize_on_exception = false);
-  // Create and initialize with the result values of a call
-  static ValueTypePtrNode* make_from_call(GraphKit* kit, ciValueKlass* vk, CallNode* call);
   // Create and initialize by loading the field values from an oop
   static ValueTypePtrNode* make_from_oop(GraphKit* kit, Node* oop);
 
--- a/src/hotspot/share/runtime/globals.hpp	Thu Oct 18 09:09:56 2018 +0200
+++ b/src/hotspot/share/runtime/globals.hpp	Wed Oct 24 14:25:20 2018 +0200
@@ -2659,6 +2659,9 @@
   develop(bool, ScalarizeValueTypes, true,                                  \
           "Scalarize value types in compiled code")                         \
                                                                             \
+  product(bool, NullableValueTypes, false,                                  \
+          "Treat all value types as nullable")                              \
+                                                                            \
   experimental(bool, UsePointerPerturbation, false,                         \
                "With value types, use the perturbation scheme for acmp")    \
 
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBasicFunctionality.java	Thu Oct 18 09:09:56 2018 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBasicFunctionality.java	Wed Oct 24 14:25:20 2018 +0200
@@ -166,7 +166,9 @@
     }
 
     // Merge value types created from two branches
-    @Test(failOn = ALLOC + STORE + TRAP)
+// TODO fix this once we can distinguish between nullable and non-nullable value types
+//    @Test(failOn = ALLOC + STORE + TRAP)
+    @Test()
     public long test8(boolean b) {
         MyValue1 v;
         if (b) {
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java	Thu Oct 18 09:09:56 2018 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java	Wed Oct 24 14:25:20 2018 +0200
@@ -39,7 +39,6 @@
  *          java.base/jdk.experimental.value
  * @library /testlibrary /test/lib /compiler/whitebox /
  * @requires os.simpleArch == "x64"
- * @build TestLWorld_mismatched
  * @compile -XDenableValueTypes -XDallowWithFieldOperator -XDallowFlattenabilityModifiers TestLWorld.java
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
@@ -63,7 +62,7 @@
     public static void main(String[] args) throws Throwable {
         TestLWorld test = new TestLWorld();
         test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, MyValue3.class,
-                 MyValue3Inline.class, Test65Value.class, TestLWorld_mismatched.class);
+                 MyValue3Inline.class, Test51Value.class, Test77Value.class);
     }
 
     // Helper methods
@@ -280,263 +279,9 @@
         Asserts.assertFalse(result);
     }
 
-    // Test correct handling of null-ness of value types
-
-    __NotFlattened MyValue1 nullField;
-
-    @Test
-    @Warmup(10000) // Warmup to make sure 'callTest7WithNull' is compiled
-    public long test7(MyValue1 vt) {
-        long result = 0;
-        try {
-            result = vt.hash();
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        return result;
-    }
-
-    private static final MethodHandle callTest7WithNull = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
-        "callTest7WithNull",
-        MethodType.methodType(void.class, TestLWorld.class),
-        CODE -> {
-            CODE.
-            aload_0().
-            aconst_null().
-            invokevirtual(TestLWorld.class, "test7", "(Lcompiler/valhalla/valuetypes/MyValue1;)J", false).
-            return_();
-        },
-        MyValue1.class);
-
-    @DontCompile
-    public void test7_verifier(boolean warmup) throws Throwable {
-        long result = (long)callTest7WithNull.invoke(this);
-        Asserts.assertEquals(result, 0L);
-    }
-
-    @Test
-    public long test8(MyValue1 vt) {
-        long result = 0;
-        try {
-            result = vt.hashInterpreted();
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        return result;
-    }
-
-    @DontCompile
-    public void test8_verifier(boolean warmup) {
-        long result = test8(nullField);
-        Asserts.assertEquals(result, 0L);
-    }
-
-    @Test
-    public long test9() {
-        long result = 0;
-        try {
-            if ((Object)nullField != null) {
-                throw new RuntimeException("nullField should be null");
-            }
-            result = nullField.hash();
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        return result;
-    }
-
-    @DontCompile
-    public void test9_verifier(boolean warmup) {
-        long result = test9();
-        Asserts.assertEquals(result, 0L);
-    }
-
-    @Test
-    public void test10() {
-        try {
-            valueField1 = nullField;
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-    }
-
-    @DontCompile
-    public void test10_verifier(boolean warmup) {
-        test10();
-    }
-
-    @Test
-    public MyValue1 test11(MyValue1 vt) {
-        try {
-            Object o = vt;
-            vt = (MyValue1)o;
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-
-        // Should not throw
-        vt = test11_dontinline(vt);
-        vt = test11_inline(vt);
-        return vt;
-    }
-
-    @DontCompile
-    public void test11_verifier(boolean warmup) {
-        MyValue1 vt = test11(nullField);
-        Asserts.assertEquals((Object)vt, null);
-    }
-
-    @DontInline
-    public MyValue1 test11_dontinline(MyValue1 vt) {
-        return vt;
-    }
-
-    @ForceInline
-    public MyValue1 test11_inline(MyValue1 vt) {
-        return vt;
-    }
-
-    @Test
-    public MyValue1 test12(Object obj) {
-        MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
-        try {
-            vt = (MyValue1)obj;
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        return vt;
-    }
-
-    @DontCompile
-    public void test12_verifier(boolean warmup) {
-        MyValue1 vt = test12(null);
-        Asserts.assertEquals(vt.hash(), hash());
-    }
-
-    private static final MethodHandle getNull = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
-        "getNull",
-        MethodType.methodType(MyValue1.class),
-        CODE -> {
-            CODE.
-            aconst_null().
-            areturn();
-        },
-        MyValue1.class);
-
-    @Test
-    public void test13() throws Throwable {
-        try {
-            valueField1 = (MyValue1)getNull.invoke();
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        nullField = (MyValue1)getNull.invoke(); // Should not throw
-    }
-
-    @DontCompile
-    public void test13_verifier(boolean warmup) throws Throwable {
-        test13();
-    }
-
-    // null constant
-    private static final MethodHandle setNull = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
-        "setNull",
-        MethodType.methodType(void.class, TestLWorld.class),
-        CODE -> {
-            CODE.
-            aload_0().
-            aconst_null().
-            putfield(TestLWorld.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
-            return_();
-        },
-        MyValue1.class);
-
-    @Test
-    public void test14() throws Throwable {
-        try {
-            setNull.invoke(this);
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-    }
-
-    @DontCompile
-    public void test14_verifier(boolean warmup) throws Throwable {
-        test14();
-    }
-
-    // merge of 2 values, one being null
-    @Test
-    public void test15(boolean flag1) {
-        MyValue1 v;
-        if (flag1) {
-            v = valueField1;
-        } else {
-            v = valueField5;
-        }
-        valueField1 = v;
-    }
-
-    @DontCompile
-    public void test15_verifier(boolean warmup) {
-        test15(true);
-        try {
-            test15(false);
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-    }
-
-    // null constant
-    private static final MethodHandle mergeNull = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
-        "mergeNull",
-        MethodType.methodType(void.class, TestLWorld.class, boolean.class),
-        CODE -> {
-            CODE.
-            iload_1().
-            iconst_0().
-            ifcmp(TypeTag.I, CondKind.EQ, "null").
-            aload_0().
-            getfield(TestLWorld.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
-            goto_("continue").
-            label("null").
-            aconst_null().
-            label("continue").
-            aload_0().
-            swap().
-            putfield(TestLWorld.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
-            return_();
-        },
-        MyValue1.class);
-
-    @Test
-    public void test16(boolean flag) throws Throwable {
-        mergeNull.invoke(this, flag);
-    }
-
-    @DontCompile
-    public void test16_verifier(boolean warmup) throws Throwable {
-        test16(true);
-        try {
-            test16(false);
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-    }
-
     // merge of value and non value
     @Test
-    public Object test17(boolean flag) {
+    public Object test7(boolean flag) {
         Object res = null;
         if (flag) {
             res = valueField1;
@@ -547,13 +292,13 @@
     }
 
     @DontCompile
-    public void test17_verifier(boolean warmup) {
-        test17(true);
-        test17(false);
+    public void test7_verifier(boolean warmup) {
+        test7(true);
+        test7(false);
     }
 
     @Test
-    public Object test18(boolean flag) {
+    public Object test8(boolean flag) {
         Object res = null;
         if (flag) {
             res = objectField1;
@@ -564,52 +309,14 @@
     }
 
     @DontCompile
-    public void test18_verifier(boolean warmup) {
-        test18(true);
-        test18(false);
-    }
-
-    // null constant
-    private static final MethodHandle mergeNull2 = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
-        "mergeNull2",
-        MethodType.methodType(void.class, TestLWorld.class, boolean.class),
-        CODE -> {
-            CODE.
-            iload_1().
-            iconst_0().
-            ifcmp(TypeTag.I, CondKind.EQ, "not_null").
-            aconst_null().
-            goto_("continue").
-            label("not_null").
-            aload_0().
-            getfield(TestLWorld.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
-            label("continue").
-            aload_0().
-            swap().
-            putfield(TestLWorld.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
-            return_();
-        },
-        MyValue1.class);
-
-    @Test
-    public void test19(boolean flag) throws Throwable {
-        mergeNull2.invoke(this, flag);
-    }
-
-    @DontCompile
-    public void test19_verifier(boolean warmup) throws Throwable {
-        test19(false);
-        try {
-            test19(true);
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
+    public void test8_verifier(boolean warmup) {
+        test8(true);
+        test8(false);
     }
 
     // merge of values in a loop, stored in an object local
     @Test
-    public Object test20() {
+    public Object test9() {
         Object o = valueField1;
         for (int i = 1; i < 100; i *= 2) {
             MyValue1 v = (MyValue1)o;
@@ -619,151 +326,67 @@
     }
 
     @DontCompile
-    public void test20_verifier(boolean warmup) {
-        test20();
+    public void test9_verifier(boolean warmup) {
+        test9();
     }
 
     // merge of values in an object local
-    public Object test21_helper() {
+    public Object test10_helper() {
         return valueField1;
     }
 
     @Test(failOn = ALLOC + LOAD + STORE)
-    public void test21(boolean flag) {
+    public void test10(boolean flag) {
         Object o = null;
         if (flag) {
             o = valueField1;
         } else {
-            o = test21_helper();
+            o = test10_helper();
         }
         valueField1 = (MyValue1)o;
     }
 
     @DontCompile
-    public void test21_verifier(boolean warmup) {
-        test21(true);
-        test21(false);
+    public void test10_verifier(boolean warmup) {
+        test10(true);
+        test10(false);
     }
 
-    // null return
-    int test_22_cnt;
-
-    @DontInline
-    public MyValue1 test22_helper() {
-        test_22_cnt++;
-        return valueField5;
-    }
-
-    @Test
-    public void test22() {
-        valueField1 = test22_helper();
-    }
-
-    @DontCompile
-    public void test22_verifier(boolean warmup) {
-        try {
-            test_22_cnt = 0;
-            test22();
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        if (test_22_cnt != 1) {
-            throw new RuntimeException("call executed twice");
-        }
-    }
-
-    // null return at virtual call
-    class A {
-        public MyValue1 test23_helper() {
-            return valueField5;
-        }
-    }
-
-    class B extends A {
-        public MyValue1 test23_helper() {
-            return valueField5;
-        }
-    }
-
-    class C extends A {
-        public MyValue1 test23_helper() {
-            return valueField5;
-        }
-    }
-
-    class D extends A {
-        public MyValue1 test23_helper() {
-            return valueField5;
-        }
-    }
-
-    @Test
-    public void test23(A a) {
-        valueField1 = a.test23_helper();
-    }
-
-    @DontCompile
-    public void test23_verifier(boolean warmup) {
-        A b = new B();
-        A c = new C();
-        A d = new D();
-        try {
-            test23(b);
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        try {
-            test23(c);
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        try {
-            test23(d);
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-    }
-
-
     // Interface tests
 
     @DontInline
-    public MyInterface test24_dontinline1(MyInterface o) {
+    public MyInterface test11_dontinline1(MyInterface o) {
         return o;
     }
 
     @DontInline
-    public MyValue1 test24_dontinline2(MyInterface o) {
+    public MyValue1 test11_dontinline2(MyInterface o) {
         return (MyValue1)o;
     }
 
     @ForceInline
-    public MyInterface test24_inline1(MyInterface o) {
+    public MyInterface test11_inline1(MyInterface o) {
         return o;
     }
 
     @ForceInline
-    public MyValue1 test24_inline2(MyInterface o) {
+    public MyValue1 test11_inline2(MyInterface o) {
         return (MyValue1)o;
     }
 
     @Test()
-    public MyValue1 test24() {
+    public MyValue1 test11() {
         MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
-        vt = (MyValue1)test24_dontinline1(vt);
-        vt =           test24_dontinline2(vt);
-        vt = (MyValue1)test24_inline1(vt);
-        vt =           test24_inline2(vt);
+        vt = (MyValue1)test11_dontinline1(vt);
+        vt =           test11_dontinline2(vt);
+        vt = (MyValue1)test11_inline1(vt);
+        vt =           test11_inline2(vt);
         return vt;
     }
 
     @DontCompile
-    public void test24_verifier(boolean warmup) {
-        Asserts.assertEQ(test24().hash(), hash());
+    public void test11_verifier(boolean warmup) {
+        Asserts.assertEQ(test11().hash(), hash());
     }
 
     // Test storing/loading value types to/from interface and value type fields
@@ -785,7 +408,7 @@
     }
 
     @Test()
-    public long test25(MyValue1 vt1, MyInterface vt2) {
+    public long test12(MyValue1 vt1, MyInterface vt2) {
         interfaceField1 = vt1;
         interfaceField2 = (MyValue1)vt2;
         interfaceField3 = MyValue1.createWithFieldsInline(rI, rL);
@@ -809,10 +432,10 @@
     }
 
     @DontCompile
-    public void test25_verifier(boolean warmup) {
+    public void test12_verifier(boolean warmup) {
         MyValue1 vt = testValue1;
         MyValue1 def = MyValue1.createDefaultDontInline();
-        long result = test25(vt, vt);
+        long result = test12(vt, vt);
         Asserts.assertEQ(result, 11*vt.hash() + 2*def.hashPrimitive());
     }
 
@@ -831,7 +454,7 @@
 
     // Test merging value types and interfaces
     @Test()
-    public MyInterface test26(int state) {
+    public MyInterface test13(int state) {
         MyInterface res = null;
         if (state == 0) {
             res = new MyObject(rI);
@@ -850,26 +473,26 @@
     }
 
     @DontCompile
-    public void test26_verifier(boolean warmup) {
+    public void test13_verifier(boolean warmup) {
         objectField1 = valueField1;
         MyInterface result = null;
-        result = test26(0);
+        result = test13(0);
         Asserts.assertEQ(((MyObject)result).x, rI);
-        result = test26(1);
+        result = test13(1);
         Asserts.assertEQ(((MyValue1)result).hash(), hash());
-        result = test26(2);
+        result = test13(2);
         Asserts.assertEQ(((MyValue1)result).hash(), hash());
-        result = test26(3);
+        result = test13(3);
         Asserts.assertEQ(((MyValue1)result).hash(), hash());
-        result = test26(4);
+        result = test13(4);
         Asserts.assertEQ(((MyValue1)result).hash(), hash());
-        result = test26(5);
+        result = test13(5);
         Asserts.assertEQ(result, null);
     }
 
     // Test merging value types and interfaces in loops
     @Test()
-    public MyInterface test27(int iters) {
+    public MyInterface test14(int iters) {
         MyInterface res = new MyObject(rI);
         for (int i = 0; i < iters; ++i) {
             if (res instanceof MyObject) {
@@ -882,39 +505,39 @@
     }
 
     @DontCompile
-    public void test27_verifier(boolean warmup) {
-        MyObject result1 = (MyObject)test27(0);
+    public void test14_verifier(boolean warmup) {
+        MyObject result1 = (MyObject)test14(0);
         Asserts.assertEQ(result1.x, rI);
         int iters = (Math.abs(rI) % 10) + 1;
-        MyValue1 result2 = (MyValue1)test27(iters);
+        MyValue1 result2 = (MyValue1)test14(iters);
         MyValue1 vt = MyValue1.createWithFieldsInline(rI + iters - 1, rL);
         Asserts.assertEQ(result2.hash(), vt.hash());
     }
 
     // Test value types in interface variables that are live at safepoint
     @Test(failOn = ALLOC + STORE + LOOP)
-    public long test28(MyValue1 arg, boolean deopt) {
+    public long test15(MyValue1 arg, boolean deopt) {
         MyInterface vt1 = MyValue1.createWithFieldsInline(rI, rL);
         MyInterface vt2 = MyValue1.createWithFieldsDontInline(rI, rL);
         MyInterface vt3 = arg;
         MyInterface vt4 = valueField1;
         if (deopt) {
             // uncommon trap
-            WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test28"));
+            WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test15"));
         }
         return ((MyValue1)vt1).hash() + ((MyValue1)vt2).hash() +
                ((MyValue1)vt3).hash() + ((MyValue1)vt4).hash();
     }
 
     @DontCompile
-    public void test28_verifier(boolean warmup) {
-        long result = test28(valueField1, !warmup);
+    public void test15_verifier(boolean warmup) {
+        long result = test15(valueField1, !warmup);
         Asserts.assertEQ(result, 4*hash());
     }
 
     // Test comparing value types with interfaces
     @Test(failOn = ALLOC + LOAD + STORE + LOOP)
-    public boolean test29(Object arg) {
+    public boolean test16(Object arg) {
         MyInterface vt = MyValue1.createWithFieldsInline(rI, rL);
         if (vt == arg || vt == (MyInterface)valueField1 || vt == interfaceField1 || vt == null ||
             arg == vt || (MyInterface)valueField1 == vt || interfaceField1 == vt || null == vt) {
@@ -924,14 +547,14 @@
     }
 
     @DontCompile
-    public void test29_verifier(boolean warmup) {
-        boolean result = test29(null);
+    public void test16_verifier(boolean warmup) {
+        boolean result = test16(null);
         Asserts.assertFalse(result);
     }
 
     // Test subtype check when casting to value type
     @Test
-    public MyValue1 test30(MyValue1 vt, Object obj) {
+    public MyValue1 test17(MyValue1 vt, Object obj) {
         try {
             vt = (MyValue1)obj;
             throw new RuntimeException("ClassCastException expected");
@@ -942,28 +565,28 @@
     }
 
     @DontCompile
-    public void test30_verifier(boolean warmup) {
+    public void test17_verifier(boolean warmup) {
         MyValue1 vt = testValue1;
-        MyValue1 result = test30(vt, new Integer(rI));
+        MyValue1 result = test17(vt, new Integer(rI));
         Asserts.assertEquals(result.hash(), vt.hash());
     }
 
     @Test
-    public MyValue1 test31(MyValue1 vt) {
+    public MyValue1 test18(MyValue1 vt) {
         Object obj = vt;
         vt = (MyValue1)obj;
         return vt;
     }
 
     @DontCompile
-    public void test31_verifier(boolean warmup) {
+    public void test18_verifier(boolean warmup) {
         MyValue1 vt = testValue1;
-        MyValue1 result = test31(vt);
+        MyValue1 result = test18(vt);
         Asserts.assertEquals(result.hash(), vt.hash());
     }
 
     @Test
-    public void test32(MyValue1 vt) {
+    public void test19(MyValue1 vt) {
         Object obj = vt;
         try {
             MyValue2 vt2 = (MyValue2)obj;
@@ -974,12 +597,12 @@
     }
 
     @DontCompile
-    public void test32_verifier(boolean warmup) {
-        test32(valueField1);
+    public void test19_verifier(boolean warmup) {
+        test19(valueField1);
     }
 
     @Test
-    public void test33(MyValue1 vt) {
+    public void test20(MyValue1 vt) {
         Object obj = vt;
         try {
             Integer i = (Integer)obj;
@@ -990,11 +613,10 @@
     }
 
     @DontCompile
-    public void test33_verifier(boolean warmup) {
-        test33(valueField1);
+    public void test20_verifier(boolean warmup) {
+        test20(valueField1);
     }
 
-
     // Array tests
 
     private static final MyValue1[] testValue1Array = new MyValue1[] {testValue1,
@@ -1013,49 +635,49 @@
 
     // Test load from (flattened) value type array disguised as object array
     @Test()
-    public Object test34(Object[] oa, int index) {
+    public Object test21(Object[] oa, int index) {
         return oa[index];
     }
 
     @DontCompile
-    public void test34_verifier(boolean warmup) {
-        MyValue1 result = (MyValue1)test34(testValue1Array, Math.abs(rI) % 3);
+    public void test21_verifier(boolean warmup) {
+        MyValue1 result = (MyValue1)test21(testValue1Array, Math.abs(rI) % 3);
         Asserts.assertEQ(result.hash(), hash());
     }
 
     // Test load from (flattened) value type array disguised as interface array
     @Test()
-    public Object test35(MyInterface[] ia, int index) {
+    public Object test22(MyInterface[] ia, int index) {
         return ia[index];
     }
 
     @DontCompile
-    public void test35_verifier(boolean warmup) {
-        MyValue1 result = (MyValue1)test35(testValue1Array, Math.abs(rI) % 3);
+    public void test22_verifier(boolean warmup) {
+        MyValue1 result = (MyValue1)test22(testValue1Array, Math.abs(rI) % 3);
         Asserts.assertEQ(result.hash(), hash());
     }
 
     // Test value store to (flattened) value type array disguised as object array
 
     @ForceInline
-    public void test36_inline(Object[] oa, Object o, int index) {
+    public void test23_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test36(Object[] oa, MyValue1 vt, int index) {
-        test36_inline(oa, vt, index);
+    public void test23(Object[] oa, MyValue1 vt, int index) {
+        test23_inline(oa, vt, index);
     }
 
     @DontCompile
-    public void test36_verifier(boolean warmup) {
+    public void test23_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         MyValue1 vt = MyValue1.createWithFieldsInline(rI + 1, rL + 1);
-        test36(testValue1Array, vt, index);
+        test23(testValue1Array, vt, index);
         Asserts.assertEQ(testValue1Array[index].hash(), vt.hash());
         testValue1Array[index] = testValue1;
         try {
-            test36(testValue2Array, vt, index);
+            test23(testValue2Array, vt, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1064,20 +686,20 @@
     }
 
     @ForceInline
-    public void test37_inline(Object[] oa, Object o, int index) {
+    public void test24_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test37(Object[] oa, MyValue1 vt, int index) {
-        test37_inline(oa, vt, index);
+    public void test24(Object[] oa, MyValue1 vt, int index) {
+        test24_inline(oa, vt, index);
     }
 
     @DontCompile
-    public void test37_verifier(boolean warmup) {
+    public void test24_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test37(testIntegerArray, testValue1, index);
+            test24(testIntegerArray, testValue1, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1085,20 +707,20 @@
     }
 
     @ForceInline
-    public void test38_inline(Object[] oa, Object o, int index) {
+    public void test25_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test38(Object[] oa, MyValue1 vt, int index) {
-        test38_inline(oa, vt, index);
+    public void test25(Object[] oa, MyValue1 vt, int index) {
+        test25_inline(oa, vt, index);
     }
 
     @DontCompile
-    public void test38_verifier(boolean warmup) {
+    public void test25_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test38(null, testValue1, index);
+            test25(null, testValue1, index);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
@@ -1108,24 +730,24 @@
     // Test value store to (flattened) value type array disguised as interface array
 
     @ForceInline
-    public void test39_inline(MyInterface[] ia, MyInterface i, int index) {
+    public void test26_inline(MyInterface[] ia, MyInterface i, int index) {
         ia[index] = i;
     }
 
     @Test()
-    public void test39(MyInterface[] ia, MyValue1 vt, int index) {
-      test39_inline(ia, vt, index);
+    public void test26(MyInterface[] ia, MyValue1 vt, int index) {
+      test26_inline(ia, vt, index);
     }
 
     @DontCompile
-    public void test39_verifier(boolean warmup) {
+    public void test26_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         MyValue1 vt = MyValue1.createWithFieldsInline(rI + 1, rL + 1);
-        test39(testValue1Array, vt, index);
+        test26(testValue1Array, vt, index);
         Asserts.assertEQ(testValue1Array[index].hash(), vt.hash());
         testValue1Array[index] = testValue1;
         try {
-            test39(testValue2Array, vt, index);
+            test26(testValue2Array, vt, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1134,20 +756,20 @@
     }
 
     @ForceInline
-    public void test40_inline(MyInterface[] ia, MyInterface i, int index) {
+    public void test27_inline(MyInterface[] ia, MyInterface i, int index) {
         ia[index] = i;
     }
 
     @Test()
-    public void test40(MyInterface[] ia, MyValue1 vt, int index) {
-        test40_inline(ia, vt, index);
+    public void test27(MyInterface[] ia, MyValue1 vt, int index) {
+        test27_inline(ia, vt, index);
     }
 
     @DontCompile
-    public void test40_verifier(boolean warmup) {
+    public void test27_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test40(null, testValue1, index);
+            test27(null, testValue1, index);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
@@ -1157,23 +779,23 @@
     // Test object store to (flattened) value type array disguised as object array
 
     @ForceInline
-    public void test41_inline(Object[] oa, Object o, int index) {
+    public void test28_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test41(Object[] oa, Object o, int index) {
-        test41_inline(oa, o, index);
+    public void test28(Object[] oa, Object o, int index) {
+        test28_inline(oa, o, index);
     }
 
     @DontCompile
-    public void test41_verifier(boolean warmup) {
+    public void test28_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         MyValue1 vt1 = MyValue1.createWithFieldsInline(rI + 1, rL + 1);
-        test41(testValue1Array, vt1, index);
+        test28(testValue1Array, vt1, index);
         Asserts.assertEQ(testValue1Array[index].hash(), vt1.hash());
         try {
-            test41(testValue1Array, testValue2, index);
+            test28(testValue1Array, testValue2, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1183,20 +805,20 @@
     }
 
     @ForceInline
-    public void test42_inline(Object[] oa, Object o, int index) {
+    public void test29_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test42(Object[] oa, Object o, int index) {
-        test42_inline(oa, o, index);
+    public void test29(Object[] oa, Object o, int index) {
+        test29_inline(oa, o, index);
     }
 
     @DontCompile
-    public void test42_verifier(boolean warmup) {
+    public void test29_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test42(testValue2Array, testValue1, index);
+            test29(testValue2Array, testValue1, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1205,20 +827,20 @@
     }
 
     @ForceInline
-    public void test43_inline(Object[] oa, Object o, int index) {
+    public void test30_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test43(Object[] oa, Object o, int index) {
-        test43_inline(oa, o, index);
+    public void test30(Object[] oa, Object o, int index) {
+        test30_inline(oa, o, index);
     }
 
     @DontCompile
-    public void test43_verifier(boolean warmup) {
+    public void test30_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test43(testIntegerArray, testValue1, index);
+            test30(testIntegerArray, testValue1, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1228,23 +850,23 @@
     // Test value store to (flattened) value type array disguised as interface array
 
     @ForceInline
-    public void test44_inline(MyInterface[] ia, MyInterface i, int index) {
+    public void test31_inline(MyInterface[] ia, MyInterface i, int index) {
         ia[index] = i;
     }
 
     @Test()
-    public void test44(MyInterface[] ia, MyInterface i, int index) {
-        test44_inline(ia, i, index);
+    public void test31(MyInterface[] ia, MyInterface i, int index) {
+        test31_inline(ia, i, index);
     }
 
     @DontCompile
-    public void test44_verifier(boolean warmup) {
+    public void test31_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         MyValue1 vt1 = MyValue1.createWithFieldsInline(rI + 1, rL + 1);
-        test44(testValue1Array, vt1, index);
+        test31(testValue1Array, vt1, index);
         Asserts.assertEQ(testValue1Array[index].hash(), vt1.hash());
         try {
-            test44(testValue1Array, testValue2, index);
+            test31(testValue1Array, testValue2, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1254,20 +876,20 @@
     }
 
     @ForceInline
-    public void test45_inline(MyInterface[] ia, MyInterface i, int index) {
+    public void test32_inline(MyInterface[] ia, MyInterface i, int index) {
         ia[index] = i;
     }
 
     @Test()
-    public void test45(MyInterface[] ia, MyInterface i, int index) {
-        test45_inline(ia, i, index);
+    public void test32(MyInterface[] ia, MyInterface i, int index) {
+        test32_inline(ia, i, index);
     }
 
     @DontCompile
-    public void test45_verifier(boolean warmup) {
+    public void test32_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test45(testValue2Array, testValue1, index);
+            test32(testValue2Array, testValue1, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1277,20 +899,20 @@
     // Test writing null to a (flattened) value type array disguised as object array
 
     @ForceInline
-    public void test46_inline(Object[] oa, Object o, int index) {
+    public void test33_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test46(Object[] oa, Object o, int index) {
-        test46_inline(oa, o, index);
+    public void test33(Object[] oa, Object o, int index) {
+        test33_inline(oa, o, index);
     }
 
     @DontCompile
-    public void test46_verifier(boolean warmup) {
+    public void test33_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test46(testValue1Array, null, index);
+            test33(testValue1Array, null, index);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
@@ -1301,44 +923,20 @@
     // Test writing constant null to a (flattened) value type array disguised as object array
 
     @ForceInline
-    public void test47_inline(Object[] oa, Object o, int index) {
+    public void test34_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test47(Object[] oa, int index) {
-        test47_inline(oa, null, index);
+    public void test34(Object[] oa, int index) {
+        test34_inline(oa, null, index);
     }
 
     @DontCompile
-    public void test47_verifier(boolean warmup) {
+    public void test34_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test47(testValue1Array, index);
-            throw new RuntimeException("No NPE thrown");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-        Asserts.assertEQ(testValue1Array[index].hash(), hash());
-    }
-
-    // Test writing null to a (flattened) value type array
-
-    @ForceInline
-    public void test48_inline(Object[] oa, Object o, int index) {
-        oa[index] = o;
-    }
-
-    @Test()
-    public void test48(MyValue1[] va, int index) {
-        test48_inline(va, nullField, index);
-    }
-
-    @DontCompile
-    public void test48_verifier(boolean warmup) {
-        int index = Math.abs(rI) % 3;
-        try {
-            test48(testValue1Array, index);
+            test34(testValue1Array, index);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
@@ -1362,15 +960,15 @@
         MyValue1.class);
 
     @Test()
-    public void test49(MyValue1[] va, int index) throws Throwable {
+    public void test35(MyValue1[] va, int index) throws Throwable {
         setArrayElementNull.invoke(this, va, index);
     }
 
     @DontCompile
-    public void test49_verifier(boolean warmup) throws Throwable {
+    public void test35_verifier(boolean warmup) throws Throwable {
         int index = Math.abs(rI) % 3;
         try {
-            test49(testValue1Array, index);
+            test35(testValue1Array, index);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
@@ -1380,15 +978,15 @@
 
     // Test writing a value type to a null value type array
     @Test()
-    public void test50(MyValue1[] va, MyValue1 vt, int index) {
+    public void test36(MyValue1[] va, MyValue1 vt, int index) {
         va[index] = vt;
     }
 
     @DontCompile
-    public void test50_verifier(boolean warmup) {
+    public void test36_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         try {
-            test50(null, testValue1Array[index], index);
+            test36(null, testValue1Array[index], index);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
@@ -1398,23 +996,23 @@
     // Test incremental inlining
 
     @ForceInline
-    public void test51_inline(Object[] oa, Object o, int index) {
+    public void test37_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test51(MyValue1[] va, Object o, int index) {
-        test51_inline(va, o, index);
+    public void test37(MyValue1[] va, Object o, int index) {
+        test37_inline(va, o, index);
     }
 
     @DontCompile
-    public void test51_verifier(boolean warmup) {
+    public void test37_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         MyValue1 vt1 = MyValue1.createWithFieldsInline(rI + 1, rL + 1);
-        test51(testValue1Array, vt1, index);
+        test37(testValue1Array, vt1, index);
         Asserts.assertEQ(testValue1Array[index].hash(), vt1.hash());
         try {
-            test51(testValue1Array, testValue2, index);
+            test37(testValue1Array, testValue2, index);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1426,16 +1024,16 @@
     // Test merging of value type arrays
 
     @ForceInline
-    public Object[] test52_inline() {
+    public Object[] test38_inline() {
         return new MyValue1[42];
     }
 
     @Test()
-    public Object[] test52(Object[] oa, Object o, int i1, int i2, int num) {
+    public Object[] test38(Object[] oa, Object o, int i1, int i2, int num) {
         Object[] result = null;
         switch (num) {
         case 0:
-            result = test52_inline();
+            result = test38_inline();
             break;
         case 1:
             result = oa;
@@ -1462,47 +1060,47 @@
     }
 
     @DontCompile
-    public void test52_verifier(boolean warmup) {
+    public void test38_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         MyValue1[] va = new MyValue1[42];
-        Object[] result = test52(null, testValue1, index, index, 0);
+        Object[] result = test38(null, testValue1, index, index, 0);
         Asserts.assertEQ(((MyValue1)result[index]).hash(), testValue1.hash());
-        result = test52(testValue1Array, testValue1, index, index, 1);
+        result = test38(testValue1Array, testValue1, index, index, 1);
         Asserts.assertEQ(((MyValue1)result[index]).hash(), testValue1.hash());
-        result = test52(null, testValue1, index, index, 2);
+        result = test38(null, testValue1, index, index, 2);
         Asserts.assertEQ(((MyValue1)result[index]).hash(), testValue1.hash());
-        result = test52(null, testValue2, index, index, 3);
+        result = test38(null, testValue2, index, index, 3);
         Asserts.assertEQ(((MyValue2)result[index]).hash(), testValue2.hash());
         try {
-            result = test52(null, null, index, index, 3);
+            result = test38(null, null, index, index, 3);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
         }
-        result = test52(null, null, index, index, 4);
+        result = test38(null, null, index, index, 4);
         try {
-            result = test52(null, testValue1, index, index, 4);
+            result = test38(null, testValue1, index, index, 4);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
         }
         try {
-            result = test52(null, testValue1, index, index, 5);
+            result = test38(null, testValue1, index, index, 5);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
         }
-        result = test52(null, testValue1Array, index, index, 6);
+        result = test38(null, testValue1Array, index, index, 6);
         Asserts.assertEQ(((MyValue1[][])result)[index][index].hash(), testValue1.hash());
     }
 
     // Same as above but merging into Object instead of Object[]
     @Test()
-    public Object test53(Object oa, Object o, int i1, int i2, int num) {
+    public Object test39(Object oa, Object o, int i1, int i2, int num) {
         Object result = null;
         switch (num) {
         case 0:
-            result = test52_inline();
+            result = test38_inline();
             break;
         case 1:
             result = oa;
@@ -1543,47 +1141,47 @@
     }
 
     @DontCompile
-    public void test53_verifier(boolean warmup) {
+    public void test39_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
         MyValue1[] va = new MyValue1[42];
-        Object result = test53(null, testValue1, index, index, 0);
+        Object result = test39(null, testValue1, index, index, 0);
         Asserts.assertEQ(((MyValue1[])result)[index].hash(), testValue1.hash());
-        result = test53(testValue1Array, testValue1, index, index, 1);
+        result = test39(testValue1Array, testValue1, index, index, 1);
         Asserts.assertEQ(((MyValue1[])result)[index].hash(), testValue1.hash());
-        result = test53(null, testValue1, index, index, 2);
+        result = test39(null, testValue1, index, index, 2);
         Asserts.assertEQ(((MyValue1[])result)[index].hash(), testValue1.hash());
-        result = test53(null, testValue2, index, index, 3);
+        result = test39(null, testValue2, index, index, 3);
         Asserts.assertEQ(((MyValue2[])result)[index].hash(), testValue2.hash());
         try {
-            result = test53(null, null, index, index, 3);
+            result = test39(null, null, index, index, 3);
             throw new RuntimeException("No NPE thrown");
         } catch (NullPointerException e) {
             // Expected
         }
-        result = test53(null, null, index, index, 4);
+        result = test39(null, null, index, index, 4);
         try {
-            result = test53(null, testValue1, index, index, 4);
+            result = test39(null, testValue1, index, index, 4);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
         }
-        result = test53(null, testValue1, index, index, 5);
+        result = test39(null, testValue1, index, index, 5);
         Asserts.assertEQ(result, null);
-        result = test53(null, testValue1, index, index, 6);
+        result = test39(null, testValue1, index, index, 6);
         Asserts.assertEQ(((MyValue1)result).hash(), testValue1.hash());
-        result = test53(null, testValue1, index, index, 7);
+        result = test39(null, testValue1, index, index, 7);
         Asserts.assertEQ(((MyValue2)result).hash(), testValue2.hash());
-        result = test53(null, testValue1, index, index, 8);
+        result = test39(null, testValue1, index, index, 8);
         Asserts.assertEQ(((MyValue1)result).hash(), testValue1.hash());
-        result = test53(null, testValue1, index, index, 9);
+        result = test39(null, testValue1, index, index, 9);
         Asserts.assertEQ(((Integer)result), 42);
-        result = test53(null, testValue1Array, index, index, 10);
+        result = test39(null, testValue1Array, index, index, 10);
         Asserts.assertEQ(((MyValue1[][])result)[index][index].hash(), testValue1.hash());
     }
 
     // Test instanceof with value types and arrays
     @Test()
-    public long test54(Object o, int index) {
+    public long test40(Object o, int index) {
         if (o instanceof MyValue1) {
           return ((MyValue1)o).hashInterpreted();
         } else if (o instanceof MyValue1[]) {
@@ -1601,74 +1199,74 @@
     }
 
     @DontCompile
-    public void test54_verifier(boolean warmup) {
+    public void test40_verifier(boolean warmup) {
         int index = Math.abs(rI) % 3;
-        long result = test54(testValue1, 0);
+        long result = test40(testValue1, 0);
         Asserts.assertEQ(result, testValue1.hash());
-        result = test54(testValue1Array, index);
+        result = test40(testValue1Array, index);
         Asserts.assertEQ(result, testValue1.hash());
-        result = test54(testValue2, index);
+        result = test40(testValue2, index);
         Asserts.assertEQ(result, testValue2.hash());
-        result = test54(testValue2Array, index);
+        result = test40(testValue2Array, index);
         Asserts.assertEQ(result, testValue2.hash());
-        result = test54(testValue1Array2, index);
+        result = test40(testValue1Array2, index);
         Asserts.assertEQ(result, testValue1.hash());
-        result = test54(new Long(42), index);
+        result = test40(new Long(42), index);
         Asserts.assertEQ(result, 42L);
     }
 
     // Test for bug in Escape Analysis
     @DontInline
-    public void test55_dontinline(Object o) {
+    public void test41_dontinline(Object o) {
         Asserts.assertEQ(o, rI);
     }
 
     @Test()
-    public void test55() {
+    public void test41() {
         MyValue1[] vals = new MyValue1[] {testValue1};
-        test55_dontinline(vals[0].oa[0]);
-        test55_dontinline(vals[0].oa[0]);
+        test41_dontinline(vals[0].oa[0]);
+        test41_dontinline(vals[0].oa[0]);
     }
 
     @DontCompile
-    public void test55_verifier(boolean warmup) {
-        test55();
+    public void test41_verifier(boolean warmup) {
+        test41();
     }
 
     // Test for bug in Escape Analysis
-    private static __NotFlattened final MyValue1 test56VT1 = MyValue1.createWithFieldsInline(rI, rL);
-    private static __NotFlattened final MyValue1 test56VT2 = MyValue1.createWithFieldsInline(rI + 1, rL + 1);
+    private static __NotFlattened final MyValue1 test42VT1 = MyValue1.createWithFieldsInline(rI, rL);
+    private static __NotFlattened final MyValue1 test42VT2 = MyValue1.createWithFieldsInline(rI + 1, rL + 1);
 
     @Test()
-    public void test56() {
-        MyValue1[] vals = new MyValue1[] {test56VT1, test56VT2};
-        Asserts.assertEQ(vals[0].hash(), test56VT1.hash());
-        Asserts.assertEQ(vals[1].hash(), test56VT2.hash());
+    public void test42() {
+        MyValue1[] vals = new MyValue1[] {test42VT1, test42VT2};
+        Asserts.assertEQ(vals[0].hash(), test42VT1.hash());
+        Asserts.assertEQ(vals[1].hash(), test42VT2.hash());
     }
 
     @DontCompile
-    public void test56_verifier(boolean warmup) {
-        if (!warmup) test56(); // We need -Xcomp behavior
+    public void test42_verifier(boolean warmup) {
+        if (!warmup) test42(); // We need -Xcomp behavior
     }
 
     // Test for bug in Escape Analysis
     @Test()
-    public long test57(boolean deopt) {
-        MyValue1[] vals = new MyValue1[] {test56VT1, test56VT2};
+    public long test43(boolean deopt) {
+        MyValue1[] vals = new MyValue1[] {test42VT1, test42VT2};
 
         if (deopt) {
             // uncommon trap
-            WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test57"));
-            Asserts.assertEQ(vals[0].hash(), test56VT1.hash());
-            Asserts.assertEQ(vals[1].hash(), test56VT2.hash());
+            WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test43"));
+            Asserts.assertEQ(vals[0].hash(), test42VT1.hash());
+            Asserts.assertEQ(vals[1].hash(), test42VT2.hash());
         }
 
         return vals[0].hash();
     }
 
     @DontCompile
-    public void test57_verifier(boolean warmup) {
-        test57(!warmup);
+    public void test43_verifier(boolean warmup) {
+        test43(!warmup);
     }
 
     // Tests writing an array element with a (statically known) incompatible type
@@ -1686,15 +1284,15 @@
         MyValue1.class, MyValue2.class);
 
     @Test()
-    public void test58(MyValue1[] va, int index, MyValue2 v) throws Throwable {
+    public void test44(MyValue1[] va, int index, MyValue2 v) throws Throwable {
         setArrayElementIncompatible.invoke(this, va, index, v);
     }
 
     @DontCompile
-    public void test58_verifier(boolean warmup) throws Throwable {
+    public void test44_verifier(boolean warmup) throws Throwable {
         int index = Math.abs(rI) % 3;
         try {
-            test58(testValue1Array, index, testValue2);
+            test44(testValue1Array, index, testValue2);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1704,20 +1302,20 @@
 
     // Tests writing an array element with a (statically known) incompatible type
     @ForceInline
-    public void test59_inline(Object[] oa, Object o, int index) {
+    public void test45_inline(Object[] oa, Object o, int index) {
         oa[index] = o;
     }
 
     @Test()
-    public void test59(MyValue1[] va, int index, MyValue2 v) throws Throwable {
-        test59_inline(va, v, index);
+    public void test45(MyValue1[] va, int index, MyValue2 v) throws Throwable {
+        test45_inline(va, v, index);
     }
 
     @DontCompile
-    public void test59_verifier(boolean warmup) throws Throwable {
+    public void test45_verifier(boolean warmup) throws Throwable {
         int index = Math.abs(rI) % 3;
         try {
-            test59(testValue1Array, index, testValue2);
+            test45(testValue1Array, index, testValue2);
             throw new RuntimeException("No ArrayStoreException thrown");
         } catch (ArrayStoreException e) {
             // Expected
@@ -1727,68 +1325,68 @@
 
     // instanceof tests with values
     @Test
-    public boolean test60(MyValue1 vt) {
+    public boolean test46(MyValue1 vt) {
         Object obj = vt;
         return obj instanceof MyValue1;
     }
 
     @DontCompile
-    public void test60_verifier(boolean warmup) {
+    public void test46_verifier(boolean warmup) {
         MyValue1 vt = testValue1;
-        boolean result = test60(vt);
+        boolean result = test46(vt);
         Asserts.assertTrue(result);
     }
 
     @Test
-    public boolean test61(MyValue1 vt) {
+    public boolean test47(MyValue1 vt) {
         Object obj = vt;
         return obj instanceof MyValue2;
     }
 
     @DontCompile
-    public void test61_verifier(boolean warmup) {
+    public void test47_verifier(boolean warmup) {
         MyValue1 vt = testValue1;
-        boolean result = test61(vt);
+        boolean result = test47(vt);
         Asserts.assertFalse(result);
     }
 
     @Test
-    public boolean test62(Object obj) {
+    public boolean test48(Object obj) {
         return obj instanceof MyValue1;
     }
 
     @DontCompile
-    public void test62_verifier(boolean warmup) {
+    public void test48_verifier(boolean warmup) {
         MyValue1 vt = testValue1;
-        boolean result = test62(vt);
+        boolean result = test48(vt);
         Asserts.assertTrue(result);
     }
 
     @Test
-    public boolean test63(Object obj) {
+    public boolean test49(Object obj) {
         return obj instanceof MyValue2;
     }
 
     @DontCompile
-    public void test63_verifier(boolean warmup) {
+    public void test49_verifier(boolean warmup) {
         MyValue1 vt = testValue1;
-        boolean result = test63(vt);
+        boolean result = test49(vt);
         Asserts.assertFalse(result);
     }
 
     @Test
-    public boolean test64(Object obj) {
+    public boolean test50(Object obj) {
         return obj instanceof MyValue1;
     }
 
     @DontCompile
-    public void test64_verifier(boolean warmup) {
-        boolean result = test63(new Integer(42));
+    public void test50_verifier(boolean warmup) {
+        boolean result = test49(new Integer(42));
         Asserts.assertFalse(result);
     }
 
     // Value type with some non-flattened fields
-    value final class Test65Value {
+    value final class Test51Value {
         final Object objectField1 = null;
         final Object objectField2 = null;
         final Object objectField3 = null;
@@ -1802,7 +1400,7 @@
         final __Flattenable  MyValue1 valueField4;
         final __NotFlattened MyValue1 valueField5;
 
-        private Test65Value() {
+        private Test51Value() {
             valueField1 = testValue1;
             valueField2 = testValue1;
             valueField3 = testValue1;
@@ -1810,15 +1408,15 @@
             valueField5 = MyValue1.createDefaultDontInline();
         }
 
-        public Test65Value init() {
-            Test65Value vt = __WithField(this.valueField1, testValue1);
+        public Test51Value init() {
+            Test51Value vt = __WithField(this.valueField1, testValue1);
             vt = __WithField(vt.valueField2, testValue1);
             vt = __WithField(vt.valueField3, testValue1);
             return vt;
         }
 
         @ForceInline
-        public long test(Test65Value holder, MyValue1 vt1, Object vt2) {
+        public long test(Test51Value holder, MyValue1 vt1, Object vt2) {
             holder = __WithField(holder.objectField1, vt1);
             holder = __WithField(holder.objectField2, (MyValue1)vt2);
             holder = __WithField(holder.objectField3, testValue1);
@@ -1844,184 +1442,184 @@
 
     // Same as test2 but with field holder being a value type
     @Test()
-    public long test65(Test65Value holder, MyValue1 vt1, Object vt2) {
+    public long test51(Test51Value holder, MyValue1 vt1, Object vt2) {
         return holder.test(holder, vt1, vt2);
     }
 
     @DontCompile
-    public void test65_verifier(boolean warmup) {
+    public void test51_verifier(boolean warmup) {
         MyValue1 vt = testValue1;
         MyValue1 def = MyValue1.createDefaultDontInline();
-        Test65Value holder = Test65Value.default;
+        Test51Value holder = Test51Value.default;
         Asserts.assertEQ(testValue1.hash(), vt.hash());
         holder = holder.init();
         Asserts.assertEQ(holder.valueField1.hash(), vt.hash());
-        long result = test65(holder, vt, vt);
+        long result = test51(holder, vt, vt);
         Asserts.assertEQ(result, 9*vt.hash() + def.hashPrimitive());
     }
 
     // Access non-flattened, uninitialized value type field with value type holder
     @Test()
-    public void test66(Test65Value holder) {
+    public void test52(Test51Value holder) {
         if ((Object)holder.valueField5 != null) {
             throw new RuntimeException("Should be null");
         }
     }
 
     @DontCompile
-    public void test66_verifier(boolean warmup) {
-        Test65Value vt = Test65Value.default;
-        test66(vt);
+    public void test52_verifier(boolean warmup) {
+        Test51Value vt = Test51Value.default;
+        test52(vt);
     }
 
     // Merging value types of different types
     @Test()
-    public Object test67(Object o, boolean b) {
+    public Object test53(Object o, boolean b) {
         MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
         return b ? vt : o;
     }
 
     @DontCompile
-    public void test67_verifier(boolean warmup) {
-        test67(new Object(), false);
-        MyValue1 result = (MyValue1)test67(new Object(), true);
+    public void test53_verifier(boolean warmup) {
+        test53(new Object(), false);
+        MyValue1 result = (MyValue1)test53(new Object(), true);
         Asserts.assertEQ(result.hash(), hash());
     }
 
     @Test()
-    public Object test68(boolean b) {
+    public Object test54(boolean b) {
         MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
         return b ? vt : testValue2;
     }
 
     @DontCompile
-    public void test68_verifier(boolean warmup) {
-        MyValue1 result1 = (MyValue1)test68(true);
+    public void test54_verifier(boolean warmup) {
+        MyValue1 result1 = (MyValue1)test54(true);
         Asserts.assertEQ(result1.hash(), hash());
-        MyValue2 result2 = (MyValue2)test68(false);
+        MyValue2 result2 = (MyValue2)test54(false);
         Asserts.assertEQ(result2.hash(), testValue2.hash());
     }
 
     @Test()
-    public Object test69(boolean b) {
+    public Object test55(boolean b) {
         MyValue1 vt1 = MyValue1.createWithFieldsInline(rI, rL);
         MyValue2 vt2 = MyValue2.createWithFieldsInline(rI, true);
         return b ? vt1 : vt2;
     }
 
     @DontCompile
-    public void test69_verifier(boolean warmup) {
-        MyValue1 result1 = (MyValue1)test69(true);
+    public void test55_verifier(boolean warmup) {
+        MyValue1 result1 = (MyValue1)test55(true);
         Asserts.assertEQ(result1.hash(), hash());
-        MyValue2 result2 = (MyValue2)test69(false);
+        MyValue2 result2 = (MyValue2)test55(false);
         Asserts.assertEQ(result2.hash(), testValue2.hash());
     }
 
     // Test synchronization on value types
     @Test()
-    public void test70(Object vt) {
+    public void test56(Object vt) {
         synchronized (vt) {
-            throw new RuntimeException("test70 failed: synchronization on value type should not succeed");
+            throw new RuntimeException("test56 failed: synchronization on value type should not succeed");
         }
     }
 
     @DontCompile
-    public void test70_verifier(boolean warmup) {
+    public void test56_verifier(boolean warmup) {
         try {
-            test70(testValue1);
-            throw new RuntimeException("test70 failed: no exception thrown");
+            test56(testValue1);
+            throw new RuntimeException("test56 failed: no exception thrown");
         } catch (IllegalMonitorStateException ex) {
             // Expected
         }
     }
 
     @ForceInline
-    public void test71_inline(Object vt) {
+    public void test57_inline(Object vt) {
         synchronized (vt) {
-            throw new RuntimeException("test71 failed: synchronization on value type should not succeed");
+            throw new RuntimeException("test57 failed: synchronization on value type should not succeed");
         }
     }
 
     @Test()
-    public void test71(MyValue1 vt) {
-        test71_inline(vt);
+    public void test57(MyValue1 vt) {
+        test57_inline(vt);
     }
 
     @DontCompile
-    public void test71_verifier(boolean warmup) {
+    public void test57_verifier(boolean warmup) {
         try {
-            test71(testValue1);
-            throw new RuntimeException("test71 failed: no exception thrown");
+            test57(testValue1);
+            throw new RuntimeException("test57 failed: no exception thrown");
         } catch (IllegalMonitorStateException ex) {
             // Expected
         }
     }
 
     @ForceInline
-    public void test72_inline(Object vt) {
+    public void test58_inline(Object vt) {
         synchronized (vt) {
-            throw new RuntimeException("test72 failed: synchronization on value type should not succeed");
+            throw new RuntimeException("test58 failed: synchronization on value type should not succeed");
         }
     }
 
     @Test()
-    public void test72() {
+    public void test58() {
         MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
-        test72_inline(vt);
+        test58_inline(vt);
     }
 
     @DontCompile
-    public void test72_verifier(boolean warmup) {
+    public void test58_verifier(boolean warmup) {
         try {
-            test72();
-            throw new RuntimeException("test72 failed: no exception thrown");
+            test58();
+            throw new RuntimeException("test58 failed: no exception thrown");
         } catch (IllegalMonitorStateException ex) {
             // Expected
         }
     }
 
     @Test()
-    public void test73(Object o, boolean b) {
+    public void test59(Object o, boolean b) {
         MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
         Object sync = b ? vt : o;
         synchronized (sync) {
             if (b) {
-                throw new RuntimeException("test73 failed: synchronization on value type should not succeed");
+                throw new RuntimeException("test59 failed: synchronization on value type should not succeed");
             }
         }
     }
 
     @DontCompile
-    public void test73_verifier(boolean warmup) {
-        test73(new Object(), false);
+    public void test59_verifier(boolean warmup) {
+        test59(new Object(), false);
         try {
-            test73(new Object(), true);
-            throw new RuntimeException("test73 failed: no exception thrown");
+            test59(new Object(), true);
+            throw new RuntimeException("test59 failed: no exception thrown");
         } catch (IllegalMonitorStateException ex) {
             // Expected
         }
     }
 
     @Test()
-    public void test74(boolean b) {
+    public void test60(boolean b) {
         MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
         Object sync = b ? vt : testValue2;
         synchronized (sync) {
-            throw new RuntimeException("test74 failed: synchronization on value type should not succeed");
+            throw new RuntimeException("test60 failed: synchronization on value type should not succeed");
         }
     }
 
     @DontCompile
-    public void test74_verifier(boolean warmup) {
+    public void test60_verifier(boolean warmup) {
         try {
-            test74(false);
-            throw new RuntimeException("test74 failed: no exception thrown");
+            test60(false);
+            throw new RuntimeException("test60 failed: no exception thrown");
         } catch (IllegalMonitorStateException ex) {
             // Expected
         }
         try {
-            test74(true);
-            throw new RuntimeException("test74 failed: no exception thrown");
+            test60(true);
+            throw new RuntimeException("test60 failed: no exception thrown");
         } catch (IllegalMonitorStateException ex) {
             // Expected
         }
@@ -2029,169 +1627,169 @@
 
     // Test catching the IllegalMonitorStateException in compiled code
     @Test()
-    public void test75(Object vt) {
+    public void test61(Object vt) {
         boolean thrown = false;
         try {
             synchronized (vt) {
-                throw new RuntimeException("test75 failed: no exception thrown");
+                throw new RuntimeException("test61 failed: no exception thrown");
             }
         } catch (IllegalMonitorStateException ex) {
             thrown = true;
         }
         if (!thrown) {
-            throw new RuntimeException("test75 failed: no exception thrown");
+            throw new RuntimeException("test61 failed: no exception thrown");
         }
     }
 
     @DontCompile
-    public void test75_verifier(boolean warmup) {
-        test75(testValue1);
+    public void test61_verifier(boolean warmup) {
+        test61(testValue1);
     }
 
     @Test()
-    public void test76(Object o) {
+    public void test62(Object o) {
         try {
             synchronized (o) { }
         } catch (IllegalMonitorStateException ex) {
             // Expected
             return;
         }
-        throw new RuntimeException("test76 failed: no exception thrown");
+        throw new RuntimeException("test62 failed: no exception thrown");
     }
 
     @DontCompile
-    public void test76_verifier(boolean warmup) {
-        test76(testValue1);
+    public void test62_verifier(boolean warmup) {
+        test62(testValue1);
     }
 
     // Test synchronization without any instructions in the synchronized block
     @Test()
-    public void test77(Object o) {
+    public void test63(Object o) {
         synchronized (o) { }
     }
 
     @DontCompile
-    public void test77_verifier(boolean warmup) {
+    public void test63_verifier(boolean warmup) {
         try {
-            test77(testValue1);
+            test63(testValue1);
         } catch (IllegalMonitorStateException ex) {
             // Expected
             return;
         }
-        throw new RuntimeException("test77 failed: no exception thrown");
+        throw new RuntimeException("test63 failed: no exception thrown");
     }
 
     // type system test with interface and value type
     @ForceInline
-    public MyInterface test78_helper(MyValue1 vt) {
+    public MyInterface test64_helper(MyValue1 vt) {
         return vt;
     }
 
     @Test()
-    public MyInterface test78(MyValue1 vt) {
-        return test78_helper(vt);
+    public MyInterface test64(MyValue1 vt) {
+        return test64_helper(vt);
     }
 
     @DontCompile
-    public void test78_verifier(boolean warmup) {
-        test78(testValue1);
+    public void test64_verifier(boolean warmup) {
+        test64(testValue1);
     }
 
     // Array store tests
     @Test()
-    public void test79(Object[] array, MyValue1 vt) {
+    public void test65(Object[] array, MyValue1 vt) {
         array[0] = vt;
     }
 
     @DontCompile
-    public void test79_verifier(boolean warmup) {
+    public void test65_verifier(boolean warmup) {
         Object[] array = new Object[1];
-        test79(array, testValue1);
+        test65(array, testValue1);
         Asserts.assertEQ(((MyValue1)array[0]).hash(), testValue1.hash());
     }
 
     @Test()
-    public void test80(Object[] array, MyValue1 vt) {
+    public void test66(Object[] array, MyValue1 vt) {
         array[0] = vt;
     }
 
     @DontCompile
-    public void test80_verifier(boolean warmup) {
+    public void test66_verifier(boolean warmup) {
         MyValue1[] array = new MyValue1[1];
-        test80(array, testValue1);
+        test66(array, testValue1);
         Asserts.assertEQ(array[0].hash(), testValue1.hash());
     }
 
     @Test()
-    public void test81(Object[] array, Object vt) {
+    public void test67(Object[] array, Object vt) {
         array[0] = vt;
     }
 
     @DontCompile
-    public void test81_verifier(boolean warmup) {
+    public void test67_verifier(boolean warmup) {
         MyValue1[] array = new MyValue1[1];
-        test81(array, testValue1);
+        test67(array, testValue1);
         Asserts.assertEQ(array[0].hash(), testValue1.hash());
     }
 
     @Test()
-    public void test82(Object[] array, Integer o) {
+    public void test68(Object[] array, Integer o) {
         array[0] = o;
     }
 
     @DontCompile
-    public void test82_verifier(boolean warmup) {
+    public void test68_verifier(boolean warmup) {
         Integer[] array = new Integer[1];
-        test82(array, 1);
+        test68(array, 1);
         Asserts.assertEQ(array[0], Integer.valueOf(1));
     }
 
     // Test convertion between a value type and java.lang.Object without an allocation
     @ForceInline
-    public Object test83_sum(Object a, Object b) {
+    public Object test69_sum(Object a, Object b) {
         int sum = ((MyValue1)a).x + ((MyValue1)b).x;
         return MyValue1.setX(((MyValue1)a), sum);
     }
 
     @Test(failOn = ALLOC + STORE)
-    public int test83(Object[] array) {
+    public int test69(Object[] array) {
         MyValue1 result = MyValue1.createDefaultInline();
         for (int i = 0; i < array.length; ++i) {
-            result = (MyValue1)test83_sum(result, (MyValue1)array[i]);
+            result = (MyValue1)test69_sum(result, (MyValue1)array[i]);
         }
         return result.x;
     }
 
     @DontCompile
-    public void test83_verifier(boolean warmup) {
-        int result = test83(testValue1Array);
+    public void test69_verifier(boolean warmup) {
+        int result = test69(testValue1Array);
         Asserts.assertEQ(result, rI * testValue1Array.length);
     }
 
-    // Same as test84 but with an Interface
+    // Same as test70 but with an Interface
     @ForceInline
-    public MyInterface test84_sum(MyInterface a, MyInterface b) {
+    public MyInterface test70_sum(MyInterface a, MyInterface b) {
         int sum = ((MyValue1)a).x + ((MyValue1)b).x;
         return MyValue1.setX(((MyValue1)a), sum);
     }
 
     @Test(failOn = ALLOC + STORE)
-    public int test84(MyInterface[] array) {
+    public int test70(MyInterface[] array) {
         MyValue1 result = MyValue1.createDefaultInline();
         for (int i = 0; i < array.length; ++i) {
-            result = (MyValue1)test84_sum(result, (MyValue1)array[i]);
+            result = (MyValue1)test70_sum(result, (MyValue1)array[i]);
         }
         return result.x;
     }
 
     @DontCompile
-    public void test84_verifier(boolean warmup) {
-        int result = test84(testValue1Array);
+    public void test70_verifier(boolean warmup) {
+        int result = test70(testValue1Array);
         Asserts.assertEQ(result, rI * testValue1Array.length);
     }
 
     // Test that allocated value type is not used in non-dominated path
-    public MyValue1 test85_inline(Object obj) {
+    public MyValue1 test71_inline(Object obj) {
         MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
         try {
             vt = (MyValue1)obj;
@@ -2203,103 +1801,68 @@
     }
 
     @Test
-    public MyValue1 test85() {
-        return test85_inline(null);
+    public MyValue1 test71() {
+        return test71_inline(null);
     }
 
     @DontCompile
-    public void test85_verifier(boolean warmup) {
-        MyValue1 vt = test85();
+    public void test71_verifier(boolean warmup) {
+        MyValue1 vt = test71();
         Asserts.assertEquals(vt.hash(), hash());
     }
 
     // Test calling a method on an uninitialized value type
-    value final class Test86Value {
+    value final class Test72Value {
         final int x = 42;
         public int get() {
             return x;
         }
     }
 
-    // Make sure Test86Value is loaded but not initialized
-    public void unused(Test86Value vt) { }
+    // Make sure Test72Value is loaded but not initialized
+    public void unused(Test72Value vt) { }
 
     @Test
     @Warmup(0)
-    public int test86() {
-        Test86Value vt = Test86Value.default;
+    public int test72() {
+        Test72Value vt = Test72Value.default;
         return vt.get();
     }
 
     @DontCompile
-    public void test86_verifier(boolean warmup) {
-        int result = test86();
+    public void test72_verifier(boolean warmup) {
+        int result = test72();
         Asserts.assertEquals(result, 0);
     }
 
-    @DontInline
-    MyValue1 get_nullField() {
-        return nullField;
-    }
-
-    // A callees that returns a VT performs null check (and deoptimizes caller) before returning.
-    @Test(match = {"CallStaticJava.*TestLWorld::get_nullField compiler/valhalla/valuetypes/MyValue1:NotNull"}, matchCount = {2})
-    public void test87() {
-        try {
-            valueField1 = get_nullField();
-            throw new RuntimeException("NullPointerException expected");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-
-        nullField = get_nullField(); // should not throw
-    }
-
-    @DontCompile
-    public void test87_verifier(boolean warmup) {
-        test87();
-    }
-
-    // A callee that's not aware of VT may return a null to the caller. An
-    // explicit null check is needed in compiled code.
-    @Test(failOn = "CallStaticJava.*TestLWorld_mismatched::test88_callee compiler/valhalla/valuetypes/MyValue1:NotNull")
-    public void test88() {
-        TestLWorld_mismatched.test88();
-    }
-
-    @DontCompile
-    public void test88_verifier(boolean warmup) {
-        test88();
-    }
-
     // Tests for loading/storing unkown values
     @Test
-    public Object test89(Object[] va) {
+    public Object test73(Object[] va) {
         return va[0];
     }
 
     @DontCompile
-    public void test89_verifier(boolean warmup) {
-        MyValue1 vt = (MyValue1)test89(testValue1Array);
+    public void test73_verifier(boolean warmup) {
+        MyValue1 vt = (MyValue1)test73(testValue1Array);
         Asserts.assertEquals(testValue1Array[0].hash(), vt.hash());
     }
 
     @Test
-    public void test90(Object[] va, Object vt) {
+    public void test74(Object[] va, Object vt) {
         va[0] = vt;
     }
 
     @DontCompile
-    public void test90_verifier(boolean warmup) {
+    public void test74_verifier(boolean warmup) {
         MyValue1[] va = new MyValue1[1];
-        test90(va, testValue1);
+        test74(va, testValue1);
         Asserts.assertEquals(va[0].hash(), testValue1.hash());
     }
 
     // Verify that mixing instances and arrays with the clone api
     // doesn't break anything
     @Test
-    public Object test91(Object o) {
+    public Object test75(Object o) {
         MyValue1[] va = new MyValue1[1];
         Object[] next = va;
         Object[] arr = va;
@@ -2311,27 +1874,8 @@
     }
 
     @DontCompile
-    public void test91_verifier(boolean warmup) {
-        test91(42);
-    }
-
-    @DontInline
-    public boolean test92_dontinline(MyValue1 vt) {
-        return (Object)vt == null;
-    }
-
-    // Test c2c call passing null for a value type
-    @Test
-    @Warmup(10000) // Warmup to make sure 'test92_dontinline' is compiled
-    public boolean test92(Object arg) throws Exception {
-        Method test92method = getClass().getMethod("test92_dontinline", MyValue1.class);
-        return (boolean)test92method.invoke(this, arg);
-    }
-
-    @DontCompile
-    public void test92_verifier(boolean warmup) throws Exception {
-        boolean res = test92(null);
-        Asserts.assertTrue(res);
+    public void test75_verifier(boolean warmup) {
+        test75(42);
     }
 
     // Cast an Integer to a value type
@@ -2348,18 +1892,58 @@
 
     // Casting a null Integer to a value type should throw an exception
     @Test
-    public void test93(Integer i) throws Throwable {
+    public void test76(Integer i) throws Throwable {
         castIntegerToValue.invoke(this, i);
     }
 
     @DontCompile
-    public void test93_verifier(boolean warmup) throws Throwable {
+    public void test76_verifier(boolean warmup) throws Throwable {
         try {
-            test93(null);
+            test76(null);
 // TODO enable this once we've fixed the interpreter to throw a NPE
 //            throw new RuntimeException("ClassCastException expected");
         } catch (ClassCastException e) {
             // Expected
         }
     }
+
+    // Test writing null to a flattenable/non-flattenable value type field in a value type
+    value final class Test77Value {
+        final __NotFlattened MyValue1 valueField1;
+        final __Flattenable  MyValue1 valueField2;
+        final __NotFlattened MyValue1 alwaysNull;
+
+        private Test77Value() {
+            valueField1 = testValue1;
+            valueField2 = testValue1;
+            alwaysNull  = testValue1;
+        }
+
+        @ForceInline
+        public Test77Value test1() {
+            return __WithField(this.valueField1, alwaysNull); // Should not throw NPE
+        }
+
+        @ForceInline
+        public Test77Value test2() {
+            return __WithField(this.valueField2, alwaysNull); // Should throw NPE
+        }
+    }
+
+    @Test
+    public Test77Value test77(Test77Value vt) {
+        vt = vt.test1();
+        try {
+            vt = vt.test2();
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        return vt;
+    }
+
+    @DontCompile
+    public void test77_verifier(boolean warmup) {
+        test77(Test77Value.default);
+    }
 }
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld_mismatched.jasm	Thu Oct 18 09:09:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2018, 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.
- */
-
-// TestLWorld.java calls this class, but this class is not
-// aware that MyValue1 is a VT.
-
-package compiler/valhalla/valuetypes;
-
-super class TestLWorld_mismatched
-	version 48:0
-{
-
-
-Method "<init>":"()V"
-	stack 1 locals 1
-{
-		aload_0;
-		invokespecial	Method java/lang/Object."<init>":"()V";
-		return;
-}
-
-static Field x:"Lcompiler/valhalla/valuetypes/MyValue1;";
-
-@+compiler/valhalla/valuetypes/ForceInline { }
-static Method test88:"()V"
-	stack 1 locals 0
-{
-		invokestatic	Method test88_callee:"()Lcompiler/valhalla/valuetypes/MyValue1;";
-		putstatic	Field x:"Lcompiler/valhalla/valuetypes/MyValue1;";
-		return;
-}
-
-@+compiler/valhalla/valuetypes/DontInline { }
-static Method test88_callee:"()Lcompiler/valhalla/valuetypes/MyValue1;"
-	stack 1 locals 0
-{
-		aconst_null;
-		areturn;
-}
-
-} // end Class TestLWorld_mismatched
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java	Thu Oct 18 09:09:56 2018 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java	Wed Oct 24 14:25:20 2018 +0200
@@ -130,14 +130,6 @@
             test11_mh = MethodHandles.guardWithTest(test11_mh_test,
                                                     MethodHandles.dropArguments(test11_mh1, 0, MethodHandle.class),
                                                     MethodHandles.invoker(myvalue2_mt));
-
-            MethodType test12_mt = MethodType.methodType(void.class, MyValue1.class);
-            test12_mh1 = lookup.findStatic(clazz, "test12_target1", test12_mt);
-            test12_mh2 = lookup.findStatic(clazz, "test12_target2", test12_mt);
-
-            MethodType test13_mt = MethodType.methodType(void.class, MyValue1.class);
-            test13_mh1 = lookup.findStatic(clazz, "test13_target1", test13_mt);
-            test13_mh2 = lookup.findStatic(clazz, "test13_target2", test13_mt);
         } catch (NoSuchMethodException | IllegalAccessException e) {
             e.printStackTrace();
             throw new RuntimeException("Method handle lookup failed");
@@ -505,85 +497,4 @@
         boolean b = (test11_i % 100) == 0;
         Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+test11_i * (b ? 1 : -1), b).hash());
     }
-
-    static final MethodHandle test12_mh1;
-    static final MethodHandle test12_mh2;
-
-    __NotFlattened static MyValue1 nullValue;
-
-    @DontInline
-    static void test12_target1(MyValue1 vt) {
-        nullValue = vt;
-    }
-
-    @ForceInline
-    static void test12_target2(MyValue1 vt) {
-        nullValue = vt;
-    }
-
-    // Test passing null for a value type
-    @Test
-    @Warmup(11000) // Make sure lambda forms get compiled
-    public void test12() throws Throwable {
-        test12_mh1.invokeExact(nullValue);
-        test12_mh2.invokeExact(nullValue);
-    }
-
-    @DontCompile
-    public void test12_verifier(boolean warmup) {
-        try {
-            test12();
-        } catch (Throwable t) {
-            throw new RuntimeException("test12 failed", t);
-        }
-    }
-
-    static MethodHandle test13_mh1;
-    static MethodHandle test13_mh2;
-
-    @DontInline
-    static void test13_target1(MyValue1 vt) {
-        nullValue = vt;
-    }
-
-    @ForceInline
-    static void test13_target2(MyValue1 vt) {
-        nullValue = vt;
-    }
-
-    // Same as test12 but with non-final mh
-    @Test
-    @Warmup(11000) // Make sure lambda forms get compiled
-    public void test13() throws Throwable {
-        test13_mh1.invokeExact(nullValue);
-        test13_mh2.invokeExact(nullValue);
-    }
-
-    @DontCompile
-    public void test13_verifier(boolean warmup) {
-        try {
-            test13();
-        } catch (Throwable t) {
-            throw new RuntimeException("test13 failed", t);
-        }
-    }
-
-    // Same as test12/13 but with constant null
-    @Test
-    @Warmup(11000) // Make sure lambda forms get compiled
-    public void test14(MethodHandle mh) throws Throwable {
-        mh.invoke(null);
-    }
-
-    @DontCompile
-    public void test14_verifier(boolean warmup) {
-        try {
-            test14(test12_mh1);
-            test14(test12_mh2);
-            test14(test13_mh1);
-            test14(test13_mh2);
-        } catch (Throwable t) {
-            throw new RuntimeException("test14 failed", t);
-        }
-    }
 }
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java	Thu Oct 18 09:09:56 2018 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java	Wed Oct 24 14:25:20 2018 +0200
@@ -1385,6 +1385,7 @@
 
     protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
     protected static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+    protected static final boolean NullableValueTypes = (Boolean)WHITE_BOX.getVMFlag("NullableValueTypes");
 
     public void runTest(Method m, Object[] args, int warmup, int nullMode) throws Exception {
         Class<?>[] parameterTypes = m.getParameterTypes();
@@ -1397,6 +1398,9 @@
             if (args[i] != null && !parameterTypes[0].isInstance(args[i])) {
                 continue;
             }
+            if (args[i] == null && parameterTypes[0] == MyValue.class && !NullableValueTypes) {
+                continue;
+            }
             if (parameterCount == 1) {
                 // Null checks
                 System.out.print("Testing " + m.getName() + "(" + args[i] + ")");
@@ -1416,6 +1420,9 @@
                     if (args[j] != null && !parameterTypes[1].isInstance(args[j])) {
                         continue;
                     }
+                    if (args[j] == null && parameterTypes[1] == MyValue.class && !NullableValueTypes) {
+                        continue;
+                    }
                     System.out.print("Testing " + m.getName() + "(" + args[i] + ", " + args[j] + ")");
                     // Avoid acmp in the computation of the expected result!
                     boolean equal = (i == j) && (i != 3);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java	Wed Oct 24 14:25:20 2018 +0200
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+package compiler.valhalla.valuetypes;
+
+import java.lang.invoke.*;
+import java.lang.reflect.Method;
+
+import jdk.experimental.value.MethodHandleBuilder;
+import jdk.experimental.bytecode.MacroCodeBuilder;
+import jdk.experimental.bytecode.MacroCodeBuilder.CondKind;
+import jdk.experimental.bytecode.TypeTag;
+import jdk.test.lib.Asserts;
+
+/*
+ * @test
+ * @summary Test correct handling of nullable value types.
+ * @modules java.base/jdk.experimental.bytecode
+ *          java.base/jdk.experimental.value
+ * @library /testlibrary /test/lib /compiler/whitebox /
+ * @requires os.simpleArch == "x64"
+ * @compile -XDenableValueTypes -XDallowWithFieldOperator -XDallowFlattenabilityModifiers TestNullableValueTypes.java
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
+ * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
+ *                               -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla -XX:+NullableValueTypes
+ *                               compiler.valhalla.valuetypes.ValueTypeTest
+ *                               compiler.valhalla.valuetypes.TestNullableValueTypes
+ */
+public class TestNullableValueTypes extends ValueTypeTest {
+    // Extra VM parameters for some test scenarios. See ValueTypeTest.getVMParameters()
+    @Override
+    public String[] getExtraVMParameters(int scenario) {
+        switch (scenario) {
+        case 1: return new String[] {"-XX:-UseOptoBiasInlining"};
+        case 2: return new String[] {"-XX:-UseBiasedLocking"};
+        case 3: return new String[] {"-XX:-MonomorphicArrayCheck", "-XX:-UseBiasedLocking", "-XX:+ValueArrayFlatten"};
+        case 4: return new String[] {"-XX:-MonomorphicArrayCheck"};
+        }
+        return null;
+    }
+
+    public static void main(String[] args) throws Throwable {
+        TestNullableValueTypes test = new TestNullableValueTypes();
+        test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, Test17Value.class);
+    }
+
+    static {
+        try {
+            Class<?> clazz = TestNullableValueTypes.class;
+            ClassLoader loader = clazz.getClassLoader();
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+            MethodType test18_mt = MethodType.methodType(void.class, MyValue1.class);
+            test18_mh1 = lookup.findStatic(clazz, "test18_target1", test18_mt);
+            test18_mh2 = lookup.findStatic(clazz, "test18_target2", test18_mt);
+
+            MethodType test19_mt = MethodType.methodType(void.class, MyValue1.class);
+            test19_mh1 = lookup.findStatic(clazz, "test19_target1", test19_mt);
+            test19_mh2 = lookup.findStatic(clazz, "test19_target2", test19_mt);
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            e.printStackTrace();
+            throw new RuntimeException("Method handle lookup failed");
+        }
+    }
+
+    private static final MyValue1 testValue1 = MyValue1.createWithFieldsInline(rI, rL);
+    private static final MyValue1[] testValue1Array = new MyValue1[] {testValue1,
+                                                                      testValue1,
+                                                                      testValue1};
+
+    __NotFlattened MyValue1 nullField;
+    __Flattenable  MyValue1 valueField1 = testValue1;
+
+    @Test
+    @Warmup(10000) // Warmup to make sure 'callTest1WithNull' is compiled
+    public long test1(MyValue1 vt) {
+        long result = 0;
+        try {
+            result = vt.hash();
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        return result;
+    }
+
+    private static final MethodHandle callTest1WithNull = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
+        "callTest1WithNull",
+        MethodType.methodType(void.class, TestNullableValueTypes.class),
+        CODE -> {
+            CODE.
+            aload_0().
+            aconst_null().
+            invokevirtual(TestNullableValueTypes.class, "test1", "(Lcompiler/valhalla/valuetypes/MyValue1;)J", false).
+            return_();
+        },
+        MyValue1.class);
+
+    @DontCompile
+    public void test1_verifier(boolean warmup) throws Throwable {
+        long result = (long)callTest1WithNull.invoke(this);
+        Asserts.assertEquals(result, 0L);
+    }
+
+    @Test
+    public long test2(MyValue1 vt) {
+        long result = 0;
+        try {
+            result = vt.hashInterpreted();
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        return result;
+    }
+
+    @DontCompile
+    public void test2_verifier(boolean warmup) {
+        long result = test2(nullField);
+        Asserts.assertEquals(result, 0L);
+    }
+
+    @Test
+    public long test3() {
+        long result = 0;
+        try {
+            if ((Object)nullField != null) {
+                throw new RuntimeException("nullField should be null");
+            }
+            result = nullField.hash();
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        return result;
+    }
+
+    @DontCompile
+    public void test3_verifier(boolean warmup) {
+        long result = test3();
+        Asserts.assertEquals(result, 0L);
+    }
+
+    @Test
+    public void test4() {
+        try {
+            valueField1 = nullField;
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    @DontCompile
+    public void test4_verifier(boolean warmup) {
+        test4();
+    }
+
+    @Test
+    public MyValue1 test5(MyValue1 vt) {
+        try {
+            Object o = vt;
+            vt = (MyValue1)o;
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+
+        // Should not throw
+        vt = test5_dontinline(vt);
+        vt = test5_inline(vt);
+        return vt;
+    }
+
+    @DontCompile
+    public void test5_verifier(boolean warmup) {
+        MyValue1 vt = test5(nullField);
+        Asserts.assertEquals((Object)vt, null);
+    }
+
+    @DontInline
+    public MyValue1 test5_dontinline(MyValue1 vt) {
+        return vt;
+    }
+
+    @ForceInline
+    public MyValue1 test5_inline(MyValue1 vt) {
+        return vt;
+    }
+
+    @Test
+    public MyValue1 test6(Object obj) {
+        MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL);
+        try {
+            vt = (MyValue1)obj;
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        return vt;
+    }
+
+    @DontCompile
+    public void test6_verifier(boolean warmup) {
+        MyValue1 vt = test6(null);
+        Asserts.assertEquals(vt.hash(), testValue1.hash());
+    }
+
+    private static final MethodHandle getNull = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
+        "getNull",
+        MethodType.methodType(MyValue1.class),
+        CODE -> {
+            CODE.
+            aconst_null().
+            areturn();
+        },
+        MyValue1.class);
+
+    @Test
+    public void test7() throws Throwable {
+        try {
+            valueField1 = (MyValue1)getNull.invoke();
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        nullField = (MyValue1)getNull.invoke(); // Should not throw
+    }
+
+    @DontCompile
+    public void test7_verifier(boolean warmup) throws Throwable {
+        test7();
+    }
+
+    // null constant
+    private static final MethodHandle setNull = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
+        "setNull",
+        MethodType.methodType(void.class, TestNullableValueTypes.class),
+        CODE -> {
+            CODE.
+            aload_0().
+            aconst_null().
+            putfield(TestNullableValueTypes.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
+            return_();
+        },
+        MyValue1.class);
+
+    @Test
+    public void test8() throws Throwable {
+        try {
+            setNull.invoke(this);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    @DontCompile
+    public void test8_verifier(boolean warmup) throws Throwable {
+        test8();
+    }
+
+    // merge of 2 values, one being null
+    @Test
+    public void test9(boolean flag1) {
+        MyValue1 v;
+        if (flag1) {
+            v = valueField1;
+        } else {
+            v = nullField;
+        }
+        valueField1 = v;
+    }
+
+    @DontCompile
+    public void test9_verifier(boolean warmup) {
+        test9(true);
+        try {
+            test9(false);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    // null constant
+    private static final MethodHandle mergeNull = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
+        "mergeNull",
+        MethodType.methodType(void.class, TestNullableValueTypes.class, boolean.class),
+        CODE -> {
+            CODE.
+            iload_1().
+            iconst_0().
+            ifcmp(TypeTag.I, CondKind.EQ, "null").
+            aload_0().
+            getfield(TestNullableValueTypes.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
+            goto_("continue").
+            label("null").
+            aconst_null().
+            label("continue").
+            aload_0().
+            swap().
+            putfield(TestNullableValueTypes.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
+            return_();
+        },
+        MyValue1.class);
+
+    @Test
+    public void test10(boolean flag) throws Throwable {
+        mergeNull.invoke(this, flag);
+    }
+
+    @DontCompile
+    public void test10_verifier(boolean warmup) throws Throwable {
+        test10(true);
+        try {
+            test10(false);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    // null constant
+    private static final MethodHandle mergeNull2 = MethodHandleBuilder.loadCode(MethodHandles.lookup(),
+        "mergeNull2",
+        MethodType.methodType(void.class, TestNullableValueTypes.class, boolean.class),
+        CODE -> {
+            CODE.
+            iload_1().
+            iconst_0().
+            ifcmp(TypeTag.I, CondKind.EQ, "not_null").
+            aconst_null().
+            goto_("continue").
+            label("not_null").
+            aload_0().
+            getfield(TestNullableValueTypes.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
+            label("continue").
+            aload_0().
+            swap().
+            putfield(TestNullableValueTypes.class, "valueField1", "Lcompiler/valhalla/valuetypes/MyValue1;").
+            return_();
+        },
+        MyValue1.class);
+
+    @Test
+    public void test11(boolean flag) throws Throwable {
+        mergeNull2.invoke(this, flag);
+    }
+
+    @DontCompile
+    public void test11_verifier(boolean warmup) throws Throwable {
+        if (!NullableValueTypes) return;
+        test11(false);
+        try {
+            test11(true);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    // null return
+    int test12_cnt;
+
+    @DontInline
+    public MyValue1 test12_helper() {
+        test12_cnt++;
+        return nullField;
+    }
+
+    @Test
+    public void test12() {
+        valueField1 = test12_helper();
+    }
+
+    @DontCompile
+    public void test12_verifier(boolean warmup) {
+        if (!NullableValueTypes) return;
+        try {
+            test12_cnt = 0;
+            test12();
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        if (test12_cnt != 1) {
+            throw new RuntimeException("call executed twice");
+        }
+    }
+
+    // null return at virtual call
+    class A {
+        public MyValue1 test13_helper() {
+            return nullField;
+        }
+    }
+
+    class B extends A {
+        public MyValue1 test13_helper() {
+            return nullField;
+        }
+    }
+
+    class C extends A {
+        public MyValue1 test13_helper() {
+            return nullField;
+        }
+    }
+
+    class D extends A {
+        public MyValue1 test13_helper() {
+            return nullField;
+        }
+    }
+
+    @Test
+    public void test13(A a) {
+        valueField1 = a.test13_helper();
+    }
+
+    @DontCompile
+    public void test13_verifier(boolean warmup) {
+        if (!NullableValueTypes) return;
+        A b = new B();
+        A c = new C();
+        A d = new D();
+        try {
+            test13(b);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            test13(c);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            test13(d);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    // Test writing null to a (flattened) value type array
+
+    @ForceInline
+    public void test14_inline(Object[] oa, Object o, int index) {
+        oa[index] = o;
+    }
+
+    @Test()
+    public void test14(MyValue1[] va, int index) {
+        test14_inline(va, nullField, index);
+    }
+
+    @DontCompile
+    public void test14_verifier(boolean warmup) {
+        int index = Math.abs(rI) % 3;
+        try {
+            test14(testValue1Array, index);
+            throw new RuntimeException("No NPE thrown");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        Asserts.assertEQ(testValue1Array[index].hash(), testValue1.hash());
+    }
+
+    @DontInline
+    MyValue1 get_nullField() {
+        return nullField;
+    }
+
+    @Test()
+    public void test15() {
+        try {
+            valueField1 = get_nullField();
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+
+        nullField = get_nullField(); // should not throw
+    }
+
+    @DontCompile
+    public void test15_verifier(boolean warmup) {
+        if (!NullableValueTypes) return;
+        test15();
+    }
+
+    @DontInline
+    public boolean test16_dontinline(MyValue1 vt) {
+        return (Object)vt == null;
+    }
+
+    // Test c2c call passing null for a value type
+    @Test
+    @Warmup(10000) // Warmup to make sure 'test17_dontinline' is compiled
+    public boolean test16(Object arg) throws Exception {
+        Method test16method = getClass().getMethod("test16_dontinline", MyValue1.class);
+        return (boolean)test16method.invoke(this, arg);
+    }
+
+    @DontCompile
+    public void test16_verifier(boolean warmup) throws Exception {
+        boolean res = test16(null);
+        Asserts.assertTrue(res);
+    }
+
+    // Test scalarization of default value type with non-flattenable field
+    value final class Test17Value {
+        public final __NotFlattened MyValue1 valueField;
+
+        public Test17Value() {
+            valueField = MyValue1.createDefaultDontInline();
+        }
+
+        @ForceInline
+        public Test17Value setValueField(MyValue1 valueField) {
+            return __WithField(this.valueField, valueField);
+        }
+    }
+
+    @Test()
+    public Test17Value test17(boolean b) {
+        Test17Value vt1 = Test17Value.default;
+        if ((Object)vt1.valueField != null) {
+            throw new RuntimeException("Should be null");
+        }
+        Test17Value vt2 = vt1.setValueField(testValue1);
+        return b ? vt1 : vt2;
+    }
+
+    @DontCompile
+    public void test17_verifier(boolean warmup) {
+        test17(true);
+        test17(false);
+    }
+
+    static final MethodHandle test18_mh1;
+    static final MethodHandle test18_mh2;
+
+    __NotFlattened static MyValue1 nullValue;
+
+    @DontInline
+    static void test18_target1(MyValue1 vt) {
+        nullValue = vt;
+    }
+
+    @ForceInline
+    static void test18_target2(MyValue1 vt) {
+        nullValue = vt;
+    }
+
+    // Test passing null for a value type
+    @Test
+    @Warmup(11000) // Make sure lambda forms get compiled
+    public void test18() throws Throwable {
+        test18_mh1.invokeExact(nullValue);
+        test18_mh2.invokeExact(nullValue);
+    }
+
+    @DontCompile
+    public void test18_verifier(boolean warmup) {
+        try {
+            test18();
+        } catch (Throwable t) {
+            throw new RuntimeException("test18 failed", t);
+        }
+    }
+
+    static MethodHandle test19_mh1;
+    static MethodHandle test19_mh2;
+
+    @DontInline
+    static void test19_target1(MyValue1 vt) {
+        nullValue = vt;
+    }
+
+    @ForceInline
+    static void test19_target2(MyValue1 vt) {
+        nullValue = vt;
+    }
+
+    // Same as test12 but with non-final mh
+    @Test
+    @Warmup(11000) // Make sure lambda forms get compiled
+    public void test19() throws Throwable {
+        test19_mh1.invokeExact(nullValue);
+        test19_mh2.invokeExact(nullValue);
+    }
+
+    @DontCompile
+    public void test19_verifier(boolean warmup) {
+        try {
+            test19();
+        } catch (Throwable t) {
+            throw new RuntimeException("test19 failed", t);
+        }
+    }
+
+    // Same as test12/13 but with constant null
+    @Test
+    @Warmup(11000) // Make sure lambda forms get compiled
+    public void test20(MethodHandle mh) throws Throwable {
+        mh.invoke(null);
+    }
+
+    @DontCompile
+    public void test20_verifier(boolean warmup) {
+        try {
+            test20(test18_mh1);
+            test20(test18_mh2);
+            test20(test19_mh1);
+            test20(test19_mh2);
+        } catch (Throwable t) {
+            throw new RuntimeException("test20 failed", t);
+        }
+    }
+}
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java	Thu Oct 18 09:09:56 2018 +0200
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java	Wed Oct 24 14:25:20 2018 +0200
@@ -123,6 +123,7 @@
     protected static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
     protected static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
     protected static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields");
+    protected static final boolean NullableValueTypes = (Boolean)WHITE_BOX.getVMFlag("NullableValueTypes");
     protected static final int COMP_LEVEL_ANY = -2;
     protected static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
     protected static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java	Thu Oct 18 09:09:56 2018 +0200
+++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java	Wed Oct 24 14:25:20 2018 +0200
@@ -37,7 +37,7 @@
  * @compile -XDenableValueTypes -XDallowWithFieldOperator -XDallowFlattenabilityModifiers Point.java JumboValue.java
  * @compile -XDenableValueTypes -XDallowWithFieldOperator -XDallowFlattenabilityModifiers FlattenableSemanticTest.java
  * @run main/othervm -Xint -XX:ValueFieldMaxFlatSize=64 -XX:+EnableValhalla runtime.valhalla.valuetypes.FlattenableSemanticTest
- * @run main/othervm -Xcomp -XX:+EnableValhalla -XX:ValueFieldMaxFlatSize=64 runtime.valhalla.valuetypes.FlattenableSemanticTest
+ * @run main/othervm -Xcomp -XX:+EnableValhalla -XX:ValueFieldMaxFlatSize=64 -XX:+NullableValueTypes runtime.valhalla.valuetypes.FlattenableSemanticTest
  * // debug: -XX:+PrintValueLayout -XX:-ShowMessageBoxOnError
  */
 public class FlattenableSemanticTest {