changeset 47318:cf12cf564f12 mvt

8188770: [MVT] Various code cleanups Reviewed-by: roland
author thartmann
date Mon, 09 Oct 2017 13:18:08 +0200
parents 02ad0a56fe5d
children 6e97467e582d
files src/hotspot/share/ci/ciValueKlass.cpp src/hotspot/share/opto/callGenerator.cpp src/hotspot/share/opto/castnode.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/macro.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/deoptimization.cpp test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTestBench.java
diffstat 18 files changed, 322 insertions(+), 345 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/ci/ciValueKlass.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/ci/ciValueKlass.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -87,8 +87,6 @@
   for (int j = 0; j < nof_nonstatic_fields(); j++) {
     ciField* f = nonstatic_field_at(j);
     BasicType bt = f->type()->basic_type();
-    // TODO re-enable when using T_VALUETYPEPTR
-    //assert(bt != T_VALUETYPE, "embedded");
     if (bt == T_LONG || bt == T_DOUBLE) {
       slots++;
     }
--- a/src/hotspot/share/opto/callGenerator.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/callGenerator.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -186,7 +186,7 @@
   if (vtptr != NULL) {
     if (!vtptr->is__Value()) {
       // Create ValueTypeNode from the oop and replace the return value
-      Node* vt = ValueTypeNode::make(&kit, ret);
+      ValueTypeNode* vt = ValueTypeNode::make_from_oop(&kit, ret);
       kit.push_node(T_VALUETYPE, vt);
     } else {
       kit.push_node(T_VALUETYPE, ret);
@@ -280,7 +280,7 @@
   if (gvn.type(ret)->isa_valuetypeptr()) {
     // Create ValueTypeNode from the oop and replace the return value
     Node* ctl = kit.control();
-    Node* vt = ValueTypeNode::make(&kit, ret);
+    ValueTypeNode* vt = ValueTypeNode::make_from_oop(&kit, ret);
     kit.set_control(ctl);
     kit.push_node(T_VALUETYPE, vt);
   } else {
@@ -440,17 +440,17 @@
       Node* arg = call->in(TypeFunc::Parms + i1);
       if (t->isa_valuetypeptr()) {
         Node* ctl = map->control();
-        arg = ValueTypeNode::make(gvn, ctl, map->memory(), arg);
+        arg = ValueTypeNode::make_from_oop(gvn, ctl, map->memory(), arg);
         map->set_control(ctl);
       }
       map->set_argument(jvms, i1, arg);
     } else {
       if (t->isa_valuetypeptr() && !t->is_valuetypeptr()->is__Value()) {
-        ciValueKlass* vk = t->is_valuetypeptr()->value_type()->value_klass();
+        ciValueKlass* vk = t->is_valuetypeptr()->value_klass();
         Node* ctl = map->control();
-        Node* vt = ValueTypeNode::make(gvn, ctl, map->memory(), call, vk, j, true);
+        ValueTypeNode* vt = ValueTypeNode::make_from_multi(gvn, ctl, map->memory(), call, vk, j, true);
         map->set_control(ctl);
-        map->set_argument(jvms, i1, gvn.transform(vt));
+        map->set_argument(jvms, i1, vt);
         j += vk->value_arg_slots();
       } else {
         map->set_argument(jvms, i1, call->in(j));
@@ -506,8 +506,8 @@
     if (result->is_ValueType()) {
       ValueTypeNode* vt = result->as_ValueType();
       if (!returned_as_fields) {
-        result = vt->allocate(&kit)->get_oop();
-        result = gvn.transform(new ValueTypePtrNode(vt, result, C));
+        vt = vt->allocate(&kit)->as_ValueType();
+        result = ValueTypePtrNode::make_from_value_type(gvn, vt);
       } else {
         // Return of multiple values (the fields of a value type)
         vt->replace_call_results(&kit, call, C);
@@ -522,7 +522,7 @@
       Node* cast = new CheckCastPPNode(NULL, result, vt_t);
       gvn.record_for_igvn(cast);
       Node* ctl = kit.control();
-      ValueTypePtrNode* vtptr = ValueTypePtrNode::make(gvn, ctl, kit.merged_memory(), gvn.transform(cast));
+      ValueTypePtrNode* vtptr = ValueTypePtrNode::make_from_oop(gvn, ctl, kit.merged_memory(), gvn.transform(cast));
       kit.set_control(ctl);
       vtptr->replace_call_results(&kit, call, C);
       result = cast;
@@ -918,17 +918,17 @@
   if (t->is_valuetype()) {
     assert(!(arg_type->isa_valuetype() && t->is__Value()), "need a pointer to the value type");
     if (arg_type->isa_valuetypeptr() && !t->is__Value()) {
+      // Value type arguments cannot be NULL
+      sig_type = sig_type->join_speculative(TypePtr::NOTNULL);
       Node* cast = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type));
-      Node* vt = ValueTypeNode::make(&kit, cast);
+      ValueTypeNode* vt = ValueTypeNode::make_from_oop(&kit, cast);
       kit.set_argument(arg_nb, vt);
     } else {
       assert(t->is__Value() || arg->is_ValueType(), "inconsistent argument");
     }
-  } else {
-    if (arg_type->isa_oopptr() && !arg_type->higher_equal(sig_type)) {
-      Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type));
-      kit.set_argument(arg_nb, cast_obj);
-    }
+  } else if (arg_type->isa_oopptr() && !arg_type->higher_equal(sig_type)) {
+    Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type));
+    kit.set_argument(arg_nb, cast_obj);
   }
 }
 
--- a/src/hotspot/share/opto/castnode.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/castnode.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -418,7 +418,7 @@
       in(1)->in(0)->as_CallStaticJava()->method() != NULL &&
       in(1)->as_Proj()->_con == TypeFunc::Parms) {
     const TypeValueTypePtr* cast_type = type()->is_valuetypeptr();
-    ciValueKlass* vk = cast_type->value_type()->value_klass();
+    ciValueKlass* vk = cast_type->value_klass();
     assert(!vk->is__Value(), "why cast to __Value?");
     PhaseIterGVN* igvn = phase->is_IterGVN();
 
@@ -494,7 +494,7 @@
       // 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(&kit, vk, call));
+      Node* res = igvn->transform(ValueTypePtrNode::make_from_call(&kit, vk, call));
       res = res->isa_ValueTypePtr()->allocate(&kit);
 
       // Get exception state
@@ -521,7 +521,7 @@
       res_cast->set_req(1, projs.resproj);
       res_cast->set_type(cast_type->cast_to_ptr_type(TypePtr::NotNull));
       Node* ctl = kit.control(); // Control may get updated below
-      res = ValueTypePtrNode::make(*igvn, ctl, kit.merged_memory(), igvn->transform(res_cast));
+      res = ValueTypePtrNode::make_from_oop(*igvn, ctl, kit.merged_memory(), igvn->transform(res_cast));
 
       region->init_req(2, ctl);
       mem_phi->init_req(2, kit.reset_memory());
@@ -561,7 +561,7 @@
         Node* mem = projs.fallthrough_memproj;
         Node* ctl_hook = new Node(1);
         igvn->replace_in_uses(ctl, ctl_hook);
-        Node* vtptr = ValueTypePtrNode::make(*phase, ctl, mem, in(1));
+        Node* vtptr = ValueTypePtrNode::make_from_oop(*phase, ctl, mem, in(1));
         // Attach users to updated control
         igvn->replace_node(ctl_hook, ctl);
         return vtptr;
--- a/src/hotspot/share/opto/compile.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/compile.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -1532,6 +1532,41 @@
     }
   }
 
