changeset 52842:61c22f976f36 lworld

[lworld] Initial C1 support for value types
author iklam
date Fri, 16 Nov 2018 10:38:55 -0800
parents af673e294495
children 34ee96ed26d7
files src/hotspot/cpu/x86/c1_FrameMap_x86.cpp src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp src/hotspot/cpu/x86/c1_globals_x86.hpp src/hotspot/share/c1/c1_Canonicalizer.cpp src/hotspot/share/c1/c1_Canonicalizer.hpp src/hotspot/share/c1/c1_FrameMap.cpp src/hotspot/share/c1/c1_GraphBuilder.cpp src/hotspot/share/c1/c1_GraphBuilder.hpp src/hotspot/share/c1/c1_Instruction.cpp src/hotspot/share/c1/c1_Instruction.hpp src/hotspot/share/c1/c1_InstructionPrinter.cpp src/hotspot/share/c1/c1_InstructionPrinter.hpp src/hotspot/share/c1/c1_LIR.cpp src/hotspot/share/c1/c1_LIR.hpp src/hotspot/share/c1/c1_LIRAssembler.cpp src/hotspot/share/c1/c1_LIRGenerator.cpp src/hotspot/share/c1/c1_LIRGenerator.hpp src/hotspot/share/c1/c1_Optimizer.cpp src/hotspot/share/c1/c1_RangeCheckElimination.hpp src/hotspot/share/c1/c1_Runtime1.cpp src/hotspot/share/c1/c1_ValueMap.hpp src/hotspot/share/c1/c1_ValueType.cpp src/hotspot/share/ci/ciArrayKlass.cpp src/hotspot/share/ci/ciArrayKlass.hpp src/hotspot/share/interpreter/bytecode.hpp src/hotspot/share/runtime/arguments.cpp src/hotspot/share/runtime/globals.hpp test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java
diffstat 29 files changed, 448 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -50,7 +50,7 @@
 #else
       opr = as_long_opr(reg2, reg);
 #endif // _LP64