+  // Value type pointers need flattening
+  const TypeValueTypePtr* tv = tj->isa_valuetypeptr();
+  if (tv != NULL && _AliasLevel >= 2) {
+    assert(tv->speculative() == NULL, "should not have speculative type information");
+    ciValueKlass* vk = tv->klass()->as_value_klass();
+    if (ptr == TypePtr::Constant) {
+      assert(!is_known_inst, "not scalarizable allocation");
+      tj = tv = TypeValueTypePtr::make(TypePtr::BotPTR, tv->value_klass(), NULL, Type::Offset(offset));
+    } else if (is_known_inst) {
+      tj = tv; // Keep NotNull and klass_is_exact for instance type
+    } else if (ptr == TypePtr::NotNull || tv->klass_is_exact()) {
+      // During the 2nd round of IterGVN, NotNull castings are removed.
+      // Make sure the Bottom and NotNull variants alias the same.
+      // Also, make sure exact and non-exact variants alias the same.
+      tj = tv = TypeValueTypePtr::make(TypePtr::BotPTR, tv->value_klass(), tv->const_oop(), Type::Offset(offset));
+    }
+    // Canonicalize the holder of this field
+    if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) {
+      // First handle header references such as a LoadKlassNode, even if the
+      // object's klass is unloaded at compile time (4965979).
+      if (!is_known_inst) { // Do it only for non-instance types
+        tj = tv = TypeValueTypePtr::make(TypePtr::BotPTR, env()->___Value_klass()->as_value_klass(), NULL, Type::Offset(offset));
+      }
+    } else if (offset < 0 || offset >= vk->size_helper() * wordSize) {
+      // Static fields are in the space above the normal instance
+      // fields in the java.lang.Class instance.
+      tv = NULL;
+      tj = TypeOopPtr::BOTTOM;
+      offset = tj->offset();
+    } else {
+      ciInstanceKlass* canonical_holder = vk->get_canonical_holder(offset);
+      assert(vk->equals(canonical_holder), "value types should not inherit fields");
+    }
+  }
+
   // Klass pointers to object array klasses need some flattening
   const TypeKlassPtr *tk = tj->isa_klassptr();
   if( tk ) {
--- a/src/hotspot/share/opto/doCall.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/doCall.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -662,17 +662,16 @@
           assert(ct == T_VALUETYPE, "value type expected but got rt=%s, ct=%s", type2name(rt), type2name(ct));
           if (rtype->is__Value()) {
             const Type* sig_type = TypeOopPtr::make_from_klass(ctype->as_klass());
+            sig_type = sig_type->join_speculative(TypePtr::NOTNULL);
             Node* retnode = pop();
             Node* cast = _gvn.transform(new CheckCastPPNode(control(), retnode, sig_type));
-            Node* vt = ValueTypeNode::make(this, cast);
+            ValueTypeNode* vt = ValueTypeNode::make_from_oop(this, cast);
             push(vt);
           } else {
             assert(ctype->is__Value(), "unexpected value type klass");
-            Node* retnode = pop();
-            assert(retnode->is_ValueType(), "inconsistent");
-            ValueTypeNode* vt = retnode->as_ValueType();
-            Node* alloc = vt->allocate(this)->get_oop();
-            Node* vtptr = _gvn.transform(new ValueTypePtrNode(vt, alloc, C));
+            ValueTypeNode* vt = pop()->as_ValueType();
+            vt = vt->allocate(this)->as_ValueType();
+            Node* vtptr = ValueTypePtrNode::make_from_value_type(_gvn, vt);
             push(vtptr);
           }
         } else {
--- a/src/hotspot/share/opto/graphKit.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/graphKit.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -1391,7 +1391,7 @@
   ld = _gvn.transform(ld);
   if (bt == T_VALUETYPE) {
     // Loading a non-flattened value type from memory requires a null check.
-    ld = ValueTypeNode::make(this, ld, true /* null check */);
+    ld = ValueTypeNode::make_from_oop(this, ld, true /* null check */);
   } else if (((bt == T_OBJECT) && C->do_escape_analysis()) || C->eliminate_boxing()) {
     // Improve graph before escape analysis and boxing elimination.
     record_for_igvn(ld);
@@ -1715,9 +1715,9 @@
       const TypeTuple* range_sig = call->tf()->range_sig();
       const Type* t = range_sig->field_at(TypeFunc::Parms);
       assert(t->isa_valuetypeptr(), "only value types for multiple return values");
-      ciValueKlass* vk = t->is_valuetypeptr()->value_type()->value_klass();
+      ciValueKlass* vk = t->is_valuetypeptr()->value_klass();
       Node* ctl = control();
-      ret = ValueTypeNode::make(_gvn, ctl, merged_memory(), call, vk, TypeFunc::Parms+1, false);
+      ret = ValueTypeNode::make_from_multi(_gvn, ctl, merged_memory(), call, vk, TypeFunc::Parms+1, false);
       set_control(ctl);
     }
   }
@@ -3678,68 +3678,61 @@
     return;
   }
 
-  // Prepare for merging control and IO
   RegionNode* res_ctl = new RegionNode(3);
-  res_ctl->init_req(1, null_ctl);
   gvn().set_type(res_ctl, Type::CONTROL);
   record_for_igvn(res_ctl);
-  Node* res_io = PhiNode::make(res_ctl, i_o(), Type::ABIO);
+
+  // Length is zero: don't execute initialization loop
+  res_ctl->init_req(1, null_ctl);
+  PhiNode* res_io  = PhiNode::make(res_ctl, i_o(), Type::ABIO);
+  PhiNode* res_mem = PhiNode::make(res_ctl, merged_memory(), Type::MEMORY, TypePtr::BOTTOM);
   gvn().set_type(res_io, Type::ABIO);
+  gvn().set_type(res_mem, Type::MEMORY);
   record_for_igvn(res_io);
-
-  // TODO comment
-  SafePointNode* loop_map = NULL;
-  {
-    PreserveJVMState pjvms(this);
-    // Create default value type and store it to memory
-    Node* oop = ValueTypeNode::make_default(gvn(), vk);
-    oop = oop->as_ValueType()->allocate(this)->get_oop();
-
-    length = SubI(length, intcon(1));
-    add_predicate(nargs);
-    RegionNode* loop = new RegionNode(3);
-    loop->init_req(1, control());
-    gvn().set_type(loop, Type::CONTROL);
-    record_for_igvn(loop);
-
-    Node* index = new PhiNode(loop, TypeInt::INT);
-    index->init_req(1, intcon(0));
-    gvn().set_type(index, TypeInt::INT);
-    record_for_igvn(index);
-
-    // TODO explain why we need to capture all memory
-    PhiNode* mem = new PhiNode(loop, Type::MEMORY, TypePtr::BOTTOM);
-    mem->init_req(1, reset_memory());
-    gvn().set_type(mem, Type::MEMORY);
-    record_for_igvn(mem);
-    set_control(loop);
-    set_all_memory(mem);
-    // Initialize array element
-    Node* adr = array_element_address(array, index, T_OBJECT);
-    const TypeOopPtr* elemtype = TypeValueTypePtr::make(TypePtr::NotNull, vk);
-    Node* store = store_oop_to_array(control(), array, adr, TypeAryPtr::OOPS, oop, elemtype, T_OBJECT, MemNode::release);
-
-    IfNode* iff = create_and_map_if(control(), Bool(CmpI(index, length), BoolTest::lt), PROB_FAIR, COUNT_UNKNOWN);
-    loop->init_req(2, IfTrue(iff));
-    mem->init_req(2, merged_memory());
-    index->init_req(2, AddI(index, intcon(1)));
-
-    res_ctl->init_req(2, IfFalse(iff));
-    res_io->set_req(2, i_o());
-    loop_map = stop();
-  }
+  record_for_igvn(res_mem);
+
+  // Length is non-zero: execute a loop that initializes the array with the default value type
+  Node* oop = ValueTypeNode::make_default(gvn(), vk);
+  oop = oop->as_ValueType()->allocate(this)->get_oop();
+
+  add_predicate(nargs);
+  RegionNode* loop = new RegionNode(3);
+  loop->init_req(1, control());
+  PhiNode* index = PhiNode::make(loop, intcon(0), TypeInt::INT);
+  PhiNode* mem   = PhiNode::make(loop, reset_memory(), Type::MEMORY, TypePtr::BOTTOM);
+
+  gvn().set_type(loop, Type::CONTROL);
+  gvn().set_type(index, TypeInt::INT);
+  gvn().set_type(mem, Type::MEMORY);
+  record_for_igvn(loop);
+  record_for_igvn(index);
+  record_for_igvn(mem);
+
+  // Loop body: initialize array element at 'index'
+  set_control(loop);
+  set_all_memory(mem);
+  Node* adr = array_element_address(array, index, T_OBJECT);
+  const TypeOopPtr* elemtype = TypeValueTypePtr::make(TypePtr::NotNull, vk);
+  store_oop_to_array(control(), array, adr, TypeAryPtr::OOPS, oop, elemtype, T_VALUETYPE, MemNode::release);
+
+  // Check if we need to execute another loop iteration
+  length = SubI(length, intcon(1));
+  IfNode* iff = create_and_map_if(control(), Bool(CmpI(index, length), BoolTest::lt), PROB_FAIR, COUNT_UNKNOWN);
+
+  // Continue with next iteration
+  loop->init_req(2, IfTrue(iff));
+  index->init_req(2, AddI(index, intcon(1)));
+  mem->init_req(2, merged_memory());
+
+  // Exit loop
+  res_ctl->init_req(2, IfFalse(iff));
+  res_io->set_req(2, i_o());
+  res_mem->set_req(2, reset_memory());
+
   // Set merged control, IO and memory
   set_control(res_ctl);
   set_i_o(res_io);
-  merge_memory(loop_map->merged_memory(), res_ctl, 2);
-
-  // Transform new memory Phis.
-  for (MergeMemStream mms(merged_memory()); mms.next_non_empty();) {
-    Node* phi = mms.memory();
-    if (phi->is_Phi() && phi->in(0) == res_ctl) {
-      mms.set_memory(gvn().transform(phi));
-    }
-  }
+  set_all_memory(res_mem);
 }
 
 // The following "Ideal_foo" functions are placed here because they recognize
@@ -4564,7 +4557,7 @@
     Node* con = makecon(con_type);
     if (field->layout_type() == T_VALUETYPE) {
       // Load value type from constant oop
-      con = ValueTypeNode::make(this, con);
+      con = ValueTypeNode::make_from_oop(this, con);
     }
     return con;
   }
--- a/src/hotspot/share/opto/graphKit.hpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/graphKit.hpp	Mon Oct 09 13:18:08 2017 +0200
@@ -892,6 +892,7 @@
   Node* new_array(Node* klass_node, Node* count_val, int nargs,
                   Node* *return_size_val = NULL,
                   bool deoptimize_on_exception = false);
+  // Initialize a non-flattened value type array with default oops
   void initialize_value_type_array(Node* array, Node* length, ciValueKlass* vk, int nargs);
 
   // java.lang.String helpers
--- a/src/hotspot/share/opto/macro.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/macro.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -673,14 +673,14 @@
   // Subtract the offset of the first field to account for the missing oop header
   offset -= vk->first_field_offset();
   // Create a new ValueTypeNode and retrieve the field values from memory
-  ValueTypeNode* vt = ValueTypeNode::make(_igvn, vk)->as_ValueType();
+  ValueTypeNode* vt = ValueTypeNode::make_uninitialized(_igvn, vk)->as_ValueType();
   for (int i = 0; i < vk->nof_declared_nonstatic_fields(); ++i) {
     ciType* field_type = vt->field_type(i);
     int field_offset = offset + vt->field_offset(i);
     // Each value type field has its own memory slice
     adr_type = adr_type->with_field_offset(field_offset);
     Node* value = NULL;
-    if (field_type->is_valuetype() && vt->field_is_flattened(i)) {
+    if (vt->field_is_flattened(i)) {
       value = value_type_from_mem(mem, ctl, field_type->as_value_klass(), adr_type, field_offset, alloc);
     } else {
       const Type* ft = Type::get_const_type(field_type);
--- a/src/hotspot/share/opto/parse1.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/parse1.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -125,9 +125,9 @@
   case T_OBJECT:  l = new LoadPNode(ctl, mem, adr, TypeRawPtr::BOTTOM, TypeInstPtr::BOTTOM, MemNode::unordered); break;
   case T_VALUETYPE: {
     // Load oop and create a new ValueTypeNode
-    const TypeValueTypePtr* vtptr_type = TypeValueTypePtr::make(type->is_valuetype(), TypePtr::NotNull);
+    const TypeValueTypePtr* vtptr_type = TypeValueTypePtr::make(TypePtr::NotNull, type->is_valuetype()->value_klass());
     l = _gvn.transform(new LoadPNode(ctl, mem, adr, TypeRawPtr::BOTTOM, vtptr_type, MemNode::unordered));
-    l = ValueTypeNode::make(this, l);
+    l = ValueTypeNode::make_from_oop(this, l);
     break;
   }
   case T_VALUETYPEPTR: {
@@ -808,7 +808,7 @@
         !ret_type->is_valuetypeptr()->is__Value()) {
       // When inlining or with multiple return values: return value
       // type as ValueTypeNode not as oop
-      ret_type = ret_type->is_valuetypeptr()->value_type();
+      ret_type = TypeValueType::make(ret_type->is_valuetypeptr()->value_klass());
     }
     int         ret_size = type2size[ret_type->basic_type()];
     Node*       ret_phi  = new PhiNode(region, ret_type);
@@ -858,11 +858,11 @@
         // from the value type arguments.
         const Type* t = tf->domain_sig()->field_at(i);
         if (t->isa_valuetypeptr() && !t->is_valuetypeptr()->is__Value()) {
-          ciValueKlass* vk = t->is_valuetypeptr()->value_type()->value_klass();
+          ciValueKlass* vk = t->is_valuetypeptr()->value_klass();
           Node* ctl = map->control();
-          Node* vt = ValueTypeNode::make(gvn, ctl, map->memory(), start, vk, j, true);
+          ValueTypeNode* vt = ValueTypeNode::make_from_multi(gvn, ctl, map->memory(), start, vk, j, true);
           map->set_control(ctl);
-          map->init_req(i, gvn.transform(vt));
+          map->init_req(i, vt);
           j += vk->value_arg_slots();
         } else {
           Node* parm = gvn.transform(new ParmNode(start, j));
@@ -878,7 +878,7 @@
       if (gvn.type(parm)->isa_valuetypeptr()) {
         // Create ValueTypeNode from the oop and replace the parameter
         Node* ctl = map->control();
-        parm = ValueTypeNode::make(gvn, ctl, map->memory(), parm);
+        parm = ValueTypeNode::make_from_oop(gvn, ctl, map->memory(), parm);
         map->set_control(ctl);
       }
       map->init_req(i, parm);
--- a/src/hotspot/share/opto/parse2.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/parse2.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -62,7 +62,7 @@
   const TypeAryPtr* arytype = _gvn.type(ary)->is_aryptr();
   if (arytype->klass()->is_value_array_klass()) {
     ciValueArrayKlass* vak = arytype->klass()->as_value_array_klass();
-    Node* vt = ValueTypeNode::make(this, vak->element_klass()->as_value_klass(), ary, adr);
+    ValueTypeNode* vt = ValueTypeNode::make_from_flattened(this, vak->element_klass()->as_value_klass(), ary, adr);
     push(vt);
     return;
   }
--- a/src/hotspot/share/opto/parse3.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/parse3.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -204,19 +204,13 @@
       assert(type != NULL, "field singleton type must be consistent");
     } else {
       type = TypeOopPtr::make_from_klass(field_klass->as_klass());
-      if (bt == T_VALUETYPE && !flattened) {
-        // A non-flattened value type field may be NULL
-        bool maybe_null = true;
-        if (field->is_static()) {
-          // Check if static field is already initialized
-          ciInstance* mirror = field->holder()->java_mirror();
-          ciObject* val = mirror->field_value(field).as_object();
-          if (!val->is_null_object()) {
-            maybe_null = false;
-          }
-        }
-        if (maybe_null) {
-          type = type->is_valuetypeptr()->cast_to_ptr_type(TypePtr::BotPTR);
+      if (bt == T_VALUETYPE && field->is_static()) {
+        // Check if static value type field is already initialized
+        assert(!flattened, "static fields should not be flattened");
+        ciInstance* mirror = field->holder()->java_mirror();
+        ciObject* val = mirror->field_value(field).as_object();
+        if (!val->is_null_object()) {
+          type = type->join_speculative(TypePtr::NOTNULL);
         }
       }
     }
@@ -234,7 +228,7 @@
   Node* ld = NULL;
    if (flattened) {
     // Load flattened value type
-    ld = ValueTypeNode::make(this, field_klass->as_value_klass(), obj, obj, field->holder(), offset);
+    ld = ValueTypeNode::make_from_flattened(this, field_klass->as_value_klass(), obj, obj, field->holder(), offset);
   } else {
     ld = make_load(NULL, adr, type, bt, adr_type, mo, LoadNode::DependsOnlyOnTest, needs_atomic_access);
   }
@@ -319,9 +313,6 @@
       assert(bt == T_VALUETYPE, "flattening is only supported for value type fields");
       val->as_ValueType()->store_flattened(this, obj, obj, field->holder(), offset);
     } else {
-      if (bt == T_VALUETYPE) {
-        field_type = field_type->cast_to_ptr_type(TypePtr::BotPTR)->is_oopptr();
-      }
       store_oop_to_object(control(), obj, adr, adr_type, val, field_type, bt, mo);
     }
   } else {
@@ -653,10 +644,8 @@
   // Remove object from the top of the stack
   pop();
 
-  // Create a value type node with the corresponding type
+  // Create a value type node with the corresponding type and push it onto the stack
   ciValueKlass* vk = target_dvt_klass->as_value_klass();
-  Node* vt = ValueTypeNode::make(this, vk, not_null_obj, not_null_obj, target_vcc_klass, vk->first_field_offset());
-
-  // Push the value type onto the stack
+  ValueTypeNode* vt = ValueTypeNode::make_from_flattened(this, vk, not_null_obj, not_null_obj, target_vcc_klass, vk->first_field_offset());
   push(vt);
 }
--- a/src/hotspot/share/opto/parseHelper.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/parseHelper.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -335,20 +335,15 @@
 
 //------------------------------do_vdefault-------------------------------------
 void Parse::do_vdefault() {
-  // Fixme additional checks needed?
   bool will_link;
   ciValueKlass* vk = iter().get_klass(will_link)->as_value_klass();
   assert(will_link, "vdefault: typeflow responsibility");
-
-  // Create a new ValueTypeNode
-  Node* vt = ValueTypeNode::make_default(_gvn, vk);
-
-  push(_gvn.transform(vt));
+  // Create and push a new default ValueTypeNode
+  push(ValueTypeNode::make_default(_gvn, vk));
 }
 
 //------------------------------do_vwithfield-----------------------------------
 void Parse::do_vwithfield() {
-  // Fixme additional checks needed?
   bool will_link;
   ciField* field = iter().get_field(will_link);
   assert(will_link, "vdefault: typeflow responsibility");
@@ -362,7 +357,7 @@
   int offset = field->offset();
   uint i = 0;
   for (; i < new_vt->field_count() && new_vt->field_offset(i) != offset; i++) {}
-  assert(i < new_vt->field_count(), "where's the field");
+  assert(i < new_vt->field_count(), "field not found");
   new_vt->set_field_value(i, val);
 
   push(_gvn.transform(new_vt));
--- a/src/hotspot/share/opto/type.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/type.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -1934,9 +1934,6 @@
     ciField* field = vk->nonstatic_field_at(j);
     BasicType bt = field->type()->basic_type();
     const Type* ft = Type::get_const_type(field->type());
-    if (bt == T_VALUETYPE) {
-      ft = ft->isa_valuetypeptr()->cast_to_ptr_type(TypePtr::BotPTR);
-    }
     field_array[pos++] = ft;
     if (bt == T_LONG || bt == T_DOUBLE) {
       field_array[pos++] = Type::HALF;
@@ -1991,7 +1988,8 @@
       pos++;
       collect_value_fields(vk, field_array, pos);
     } else {
-      field_array[TypeFunc::Parms] = get_const_type(return_type);
+      // Value type returns cannot be NULL
+      field_array[TypeFunc::Parms] = get_const_type(return_type)->join_speculative(TypePtr::NOTNULL);
     }
     break;
   case T_VOID:
@@ -2071,7 +2069,8 @@
         ciValueKlass* vk = (ciValueKlass*)type;
         collect_value_fields(vk, field_array, pos);
       } else {
-        field_array[pos++] = get_const_type(type);
+        // Value types arguments cannot be NULL
+        field_array[pos++] = get_const_type(type)->join_speculative(TypePtr::NOTNULL);
       }
       break;
     }
@@ -2216,6 +2215,10 @@
 
 //------------------------------make-------------------------------------------
 const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) {
+  if (elem->isa_valuetypeptr()) {
+    // Value type array elements cannot be NULL
+    elem = elem->join_speculative(TypePtr::NOTNULL)->is_oopptr();
+  }
   if (UseCompressedOops && elem->isa_oopptr()) {
     elem = elem->make_narrowoop();
   }
@@ -3367,7 +3370,7 @@
 // Computes the element-type given a klass.
 const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_change, bool try_for_exact) {
   if (klass->is_valuetype()) {
-    return TypeValueTypePtr::make(TypePtr::NotNull, klass->as_value_klass());
+    return TypeValueTypePtr::make(TypePtr::BotPTR, klass->as_value_klass());
   } else if (klass->is_instance_klass()) {
     Compile* C = Compile::current();
     Dependencies* deps = C->dependencies();
@@ -3417,18 +3420,8 @@
     return arr;
   } else if (klass->is_value_array_klass()) {
     ciValueKlass* vk = klass->as_array_klass()->element_klass()->as_value_klass();
-    const Type* etype = NULL;
-    bool xk = false;
-    if (vk->flatten_array()) {
-      etype = TypeValueType::make(vk);
-      xk = true;
-    } else {
-      const TypeOopPtr* etype_oop = TypeOopPtr::make_from_klass_common(vk, false, try_for_exact);
-      xk = etype_oop->klass_is_exact();
-      etype = etype_oop;
-    }
-    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
-    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, xk, Offset(0));
+    const TypeAry* arr0 = TypeAry::make(TypeValueType::make(vk), TypeInt::POS);
+    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0));
     return arr;
   } else {
     ShouldNotReachHere();
@@ -4784,24 +4777,24 @@
 
 const TypeValueTypePtr* TypeValueTypePtr::NOTNULL;
 //------------------------------make-------------------------------------------
-const TypeValueTypePtr* TypeValueTypePtr::make(const TypeValueType* vt, PTR ptr, ciObject* o, Offset offset, int instance_id, const TypePtr* speculative, int inline_depth, bool narrow) {
-  return (TypeValueTypePtr*)(new TypeValueTypePtr(vt, ptr, o, offset, instance_id, speculative, inline_depth))->hashcons();
+const TypeValueTypePtr* TypeValueTypePtr::make(PTR ptr, ciValueKlass* vk, ciObject* o, Offset offset, int instance_id, const TypePtr* speculative, int inline_depth, bool narrow) {
+  return (TypeValueTypePtr*)(new TypeValueTypePtr(ptr, vk, o, offset, instance_id, speculative, inline_depth))->hashcons();
 }
 
 const TypePtr* TypeValueTypePtr::add_offset(intptr_t offset) const {
-  return make(_vt, _ptr, _const_oop, Offset(offset), _instance_id, _speculative, _inline_depth);
+  return make(_ptr, value_klass(), _const_oop, Offset(offset), _instance_id, _speculative, _inline_depth);
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
 const Type* TypeValueTypePtr::cast_to_ptr_type(PTR ptr) const {
   if (ptr == _ptr) return this;
-  return make(_vt, ptr, _const_oop, _offset, _instance_id, _speculative, _inline_depth);
+  return make(ptr, value_klass(), _const_oop, _offset, _instance_id, _speculative, _inline_depth);
 }
 
 //-----------------------------cast_to_instance_id----------------------------
 const TypeOopPtr* TypeValueTypePtr::cast_to_instance_id(int instance_id) const {
   if (instance_id == _instance_id) return this;
-  return make(_vt, _ptr, _const_oop, _offset, instance_id, _speculative, _inline_depth);
+  return make(_ptr, value_klass(), _const_oop, _offset, instance_id, _speculative, _inline_depth);
 }
 
 //------------------------------meet-------------------------------------------
@@ -4848,7 +4841,7 @@
       switch (tp->ptr()) {
       case TopPTR:
       case AnyNull: {
-        return make(_vt, ptr, NULL, offset, instance_id, speculative, depth);
+        return make(ptr, value_klass(), NULL, offset, instance_id, speculative, depth);
       }
       case NotNull:
       case BotPTR: {
@@ -4872,7 +4865,7 @@
         // else fall through to AnyNull
       case TopPTR:
       case AnyNull: {
-        return make(_vt, ptr, NULL, offset, instance_id, speculative, depth);
+        return make(ptr, value_klass(), NULL, offset, instance_id, speculative, depth);
       }
       case NotNull:
       case BotPTR:
@@ -4893,20 +4886,20 @@
       ciObject* o = NULL;
       ciObject* this_oop  = const_oop();
       ciObject* tp_oop = tp->const_oop();
-      const TypeValueType* vt = NULL;
-      if (_vt != tp->_vt) {
+      ciKlass* klass = NULL;
+      if (_klass != tp->_klass) {
         assert(is__Value() || tp->is__Value(), "impossible meet");
         if (above_centerline(ptr)) {
-          vt = is__Value() ? tp->_vt : _vt;
+          klass = is__Value() ? tp->_klass : _klass;
         } else if (above_centerline(this->_ptr) && !above_centerline(tp->_ptr)) {
-          vt = tp->_vt;
+          klass = tp->_klass;
         } else if (above_centerline(tp->_ptr) && !above_centerline(this->_ptr)) {
-          vt = _vt;
+          klass = _klass;
         } else {
-          vt = is__Value() ? _vt : tp->_vt;
+          klass = is__Value() ? _klass : tp->_klass;
         }
       } else {
-        vt = _vt;
+        klass = _klass;
       }
       if (ptr == Constant) {
         if (this_oop != NULL && tp_oop != NULL &&
@@ -4920,27 +4913,27 @@
           ptr = NotNull;
         }
       }
-      return make(vt, ptr, o, offset, instance_id, speculative, depth);
+      return make(ptr, klass->as_value_klass(), o, offset, instance_id, speculative, depth);
     }
     }
 }
 
 // Dual: compute field-by-field dual
 const Type* TypeValueTypePtr::xdual() const {
-  return new TypeValueTypePtr(_vt, dual_ptr(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
+  return new TypeValueTypePtr(dual_ptr(), value_klass(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
 }
 
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeValueTypePtr::eq(const Type* t) const {
   const TypeValueTypePtr* p = t->is_valuetypeptr();
-  return _vt->eq(p->value_type()) && TypeOopPtr::eq(p);
+  return klass()->equals(p->klass()) && TypeOopPtr::eq(p);
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeValueTypePtr::hash(void) const {
-  return java_add(_vt->hash(), TypeOopPtr::hash());
+  return java_add(klass()->hash(), TypeOopPtr::hash());
 }
 
 //------------------------------is__Value--------------------------------------
--- a/src/hotspot/share/opto/type.hpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/type.hpp	Mon Oct 09 13:18:08 2017 +0200
@@ -1318,23 +1318,18 @@
 //------------------------------TypeValueTypePtr-------------------------------------
 // Class of value type pointers
 class TypeValueTypePtr : public TypeOopPtr {
-  TypeValueTypePtr(const TypeValueType* vt, PTR ptr, ciObject* o, Offset offset, int instance_id, const TypePtr* speculative, int inline_depth)
-    : TypeOopPtr(ValueTypePtr, ptr, vt->value_klass(), true, o, offset, Offset::bottom, instance_id, speculative, inline_depth) {
-    _vt = vt;
+  TypeValueTypePtr(PTR ptr, ciValueKlass* vk, ciObject* o, Offset offset, int instance_id, const TypePtr* speculative, int inline_depth)
+    : TypeOopPtr(ValueTypePtr, ptr, vk, true, o, offset, Offset::bottom, instance_id, speculative, inline_depth) {
   }
 
-  const TypeValueType* _vt;    // Value type we point to
-
 public:
   // Make a pointer to a value type
-  static const TypeValueTypePtr* make(const TypeValueType* vt, PTR ptr = TypePtr::BotPTR, ciObject* o = NULL, Offset offset = Offset(0),
+  static const TypeValueTypePtr* make(PTR ptr, ciValueKlass* vk, ciObject* o = NULL, Offset offset = Offset(0),
                                       int instance_id = InstanceBot, const TypePtr* speculative = NULL, int inline_depth = InlineDepthBottom, bool narrow = false);
-  // Make a pointer to a value type
-  static const TypeValueTypePtr* make(PTR ptr, ciValueKlass* vk, ciObject* o = NULL) { return make(TypeValueType::make(vk), ptr, o); }
   // Make a pointer to a constant value type
-  static const TypeValueTypePtr* make(ciObject* o) { return make(TypePtr::Constant, o->klass()->as_value_klass(), o);  }
+  static const TypeValueTypePtr* make(ciObject* o) { return make(TypePtr::Constant, o->klass()->as_value_klass(), o); }
 
-  const TypeValueType* value_type() const { return _vt; }
+  ciValueKlass* value_klass() const { return klass()->as_value_klass(); }
 
   virtual const TypePtr* add_offset(intptr_t offset) const;
 
--- a/src/hotspot/share/opto/valuetypenode.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/valuetypenode.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -38,10 +38,9 @@
   ValueTypeBaseNode* vt = clone()->as_ValueTypeBase();
 
   // Create a PhiNode for merging the oop values
-  const TypeValueTypePtr* vtptr = value_type_ptr();
-  vtptr = vtptr->cast_to_ptr_type(TypePtr::BotPTR)->is_valuetypeptr();
-  PhiNode* oop = PhiNode::make(region, vt->get_oop(), vtptr);
-  gvn->set_type(oop, vtptr);
+  const Type* phi_type = Type::get_const_type(value_klass());
+  PhiNode* oop = PhiNode::make(region, vt->get_oop(), phi_type);
+  gvn->set_type(oop, phi_type);
   vt->set_oop(oop);
 
   // Create a PhiNode each for merging the field values
@@ -52,7 +51,7 @@
       // Handle flattened value type fields recursively
       value = value->as_ValueType()->clone_with_phis(gvn, region);
     } else {
-      const Type* phi_type = Type::get_const_type(type);
+      phi_type = Type::get_const_type(type);
       value = PhiNode::make(region, value, phi_type);
       gvn->set_type(value, phi_type);
     }
@@ -158,7 +157,9 @@
 
 bool ValueTypeBaseNode::field_is_flattened(uint index) const {
   assert(index < field_count(), "index out of bounds");
-  return value_klass()->declared_nonstatic_field_at(index)->is_flattened();
+  ciField* field = value_klass()->declared_nonstatic_field_at(index);
+  assert(!field->is_flattened() || field->type()->is_valuetype(), "must be a value type");
+  return field->is_flattened();
 }
 
 int ValueTypeBaseNode::make_scalar_in_safepoint(Unique_Node_List& worklist, SafePointNode* sfpt, Node* root, PhaseGVN* gvn) {
@@ -221,22 +222,22 @@
   }
 }
 
-void ValueTypeBaseNode::make(PhaseGVN* gvn, Node*& ctl, Node* mem, Node* n, ValueTypeBaseNode* vt, ciValueKlass* base_vk, int base_offset, int base_input, bool in) {
-  assert(base_offset >= 0, "offset in value type always positive");
-  for (uint i = 0; i < vt->field_count(); i++) {
-    ciType* field_type = vt->field_type(i);
-    int offset = base_offset + vt->field_offset(i);
-    if (field_type->is_valuetype() && vt->field_is_flattened(i)) {
-      ciValueKlass* embedded_vk = field_type->as_value_klass();
-      ValueTypeNode* embedded_vt = ValueTypeNode::make(*gvn, embedded_vk);
-      ValueTypeBaseNode::make(gvn, ctl, mem, n, embedded_vt, base_vk, offset - vt->value_klass()->first_field_offset(), base_input, in);
-      vt->set_field_value(i, gvn->transform(embedded_vt));
+void ValueTypeBaseNode::initialize(PhaseGVN* gvn, Node*& ctl, Node* mem, MultiNode* multi, ciValueKlass* vk, int base_offset, int base_input, bool in) {
+  assert(base_offset >= 0, "offset in value type must be positive");
+  for (uint i = 0; i < field_count(); i++) {
+    ciType* ft = field_type(i);
+    int offset = base_offset + field_offset(i);
+    if (field_is_flattened(i)) {
+      // Flattened value type field
+      ValueTypeNode* vt = ValueTypeNode::make_uninitialized(*gvn, ft->as_value_klass());
+      vt->initialize(gvn, ctl, mem, multi, vk, offset - value_klass()->first_field_offset(), base_input, in);
+      set_field_value(i, gvn->transform(vt));
     } else {
       int j = 0; int extra = 0;
-      for (; j < base_vk->nof_nonstatic_fields(); j++) {
-        ciField* f = base_vk->nonstatic_field_at(j);
+      for (; j < vk->nof_nonstatic_fields(); j++) {
+        ciField* f = vk->nonstatic_field_at(j);
         if (offset == f->offset()) {
-          assert(f->type() == field_type, "inconsistent field type");
+          assert(f->type() == ft, "inconsistent field type");
           break;
         }
         BasicType bt = f->type()->basic_type();
@@ -244,25 +245,23 @@
           extra++;
         }
       }
-      assert(j != base_vk->nof_nonstatic_fields(), "must find");
+      assert(j != vk->nof_nonstatic_fields(), "must find");
       Node* parm = NULL;
-      if (n->is_Start()) {
+      if (multi->is_Start()) {
         assert(in, "return from start?");
-        parm = gvn->transform(new ParmNode(n->as_Start(), base_input + j + extra));
+        parm = gvn->transform(new ParmNode(multi->as_Start(), base_input + j + extra));
       } else {
         if (in) {
-          assert(n->is_Call(), "nothing else here");
-          parm = n->in(base_input + j + extra);
+          parm = multi->as_Call()->in(base_input + j + extra);
         } else {
-          parm = gvn->transform(new ProjNode(n->as_Call(), base_input + j + extra));
+          parm = gvn->transform(new ProjNode(multi->as_Call(), base_input + j + extra));
         }
       }
-      if (field_type->is_valuetype()) {
+      if (ft->is_valuetype()) {
         // Non-flattened value type field, check for null
-        parm = ValueTypeNode::make(*gvn, ctl, mem, parm, /* null_check */ true);
-
+        parm = ValueTypeNode::make_from_oop(*gvn, ctl, mem, parm, /* null_check */ true);
       }
-      vt->set_field_value(i, parm);
+      set_field_value(i, parm);
       // Record all these guys for later GVN.
       gvn->record_for_igvn(parm);
     }
@@ -274,11 +273,11 @@
   // memory and adding the values as input edges to the node.
   for (uint i = 0; i < field_count(); ++i) {
     int offset = holder_offset + field_offset(i);
-    ciType* ftype = field_type(i);
     Node* value = NULL;
-    if (ftype->is_valuetype() && field_is_flattened(i)) {
+    ciType* ft = field_type(i);
+    if (field_is_flattened(i)) {
       // Recursively load the flattened value type field
-      value = ValueTypeNode::make(gvn, ftype->as_value_klass(), ctl, mem, base, ptr, holder, offset);
+      value = ValueTypeNode::make_from_flattened(gvn, ft->as_value_klass(), ctl, mem, base, ptr, holder, offset);
     } else {
       const Type* con_type = NULL;
       if (base->is_Con()) {
@@ -295,30 +294,28 @@
         value = gvn.transform(gvn.makecon(con_type));
         if (con_type->isa_valuetypeptr()) {
           // Constant, non-flattened value type field
-          value = ValueTypeNode::make(gvn, ctl, mem, value);
+          value = ValueTypeNode::make_from_oop(gvn, ctl, mem, value);
         }
       } else {
         // Load field value from memory
-        const Type* base_type = gvn.type(base);
+        const TypeAryPtr* ary_type = gvn.type(base)->isa_aryptr();
         const TypePtr* adr_type = NULL;
-        if (base_type->isa_aryptr()) {
+        bool is_array = ary_type != NULL;
+        if (is_array) {
           // In the case of a flattened value type array, each field has its own slice
-          adr_type = base_type->is_aryptr()->with_field_offset(offset)->add_offset(Type::OffsetBot);
+          adr_type = ary_type->with_field_offset(offset)->add_offset(Type::OffsetBot);
         } else {
           ciField* field = holder->get_field_by_offset(offset, false);
           adr_type = gvn.C->alias_type(field)->adr_type();
         }
         Node* adr = gvn.transform(new AddPNode(base, ptr, gvn.MakeConX(offset)));
-        BasicType bt = type2field[ftype->basic_type()];
-        const Type* ft = Type::get_const_type(ftype);
-        if (bt == T_VALUETYPE) {
-          ft = ft->is_valuetypeptr()->cast_to_ptr_type(TypePtr::BotPTR);
-        }
+        BasicType bt = type2field[ft->basic_type()];
         assert(is_java_primitive(bt) || adr->bottom_type()->is_ptr_to_narrowoop() == UseCompressedOops, "inconsistent");
-        value = gvn.transform(LoadNode::make(gvn, NULL, mem, adr, adr_type, ft, bt, MemNode::unordered));
+        const Type* rt = Type::get_const_type(ft);
+        value = gvn.transform(LoadNode::make(gvn, is_array ? ctl : NULL, mem, adr, adr_type, rt, bt, MemNode::unordered));
         if (bt == T_VALUETYPE) {
           // Non-flattened value type field, check for null
-          value = ValueTypeNode::make(gvn, ctl, mem, value, /* null_check */ true);
+          value = ValueTypeNode::make_from_oop(gvn, ctl, mem, value, /* null_check */ true);
         }
       }
     }
@@ -341,30 +338,29 @@
   for (uint i = 0; i < field_count(); ++i) {
     int offset = holder_offset + field_offset(i);
     Node* value = field_value(i);
-    if (value->is_ValueType() && field_is_flattened(i)) {
+    ciType* ft = field_type(i);
+    if (field_is_flattened(i)) {
       // Recursively store the flattened value type field
-      value->isa_ValueType()->store_flattened(kit, base, ptr, holder, offset);
+      value->as_ValueType()->store_flattened(kit, base, ptr, holder, offset);
     } else {
-      const Type* base_type = kit->gvn().type(base);
+      const TypeAryPtr* ary_type = kit->gvn().type(base)->isa_aryptr();
       const TypePtr* adr_type = NULL;
-      if (base_type->isa_aryptr()) {
+      bool is_array = ary_type != NULL;
+      if (is_array) {
         // In the case of a flattened value type array, each field has its own slice
-        adr_type = base_type->is_aryptr()->with_field_offset(offset)->add_offset(Type::OffsetBot);
+        adr_type = ary_type->with_field_offset(offset)->add_offset(Type::OffsetBot);
       } else {
         ciField* field = holder->get_field_by_offset(offset, false);
         adr_type = kit->C->alias_type(field)->adr_type();
       }
       Node* adr = kit->basic_plus_adr(base, ptr, offset);
-      BasicType bt = type2field[field_type(i)->basic_type()];
+      BasicType bt = type2field[ft->basic_type()];
       if (is_java_primitive(bt)) {
         kit->store_to_memory(kit->control(), adr, value, bt, adr_type, MemNode::unordered);
       } else {
-        const TypeOopPtr* ft = TypeOopPtr::make_from_klass(field_type(i)->as_klass());
-        // Field may be NULL
-        ft = ft->cast_to_ptr_type(TypePtr::BotPTR)->is_oopptr();
+        const TypeOopPtr* val_type = Type::get_const_type(ft)->is_oopptr();
         assert(adr->bottom_type()->is_ptr_to_narrowoop() == UseCompressedOops, "inconsistent");
-        bool is_array = base_type->isa_aryptr() != NULL;
-        kit->store_oop(kit->control(), base, adr, adr_type, value, ft, bt, is_array, MemNode::unordered);
+        kit->store_oop(kit->control(), base, adr, adr_type, value, val_type, bt, is_array, MemNode::unordered);
       }
     }
   }
@@ -382,12 +378,8 @@
   // Not able to prove that value type is allocated.
   // Emit runtime check that may be folded later.
   assert(!is_allocated(&kit->gvn()), "should not be allocated");
-  const TypeValueTypePtr* vtptr_type = bottom_type()->isa_valuetypeptr();
-  if (vtptr_type == NULL) {
-    vtptr_type = TypeValueTypePtr::make(bottom_type()->isa_valuetype(), TypePtr::NotNull);
-  }
   RegionNode* region = new RegionNode(3);
-  PhiNode* oop = new PhiNode(region, vtptr_type);
+  PhiNode* oop = new PhiNode(region, value_type_ptr());
   PhiNode* io  = new PhiNode(region, Type::ABIO);
   PhiNode* mem = new PhiNode(region, Type::MEMORY, TypePtr::BOTTOM);
 
@@ -467,16 +459,15 @@
   }
 }
 
-ValueTypeNode* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* klass) {
+ValueTypeNode* ValueTypeNode::make_uninitialized(PhaseGVN& gvn, ciValueKlass* klass) {
   // Create a new ValueTypeNode with uninitialized values and NULL oop
   const TypeValueType* type = TypeValueType::make(klass);
-  return new ValueTypeNode(type, gvn.zerocon(T_VALUETYPE), gvn.C);
+  return new ValueTypeNode(type, gvn.zerocon(T_VALUETYPE));
 }
 
-Node* ValueTypeNode::make_default(PhaseGVN& gvn, ciValueKlass* vk) {
-  // TODO re-use constant oop of pre-allocated default value type here?
+ValueTypeNode* ValueTypeNode::make_default(PhaseGVN& gvn, ciValueKlass* vk) {
   // Create a new ValueTypeNode with default values
-  ValueTypeNode* vt = ValueTypeNode::make(gvn, vk);
+  ValueTypeNode* vt = ValueTypeNode::make_uninitialized(gvn, vk);
   for (uint i = 0; i < vt->field_count(); ++i) {
     ciType* field_type = vt->field_type(i);
     Node* value = NULL;
@@ -487,14 +478,14 @@
     }
     vt->set_field_value(i, value);
   }
-  return gvn.transform(vt);
+  return gvn.transform(vt)->as_ValueType();
 }
 
-Node* ValueTypeNode::make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop, bool null_check) {
+ValueTypeNode* ValueTypeNode::make_from_oop(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop, bool null_check) {
   // Create and initialize a ValueTypeNode by loading all field
   // values from a heap-allocated version and also save the oop.
-  const TypeValueType* type = gvn.type(oop)->is_valuetypeptr()->value_type();
-  ValueTypeNode* vt = new ValueTypeNode(type, oop, gvn.C);
+  ciValueKlass* vk = gvn.type(oop)->is_valuetypeptr()->value_klass();
+  ValueTypeNode* vt = new ValueTypeNode(TypeValueType::make(vk), oop);
 
   if (null_check && !vt->is_allocated(&gvn)) {
     // Add oop null check
@@ -509,63 +500,68 @@
     oop = new CastPPNode(oop, TypePtr::NOTNULL);
     oop->set_req(0, not_null);
     oop = gvn.transform(oop);
-    vt->load(gvn, not_null, mem, oop, oop, type->value_klass());
+    vt->load(gvn, not_null, mem, oop, oop, vk);
     region->init_req(1, not_null);
 
     // Use default value type if oop is null
-    Node* def = make_default(gvn, type->value_klass());
+    ValueTypeNode* def = make_default(gvn, vk);
     region->init_req(2, null);
 
     // Merge the two value types and update control
     vt = vt->clone_with_phis(&gvn, region)->as_ValueType();
-    vt->merge_with(&gvn, def->as_ValueType(), 2, true);
+    vt->merge_with(&gvn, def, 2, true);
     ctl = gvn.transform(region);
   } else {
     Node* init_ctl = ctl;
-    vt->load(gvn, ctl, mem, oop, oop, type->value_klass());
+    vt->load(gvn, ctl, mem, oop, oop, vk);
     vt = gvn.transform(vt)->as_ValueType();
     assert(vt->is_allocated(&gvn), "value type should be allocated");
     assert(init_ctl != ctl || oop->is_Con() || oop->is_CheckCastPP() || oop->Opcode() == Op_ValueTypePtr ||
-           vt->is_loaded(&gvn, type) == oop, "value type should be loaded");
+           vt->is_loaded(&gvn) == oop, "value type should be loaded");
   }
   return vt;
 }
 
-Node* ValueTypeNode::make(GraphKit* kit, Node* oop, bool null_check) {
+// GraphKit wrapper for the 'make_from_oop' method
+ValueTypeNode* ValueTypeNode::make_from_oop(GraphKit* kit, Node* oop, bool null_check) {
   Node* ctl = kit->control();
-  Node* vt = make(kit->gvn(), ctl, kit->merged_memory(), oop, null_check);
+  ValueTypeNode* vt = make_from_oop(kit->gvn(), ctl, kit->merged_memory(), oop, null_check);
   kit->set_control(ctl);
   return vt;
 }
 
-Node* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* vk, Node*& ctl, Node* mem, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
+ValueTypeNode* ValueTypeNode::make_from_flattened(PhaseGVN& gvn, ciValueKlass* vk, Node*& ctl, Node* mem, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
   // Create and initialize a ValueTypeNode by loading all field values from
   // a flattened value type field at 'holder_offset' or from a value type array.
-  ValueTypeNode* vt = make(gvn, vk);
+  ValueTypeNode* vt = make_uninitialized(gvn, vk);
   // The value type is flattened into the object without an oop header. Subtract the
   // offset of the first field to account for the missing header when loading the values.
   holder_offset -= vk->first_field_offset();
   vt->load(gvn, ctl, mem, obj, ptr, holder, holder_offset);
-  assert(vt->is_loaded(&gvn, vt->type()->isa_valuetype()) != obj, "holder oop should not be used as flattened value type oop");
+  assert(vt->is_loaded(&gvn) != obj, "holder oop should not be used as flattened value type oop");
   return gvn.transform(vt)->as_ValueType();
 }
 
-Node* ValueTypeNode::make(GraphKit* kit, ciValueKlass* vk, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
+// GraphKit wrapper for the 'make_from_flattened' method
+ValueTypeNode* ValueTypeNode::make_from_flattened(GraphKit* kit, ciValueKlass* vk, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
   Node* ctl = kit->control();
-  Node* vt = make(kit->gvn(), vk, ctl, kit->merged_memory(), obj, ptr, holder, holder_offset);
+  ValueTypeNode* vt = make_from_flattened(kit->gvn(), vk, ctl, kit->merged_memory(), obj, ptr, holder, holder_offset);
   kit->set_control(ctl);
   return vt;
 }
 
-Node* ValueTypeNode::make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* n, ciValueKlass* vk, int base_input, bool in) {
-  ValueTypeNode* vt = ValueTypeNode::make(gvn, vk);
-  ValueTypeBaseNode::make(&gvn, ctl, mem, n, vt, vk, 0, base_input, in);
-  return gvn.transform(vt);
+ValueTypeNode* ValueTypeNode::make_from_multi(PhaseGVN& gvn, Node*& ctl, Node* mem, MultiNode* multi, ciValueKlass* vk, int base_input, bool in) {
+  ValueTypeNode* vt = ValueTypeNode::make_uninitialized(gvn, vk);
+  vt->initialize(&gvn, ctl, mem, multi, vk, 0, base_input, in);
+  return gvn.transform(vt)->as_ValueType();
 }
 
-Node* ValueTypeNode::is_loaded(PhaseGVN* phase, const TypeValueType* t, Node* base, int holder_offset) {
+Node* ValueTypeNode::is_loaded(PhaseGVN* phase, ciValueKlass* vk, Node* base, int holder_offset) {
+  if (vk == NULL) {
+    vk = value_klass();
+  }
   if (field_count() == 0) {
-    assert(t->value_klass()->is__Value(), "unexpected value type klass");
+    assert(vk->is__Value(), "unexpected value type klass");
     assert(is_allocated(phase), "must be allocated");
     return get_oop();
   }
@@ -586,14 +582,14 @@
         // Set base and check if pointer type matches
         base = lbase;
         const TypeValueTypePtr* vtptr = phase->type(base)->isa_valuetypeptr();
-        if (vtptr == NULL || !vtptr->value_type()->eq(t)) {
+        if (vtptr == NULL || !vtptr->value_klass()->equals(vk)) {
           return NULL;
         }
       }
     } else if (value->isa_ValueType()) {
       // Check value type field load recursively
       ValueTypeNode* vt = value->as_ValueType();
-      base = vt->is_loaded(phase, t, base, offset - vt->value_klass()->first_field_offset());
+      base = vt->is_loaded(phase, vk, base, offset - vt->value_klass()->first_field_offset());
       if (base == NULL) {
         return NULL;
       }
@@ -607,16 +603,14 @@
 Node* ValueTypeNode::allocate_fields(GraphKit* kit) {
   ValueTypeNode* vt = clone()->as_ValueType();
   for (uint i = 0; i < field_count(); i++) {
-    Node* value = field_value(i);
-    if (value->is_ValueType()) {
-      if (field_is_flattened(i)) {
-        value = value->as_ValueType()->allocate_fields(kit);
-      } else {
-        // Non-flattened value type field
-        value = value->as_ValueType()->allocate(kit);
-      }
-      vt->set_field_value(i, value);
-    }
+     ValueTypeNode* value = field_value(i)->isa_ValueType();
+     if (field_is_flattened(i)) {
+       // Flattened value type field
+       vt->set_field_value(i, value->allocate_fields(kit));
+     } else if (value != NULL){
+       // Non-flattened value type field
+       vt->set_field_value(i, value->allocate(kit));
+     }
   }
   vt = kit->gvn().transform(vt)->as_ValueType();
   kit->replace_in_map(this, vt);
@@ -642,21 +636,20 @@
   }
   uint edges = 0;
   for (uint i = 0; i < field_count(); i++) {
-    ciType* f_type = field_type(i);
     int offset = base_offset + field_offset(i) - (base_offset > 0 ? vk->first_field_offset() : 0);
     Node* arg = field_value(i);
-    if (f_type->is_valuetype() && field_is_flattened(i)) {
-      ciValueKlass* embedded_vk = f_type->as_value_klass();
-      edges += arg->as_ValueType()->pass_fields(n, base_input, kit, assert_allocated, base_vk, offset);
+    if (field_is_flattened(i)) {
+       // Flattened value type field
+       edges += arg->as_ValueType()->pass_fields(n, base_input, kit, assert_allocated, base_vk, offset);
     } else {
       int j = 0; int extra = 0;
       for (; j < base_vk->nof_nonstatic_fields(); j++) {
-        ciField* f = base_vk->nonstatic_field_at(j);
-        if (offset == f->offset()) {
-          assert(f->type() == f_type, "inconsistent field type");
+        ciField* field = base_vk->nonstatic_field_at(j);
+        if (offset == field->offset()) {
+          assert(field->type() == field_type(i), "inconsistent field type");
           break;
         }
-        BasicType bt = f->type()->basic_type();
+        BasicType bt = field->type()->basic_type();
         if (bt == T_LONG || bt == T_DOUBLE) {
           extra++;
         }
@@ -669,7 +662,7 @@
       }
       n->init_req(base_input + j + extra, arg);
       edges++;
-      BasicType bt = f_type->basic_type();
+      BasicType bt = field_type(i)->basic_type();
       if (bt == T_LONG || bt == T_DOUBLE) {
         n->init_req(base_input + j + extra + 1, kit.top());
         edges++;
@@ -682,7 +675,7 @@
 Node* ValueTypeNode::Ideal(PhaseGVN* phase, bool can_reshape) {
   if (!is_allocated(phase)) {
     // Check if this value type is loaded from memory
-    Node* base = is_loaded(phase, type()->is_valuetype());
+    Node* base = is_loaded(phase);
     if (base != NULL) {
       // Save the oop
       set_oop(base);
@@ -796,27 +789,27 @@
   igvn->remove_dead_node(this);
 }
 
-#ifndef PRODUCT
-
-void ValueTypeNode::dump_spec(outputStream* st) const {
-  TypeNode::dump_spec(st);
+ValueTypePtrNode* ValueTypePtrNode::make_from_value_type(PhaseGVN& gvn, ValueTypeNode* vt) {
+  ValueTypePtrNode* vtptr = new ValueTypePtrNode(vt->value_klass(), vt->get_oop());
+  for (uint i = Oop+1; i < vt->req(); i++) {
+    vtptr->init_req(i, vt->in(i));
+  }
+  return gvn.transform(vtptr)->as_ValueTypePtr();
 }
 
-#endif
-
-ValueTypePtrNode* ValueTypePtrNode::make(GraphKit* kit, ciValueKlass* vk, CallNode* call) {
-  ValueTypePtrNode* vt = new ValueTypePtrNode(vk, kit->zerocon(T_VALUETYPE), kit->C);
+ValueTypePtrNode* ValueTypePtrNode::make_from_call(GraphKit* kit, ciValueKlass* vk, CallNode* call) {
+  ValueTypePtrNode* vtptr = new ValueTypePtrNode(vk, kit->zerocon(T_VALUETYPE));
   Node* ctl = kit->control();
-  ValueTypeBaseNode::make(&kit->gvn(), ctl, kit->merged_memory(), call, vt, vk, 0, TypeFunc::Parms+1, false);
+  vtptr->initialize(&kit->gvn(), ctl, kit->merged_memory(), call, vk);
   kit->set_control(ctl);
-  return vt;
+  return vtptr;
 }
 
-ValueTypePtrNode* ValueTypePtrNode::make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop) {
+ValueTypePtrNode* ValueTypePtrNode::make_from_oop(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop) {
   // Create and initialize a ValueTypePtrNode by loading all field
   // values from a heap-allocated version and also save the oop.
-  ciValueKlass* vk = gvn.type(oop)->is_valuetypeptr()->value_type()->value_klass();
-  ValueTypePtrNode* vtptr = new ValueTypePtrNode(vk, oop, gvn.C);
+  ciValueKlass* vk = gvn.type(oop)->is_valuetypeptr()->value_klass();
+  ValueTypePtrNode* vtptr = new ValueTypePtrNode(vk, oop);
   vtptr->load(gvn, ctl, mem, oop, oop, vk);
   return vtptr;
 }
--- a/src/hotspot/share/opto/valuetypenode.hpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/opto/valuetypenode.hpp	Mon Oct 09 13:18:08 2017 +0200
@@ -32,25 +32,26 @@
 
 class ValueTypeBaseNode : public TypeNode {
 protected:
-  ValueTypeBaseNode(const Type* t, int nb_fields, Compile* C)
+  ValueTypeBaseNode(const Type* t, int nb_fields)
     : TypeNode(t, nb_fields) {
     init_class_id(Class_ValueTypeBase);
-    C->add_value_type(this);
+    Compile::current()->add_value_type(this);
   }
 
   enum { Control,   // Control input
          Oop,       // Oop of TypeValueTypePtr
          Values     // Nodes corresponding to values of the value type's fields.
-                    // Nodes are connected in increasing order of the index of the field
-                    // they correspond to. Field indeces are defined in ciValueKlass::_field_index_map.
+                    // Nodes are connected in increasing order of the index of the field they correspond to.
   };
 
   virtual const TypeValueTypePtr* value_type_ptr() const = 0;
   // Get the klass defining the field layout of the value type
   virtual ciValueKlass* value_klass() const = 0;
+
   int make_scalar_in_safepoint(Unique_Node_List& worklist, SafePointNode* sfpt, Node* root, PhaseGVN* gvn);
 
-  static void make(PhaseGVN* gvn, Node*& ctl, Node* mem, Node* n, ValueTypeBaseNode* vt, ciValueKlass* base_vk, int base_offset, int base_input, bool in);
+  // Initialize the value type fields with the inputs or outputs of a MultiNode
+  void initialize(PhaseGVN* gvn, Node*& ctl, Node* mem, MultiNode* multi, ciValueKlass* vk, int base_offset = 0, int base_input = TypeFunc::Parms+1, bool in = false);
 
 public:
   // Support for control flow merges
@@ -78,11 +79,10 @@
   void store_flattened(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder = NULL, int holder_offset = 0) const;
   // Store the field values to memory
   void store(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset = 0) const;
-
   // Initialize the value type by loading its field values from memory
   void load(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset = 0);
 
-  // Allocates the value type (if not yet allocated) and returns the oop
+  // Allocates the value type (if not yet allocated)
   ValueTypeBaseNode* allocate(GraphKit* kit);
   bool is_allocated(PhaseGVN* phase) const;
 
@@ -93,33 +93,33 @@
 // Node representing a value type in C2 IR
 class ValueTypeNode : public ValueTypeBaseNode {
   friend class ValueTypeBaseNode;
+  friend class ValueTypePtrNode;
 private:
-  ValueTypeNode(const TypeValueType* t, Node* oop, Compile* C)
-    : ValueTypeBaseNode(t, Values + t->value_klass()->nof_declared_nonstatic_fields(), C) {
+  ValueTypeNode(const TypeValueType* t, Node* oop)
+    : ValueTypeBaseNode(t, Values + t->value_klass()->nof_declared_nonstatic_fields()) {
     init_class_id(Class_ValueType);
     init_req(Oop, oop);
   }
 
   // Checks if the value type is loaded from memory and if so returns the oop
-  Node* is_loaded(PhaseGVN* phase, const TypeValueType* t, Node* base = NULL, int holder_offset = 0);
+  Node* is_loaded(PhaseGVN* phase, ciValueKlass* vk = NULL, Node* base = NULL, int holder_offset = 0);
 
-  const TypeValueTypePtr* value_type_ptr() const { return TypeValueTypePtr::make(bottom_type()->isa_valuetype()); }
-  // Get the klass defining the field layout of the value type
+  const TypeValueTypePtr* value_type_ptr() const { return TypeValueTypePtr::make(TypePtr::BotPTR, value_klass()); }
   ciValueKlass* value_klass() const { return type()->is_valuetype()->value_klass(); }
 
 public:
-  // Create a new ValueTypeNode with uninitialized values
-  static ValueTypeNode* make(PhaseGVN& gvn, ciValueKlass* klass);
-  // Create a new ValueTypeNode with default values
-  static Node* make_default(PhaseGVN& gvn, ciValueKlass* vk);
-  // Create a new ValueTypeNode and load its values from an oop
-  static Node* make(GraphKit* kit, Node* oop, bool null_check = false);
-  static Node* make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop, bool null_check = false);
-  // Create a new ValueTypeNode and load its values from a flattened value type field or array
-  static Node* make(GraphKit* kit, ciValueKlass* vk, Node* obj, Node* ptr, ciInstanceKlass* holder = NULL, int holder_offset = 0);
-  static Node* make(PhaseGVN& gvn, ciValueKlass* vk, Node*& ctl, Node* mem, Node* obj, Node* ptr, ciInstanceKlass* holder = NULL, int holder_offset = 0);
-  // Create value type node from arguments at method entry and calls
-  static Node* make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* n, ciValueKlass* vk, int base_input, bool in);
+  // Create uninitialized
+  static ValueTypeNode* make_uninitialized(PhaseGVN& gvn, ciValueKlass* klass);
+  // 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, bool null_check = false);
+  static ValueTypeNode* make_from_oop(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop, bool null_check = false);
+  // 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);
+  static ValueTypeNode* make_from_flattened(PhaseGVN& gvn, ciValueKlass* vk, Node*& ctl, Node* mem, 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)
+  static ValueTypeNode* make_from_multi(PhaseGVN& gvn, Node*& ctl, Node* mem, MultiNode* multi, ciValueKlass* vk, int base_input, bool in);
 
   // Allocate all non-flattened value type fields
   Node* allocate_fields(GraphKit* kit);
@@ -133,37 +133,29 @@
 
   virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
   virtual int Opcode() const;
-
-#ifndef PRODUCT
-  virtual void dump_spec(outputStream* st) const;
-#endif
 };
 
 //------------------------------ValueTypePtrNode-------------------------------------
 // Node representing a value type as a pointer in C2 IR
 class ValueTypePtrNode : public ValueTypeBaseNode {
 private:
-  ciValueKlass* value_klass() const { return type()->is_valuetypeptr()->value_type()->value_klass(); }
-  const TypeValueTypePtr* value_type_ptr() const { return bottom_type()->isa_valuetypeptr(); }
+  const TypeValueTypePtr* value_type_ptr() const { return type()->isa_valuetypeptr(); }
+  ciValueKlass* value_klass() const { return value_type_ptr()->value_klass(); }
 
-  ValueTypePtrNode(ciValueKlass* vk, Node* oop, Compile* C)
-    : ValueTypeBaseNode(TypeValueTypePtr::make(TypePtr::NotNull, vk), Values + vk->nof_declared_nonstatic_fields(), C) {
+  ValueTypePtrNode(ciValueKlass* vk, Node* oop)
+    : ValueTypeBaseNode(TypeValueTypePtr::make(TypePtr::NotNull, vk), Values + vk->nof_declared_nonstatic_fields()) {
     init_class_id(Class_ValueTypePtr);
     init_req(Oop, oop);
   }
+
 public:
+  // Create and initialize with the values of a ValueTypeNode
+  static ValueTypePtrNode* make_from_value_type(PhaseGVN& gvn, ValueTypeNode* vt);
+  // 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(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop);
 
-  ValueTypePtrNode(ValueTypeNode* vt, Node* oop, Compile* C)
-    : ValueTypeBaseNode(TypeValueTypePtr::make(vt->type()->is_valuetype())->cast_to_ptr_type(TypePtr::NotNull), vt->req(), C) {
-    init_class_id(Class_ValueTypePtr);
-    for (uint i = Oop+1; i < vt->req(); i++) {
-      init_req(i, vt->in(i));
-    }
-    init_req(Oop, oop);
-  }
-
-  static ValueTypePtrNode* make(GraphKit* kit, ciValueKlass* vk, CallNode* call);
-  static ValueTypePtrNode* make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop);
   virtual int Opcode() const;
 };
 
--- a/src/hotspot/share/runtime/deoptimization.cpp	Fri Oct 06 08:53:50 2017 -0400
+++ b/src/hotspot/share/runtime/deoptimization.cpp	Mon Oct 09 13:18:08 2017 +0200
@@ -1036,8 +1036,7 @@
           field._klass = InstanceKlass::cast(vk);
         } else {
           // Non-flattened value type field
-          // TODO change this when we use T_VALUETYPEPTR
-          field._type = T_OBJECT;
+          field._type = T_VALUETYPEPTR;
         }
       }
       fields->append(field);
@@ -1051,7 +1050,9 @@
     int offset = base_offset + fields->at(i)._offset;
     BasicType type = fields->at(i)._type;
     switch (type) {
-      case T_OBJECT: case T_ARRAY:
+      case T_OBJECT:
+      case T_VALUETYPEPTR:
+      case T_ARRAY:
         assert(value->type() == T_OBJECT, "Agreement.");
         obj->obj_field_put(offset, value->get_obj()());
         break;
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTestBench.java	Fri Oct 06 08:53:50 2017 -0400
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTestBench.java	Mon Oct 09 13:18:08 2017 +0200
@@ -38,36 +38,29 @@
  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
  *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  *                   -XX:ValueFieldMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
- *                   -XX:ValueTypesBufferMaxMemory=0
  *                   -Djdk.lang.reflect.DVT=true compiler.valhalla.valuetypes.ValueTypeTestBench
  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:-UseCompressedOops
- *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
+ *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
  *                   -XX:ValueFieldMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
- *                   -XX:ValueTypesBufferMaxMemory=0
  *                   -Djdk.lang.reflect.DVT=true compiler.valhalla.valuetypes.ValueTypeTestBench
  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:-UseCompressedOops
  *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=0 -XX:ValueArrayElemMaxFlatOops=0
- *                   -XX:ValueTypesBufferMaxMemory=0
  *                   -Djdk.lang.reflect.DVT=true -DVerifyIR=false compiler.valhalla.valuetypes.ValueTypeTestBench
  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
  *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=0 -XX:ValueArrayElemMaxFlatOops=0
- *                   -XX:ValueTypesBufferMaxMemory=0
  *                   -Djdk.lang.reflect.DVT=true -DVerifyIR=false compiler.valhalla.valuetypes.ValueTypeTestBench
  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation
  *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
- *                   -XX:ValueTypesBufferMaxMemory=0
  *                   -Djdk.lang.reflect.DVT=true -DVerifyIR=false compiler.valhalla.valuetypes.ValueTypeTestBench
  */
 
-// TODO remove -XX:ValueTypesBufferMaxMemory=0 when interpreter buffering is fixed
-
 package compiler.valhalla.valuetypes;
 
 import compiler.whitebox.CompilerWhiteBoxTest;