-    } else if (type == T_OBJECT || type == T_ARRAY) {
+    } else if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) {
       opr = as_oop_opr(reg);
     } else if (type == T_METADATA) {
       opr = as_metadata_opr(reg);
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -200,7 +200,7 @@
     __ push_addr(frame_map()->address_for_slot(opr->single_stack_ix()));
   } else if (opr->is_constant()) {
     LIR_Const* const_opr = opr->as_constant_ptr();
-    if (const_opr->type() == T_OBJECT) {
+    if (const_opr->type() == T_OBJECT || const_opr->type() == T_VALUETYPE) {
       __ push_oop(const_opr->as_jobject());
     } else if (const_opr->type() == T_INT) {
       __ push_jint(const_opr->as_jint());
@@ -630,6 +630,7 @@
       break;
     }
 
+    case T_VALUETYPE: // Fall through
     case T_OBJECT: {
       if (patch_code != lir_patch_none) {
         jobject2reg_with_patching(dest->as_register(), info);
@@ -712,6 +713,7 @@
       __ movptr(frame_map()->address_for_slot(dest->single_stack_ix()), c->as_jint_bits());
       break;
 
+    case T_VALUETYPE: // Fall through
     case T_OBJECT:
       __ movoop(frame_map()->address_for_slot(dest->single_stack_ix()), c->as_jobject());
       break;
@@ -751,6 +753,7 @@
       __ movptr(as_Address(addr), c->as_jint_bits());
       break;
 
+    case T_VALUETYPE: // fall through
     case T_OBJECT:  // fall through
     case T_ARRAY:
       if (c->as_jobject() == NULL) {
@@ -839,14 +842,14 @@
     }
 #endif
     assert(src->is_single_cpu(), "must match");
-    if (src->type() == T_OBJECT) {
+    if (src->type() == T_OBJECT || src->type() == T_VALUETYPE) {
       __ verify_oop(src->as_register());
     }
     move_regs(src->as_register(), dest->as_register());
 
   } else if (dest->is_double_cpu()) {
 #ifdef _LP64
-    if (src->type() == T_OBJECT || src->type() == T_ARRAY) {
+    if (src->type() == T_OBJECT || src->type() == T_ARRAY || src->type() == T_VALUETYPE) {
       // Surprising to me but we can see move of a long to t_object
       __ verify_oop(src->as_register());
       move_regs(src->as_register(), dest->as_register_lo());
@@ -917,7 +920,7 @@
 
   if (src->is_single_cpu()) {
     Address dst = frame_map()->address_for_slot(dest->single_stack_ix());
-    if (type == T_OBJECT || type == T_ARRAY) {
+    if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) {
       __ verify_oop(src->as_register());
       __ movptr (dst, src->as_register());
     } else if (type == T_METADATA) {
@@ -963,7 +966,7 @@
   PatchingStub* patch = NULL;
   Register compressed_src = rscratch1;
 
-  if (type == T_ARRAY || type == T_OBJECT) {
+  if (type == T_ARRAY || type == T_OBJECT || type == T_VALUETYPE) {
     __ verify_oop(src->as_register());
 #ifdef _LP64
     if (UseCompressedOops && !wide) {
@@ -1008,6 +1011,7 @@
       break;
     }
 
+    case T_VALUETYPE: // fall through
     case T_ARRAY:   // fall through
     case T_OBJECT:  // fall through
       if (UseCompressedOops && !wide) {
@@ -1098,7 +1102,7 @@
   assert(dest->is_register(), "should not call otherwise");
 
   if (dest->is_single_cpu()) {
-    if (type == T_ARRAY || type == T_OBJECT) {
+    if (type == T_ARRAY || type == T_OBJECT || type == T_VALUETYPE) {
       __ movptr(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix()));
       __ verify_oop(dest->as_register());
     } else if (type == T_METADATA) {
@@ -1139,7 +1143,7 @@
 
 void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) {
   if (src->is_single_stack()) {
-    if (type == T_OBJECT || type == T_ARRAY) {
+    if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) {
       __ pushptr(frame_map()->address_for_slot(src ->single_stack_ix()));
       __ popptr (frame_map()->address_for_slot(dest->single_stack_ix()));
     } else {
@@ -1178,7 +1182,7 @@
   LIR_Address* addr = src->as_address_ptr();
   Address from_addr = as_Address(addr);
 
-  if (addr->base()->type() == T_OBJECT) {
+  if (addr->base()->type() == T_OBJECT || addr->base()->type() == T_VALUETYPE) {
     __ verify_oop(addr->base()->as_pointer_register());
   }
 
@@ -1231,6 +1235,7 @@
       break;
     }
 
+    case T_VALUETYPE: // fall through
     case T_OBJECT:  // fall through
     case T_ARRAY:   // fall through
       if (UseCompressedOops && !wide) {
@@ -1340,7 +1345,7 @@
     patching_epilog(patch, patch_code, addr->base()->as_register(), info);
   }
 
-  if (type == T_ARRAY || type == T_OBJECT) {
+  if (type == T_ARRAY || type == T_OBJECT || type == T_VALUETYPE) {
 #ifdef _LP64
     if (UseCompressedOops && !wide) {
       __ decode_heap_oop(dest->as_register());
@@ -1577,7 +1582,7 @@
   Register len =  op->len()->as_register();
   LP64_ONLY( __ movslq(len, len); )
 
-  if (UseSlowPath ||
+  if (UseSlowPath || op->type() == T_VALUETYPE ||
       (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) ||
       (!UseFastNewTypeArray   && (op->type() != T_OBJECT && op->type() != T_ARRAY))) {
     __ jmp(*op->stub()->entry());
@@ -2498,7 +2503,7 @@
     } else {
 #ifdef _LP64
       Register r_lo;
-      if (right->type() == T_OBJECT || right->type() == T_ARRAY) {
+      if (right->type() == T_OBJECT || right->type() == T_ARRAY || right->type() == T_VALUETYPE) {
         r_lo = right->as_register();
       } else {
         r_lo = right->as_register_lo();
@@ -2611,15 +2616,15 @@
     Register reg1 = opr1->as_register();
     if (opr2->is_single_cpu()) {
       // cpu register - cpu register
-      if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) {
+      if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY || opr1->type() == T_VALUETYPE) {
         __ cmpoop(reg1, opr2->as_register());
       } else {
-        assert(opr2->type() != T_OBJECT && opr2->type() != T_ARRAY, "cmp int, oop?");
+        assert(opr2->type() != T_OBJECT && opr2->type() != T_ARRAY && opr2->type() != T_VALUETYPE, "cmp int, oop?");
         __ cmpl(reg1, opr2->as_register());
       }
     } else if (opr2->is_stack()) {
       // cpu register - stack
-      if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) {
+      if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY || opr1->type() == T_VALUETYPE) {
         __ cmpoop(reg1, frame_map()->address_for_slot(opr2->single_stack_ix()));
       } else {
         __ cmpl(reg1, frame_map()->address_for_slot(opr2->single_stack_ix()));
@@ -2629,7 +2634,7 @@
       LIR_Const* c = opr2->as_constant_ptr();
       if (c->type() == T_INT) {
         __ cmpl(reg1, c->as_jint());
-      } else if (c->type() == T_OBJECT || c->type() == T_ARRAY) {
+      } else if (c->type() == T_OBJECT || c->type() == T_ARRAY || c->type() == T_VALUETYPE) {
         // In 64bit oops are single register
         jobject o = c->as_jobject();
         if (o == NULL) {
@@ -2729,7 +2734,7 @@
   } else if (opr1->is_address() && opr2->is_constant()) {
     LIR_Const* c = opr2->as_constant_ptr();
 #ifdef _LP64
-    if (c->type() == T_OBJECT || c->type() == T_ARRAY) {
+    if (c->type() == T_OBJECT || c->type() == T_ARRAY || c->type() == T_VALUETYPE) {
       assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "need to reverse");
       __ movoop(rscratch1, c->as_jobject());
     }
@@ -2741,7 +2746,7 @@
     LIR_Address* addr = opr1->as_address_ptr();
     if (c->type() == T_INT) {
       __ cmpl(as_Address(addr), c->as_jint());
-    } else if (c->type() == T_OBJECT || c->type() == T_ARRAY) {
+    } else if (c->type() == T_OBJECT || c->type() == T_ARRAY || c->type() == T_VALUETYPE) {
 #ifdef _LP64
       // %%% Make this explode if addr isn't reachable until we figure out a
       // better strategy by giving noreg as the temp for as_Address
--- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -33,6 +33,7 @@
 #include "ci/ciArray.hpp"
 #include "ci/ciObjArrayKlass.hpp"
 #include "ci/ciTypeArrayKlass.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "gc/shared/c1/barrierSetC1.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
@@ -1198,6 +1199,21 @@
   __ move(reg, result);
 }
 
+void LIRGenerator::do_NewValueTypeInstance  (NewValueTypeInstance* x) {
+  // Mapping to do_NewInstance (same code)
+  CodeEmitInfo* info = state_for(x, x->state());
+  x->set_to_object_type();
+  LIR_Opr reg = result_register_for(x->type());
+  new_instance(reg, x->klass(), x->is_unresolved(),
+             FrameMap::rcx_oop_opr,
+             FrameMap::rdi_oop_opr,
+             FrameMap::rsi_oop_opr,
+             LIR_OprFact::illegalOpr,
+             FrameMap::rdx_metadata_opr, info);
+  LIR_Opr result = rlock_result(x);
+  __ move(reg, result);
+
+}
 
 void LIRGenerator::do_NewTypeArray(NewTypeArray* x) {
   CodeEmitInfo* info = state_for(x, x->state());
--- a/src/hotspot/cpu/x86/c1_globals_x86.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/cpu/x86/c1_globals_x86.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -39,7 +39,7 @@
 define_pd_global(bool, PreferInterpreterNativeStubs,   false);
 define_pd_global(bool, ProfileTraps,                   false);
 define_pd_global(bool, UseOnStackReplacement,          true );
-define_pd_global(bool, TieredCompilation,              false);
+define_pd_global(bool, TieredCompilation,              true);
 define_pd_global(intx, CompileThreshold,               1500 );
 
 define_pd_global(intx,   OnStackReplacePercentage,     933  );
--- a/src/hotspot/share/c1/c1_Canonicalizer.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_Canonicalizer.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -644,6 +644,7 @@
 void Canonicalizer::do_TypeCast       (TypeCast*        x) {}
 void Canonicalizer::do_Invoke         (Invoke*          x) {}
 void Canonicalizer::do_NewInstance    (NewInstance*     x) {}
+void Canonicalizer::do_NewValueTypeInstance(NewValueTypeInstance* x) {}
 void Canonicalizer::do_NewTypeArray   (NewTypeArray*    x) {}
 void Canonicalizer::do_NewObjectArray (NewObjectArray*  x) {}
 void Canonicalizer::do_NewMultiArray  (NewMultiArray*   x) {}
--- a/src/hotspot/share/c1/c1_Canonicalizer.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_Canonicalizer.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -81,6 +81,7 @@
   virtual void do_TypeCast       (TypeCast*        x);
   virtual void do_Invoke         (Invoke*          x);
   virtual void do_NewInstance    (NewInstance*     x);
+  virtual void do_NewValueTypeInstance(NewValueTypeInstance* x);
   virtual void do_NewTypeArray   (NewTypeArray*    x);
   virtual void do_NewObjectArray (NewObjectArray*  x);
   virtual void do_NewMultiArray  (NewMultiArray*   x);
--- a/src/hotspot/share/c1/c1_FrameMap.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_FrameMap.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -41,7 +41,7 @@
   for (int i = 0; i < sig->count(); i++) {
     ciType* type = sig->type_at(i);
     BasicType t = type->basic_type();
-    if (t == T_ARRAY) {
+    if (t == T_ARRAY || t == T_VALUETYPE) {
       t = T_OBJECT;
     }
     sta->append(t);
--- a/src/hotspot/share/c1/c1_GraphBuilder.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -33,6 +33,7 @@
 #include "ci/ciKlass.hpp"
 #include "ci/ciMemberName.hpp"
 #include "ci/ciUtilities.inline.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "compiler/compileBroker.hpp"
 #include "interpreter/bytecode.hpp"
 #include "jfr/jfrEvents.hpp"
@@ -648,6 +649,17 @@
     }
   }
 
+  // Record this newly allocated object
+  void new_instance(NewValueTypeInstance* object) {
+    int index = _newobjects.length();
+    _newobjects.append(object);
+    if (_fields.at_grow(index, NULL) == NULL) {
+      _fields.at_put(index, new FieldBuffer());
+    } else {
+      _fields.at(index)->kill();
+    }
+  }
+
   void store_value(Value value) {
     int index = _newobjects.find(value);
     if (index != -1) {
@@ -979,7 +991,19 @@
       (array->as_NewArray() && array->as_NewArray()->length() && array->as_NewArray()->length()->type()->is_constant())) {
     length = append(new ArrayLength(array, state_before));
   }
-  push(as_ValueType(type), append(new LoadIndexed(array, index, length, type, state_before)));
+
+  if (array->is_flattened_array()) {
+    ciType* array_type = array->declared_type();
+    ciValueKlass* elem_klass = array_type->as_value_array_klass()->element_klass()->as_value_klass();
+    NewValueTypeInstance* new_instance = new NewValueTypeInstance(elem_klass, state_before, false);
+    _memory->new_instance(new_instance);
+    apush(append_split(new_instance));
+    LoadIndexed* load_indexed = new LoadIndexed(array, index, length, type, state_before);
+    load_indexed->set_vt(new_instance);
+    append(load_indexed);
+  } else {
+    push(as_ValueType(type), append(new LoadIndexed(array, index, length, type, state_before)));
+  }
 }
 
 
@@ -1700,7 +1724,7 @@
       Value constant = NULL;
       obj = apop();
       ObjectType* obj_type = obj->type()->as_ObjectType();
-      if (field->is_constant() && obj_type->is_constant() && !PatchALot) {
+      if (field->is_constant() && !field->is_flattened() && obj_type->is_constant() && !PatchALot) {
         ciObject* const_oop = obj_type->constant_value();
         if (!const_oop->is_null_object() && const_oop->is_loaded()) {
           ciConstant field_value = field->constant_value_of(const_oop);
@@ -1723,13 +1747,34 @@
         if (state_before == NULL) {
           state_before = copy_state_for_exception();
         }
-        LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching);
-        Value replacement = !needs_patching ? _memory->load(load) : load;
-        if (replacement != load) {
-          assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked");
-          push(type, replacement);
-        } else {
-          push(type, append(load));
+        // Pb with test below, is_flattened() can return true for fields that are not value types
+        // (initialization issue of ciField?)
+        if (!(field->type()->is_valuetype() && field->is_flattened())) {
+          LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching);
+          Value replacement = !needs_patching ? _memory->load(load) : load;
+          if (replacement != load) {
+            assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked");
+            push(type, replacement);
+          } else {
+            push(type, append(load));
+          }
+        } else { // flattened field, not optimized solution: re-instantiate the flattened value
+          ciValueKlass* value_klass = field->type()->as_value_klass();
+          int flattening_offset = field->offset() - value_klass->first_field_offset();
+          assert(field->type()->is_valuetype(), "Sanity check");
+          scope()->set_wrote_final();
+          scope()->set_wrote_fields();
+          NewValueTypeInstance* new_instance = new NewValueTypeInstance(value_klass, state_before, false);
+          _memory->new_instance(new_instance);
+          apush(append_split(new_instance));
+          for (int i = 0; i < holder->nof_nonstatic_fields(); i++) {
+            ciField* inner_field = holder->nonstatic_field_at(i);
+            int off = inner_field->offset();
+            LoadField* load = new LoadField(obj, off + flattening_offset, inner_field, false, state_before, needs_patching);
+            Value replacement = append(load);
+            StoreField* store = new StoreField(new_instance, off, inner_field, replacement, false, state_before, needs_patching);
+            append(store);
+          }
         }
       }
       break;
@@ -1744,10 +1789,25 @@
         Value mask = append(new Constant(new IntConstant(1)));
         val = append(new LogicOp(Bytecodes::_iand, val, mask));
       }
-      StoreField* store = new StoreField(obj, offset, field, val, false, state_before, needs_patching);
-      if (!needs_patching) store = _memory->store(store);
-      if (store != NULL) {
-        append(store);
+      // Pb with test below, is_flattened() can return true for fields that are not value types
+      // (initialization issue of ciField?) <---- FIXME
+      if (!(field->type()->is_valuetype() && field->is_flattened())) {
+        StoreField* store = new StoreField(obj, offset, field, val, false, state_before, needs_patching);
+        if (!needs_patching) store = _memory->store(store);
+        if (store != NULL) {
+          append(store);
+        }
+      } else {
+        ciValueKlass* value_klass = field->type()->as_value_klass();
+        int flattening_offset = field->offset() - value_klass->first_field_offset();
+        for (int i = 0; i < holder->nof_nonstatic_fields(); i++) {
+          ciField* inner_field = holder->nonstatic_field_at(i);
+          int off = inner_field->offset();
+          LoadField* load = new LoadField(val, off, inner_field, false, state_before, needs_patching);
+          Value replacement = append(load);
+          StoreField* store = new StoreField(obj, off + flattening_offset, inner_field, replacement, false, state_before, needs_patching);
+          append(store);
+        }
       }
       break;
     }
@@ -1757,6 +1817,57 @@
   }
 }
 
+// Baseline version of withfield, allocate every time
+void GraphBuilder::withfield(int field_index)
+{
+  bool will_link;
+  ciField* field_modify = stream()->get_field(will_link);
+  ciInstanceKlass* holder = field_modify->holder();
+  assert(holder->is_valuetype(), "must be a value klass");
+  BasicType field_type = field_modify->type()->basic_type();
+  ValueType* type = as_ValueType(field_type);
+
+  // call will_link again to determine if the field is valid.
+  const bool needs_patching = !holder->is_loaded() ||
+                              !field_modify->will_link(method(), Bytecodes::_withfield) ||
+                              PatchALot;
+
+
+  scope()->set_wrote_final();
+  scope()->set_wrote_fields();
+
+  const int offset = !needs_patching ? field_modify->offset() : -1;
+  Value val = pop(type);
+  Value obj = apop();
+
+  ValueStack* state_before = copy_state_for_exception();
+
+  NewValueTypeInstance* new_instance = new NewValueTypeInstance(holder->as_value_klass(), state_before, false);
+  _memory->new_instance(new_instance);
+  apush(append_split(new_instance));
+
+  for (int i = 0; i < holder->nof_nonstatic_fields(); i++) {
+    ciField* field = holder->nonstatic_field_at(i);
+    int off = field->offset();
+
+    if (field->offset() != offset) {
+      // Only load those fields who are not modified
+      LoadField* load = new LoadField(obj, off, field, false, state_before, needs_patching);
+      Value replacement = append(load);
+
+      StoreField* store = new StoreField(new_instance, off, field, replacement, false, state_before, needs_patching);
+      append(store);
+    }
+  }
+
+  // Field to modify
+  if (field_modify->type()->basic_type() == T_BOOLEAN) {
+    Value mask = append(new Constant(new IntConstant(1)));
+    val = append(new LogicOp(Bytecodes::_iand, val, mask));
+  }
+  StoreField* store = new StoreField(new_instance, offset, field_modify, val, false, state_before, needs_patching);
+  append(store);
+}
 
 Dependencies* GraphBuilder::dependency_recorder() const {
   assert(DeoptC1, "need debug information");
@@ -2144,11 +2255,22 @@
   bool will_link;
   ciKlass* klass = stream()->get_klass(will_link);
   assert(klass->is_instance_klass(), "must be an instance klass");
+  assert(!klass->is_valuetype(), "must not be a value klass");
   NewInstance* new_instance = new NewInstance(klass->as_instance_klass(), state_before, stream()->is_unresolved_klass());
   _memory->new_instance(new_instance);
   apush(append_split(new_instance));
 }
 
+void GraphBuilder::new_value_type_instance(int klass_index) {
+  ValueStack* state_before = copy_state_exhandling();
+  bool will_link;
+  ciKlass* klass = stream()->get_klass(will_link);
+  assert(klass->is_valuetype(), "must be a value klass");
+  NewValueTypeInstance* new_instance = new NewValueTypeInstance(klass->as_value_klass(),
+      state_before, stream()->is_unresolved_klass());
+  _memory->new_instance(new_instance);
+  apush(append_split(new_instance));
+}
 
 void GraphBuilder::new_type_array() {
   ValueStack* state_before = copy_state_exhandling();
@@ -2883,6 +3005,8 @@
       case Bytecodes::_ifnonnull      : if_null(objectType, If::neq); break;
       case Bytecodes::_goto_w         : _goto(s.cur_bci(), s.get_far_dest()); break;
       case Bytecodes::_jsr_w          : jsr(s.get_far_dest()); break;
+      case Bytecodes::_defaultvalue   : new_value_type_instance(s.get_index_u2()); break;
+      case Bytecodes::_withfield      : withfield(s.get_index_u2()); break;
       case Bytecodes::_breakpoint     : BAILOUT_("concurrent setting of breakpoint", NULL);
       default                         : ShouldNotReachHere(); break;
     }
@@ -3178,7 +3302,7 @@
     ciType* type = sig->type_at(i);
     BasicType basic_type = type->basic_type();
     // don't allow T_ARRAY to propagate into locals types
-    if (basic_type == T_ARRAY) basic_type = T_OBJECT;
+    if (basic_type == T_ARRAY || basic_type == T_VALUETYPE) basic_type = T_OBJECT;
     ValueType* vt = as_ValueType(basic_type);
     state->store_local(idx, new Local(type, vt, idx, false));
     idx += type->size();
--- a/src/hotspot/share/c1/c1_GraphBuilder.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_GraphBuilder.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -267,6 +267,10 @@
   void throw_op(int bci);
   Value round_fp(Value fp_value);
 
+  // value types
+  void new_value_type_instance(int klass_index);
+  void withfield(int field_index);
+
   // stack/code manipulation helpers
   Instruction* append_with_bci(Instruction* instr, int bci);
   Instruction* append(Instruction* instr);
--- a/src/hotspot/share/c1/c1_Instruction.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_Instruction.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -29,6 +29,8 @@
 #include "c1/c1_ValueStack.hpp"
 #include "ci/ciObjArrayKlass.hpp"
 #include "ci/ciTypeArrayKlass.hpp"
+#include "ci/ciValueArrayKlass.hpp"
+#include "ci/ciValueKlass.hpp"
 
 
 // Implementation of Instruction
@@ -112,6 +114,18 @@
   return NULL;
 }
 
+bool Instruction::is_flattened_array() const {
+  if (ValueArrayFlatten) {
+    ciType* type = declared_type();
+    if (type != NULL &&
+        type->is_value_array_klass() &&
+        type->as_value_array_klass()->element_klass()->as_value_klass()->flatten_array()) {
+    return true;
+    }
+  }
+
+  return false;
+}
 
 #ifndef PRODUCT
 void Instruction::check_state(ValueStack* state) {
@@ -223,6 +237,23 @@
   return exact_type();
 }
 
+Value NewValueTypeInstance::depends_on() {
+  if (_depends_on != this) {
+    if (_depends_on->as_NewValueTypeInstance() != NULL) {
+      return _depends_on->as_NewValueTypeInstance()->depends_on();
+    }
+  }
+  return _depends_on;
+}
+
+ciType* NewValueTypeInstance::exact_type() const {
+  return klass();
+}
+
+ciType* NewValueTypeInstance::declared_type() const {
+  return exact_type();
+}
+
 ciType* CheckCast::declared_type() const {
   return klass();
 }
--- a/src/hotspot/share/c1/c1_Instruction.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_Instruction.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -72,6 +72,7 @@
 class   StateSplit;
 class     Invoke;
 class     NewInstance;
+class     NewValueTypeInstance;
 class     NewArray;
 class       NewTypeArray;
 class       NewObjectArray;
@@ -177,6 +178,7 @@
   virtual void do_TypeCast       (TypeCast*        x) = 0;
   virtual void do_Invoke         (Invoke*          x) = 0;
   virtual void do_NewInstance    (NewInstance*     x) = 0;
+  virtual void do_NewValueTypeInstance(NewValueTypeInstance* x) = 0;
   virtual void do_NewTypeArray   (NewTypeArray*    x) = 0;
   virtual void do_NewObjectArray (NewObjectArray*  x) = 0;
   virtual void do_NewMultiArray  (NewMultiArray*   x) = 0;
@@ -503,6 +505,8 @@
     return _next;
   }
 
+  bool is_flattened_array() const;
+
   Instruction *insert_after_same_bci(Instruction *i) {
 #ifndef PRODUCT
     i->set_printable_bci(printable_bci());
@@ -550,6 +554,7 @@
   virtual StateSplit*       as_StateSplit()      { return NULL; }
   virtual Invoke*           as_Invoke()          { return NULL; }
   virtual NewInstance*      as_NewInstance()     { return NULL; }
+  virtual NewValueTypeInstance* as_NewValueTypeInstance() { return NULL; }
   virtual NewArray*         as_NewArray()        { return NULL; }
   virtual NewTypeArray*     as_NewTypeArray()    { return NULL; }
   virtual NewObjectArray*   as_NewObjectArray()  { return NULL; }
@@ -947,6 +952,7 @@
 LEAF(LoadIndexed, AccessIndexed)
  private:
   NullCheck*  _explicit_null_check;              // For explicit null check elimination
+  NewValueTypeInstance* _vt;
 
  public:
   // creation
@@ -964,6 +970,9 @@
   ciType* exact_type() const;
   ciType* declared_type() const;
 
+  NewValueTypeInstance* vt() { return _vt; }
+  void set_vt(NewValueTypeInstance* vt) { _vt = vt; }
+
   // generic
   HASHING2(LoadIndexed, true, array()->subst(), index()->subst())
 };
@@ -1315,6 +1324,42 @@
   ciType* declared_type() const;
 };
 
+LEAF(NewValueTypeInstance, StateSplit)
+  bool _is_unresolved;
+  ciValueKlass* _klass;
+  Value _depends_on;      // Link to instance on with withfield was called on
+
+public:
+
+  // Default creation, always allocated for now
+  NewValueTypeInstance(ciValueKlass* klass, ValueStack* state_before, bool is_unresolved, Value depends_on = NULL)
+  : StateSplit(instanceType, state_before)
+   , _is_unresolved(is_unresolved)
+   , _klass(klass)
+  {
+    if (depends_on == NULL) {
+      _depends_on = this;
+    } else {
+      _depends_on = depends_on;
+    }
+  }
+
+  // accessors
+  bool is_unresolved() const                     { return _is_unresolved; }
+  Value depends_on();
+
+  ciValueKlass* klass() const { return _klass; }
+
+  virtual bool needs_exception_state() const     { return false; }
+
+  // generic
+  virtual bool can_trap() const                  { return true; }
+  ciType* exact_type() const;
+  ciType* declared_type() const;
+
+  // Only done in LIR Generator -> map everything to object
+  void set_to_object_type() { set_type(instanceType); }
+};
 
 BASE(NewArray, StateSplit)
  private:
--- a/src/hotspot/share/c1/c1_InstructionPrinter.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_InstructionPrinter.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -28,6 +28,7 @@
 #include "ci/ciArray.hpp"
 #include "ci/ciInstance.hpp"
 #include "ci/ciObject.hpp"
+#include "ci/ciValueKlass.hpp"
 
 
 #ifndef PRODUCT
@@ -44,6 +45,7 @@
     case T_DOUBLE : return "double";
     case T_ARRAY  : return "array";
     case T_OBJECT : return "object";
+    case T_VALUETYPE : return "value type";
     default       : return "???";
   }
 }
@@ -516,6 +518,10 @@
   output()->put(']');
 }
 
+void InstructionPrinter::do_NewValueTypeInstance(NewValueTypeInstance* x) {
+  output()->print("new value type instance ");
+  print_klass(x->klass());
+}
 
 void InstructionPrinter::do_NewObjectArray(NewObjectArray* x) {
   output()->print("new object array [");
--- a/src/hotspot/share/c1/c1_InstructionPrinter.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_InstructionPrinter.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -104,6 +104,7 @@
   virtual void do_TypeCast       (TypeCast*        x);
   virtual void do_Invoke         (Invoke*          x);
   virtual void do_NewInstance    (NewInstance*     x);
+  virtual void do_NewValueTypeInstance(NewValueTypeInstance* x);
   virtual void do_NewTypeArray   (NewTypeArray*    x);
   virtual void do_NewObjectArray (NewObjectArray*  x);
   virtual void do_NewMultiArray  (NewMultiArray*   x);
--- a/src/hotspot/share/c1/c1_LIR.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_LIR.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -107,6 +107,7 @@
 char LIR_OprDesc::type_char(BasicType t) {
   switch (t) {
     case T_ARRAY:
+    case T_VALUETYPE:
       t = T_OBJECT;
     case T_BOOLEAN:
     case T_CHAR:
@@ -165,6 +166,7 @@
     case T_OBJECT:
     case T_METADATA:
     case T_ARRAY:
+    case T_VALUETYPE:
       assert((kindfield == cpu_register || kindfield == stack_value) &&
              size_field() == single_size, "must match");
       break;
--- a/src/hotspot/share/c1/c1_LIR.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_LIR.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -316,6 +316,7 @@
       case T_INT:
       case T_ADDRESS:
       case T_OBJECT:
+      case T_VALUETYPE:
       case T_ARRAY:
       case T_METADATA:
         return single_size;
@@ -466,6 +467,7 @@
   case T_FLOAT:    return LIR_OprDesc::float_type;
   case T_DOUBLE:   return LIR_OprDesc::double_type;
   case T_OBJECT:
+  case T_VALUETYPE:
   case T_ARRAY:    return LIR_OprDesc::object_type;
   case T_ADDRESS:  return LIR_OprDesc::address_type;
   case T_METADATA: return LIR_OprDesc::metadata_type;
@@ -651,6 +653,7 @@
     LIR_Opr res;
     switch (type) {
       case T_OBJECT: // fall through
+      case T_VALUETYPE: // fall through
       case T_ARRAY:
         res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift)  |
                                             LIR_OprDesc::object_type  |
@@ -756,6 +759,7 @@
   static LIR_Opr stack(int index, BasicType type) {
     LIR_Opr res;
     switch (type) {
+      case T_VALUETYPE: // fall through
       case T_OBJECT: // fall through
       case T_ARRAY:
         res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) |
--- a/src/hotspot/share/c1/c1_LIRAssembler.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -59,6 +59,7 @@
   } else if (patch->id() == PatchingStub::load_klass_id) {
     switch (code) {
       case Bytecodes::_new:
+      case Bytecodes::_defaultvalue:
       case Bytecodes::_anewarray:
       case Bytecodes::_multianewarray:
       case Bytecodes::_instanceof:
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -34,6 +34,8 @@
 #include "ci/ciInstance.hpp"
 #include "ci/ciObjArray.hpp"
 #include "ci/ciUtilities.hpp"
+#include "ci/ciValueArrayKlass.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "gc/shared/barrierSet.hpp"
 #include "gc/shared/c1/barrierSetC1.hpp"
 #include "runtime/arguments.hpp"
@@ -1548,12 +1550,85 @@
                   value.result(), info != NULL ? new CodeEmitInfo(info) : NULL, info);
 }
 
+// FIXME -- I can't find any other way to pass an address to access_load_at().
+class TempResolvedAddress: public Instruction {
+ public:
+  TempResolvedAddress(ValueType* type, LIR_Opr addr) : Instruction(type) {
+    set_operand(addr);
+  }
+  virtual void input_values_do(ValueVisitor*) {}
+  virtual void visit(InstructionVisitor* v)   {}
+  virtual const char* name() const  { return "TempResolvedAddress"; }
+};
+
+void LIRGenerator::access_flattened_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item) {
+  // Find the starting address of the source (inside the array)
+  ciType* array_type = array.value()->declared_type();
+  ciValueArrayKlass* value_array_klass = array_type->as_value_array_klass();
+  ciValueKlass* elem_klass = value_array_klass->element_klass()->as_value_klass();
+  int array_header_size = value_array_klass->array_header_in_bytes();
+
+#ifndef _LP64
+  LIR_Opr index_op = index.result();
+#else
+  LIR_Opr index_op = new_register(T_LONG);
+  __ convert(Bytecodes::_i2l, index.result(), index_op);
+#endif
+  // Need to shift manually, as LIR_Address can scale only up to 3.
+  __ shift_left(index_op, value_array_klass->log2_element_size(), index_op);
+
+  LIR_Opr elm_op = new_pointer_register();
+  LIR_Address* elm_address = new LIR_Address(array.result(), index_op, array_header_size, T_ADDRESS);
+  __ leal(LIR_OprFact::address(elm_address), elm_op);
+
+  for (int i = 0; i < elem_klass->nof_nonstatic_fields(); i++) {
+    ciField* inner_field = elem_klass->nonstatic_field_at(i);
+    int obj_offset = inner_field->offset();
+    int elm_offset = obj_offset - elem_klass->first_field_offset(); // object header is not stored in array.
+
+    BasicType field_type = inner_field->type()->basic_type();
+    switch (field_type) {
+    case T_BYTE:
+    case T_BOOLEAN:
+    case T_SHORT:
+    case T_CHAR:
+     field_type = T_INT;
+      break;
+    default:
+      break;
+    }
+
+    LIR_Opr temp = new_register(field_type);
+    TempResolvedAddress* elm_resolved_addr = new TempResolvedAddress(as_ValueType(field_type), elm_op);
+    LIRItem elm_item(elm_resolved_addr, this);
+
+    DecoratorSet decorators = IN_HEAP;
+    if (is_load) {
+      access_load_at(decorators, field_type,
+                     elm_item, LIR_OprFact::intConst(elm_offset), temp,
+                     NULL, NULL);
+      access_store_at(decorators, field_type,
+                      obj_item, LIR_OprFact::intConst(obj_offset), temp,
+                      NULL, NULL);
+    } else {
+    access_load_at(decorators, field_type,
+                   obj_item, LIR_OprFact::intConst(obj_offset), temp,
+                   NULL, NULL);
+    access_store_at(decorators, field_type,
+                    elm_item, LIR_OprFact::intConst(elm_offset), temp,
+                    NULL, NULL);
+    }
+  }
+}
+
 void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
   assert(x->is_pinned(),"");
+  bool is_flattened = x->array()->is_flattened_array();
   bool needs_range_check = x->compute_needs_range_check();
   bool use_length = x->length() != NULL;
   bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
-  bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
+  bool needs_store_check = obj_store && !is_flattened &&
+                                        (x->value()->as_Constant() == NULL ||
                                          !get_jobject_constant(x->value())->is_null_object() ||
                                          x->should_profile());
 
@@ -1570,7 +1645,8 @@
     length.load_item();
 
   }
-  if (needs_store_check || x->check_boolean()) {
+
+  if (needs_store_check || x->check_boolean() || is_flattened) {
     value.load_item();
   } else {
     value.load_for_store(x->elt_type());
@@ -1603,13 +1679,18 @@
     array_store_check(value.result(), array.result(), store_check_info, x->profiled_method(), x->profiled_bci());
   }
 
-  DecoratorSet decorators = IN_HEAP | IS_ARRAY;
-  if (x->check_boolean()) {
-    decorators |= C1_MASK_BOOLEAN;
+  if (is_flattened) {
+    index.load_item();
+    access_flattened_array(false, array, index, value);
+  } else {
+    DecoratorSet decorators = IN_HEAP | IS_ARRAY;
+    if (x->check_boolean()) {
+      decorators |= C1_MASK_BOOLEAN;
+    }
+
+    access_store_at(decorators, x->elt_type(), array, index.result(), value.result(),
+                    NULL, null_check_info);
   }
-
-  access_store_at(decorators, x->elt_type(), array, index.result(), value.result(),
-                  NULL, null_check_info);
 }
 
 void LIRGenerator::access_load_at(DecoratorSet decorators, BasicType type,
@@ -1870,12 +1951,20 @@
     }
   }
 
-  DecoratorSet decorators = IN_HEAP | IS_ARRAY;
-
-  LIR_Opr result = rlock_result(x, x->elt_type());
-  access_load_at(decorators, x->elt_type(),
-                 array, index.result(), result,
-                 NULL, null_check_info);
+  if (x->array()->is_flattened_array()) {
+    // Find the destination address (of the NewValueTypeInstance)
+    LIR_Opr obj = x->vt()->operand();
+    LIRItem obj_item(x->vt(), this);
+
+    access_flattened_array(true, array, index, obj_item);
+    set_no_result(x);
+  } else {
+    DecoratorSet decorators = IN_HEAP | IS_ARRAY;
+    LIR_Opr result = rlock_result(x, x->elt_type());
+    access_load_at(decorators, x->elt_type(),
+                   array, index.result(), result,
+                   NULL, null_check_info);
+  }
 }
 
 
@@ -2735,6 +2824,7 @@
     } else {
       LIR_Address* addr = loc->as_address_ptr();
       param->load_for_store(addr->type());
+      assert(addr->type() != T_VALUETYPE, "not supported yet");
       if (addr->type() == T_OBJECT) {
         __ move_wide(param->result(), addr);
       } else
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -266,6 +266,8 @@
   void do_update_CRC32C(Intrinsic* x);
   void do_vectorizedMismatch(Intrinsic* x);
 
+  void access_flattened_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item);
+
  public:
   LIR_Opr call_runtime(BasicTypeArray* signature, LIRItemList* args, address entry, ValueType* result_type, CodeEmitInfo* info);
   LIR_Opr call_runtime(BasicTypeArray* signature, LIR_OprList* args, address entry, ValueType* result_type, CodeEmitInfo* info);
@@ -565,6 +567,7 @@
   virtual void do_TypeCast       (TypeCast*        x);
   virtual void do_Invoke         (Invoke*          x);
   virtual void do_NewInstance    (NewInstance*     x);
+  virtual void do_NewValueTypeInstance(NewValueTypeInstance* x);
   virtual void do_NewTypeArray   (NewTypeArray*    x);
   virtual void do_NewObjectArray (NewObjectArray*  x);
   virtual void do_NewMultiArray  (NewMultiArray*   x);
--- a/src/hotspot/share/c1/c1_Optimizer.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_Optimizer.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -502,6 +502,7 @@
   void do_TypeCast       (TypeCast*        x);
   void do_Invoke         (Invoke*          x);
   void do_NewInstance    (NewInstance*     x);
+  void do_NewValueTypeInstance(NewValueTypeInstance* x);
   void do_NewTypeArray   (NewTypeArray*    x);
   void do_NewObjectArray (NewObjectArray*  x);
   void do_NewMultiArray  (NewMultiArray*   x);
@@ -650,6 +651,7 @@
   void handle_NullCheck       (NullCheck* x);
   void handle_Invoke          (Invoke* x);
   void handle_NewInstance     (NewInstance* x);
+  void handle_NewValueTypeInstance(NewValueTypeInstance* x);
   void handle_NewArray        (NewArray* x);
   void handle_AccessMonitor   (AccessMonitor* x);
   void handle_Intrinsic       (Intrinsic* x);
@@ -688,6 +690,7 @@
 void NullCheckVisitor::do_TypeCast       (TypeCast*        x) {}
 void NullCheckVisitor::do_Invoke         (Invoke*          x) { nce()->handle_Invoke(x); }
 void NullCheckVisitor::do_NewInstance    (NewInstance*     x) { nce()->handle_NewInstance(x); }
+void NullCheckVisitor::do_NewValueTypeInstance(NewValueTypeInstance*     x) { nce()->handle_NewValueTypeInstance(x); }
 void NullCheckVisitor::do_NewTypeArray   (NewTypeArray*    x) { nce()->handle_NewArray(x); }
 void NullCheckVisitor::do_NewObjectArray (NewObjectArray*  x) { nce()->handle_NewArray(x); }
 void NullCheckVisitor::do_NewMultiArray  (NewMultiArray*   x) { nce()->handle_NewArray(x); }
@@ -862,7 +865,7 @@
       if (field->is_constant()) {
         ciConstant field_val = field->constant_value();
         BasicType field_type = field_val.basic_type();
-        if (field_type == T_OBJECT || field_type == T_ARRAY) {
+        if (field_type == T_OBJECT || field_type == T_ARRAY || field_type == T_VALUETYPE) {
           ciObject* obj_val = field_val.as_object();
           if (!obj_val->is_null_object()) {
             if (PrintNullCheckElimination) {
@@ -1040,6 +1043,13 @@
   }
 }
 
+void NullCheckEliminator::handle_NewValueTypeInstance(NewValueTypeInstance* x) {
+  set_put(x);
+  if (PrintNullCheckElimination) {
+    tty->print_cr("NewValueTypeInstance %d is non-null", x->id());
+  }
+}
+
 
 void NullCheckEliminator::handle_NewArray(NewArray* x) {
   set_put(x);
--- a/src/hotspot/share/c1/c1_RangeCheckElimination.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_RangeCheckElimination.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -143,6 +143,7 @@
     void do_NullCheck      (NullCheck*       x) { /* nothing to do */ };
     void do_TypeCast       (TypeCast*        x) { /* nothing to do */ };
     void do_NewInstance    (NewInstance*     x) { /* nothing to do */ };
+    void do_NewValueTypeInstance  (NewValueTypeInstance*   x) { /* nothing to do */ };
     void do_NewTypeArray   (NewTypeArray*    x) { /* nothing to do */ };
     void do_NewObjectArray (NewObjectArray*  x) { /* nothing to do */ };
     void do_NewMultiArray  (NewMultiArray*   x) { /* nothing to do */ };
--- a/src/hotspot/share/c1/c1_Runtime1.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -932,6 +932,11 @@
           k = caller_method->constants()->klass_at(bnew.index(), CHECK);
         }
         break;
+      case Bytecodes::_defaultvalue:
+        { Bytecode_defaultvalue bdefaultvalue(caller_method(), caller_method->bcp_from(bci));
+          k = caller_method->constants()->klass_at(bdefaultvalue.index(), CHECK);
+        }
+        break;
       case Bytecodes::_multianewarray:
         { Bytecode_multianewarray mna(caller_method(), caller_method->bcp_from(bci));
           k = caller_method->constants()->klass_at(mna.index(), CHECK);
--- a/src/hotspot/share/c1/c1_ValueMap.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_ValueMap.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -186,6 +186,7 @@
   void do_NullCheck      (NullCheck*       x) { /* nothing to do */ }
   void do_TypeCast       (TypeCast*        x) { /* nothing to do */ }
   void do_NewInstance    (NewInstance*     x) { /* nothing to do */ }
+  void do_NewValueTypeInstance (NewValueTypeInstance* x) { /* nothing to do */ }
   void do_NewTypeArray   (NewTypeArray*    x) { /* nothing to do */ }
   void do_NewObjectArray (NewObjectArray*  x) { /* nothing to do */ }
   void do_NewMultiArray  (NewMultiArray*   x) { /* nothing to do */ }
--- a/src/hotspot/share/c1/c1_ValueType.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/c1/c1_ValueType.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -135,6 +135,7 @@
     case T_DOUBLE : return doubleType;
     case T_ARRAY  : return arrayType;
     case T_OBJECT : return objectType;
+    case T_VALUETYPE: return objectType;
     case T_ADDRESS: return addressType;
     case T_ILLEGAL: return illegalType;
     default       : ShouldNotReachHere();
@@ -154,6 +155,7 @@
     case T_FLOAT  : return new FloatConstant (value.as_float ());
     case T_DOUBLE : return new DoubleConstant(value.as_double());
     case T_ARRAY  : // fall through (ciConstant doesn't have an array accessor)
+    case T_VALUETYPE: // fall through
     case T_OBJECT : {
       // TODO: Common the code with GraphBuilder::load_constant?
       ciObject* obj = value.as_object();
--- a/src/hotspot/share/ci/ciArrayKlass.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/ci/ciArrayKlass.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -109,3 +109,7 @@
     return ciObjArrayKlass::make(element_type->as_klass());
   }
 }
+
+int ciArrayKlass::array_header_in_bytes() {
+  return get_ArrayKlass()->array_header_in_bytes();
+}
--- a/src/hotspot/share/ci/ciArrayKlass.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/ci/ciArrayKlass.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -60,6 +60,8 @@
   virtual ciKlass* element_klass() { return NULL; }
 
   static ciArrayKlass* make(ciType* element_type);
+
+  int array_header_in_bytes();
 };
 
 #endif // SHARE_VM_CI_CIARRAYKLASS_HPP
--- a/src/hotspot/share/interpreter/bytecode.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/interpreter/bytecode.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -293,6 +293,15 @@
   long index() const   { return get_index_u2(Bytecodes::_new); };
 };
 
+class Bytecode_defaultvalue: public Bytecode {
+ public:
+  Bytecode_defaultvalue(Method* method, address bcp): Bytecode(method, bcp) { verify(); }
+  void verify() const { assert(java_code() == Bytecodes::_defaultvalue, "check defaultvalue"); }
+
+  // Returns index
+  long index() const   { return get_index_u2(Bytecodes::_defaultvalue); };
+};
+
 class Bytecode_multianewarray: public Bytecode {
  public:
   Bytecode_multianewarray(Method* method, address bcp): Bytecode(method, bcp) { verify(); }
--- a/src/hotspot/share/runtime/arguments.cpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/runtime/arguments.cpp	Fri Nov 16 10:38:55 2018 -0800
@@ -2098,11 +2098,18 @@
   }
 
   if (EnableValhalla) {
-    // C1 has no support for value types
-    if (!FLAG_IS_DEFAULT(TieredCompilation)) {
-      warning("TieredCompilation disabled because value types are not supported by C1");
+    if (!EnableValhallaC1) {
+      // C1 support for value types is incomplete. Don't use it by default.
+      if (!FLAG_IS_DEFAULT(TieredCompilation)) {
+        warning("TieredCompilation disabled because value types are not supported by C1");
+      }
+      FLAG_SET_CMDLINE(bool, TieredCompilation, false);
+    } else {
+      if (TieredStopAtLevel > 1) {
+        warning("C1 doesn't work with C2 yet. Forcing TieredStopAtLevel=1");
+        FLAG_SET_CMDLINE(intx, TieredStopAtLevel, 1);
+      }
     }
-    FLAG_SET_CMDLINE(bool, TieredCompilation, false);
   } else {
     FLAG_SET_CMDLINE(bool, ValueArrayFlatten, false);
   }
--- a/src/hotspot/share/runtime/globals.hpp	Tue Nov 20 16:10:51 2018 -0500
+++ b/src/hotspot/share/runtime/globals.hpp	Fri Nov 16 10:38:55 2018 -0800
@@ -2647,6 +2647,9 @@
   product(bool, EnableValhalla, false,                                      \
           "Enable experimental Valhalla features")                          \
                                                                             \
+  product(bool, EnableValhallaC1, false,                                    \
+          "Enable C1 compiler for Valhalla")                                \
+                                                                            \
   product_pd(bool, ValueTypePassFieldsAsArgs,                               \
              "Pass each value type field as an argument at calls")          \
                                                                             \
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java	Tue Nov 20 16:10:51 2018 -0500
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java	Fri Nov 16 10:38:55 2018 -0800
@@ -84,6 +84,9 @@
 }
 
 public abstract class ValueTypeTest {
+    // Run "jtreg -Dtest.c1=true" to enable experimental C1 testing.
+    static final boolean TEST_C1 = Boolean.getBoolean("test.c1");
+
     // Random test values
     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
@@ -91,7 +94,7 @@
     // User defined settings
     private static final boolean PRINT_GRAPH = true;
     private static final boolean PRINT_TIMES = Boolean.parseBoolean(System.getProperty("PrintTimes", "false"));
-    private static       boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true"));
+    private static       boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true")) && (!TEST_C1);
     private static final boolean VERIFY_VM = Boolean.parseBoolean(System.getProperty("VerifyVM", "false"));
     private static final String SCENARIOS = System.getProperty("Scenarios", "");
     private static final String TESTLIST = System.getProperty("Testlist", "");
@@ -125,7 +128,7 @@
     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 int COMP_LEVEL_FULL_OPTIMIZATION = TEST_C1 ? 1 : 4;
     protected static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
     protected static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
     protected static final boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
@@ -170,7 +173,11 @@
      * the 5 built-in scenarios
      */
     public int getNumScenarios() {
-        return 5;
+        if (TEST_C1) {
+            return 1;
+        } else {
+            return 5;
+        }
     }
 
     /**
@@ -178,6 +185,12 @@
      * extra parameters for (some of) these scenarios, override getExtraVMParameters().
      */
     public String[] getVMParameters(int scenario) {
+        if (TEST_C1) {
+            return new String[] {
+                    "-XX:+EnableValhallaC1",
+            };
+        }
+
         switch (scenario) {
         case 0: return new String[] {
                 "-XX:+AlwaysIncrementalInline",