changeset 12964:d16eda688d5d

Initial valhalla/jdk10 merge for runtime and interpreter
author fparain
date Wed, 26 Apr 2017 13:37:50 -0400
parents 08fb5778467b
children 502a813008e8
files src/cpu/x86/vm/abstractInterpreter_x86.cpp src/cpu/x86/vm/frame_x86.cpp src/cpu/x86/vm/globals_x86.hpp src/cpu/x86/vm/interp_masm_x86.cpp src/cpu/x86/vm/interpreterRT_x86.hpp src/cpu/x86/vm/interpreterRT_x86_32.cpp src/cpu/x86/vm/interpreterRT_x86_64.cpp src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp src/cpu/x86/vm/templateTable_x86.cpp src/share/vm/ci/ciArrayKlass.cpp src/share/vm/ci/ciArrayKlass.hpp src/share/vm/ci/ciClassList.hpp src/share/vm/ci/ciConstant.hpp src/share/vm/ci/ciEnv.cpp src/share/vm/ci/ciEnv.hpp src/share/vm/ci/ciField.cpp src/share/vm/ci/ciField.hpp src/share/vm/ci/ciInstance.cpp src/share/vm/ci/ciInstanceKlass.cpp src/share/vm/ci/ciInstanceKlass.hpp src/share/vm/ci/ciKlass.hpp src/share/vm/ci/ciMetadata.hpp src/share/vm/ci/ciMethod.cpp src/share/vm/ci/ciMethodBlocks.cpp src/share/vm/ci/ciObjArrayKlass.cpp src/share/vm/ci/ciObjectFactory.cpp src/share/vm/ci/ciReplay.cpp src/share/vm/ci/ciStreams.cpp src/share/vm/ci/ciSymbol.hpp src/share/vm/ci/ciType.cpp src/share/vm/ci/ciType.hpp src/share/vm/ci/ciTypeFlow.cpp src/share/vm/ci/ciTypeFlow.hpp src/share/vm/ci/ciValueArrayKlass.cpp src/share/vm/ci/ciValueArrayKlass.hpp src/share/vm/ci/ciValueKlass.cpp src/share/vm/ci/ciValueKlass.hpp src/share/vm/ci/compilerInterface.hpp src/share/vm/classfile/classFileParser.cpp src/share/vm/classfile/classFileParser.hpp src/share/vm/classfile/classLoader.cpp src/share/vm/classfile/javaClasses.cpp src/share/vm/classfile/systemDictionary.cpp src/share/vm/classfile/systemDictionary.hpp src/share/vm/classfile/vmSymbols.cpp src/share/vm/classfile/vmSymbols.hpp src/share/vm/gc/parallel/psCompactionManager.cpp src/share/vm/gc/parallel/psParallelCompact.cpp src/share/vm/gc/parallel/psPromotionManager.cpp src/share/vm/gc/serial/markSweep.cpp src/share/vm/interpreter/abstractInterpreter.cpp src/share/vm/interpreter/abstractInterpreter.hpp src/share/vm/interpreter/bytecode.hpp src/share/vm/interpreter/bytecodeTracer.cpp src/share/vm/interpreter/bytecodes.cpp src/share/vm/interpreter/bytecodes.hpp src/share/vm/interpreter/interpreterRuntime.cpp src/share/vm/interpreter/interpreterRuntime.hpp src/share/vm/interpreter/linkResolver.cpp src/share/vm/interpreter/oopMapCache.cpp src/share/vm/interpreter/rewriter.cpp src/share/vm/interpreter/templateInterpreter.cpp src/share/vm/interpreter/templateInterpreter.hpp src/share/vm/interpreter/templateInterpreterGenerator.cpp src/share/vm/interpreter/templateInterpreterGenerator.hpp src/share/vm/interpreter/templateTable.cpp src/share/vm/interpreter/templateTable.hpp src/share/vm/jvmci/jvmciCompilerToVM.hpp src/share/vm/memory/iterator.inline.hpp src/share/vm/memory/oopFactory.cpp src/share/vm/memory/oopFactory.hpp src/share/vm/memory/universe.inline.hpp src/share/vm/oops/arrayKlass.cpp src/share/vm/oops/arrayKlass.hpp src/share/vm/oops/arrayOop.hpp src/share/vm/oops/cpCache.cpp src/share/vm/oops/cpCache.hpp src/share/vm/oops/generateOopMap.cpp src/share/vm/oops/generateOopMap.hpp src/share/vm/oops/instanceKlass.cpp src/share/vm/oops/instanceKlass.hpp src/share/vm/oops/instanceKlass.inline.hpp src/share/vm/oops/instanceOop.hpp src/share/vm/oops/klass.hpp src/share/vm/oops/klassVtable.cpp src/share/vm/oops/klassVtable.hpp src/share/vm/oops/method.cpp src/share/vm/oops/methodData.cpp src/share/vm/oops/objArrayKlass.cpp src/share/vm/oops/oop.cpp src/share/vm/oops/oop.hpp src/share/vm/oops/oop.inline.hpp src/share/vm/oops/oopsHierarchy.hpp src/share/vm/oops/typeArrayKlass.cpp src/share/vm/oops/typeArrayOop.hpp src/share/vm/oops/valueArrayKlass.cpp src/share/vm/oops/valueArrayKlass.hpp src/share/vm/oops/valueArrayKlass.inline.hpp src/share/vm/oops/valueArrayOop.cpp src/share/vm/oops/valueArrayOop.hpp src/share/vm/oops/valueKlass.cpp src/share/vm/oops/valueKlass.hpp src/share/vm/oops/valueKlass.inline.hpp src/share/vm/prims/jni.cpp src/share/vm/prims/jni.h src/share/vm/prims/jvm.cpp src/share/vm/prims/jvm.h src/share/vm/prims/whitebox.cpp src/share/vm/runtime/arguments.cpp src/share/vm/runtime/fieldDescriptor.cpp src/share/vm/runtime/fieldType.cpp src/share/vm/runtime/fieldType.hpp src/share/vm/runtime/frame.cpp src/share/vm/runtime/globals.hpp src/share/vm/runtime/handles.hpp src/share/vm/runtime/javaCalls.cpp src/share/vm/runtime/reflection.cpp src/share/vm/runtime/sharedRuntime.cpp src/share/vm/runtime/signature.cpp src/share/vm/runtime/signature.hpp src/share/vm/utilities/accessFlags.hpp src/share/vm/utilities/exceptions.hpp src/share/vm/utilities/globalDefinitions.cpp src/share/vm/utilities/globalDefinitions.hpp test/TEST.groups
diffstat 125 files changed, 4274 insertions(+), 507 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/x86/vm/abstractInterpreter_x86.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/abstractInterpreter_x86.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -132,6 +132,7 @@
     case T_DOUBLE : i = 6; break;
     case T_OBJECT : // fall through
     case T_ARRAY  : i = 7; break;
+    case T_VALUETYPE : i = 8; break;
     default       : ShouldNotReachHere();
   }
   assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds");
@@ -152,6 +153,7 @@
     case T_DOUBLE : i = 8; break;
     case T_OBJECT : i = 9; break;
     case T_ARRAY  : i = 9; break;
+    case T_VALUETYPE : i = 10; break;
     default       : ShouldNotReachHere();
   }
   assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers,
--- a/src/cpu/x86/vm/frame_x86.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/frame_x86.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -583,6 +583,7 @@
 
   switch (type) {
     case T_OBJECT  :
+    case T_VALUETYPE:
     case T_ARRAY   : {
       oop obj;
       if (method->is_native()) {
--- a/src/cpu/x86/vm/globals_x86.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/globals_x86.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -101,6 +101,8 @@
 
 define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, LP64_ONLY(true) NOT_LP64(false));
+
 #define ARCH_FLAGS(develop, \
                    product, \
                    diagnostic, \
--- a/src/cpu/x86/vm/interp_masm_x86.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/interp_masm_x86.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -344,6 +344,7 @@
   const Address val_addr(rcx, JvmtiThreadState::earlyret_value_offset());
 #ifdef _LP64
   switch (state) {
+    case qtos: // fall through
     case atos: movptr(rax, oop_addr);
                movptr(oop_addr, (int32_t)NULL_WORD);
                verify_oop(rax, state);              break;
@@ -365,6 +366,7 @@
   const Address val_addr1(rcx, JvmtiThreadState::earlyret_value_offset()
                              + in_ByteSize(wordSize));
   switch (state) {
+    case qtos: // fall through
     case atos: movptr(rax, oop_addr);
                movptr(oop_addr, NULL_WORD);
                verify_oop(rax, state);                break;
@@ -617,6 +619,7 @@
 
 void InterpreterMacroAssembler::pop(TosState state) {
   switch (state) {
+  case qtos: // Fall through
   case atos: pop_ptr();                 break;
   case btos:
   case ztos:
@@ -635,6 +638,7 @@
 void InterpreterMacroAssembler::push(TosState state) {
   verify_oop(rax, state);
   switch (state) {
+  case qtos: // Fall through
   case atos: push_ptr();                break;
   case btos:
   case ztos:
@@ -671,6 +675,7 @@
 
 void InterpreterMacroAssembler::pop(TosState state) {
   switch (state) {
+    case qtos:                                               // fall through
     case atos: pop_ptr(rax);                                 break;
     case btos:                                               // fall through
     case ztos:                                               // fall through
@@ -720,6 +725,7 @@
 void InterpreterMacroAssembler::push(TosState state) {
   verify_oop(rax, state);
   switch (state) {
+    case qtos:                                               // fall through
     case atos: push_ptr(rax); break;
     case btos:                                               // fall through
     case ztos:                                               // fall through
--- a/src/cpu/x86/vm/interpreterRT_x86.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/interpreterRT_x86.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -52,6 +52,7 @@
   void pass_double();
 #endif // AMD64
   void pass_object();
+  void pass_valuetype();
 
  public:
   // Creation
--- a/src/cpu/x86/vm/interpreterRT_x86_32.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/interpreterRT_x86_32.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -56,6 +56,10 @@
   box (offset(), jni_offset() + 1);
 }
 
+void InterpreterRuntime::SignatureHandlerGenerator::pass_valuetype() {
+  box (offset(), jni_offset() + 1);
+}
+
 void InterpreterRuntime::SignatureHandlerGenerator::move(int from_offset, int to_offset) {
   __ movl(temp(), Address(from(), Interpreter::local_offset_in_bytes(from_offset)));
   __ movl(Address(to(), to_offset * wordSize), temp());
@@ -123,6 +127,13 @@
     _from -= Interpreter::stackElementSize;
    }
 
+  virtual void pass_valuetype() {
+    // pass address of from
+    intptr_t from_addr = (intptr_t)(_from + Interpreter::local_offset_in_bytes(0));
+    *_to++ = (*(intptr_t*)from_addr == 0) ? NULL_WORD : from_addr;
+    _from -= Interpreter::stackElementSize;
+  }
+
  public:
   SlowSignatureHandler(methodHandle method, address from, intptr_t* to) :
     NativeSignatureIterator(method) {
--- a/src/cpu/x86/vm/interpreterRT_x86_64.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/interpreterRT_x86_64.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -275,6 +275,10 @@
 #endif
 }
 
+void InterpreterRuntime::SignatureHandlerGenerator::pass_valuetype() {
+  pass_object();
+}
+
 void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) {
   // generate code to handle arguments
   iterate(fingerprint);
@@ -340,6 +344,11 @@
     }
   }
 
+  virtual void pass_valuetype() {
+    // values are handled with oops, like objects
+    pass_object();
+  }
+
   virtual void pass_float()
   {
     jint from_obj = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
@@ -433,6 +442,11 @@
     }
   }
 
+  virtual void pass_valuetype() {
+    // values are handled with oops, like objects
+    pass_object();
+  }
+
   virtual void pass_float()
   {
     jint from_obj = *(jint*)(_from+Interpreter::local_offset_in_bytes(0));
--- a/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -341,6 +341,7 @@
   case T_DOUBLE : /* nothing to do */        break;
 #endif // _LP64
 
+  case T_VALUETYPE: // fall through (value types are handled with oops)
   case T_OBJECT :
     // retrieve result from frame
     __ movptr(rax, Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize));
@@ -1796,10 +1797,12 @@
                                                          address& lep,
                                                          address& fep,
                                                          address& dep,
+                                                         address& qep,
                                                          address& vep) {
   assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
   Label L;
   aep = __ pc();  __ push_ptr();   __ jmp(L);
+  qep = __ pc();  __ push_ptr();   __ jmp(L);
 #ifndef _LP64
   fep = __ pc(); __ push(ftos); __ jmp(L);
   dep = __ pc(); __ push(dtos); __ jmp(L);
--- a/src/cpu/x86/vm/templateTable_x86.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/cpu/x86/vm/templateTable_x86.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -241,6 +241,9 @@
   Label L_patch_done;
 
   switch (bc) {
+  case Bytecodes::_fast_qputfield:
+    __ jmp(L_patch_done); // don't patch yet
+    break;
   case Bytecodes::_fast_aputfield:
   case Bytecodes::_fast_bputfield:
   case Bytecodes::_fast_zputfield:
@@ -636,6 +639,12 @@
   __ movptr(rax, aaddress(rbx));
 }
 
+void TemplateTable::vload() {
+  transition(vtos, qtos);
+  locals_index(rbx);
+  __ movptr(rax, aaddress(rbx));
+}
+
 void TemplateTable::locals_index_wide(Register reg) {
   __ load_unsigned_short(reg, at_bcp(2));
   __ bswapl(reg);
@@ -674,6 +683,12 @@
   __ movptr(rax, aaddress(rbx));
 }
 
+void TemplateTable::wide_vload() {
+  transition(vtos, qtos);
+  locals_index_wide(rbx);
+  __ movptr(rax, aaddress(rbx));
+}
+
 void TemplateTable::index_check(Register array, Register index) {
   // Pop ptr into array
   __ pop_ptr(array);
@@ -751,6 +766,17 @@
                                 arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
 }
 
+void TemplateTable::vaload() {
+  transition(itos, qtos);
+
+  Register array = rcx;
+  Register index = rax;
+
+  index_check(array, index); // kills rbx, pops array
+
+  __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::value_array_load) , array, index);
+}
+
 void TemplateTable::baload() {
   transition(itos, itos);
   // rax: index
@@ -929,6 +955,13 @@
   __ movptr(aaddress(rbx), rax);
 }
 
+void TemplateTable::vstore() {
+  transition(vtos, vtos);
+  __ pop_ptr(rax);
+  locals_index(rbx);
+  __ movptr(aaddress(rbx), rax);
+}
+
 void TemplateTable::wide_istore() {
   transition(vtos, vtos);
   __ pop_i();
@@ -974,6 +1007,13 @@
   __ movptr(aaddress(rbx), rax);
 }
 
+void TemplateTable::wide_vstore() {
+  transition(vtos, vtos);
+  __ pop_ptr(rax);
+  locals_index_wide(rbx);
+  __ movptr(aaddress(rbx), rax);
+}
+
 void TemplateTable::iastore() {
   transition(itos, vtos);
   __ pop_i(rbx);
@@ -1074,6 +1114,23 @@
   __ addptr(rsp, 3 * Interpreter::stackElementSize);
 }
 
+void TemplateTable::vastore() {
+  transition(vtos, vtos);
+
+  Register value = rcx;
+  Register index = rbx;
+  Register array = rax;
+
+  // stack: ..., array, index, value
+  __ pop_ptr(value);
+  __ pop_i(index);
+  __ pop_ptr(array);
+
+  index_check_without_pop(array, index);
+
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::value_array_store), array, index, value);
+}
+
 void TemplateTable::bastore() {
   transition(itos, vtos);
   __ pop_i(rbx);
@@ -2746,7 +2803,7 @@
   __ verify_oop(r);
 }
 
-void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) {
+void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc, bool is_vgetfield) {
   transition(vtos, vtos);
 
   const Register cache = rcx;
@@ -2760,12 +2817,10 @@
   jvmti_post_field_access(cache, index, is_static, false);
   load_field_cp_cache_entry(obj, cache, index, off, flags, is_static);
 
-  if (!is_static) pop_and_check_object(obj);
-
   const Address field(obj, off, Address::times_1, 0*wordSize);
   NOT_LP64(const Address hi(obj, off, Address::times_1, 1*wordSize));
 
-  Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble;
+  Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notValueType, notDouble;
 
   __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
   // Make sure we don't need to mask edx after the above shift
@@ -2775,6 +2830,7 @@
 
   __ jcc(Assembler::notZero, notByte);
   // btos
+  if (!is_static) pop_and_check_object(obj);
   __ load_signed_byte(rax, field);
   __ push(btos);
   // Rewrite bytecode to be faster
@@ -2784,6 +2840,37 @@
   __ jmp(Done);
 
   __ bind(notByte);
+
+  __ cmpl(flags, qtos);
+  __ jcc(Assembler::notEqual, notValueType);
+  // qtos
+  if (is_static) {
+    __ load_heap_oop(rax, field);
+    __ push(qtos);
+    //    if (!is_static && !is_vgetfield) {
+    //      patch_bytecode(Bytecodes::_fast_qgetfield, bc, rbx);
+    //    }
+  } else {
+
+    // cp cache entry pointer
+//    __ addptr(cache, in_bytes(ConstantPoolCache::base_offset()));
+//    __ shll(index, LogBytesPerWord);
+//    __ addptr(cache, index);
+
+    pop_and_check_object(obj);
+
+    call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::qgetfield),
+        obj, off);
+    __ verify_oop(rax);
+    __ push(qtos);
+    // Bytecode rewrite?
+  }
+  __ jmp(Done);
+
+  __ bind(notValueType);
+
+  if (!is_static) pop_and_check_object(obj);
+
   __ cmpl(flags, ztos);
   __ jcc(Assembler::notEqual, notBool);
 
@@ -2917,6 +3004,25 @@
   getfield_or_static(byte_no, true);
 }
 
+void TemplateTable::vgetfield() {
+  getfield_or_static(f1_byte, false, may_not_rewrite, true);
+}
+
+void TemplateTable::vwithfield() {
+  transition(vtos, qtos);
+
+  Register cache = LP64_ONLY(c_rarg1) NOT_LP64(rcx);
+  Register index = LP64_ONLY(c_rarg2) NOT_LP64(rdx);
+
+  resolve_cache_and_index(f2_byte, cache, index, sizeof(u2));
+
+  call_VM(rbx, CAST_FROM_FN_PTR(address, InterpreterRuntime::vwithfield), cache);
+  // new value type is returned in rbx
+  // stack adjustement is returned in rax
+  __ verify_oop(rbx);
+  __ addptr(rsp, rax);
+  __ movptr(rax, rbx);
+}
 
 // The registers cache and index expected to be set before call.
 // The function may destroy various registers, just not the cache and index registers.
@@ -3032,7 +3138,7 @@
   NOT_LP64( const Address hi(obj, off, Address::times_1, 1*wordSize);)
 
   Label notByte, notBool, notInt, notShort, notChar,
-        notLong, notFloat, notObj, notDouble;
+        notLong, notFloat, notObj, notValueType, notDouble;
 
   __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
 
@@ -3084,6 +3190,28 @@
   }
 
   __ bind(notObj);
+  __ cmpl(flags, qtos);
+  __ jcc(Assembler::notEqual, notValueType);
+
+  // qtos
+  {
+    __ pop(qtos); // => rax == value
+    if (!is_static) {
+      // value types in non-static fields are embedded
+      __ movl(rcx, off);
+      pop_and_check_object(rbx);
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::qputfield),
+          rbx, rax, rcx);
+      __ jmp(notVolatile); // value types are never volatile
+    } else {
+      // Store into the static field
+      // Value types in static fields are currently handled with indirection
+      do_oop_store(_masm, field, rax, _bs->kind(), false);
+    }
+    __ jmp(Done);
+  }
+
+  __ bind(notValueType);
   __ cmpl(flags, itos);
   __ jcc(Assembler::notEqual, notInt);
 
@@ -3253,6 +3381,7 @@
     // to do it for every data type, we use the saved values as the
     // jvalue object.
     switch (bytecode()) {          // load values into the jvalue object
+    case Bytecodes::_fast_qputfield: //fall through
     case Bytecodes::_fast_aputfield: __ push_ptr(rax); break;
     case Bytecodes::_fast_bputfield: // fall through
     case Bytecodes::_fast_zputfield: // fall through
@@ -3278,6 +3407,7 @@
     NOT_LP64(__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), rbx, rax, rcx));
 
     switch (bytecode()) {             // restore tos values
+    case Bytecodes::_fast_qputfield: // fall through
     case Bytecodes::_fast_aputfield: __ pop_ptr(rax); break;
     case Bytecodes::_fast_bputfield: // fall through
     case Bytecodes::_fast_zputfield: // fall through
@@ -3327,6 +3457,9 @@
 
   // access field
   switch (bytecode()) {
+  case Bytecodes::_fast_qputfield:
+    __ stop("should not be rewritten yet");
+    break;
   case Bytecodes::_fast_aputfield:
     do_oop_store(_masm, field, rax, _bs->kind(), false);
     break;
@@ -3416,6 +3549,9 @@
 
   // access field
   switch (bytecode()) {
+  case Bytecodes::_fast_qgetfield:
+    __ stop("should not be rewritten yet");
+    break;
   case Bytecodes::_fast_agetfield:
     __ load_heap_oop(rax, field);
     __ verify_oop(rax);
@@ -3525,11 +3661,12 @@
   const bool is_invokedynamic    = code == Bytecodes::_invokedynamic;
   const bool is_invokehandle     = code == Bytecodes::_invokehandle;
   const bool is_invokevirtual    = code == Bytecodes::_invokevirtual;
+  const bool is_invokedirect     = code == Bytecodes::_invokedirect;
   const bool is_invokespecial    = code == Bytecodes::_invokespecial;
   const bool load_receiver       = (recv  != noreg);
   const bool save_flags          = (flags != noreg);
   assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), "");
-  assert(save_flags    == (is_invokeinterface || is_invokevirtual), "need flags for vfinal");
+  assert(save_flags    == (is_invokeinterface || is_invokevirtual || is_invokedirect), "need flags for vfinal");
   assert(flags == noreg || flags == rdx, "");
   assert(recv  == noreg || recv  == rcx, "");
 
@@ -3541,7 +3678,9 @@
   // save 'interpreter return address'
   __ save_bcp();
 
-  load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
+  load_invoke_cp_cache_entry(byte_no, method, index, flags,
+                             is_invokevirtual || is_invokedirect,
+                             false, is_invokedynamic);
 
   // maybe push appendix to arguments (just before return address)
   if (is_invokedynamic || is_invokehandle) {
@@ -3661,6 +3800,36 @@
   invokevirtual_helper(rbx, rcx, rdx);
 }
 
+/*
+ * The invokedirect bytecode is implemented as an invokevirtual bytecode:
+ * The implementation blindly uses resolve_invokevirtual() and assumes
+ * that a final call will be picked at the end. (Currently unsure about interfaces,
+ * default methods, and about where "Value.equals(QValue;)Z" should live.)
+ */
+void TemplateTable::invokedirect(int byte_no) {
+  transition(vtos, vtos);
+  assert(byte_no == f2_byte, "use this argument");
+  prepare_invoke(byte_no,
+      rbx,       // method (and not vtable index, as the method to be invoked should be final)
+      noreg,
+      rcx, rdx); // recv, flags
+
+  // Check if the method is final
+  Label notFinal;
+  __ movl(rax, rdx);
+  __ andl(rax, (1 << ConstantPoolCacheEntry::is_vfinal_shift));
+  __ jcc(Assembler::zero, notFinal);
+
+  __ verify_oop(rcx);
+  __ null_check(rcx);
+  __ profile_final_call(rax);
+  __ profile_arguments_type(rax, rbx, rbcp, true);
+  __ jump_from_interpreted(rbx, rax);
+
+  __ bind(notFinal);
+  __ stop("Interpreter observed a non-final method as a target of an invokedirect instruction");
+}
+
 void TemplateTable::invokespecial(int byte_no) {
   transition(vtos, vtos);
   assert(byte_no == f1_byte, "use this argument");
@@ -4001,6 +4170,20 @@
   __ bind(done);
 }
 
+void TemplateTable::vdefault() {
+  transition(vtos, qtos);
+
+  Register rarg1 = LP64_ONLY(c_rarg1) NOT_LP64(rcx);
+  Register rarg2 = LP64_ONLY(c_rarg2) NOT_LP64(rdx);
+
+  __ get_unsigned_2_byte_index_at_bcp(rarg2, 1);
+  __ get_constant_pool(rarg1);
+
+  call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::vdefault),
+      rarg1, rarg2);
+  __ verify_oop(rax);
+}
+
 void TemplateTable::newarray() {
   transition(itos, atos);
   Register rarg1 = LP64_ONLY(c_rarg1) NOT_LP64(rdx);
@@ -4157,6 +4340,29 @@
   // rax = 1: obj != NULL and obj is     an instanceof the specified klass
 }
 
+void TemplateTable::_vbox() {
+  transition(qtos, atos);
+
+  Register rarg1 = LP64_ONLY(c_rarg1) NOT_LP64(rcx);
+  Register rarg2 = LP64_ONLY(c_rarg2) NOT_LP64(rdx);
+
+  __ get_unsigned_2_byte_index_at_bcp(rarg2, 1);
+  __ get_constant_pool(rarg1);
+  call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::vbox),
+      rarg1, rarg2, rax);
+}
+
+void TemplateTable::_vunbox() {
+  transition(atos, qtos);
+
+  Register rarg1 = LP64_ONLY(c_rarg1) NOT_LP64(rcx);
+  Register rarg2 = LP64_ONLY(c_rarg2) NOT_LP64(rdx);
+
+  __ get_unsigned_2_byte_index_at_bcp(rarg2, 1);
+  __ get_constant_pool(rarg1);
+  call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::vunbox),
+      rarg1, rarg2, rax);
+}
 
 //----------------------------------------------------------------------------------------------------
 // Breakpoints
--- a/src/share/vm/ci/ciArrayKlass.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciArrayKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -27,6 +27,8 @@
 #include "ci/ciObjArrayKlass.hpp"
 #include "ci/ciTypeArrayKlass.hpp"
 #include "ci/ciUtilities.hpp"
+#include "ci/ciValueArrayKlass.hpp"
+#include "ci/ciValueKlass.hpp"
 
 // ciArrayKlass
 //
@@ -59,7 +61,7 @@
   if (is_type_array_klass()) {
     return ciType::make(as_type_array_klass()->element_type());
   } else {
-    return as_obj_array_klass()->element_klass()->as_klass();
+    return element_klass()->as_klass();
   }
 }
 
@@ -71,12 +73,14 @@
 ciType* ciArrayKlass::base_element_type() {
   if (is_type_array_klass()) {
     return ciType::make(as_type_array_klass()->element_type());
-  } else {
+  } else if (is_obj_array_klass()) {
     ciKlass* ek = as_obj_array_klass()->base_element_klass();
     if (ek->is_type_array_klass()) {
       return ciType::make(ek->as_type_array_klass()->element_type());
     }
     return ek;
+  } else {
+    return as_value_array_klass()->base_element_klass();
   }
 }
 
@@ -99,6 +103,8 @@
 ciArrayKlass* ciArrayKlass::make(ciType* element_type) {
   if (element_type->is_primitive_type()) {
     return ciTypeArrayKlass::make(element_type->basic_type());
+  } else if (element_type->is_valuetype() && element_type->as_value_klass()->flatten_array()) {
+    return ciValueArrayKlass::make(element_type->as_klass());
   } else {
     return ciObjArrayKlass::make(element_type->as_klass());
   }
--- a/src/share/vm/ci/ciArrayKlass.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciArrayKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -56,6 +56,9 @@
   bool is_array_klass() const { return true; }
   bool is_java_klass() const  { return true; }
 
+  // The one-level type of the array elements.
+  virtual ciKlass* element_klass() { return NULL; }
+
   static ciArrayKlass* make(ciType* element_type);
 };
 
--- a/src/share/vm/ci/ciClassList.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciClassList.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -62,7 +62,9 @@
 class    ciReturnAddress;
 class    ciKlass;
 class     ciInstanceKlass;
+class       ciValueKlass;
 class     ciArrayKlass;
+class       ciValueArrayKlass;
 class       ciObjArrayKlass;
 class       ciTypeArrayKlass;
 
@@ -114,7 +116,9 @@
 friend class ciReturnAddress;          \
 friend class ciKlass;                  \
 friend class ciInstanceKlass;          \
+friend class ciValueKlass;             \
 friend class ciArrayKlass;             \
+friend class ciValueArrayKlass;        \
 friend class ciObjArrayKlass;          \
 friend class ciTypeArrayKlass;         \
 
--- a/src/share/vm/ci/ciConstant.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciConstant.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -106,7 +106,7 @@
     return _value._double;
   }
   ciObject* as_object() const {
-    assert(basic_type() == T_OBJECT || basic_type() == T_ARRAY, "wrong type");
+    assert(basic_type() == T_OBJECT || basic_type() == T_ARRAY || basic_type() == T_VALUETYPE, "wrong type");
     return _value._object;
   }
 
--- a/src/share/vm/ci/ciEnv.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciEnv.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -32,6 +32,7 @@
 #include "ci/ciNullObject.hpp"
 #include "ci/ciReplay.hpp"
 #include "ci/ciUtilities.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/codeCache.hpp"
@@ -393,7 +394,7 @@
 
   // Now we need to check the SystemDictionary
   Symbol* sym = name->get_symbol();
-  if (sym->byte_at(0) == 'L' &&
+  if ((sym->byte_at(0) == 'L' || sym->byte_at(0) == 'Q') &&
     sym->byte_at(sym->utf8_length()-1) == ';') {
     // This is a name from a signature.  Strip off the trimmings.
     // Call recursive to keep scope of strippedsym.
@@ -448,7 +449,7 @@
   // to be loaded if their element klasses are loaded, except when memory
   // is exhausted.
   if (sym->byte_at(0) == '[' &&
-      (sym->byte_at(1) == '[' || sym->byte_at(1) == 'L')) {
+      (sym->byte_at(1) == '[' || sym->byte_at(1) == 'L' || sym->byte_at(1) == 'Q')) {
     // We have an unloaded array.
     // Build it on the fly if the element class exists.
     TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1,
@@ -463,7 +464,11 @@
                              require_local);
     if (elem_klass != NULL && elem_klass->is_loaded()) {
       // Now make an array for it
-      return ciObjArrayKlass::make_impl(elem_klass);
+      if (elem_klass->is_valuetype() && elem_klass->as_value_klass()->flatten_array()) {
+        return ciValueArrayKlass::make_impl(elem_klass);
+      } else {
+        return ciObjArrayKlass::make_impl(elem_klass);
+      }
     }
   }
 
@@ -731,6 +736,7 @@
       LinkResolver::linktime_resolve_interface_method_or_null(link_info);
     break;
   case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokedirect:
     dest_method =
       LinkResolver::linktime_resolve_virtual_method_or_null(link_info);
     break;
@@ -786,6 +792,7 @@
       // if the names are not resolvable in the boot class loader (7056328).
       switch (bc) {
       case Bytecodes::_invokevirtual:
+      case Bytecodes::_invokedirect:
       case Bytecodes::_invokeinterface:
       case Bytecodes::_invokespecial:
       case Bytecodes::_invokestatic:
--- a/src/share/vm/ci/ciEnv.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciEnv.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -195,6 +195,10 @@
     if (o == NULL) return NULL;
     return get_object(o)->as_instance();
   }
+  ciValueArrayKlass* get_value_array_klass(Klass* o) {
+    if (o == NULL) return NULL;
+    return get_metadata(o)->as_value_array_klass();
+  }
   ciObjArrayKlass* get_obj_array_klass(Klass* o) {
     if (o == NULL) return NULL;
     return get_metadata(o)->as_obj_array_klass();
--- a/src/share/vm/ci/ciField.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciField.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -90,7 +90,7 @@
 
   // If the field is a pointer type, get the klass of the
   // field.
-  if (field_type == T_OBJECT || field_type == T_ARRAY) {
+  if (field_type == T_OBJECT || field_type == T_ARRAY || field_type == T_VALUETYPE) {
     bool ignore;
     // This is not really a class reference; the index always refers to the
     // field's type signature, as a symbol.  Linkage checks do not apply.
@@ -187,7 +187,7 @@
 
   // If the field is a pointer type, get the klass of the
   // field.
-  if (field_type == T_OBJECT || field_type == T_ARRAY) {
+  if (field_type == T_OBJECT || field_type == T_ARRAY || field_type == T_VALUETYPE) {
     _type = NULL;  // must call compute_type on first access
   } else {
     _type = ciType::make(field_type);
@@ -200,6 +200,26 @@
          "bootstrap classes must not create & cache unshared fields");
 }
 
+// Special copy constructor used to flatten value type fields by
+// copying the fields of the value type to a new holder klass.
+ciField::ciField(ciField* field, ciInstanceKlass* holder, int offset, bool is_final) {
+  assert(field->holder()->is_valuetype(), "should only be used for value type field flattening");
+  // Set the is_final flag
+  jint final = is_final ? JVM_ACC_FINAL : ~JVM_ACC_FINAL;
+  AccessFlags flags(field->flags().as_int() & final);
+  _flags = ciFlags(flags);
+  _holder = holder;
+  _offset = offset;
+  // Copy remaining fields
+  _name = field->_name;
+  _signature = field->_signature;
+  _type = field->_type;
+  _is_constant = field->_is_constant;
+  _known_to_link_with_put = field->_known_to_link_with_put;
+  _known_to_link_with_get = field->_known_to_link_with_get;
+  _constant_value = field->_constant_value;
+}
+
 static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
   if (holder == NULL)
     return false;
@@ -347,7 +367,8 @@
                         Bytecodes::Code bc) {
   VM_ENTRY_MARK;
   assert(bc == Bytecodes::_getstatic || bc == Bytecodes::_putstatic ||
-         bc == Bytecodes::_getfield  || bc == Bytecodes::_putfield,
+         bc == Bytecodes::_getfield  || bc == Bytecodes::_putfield  ||
+         bc == Bytecodes::_vgetfield || bc == Bytecodes::_vwithfield,
          "unexpected bytecode");
 
   if (_offset == -1) {
--- a/src/share/vm/ci/ciField.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciField.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -57,6 +57,7 @@
 
   ciField(ciInstanceKlass* klass, int index);
   ciField(fieldDescriptor* fd);
+  ciField(ciField* field, ciInstanceKlass* holder, int offset, bool is_final);
 
   // shared constructor code
   void initialize_from(fieldDescriptor* fd);
--- a/src/share/vm/ci/ciInstance.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciInstance.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -98,7 +98,8 @@
 ciConstant ciInstance::field_value(ciField* field) {
   assert(is_loaded(), "invalid access - must be loaded");
   assert(field->holder()->is_loaded(), "invalid access - holder must be loaded");
-  assert(field->is_static() || klass()->is_subclass_of(field->holder()), "invalid access - must be subclass");
+  assert(field->is_static() || field->holder()->is_valuetype() || klass()->is_subclass_of(field->holder()),
+         "invalid access - must be subclass");
 
   GUARDED_VM_ENTRY(return field_value_impl(field->type()->basic_type(), field->offset());)
 }
--- a/src/share/vm/ci/ciInstanceKlass.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciInstanceKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -27,12 +27,14 @@
 #include "ci/ciInstance.hpp"
 #include "ci/ciInstanceKlass.hpp"
 #include "ci/ciUtilities.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/fieldStreams.hpp"
+#include "oops/valueKlass.hpp"
 #include "runtime/fieldDescriptor.hpp"
 
 // ciInstanceKlass
@@ -60,7 +62,8 @@
   _has_nonstatic_fields = ik->has_nonstatic_fields();
   _has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods();
   _is_anonymous = ik->is_anonymous();
-  _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
+  _nonstatic_fields = NULL;            // initialized lazily by compute_nonstatic_fields
+  _nof_declared_nonstatic_fields = -1; // initialized lazily by compute_nonstatic_fields
   _has_injected_fields = -1;
   _implementor = NULL; // we will fill these lazily
 
@@ -101,7 +104,8 @@
   _init_state = (InstanceKlass::ClassState)0;
   _nonstatic_field_size = -1;
   _has_nonstatic_fields = false;
-  _nonstatic_fields = NULL;
+  _nonstatic_fields = NULL;            // initialized lazily by compute_nonstatic_fields
+  _nof_declared_nonstatic_fields = -1; // initialized lazily by compute_nonstatic_fields
   _has_injected_fields = -1;
   _is_anonymous = false;
   _loader = loader;
@@ -398,6 +402,29 @@
 }
 
 // ------------------------------------------------------------------
+// ciInstanceKlass::get_field_type_by_offset
+ciType* ciInstanceKlass::get_field_type_by_offset(int field_offset) {
+  ASSERT_IN_VM;
+  fieldDescriptor fd;
+  InstanceKlass* klass = get_instanceKlass();
+  // Important: We cannot get the field type via get_field_by_offset() because if the field
+  // is another value type, the offset would refer to the first field of that value type due
+  // to flattening. Instead, do a SystemDictionary lookup for the type of the declared field.
+  bool found = klass->find_field_from_offset(field_offset, false, &fd);
+  assert(found, "field not found");
+  BasicType field_type = fd.field_type();
+  if (is_java_primitive(field_type)) {
+    // Primitive type
+    return ciType::make(field_type);
+  } else {
+    // Do a SystemDictionary lookup for the type
+    ciEnv* env = CURRENT_ENV;
+    ciSymbol* signature = env->get_symbol(fd.signature());
+    return env->get_klass_by_name_impl(this, constantPoolHandle(), signature, false);
+  }
+}
+
+// ------------------------------------------------------------------
 // ciInstanceKlass::get_field_by_name
 ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) {
   VM_ENTRY_MARK;
@@ -428,6 +455,7 @@
   if (!has_nonstatic_fields()) {
     Arena* arena = CURRENT_ENV->arena();
     _nonstatic_fields = new (arena) GrowableArray<ciField*>(arena, 0, 0, NULL);
+    _nof_declared_nonstatic_fields = 0;
     return 0;
   }
   assert(!is_java_lang_Object(), "bootstrap OK");
@@ -445,6 +473,7 @@
     // See if I am no larger than my super; if so, I can use his fields.
     if (fsize == super_fsize) {
       _nonstatic_fields = super_fields;
+      _nof_declared_nonstatic_fields = super->nof_declared_nonstatic_fields();
       return super_fields->length();
     }
   }
@@ -458,8 +487,10 @@
     // This can happen if this class (java.lang.Class) has invisible fields.
     if (super_fields != NULL) {
       _nonstatic_fields = super_fields;
+      _nof_declared_nonstatic_fields = super->nof_declared_nonstatic_fields();
       return super_fields->length();
     } else {
+      _nof_declared_nonstatic_fields = 0;
       return 0;
     }
   }
@@ -488,11 +519,14 @@
 
   // allocate the array:
   if (flen == 0) {
+    _nof_declared_nonstatic_fields = flen;
     return NULL;  // return nothing if none are locally declared
   }
   if (super_fields != NULL) {
     flen += super_fields->length();
   }
+  _nof_declared_nonstatic_fields = flen;
+
   fields = new (arena) GrowableArray<ciField*>(arena, flen, 0, NULL);
   if (super_fields != NULL) {
     fields->appendAll(super_fields);
@@ -501,8 +535,27 @@
   for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
     if (fs.access_flags().is_static())  continue;
     fieldDescriptor& fd = fs.field_descriptor();
-    ciField* field = new (arena) ciField(&fd);
-    fields->append(field);
+    if (fd.field_type() == T_VALUETYPE) {
+      // Value type fields are embedded
+      int field_offset = fd.offset();
+      // Get ValueKlass and adjust number of fields
+      ciValueKlass* vk = get_field_type_by_offset(field_offset)->as_value_klass();
+      flen += vk->flattened_field_count() - 1;
+      // Iterate over fields of the flattened value type and copy them to 'this'
+      for (int i = 0; i < vk->nof_nonstatic_fields(); ++i) {
+        ciField* flattened_field = vk->nonstatic_field_at(i);
+        // Adjust offset to account for missing oop header
+        int offset = field_offset + (flattened_field->offset() - vk->first_field_offset());
+        // A flattened field can be treated as final if the non-flattened
+        // field is declared final or the holder klass is a value type itself.
+        bool is_final = fd.is_final() || is_valuetype();
+        ciField* field = new (arena) ciField(flattened_field, this, offset, is_final);
+        fields->append(field);
+      }
+    } else {
+      ciField* field = new (arena) ciField(&fd);
+      fields->append(field);
+    }
   }
   assert(fields->length() == flen, "sanity");
   return fields;
@@ -603,77 +656,124 @@
 // only value which statically unchangeable.  For all other reference
 // types it simply prints out the dynamic type.
 
-class StaticFinalFieldPrinter : public FieldClosure {
+class StaticFieldPrinter : public FieldClosure {
+protected:
   outputStream* _out;
+public:
+  StaticFieldPrinter(outputStream* out) :
+    _out(out) {
+  }
+  void do_field_helper(fieldDescriptor* fd, oop obj, bool flattened);
+};
+
+class StaticFinalFieldPrinter : public StaticFieldPrinter {
   const char*   _holder;
  public:
   StaticFinalFieldPrinter(outputStream* out, const char* holder) :
-    _out(out),
-    _holder(holder) {
+    StaticFieldPrinter(out), _holder(holder) {
   }
   void do_field(fieldDescriptor* fd) {
     if (fd->is_final() && !fd->has_initial_value()) {
       ResourceMark rm;
-      oop mirror = fd->field_holder()->java_mirror();
+      InstanceKlass* holder = fd->field_holder();
+      oop mirror = holder->java_mirror();
       _out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii());
-      switch (fd->field_type()) {
-        case T_BYTE:    _out->print_cr("%d", mirror->byte_field(fd->offset()));   break;
-        case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset()));   break;
-        case T_SHORT:   _out->print_cr("%d", mirror->short_field(fd->offset()));  break;
-        case T_CHAR:    _out->print_cr("%d", mirror->char_field(fd->offset()));   break;
-        case T_INT:     _out->print_cr("%d", mirror->int_field(fd->offset()));    break;
-        case T_LONG:    _out->print_cr(INT64_FORMAT, (int64_t)(mirror->long_field(fd->offset())));   break;
-        case T_FLOAT: {
-          float f = mirror->float_field(fd->offset());
-          _out->print_cr("%d", *(int*)&f);
-          break;
-        }
-        case T_DOUBLE: {
-          double d = mirror->double_field(fd->offset());
-          _out->print_cr(INT64_FORMAT, *(int64_t*)&d);
-          break;
-        }
-        case T_ARRAY: {
-          oop value =  mirror->obj_field_acquire(fd->offset());
-          if (value == NULL) {
-            _out->print_cr("null");
-          } else {
-            typeArrayOop ta = (typeArrayOop)value;
-            _out->print("%d", ta->length());
-            if (value->is_objArray()) {
-              objArrayOop oa = (objArrayOop)value;
-              const char* klass_name  = value->klass()->name()->as_quoted_ascii();
-              _out->print(" %s", klass_name);
-            }
-            _out->cr();
-          }
-          break;
-        }
-        case T_OBJECT: {
-          oop value =  mirror->obj_field_acquire(fd->offset());
-          if (value == NULL) {
-            _out->print_cr("null");
-          } else if (value->is_instance()) {
-            if (value->is_a(SystemDictionary::String_klass())) {
-              _out->print("\"");
-              _out->print_raw(java_lang_String::as_quoted_ascii(value));
-              _out->print_cr("\"");
-            } else {
-              const char* klass_name  = value->klass()->name()->as_quoted_ascii();
-              _out->print_cr("%s", klass_name);
-            }
-          } else {
-            ShouldNotReachHere();
-          }
-          break;
-        }
-        default:
-          ShouldNotReachHere();
-        }
+      do_field_helper(fd, mirror, false);
+      _out->cr();
     }
   }
 };
 
+class ValueTypeFieldPrinter : public StaticFieldPrinter {
+  oop _obj;
+public:
+  ValueTypeFieldPrinter(outputStream* out, oop obj) :
+    StaticFieldPrinter(out), _obj(obj) {
+  }
+  void do_field(fieldDescriptor* fd) {
+    do_field_helper(fd, _obj, true);
+    _out->print(" ");
+  }
+};
+
+void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool flattened) {
+  switch (fd->field_type()) {
+    case T_BYTE:    _out->print_cr("%d", mirror->byte_field(fd->offset()));   break;
+    case T_BOOLEAN: _out->print("%d", mirror->bool_field(fd->offset()));   break;
+    case T_SHORT:   _out->print("%d", mirror->short_field(fd->offset()));  break;
+    case T_CHAR:    _out->print("%d", mirror->char_field(fd->offset()));   break;
+    case T_INT:     _out->print("%d", mirror->int_field(fd->offset()));    break;
+    case T_LONG:    _out->print(INT64_FORMAT, (int64_t)(mirror->long_field(fd->offset())));   break;
+    case T_FLOAT: {
+      float f = mirror->float_field(fd->offset());
+      _out->print("%d", *(int*)&f);
+      break;
+    }
+    case T_DOUBLE: {
+      double d = mirror->double_field(fd->offset());
+      _out->print(INT64_FORMAT, *(int64_t*)&d);
+      break;
+    }
+    case T_ARRAY: {
+      oop value =  mirror->obj_field_acquire(fd->offset());
+      if (value == NULL) {
+        _out->print("null");
+      } else {
+        typeArrayOop ta = (typeArrayOop)value;
+        _out->print("%d", ta->length());
+        if (value->is_objArray()) {
+          objArrayOop oa = (objArrayOop)value;
+          const char* klass_name  = value->klass()->name()->as_quoted_ascii();
+          _out->print(" %s", klass_name);
+        }
+      }
+      break;
+    }
+    case T_OBJECT: {
+      oop value =  mirror->obj_field_acquire(fd->offset());
+      if (value == NULL) {
+        _out->print("null");
+      } else if (value->is_instance()) {
+        if (value->is_a(SystemDictionary::String_klass())) {
+          _out->print("\"");
+          _out->print_raw(java_lang_String::as_quoted_ascii(value));
+          _out->print("\"");
+        } else {
+          const char* klass_name  = value->klass()->name()->as_quoted_ascii();
+          _out->print("%s", klass_name);
+        }
+      } else {
+        ShouldNotReachHere();
+      }
+      break;
+    }
+    case T_VALUETYPE: {
+      ResetNoHandleMark rnhm;
+      Thread* THREAD = Thread::current();
+      SignatureStream ss(fd->signature(), false);
+      Symbol* name = ss.as_symbol(THREAD);
+      assert(!HAS_PENDING_EXCEPTION, "can resolve klass?");
+      InstanceKlass* holder = fd->field_holder();
+      Klass* k = SystemDictionary::find(name, Handle(THREAD, holder->class_loader()),
+                                        Handle(THREAD, holder->protection_domain()), THREAD);
+      assert(k != NULL && !HAS_PENDING_EXCEPTION, "can resolve klass?");
+      ValueKlass* vk = ValueKlass::cast(k);
+      oop obj;
+      if (flattened) {
+        int field_offset = fd->offset() - vk->first_field_offset();
+        obj = (oop)((address)mirror + field_offset);
+      } else {
+        obj =  mirror->obj_field_acquire(fd->offset());
+      }
+      ValueTypeFieldPrinter print_field(_out, obj);
+      vk->do_nonstatic_fields(&print_field);
+      break;
+    }
+    default:
+      ShouldNotReachHere();
+  }
+}
+
 
 void ciInstanceKlass::dump_replay_data(outputStream* out) {
   ResourceMark rm;
--- a/src/share/vm/ci/ciInstanceKlass.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciInstanceKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -65,6 +65,9 @@
 
   ciConstantPoolCache*   _field_cache;  // cached map index->field
   GrowableArray<ciField*>* _nonstatic_fields;
+  int                    _nof_declared_nonstatic_fields; // Number of nonstatic fields declared in the bytecode
+                                                         // i.e., without value types flattened into the instance.
+
   int                    _has_injected_fields; // any non static injected fields? lazily initialized.
 
   // The possible values of the _implementor fall into following three cases:
@@ -185,6 +188,7 @@
 
   ciInstanceKlass* get_canonical_holder(int offset);
   ciField* get_field_by_offset(int field_offset, bool is_static);
+  ciType*  get_field_type_by_offset(int field_offset);
   ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);
 
   // total number of nonstatic fields (including inherited):
@@ -195,6 +199,14 @@
       return _nonstatic_fields->length();
   }
 
+  int nof_declared_nonstatic_fields() {
+    if (_nonstatic_fields == NULL) {
+      compute_nonstatic_fields();
+    }
+    assert(_nof_declared_nonstatic_fields >= 0, "after lazy initialization _nof_declared_nonstatic_fields must be at least 0");
+    return _nof_declared_nonstatic_fields;
+  }
+
   bool has_injected_fields() {
     if (_has_injected_fields == -1) {
       compute_injected_fields();
@@ -212,7 +224,7 @@
   bool has_finalizable_subclass();
 
   bool contains_field_offset(int offset) {
-    return instanceOopDesc::contains_field_offset(offset, nonstatic_field_size());
+    return instanceOopDesc::contains_field_offset(offset, nonstatic_field_size(), is_valuetype());
   }
 
   // Get the instance of java.lang.Class corresponding to
--- a/src/share/vm/ci/ciKlass.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -44,6 +44,7 @@
   friend class ciMethod;
   friend class ciMethodData;
   friend class ciObjArrayKlass;
+  friend class ciValueArrayKlass;
   friend class ciReceiverTypeData;
 
 private:
--- a/src/share/vm/ci/ciMetadata.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciMetadata.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -58,7 +58,9 @@
   virtual bool is_method_data() const       { return false; }
   virtual bool is_klass() const             { return false; }
   virtual bool is_instance_klass() const    { return false; }
+  virtual bool is_valuetype() const         { return false; }
   virtual bool is_array_klass() const       { return false; }
+  virtual bool is_value_array_klass() const { return false; }
   virtual bool is_obj_array_klass() const   { return false; }
   virtual bool is_type_array_klass() const  { return false; }
   virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
@@ -95,6 +97,10 @@
     assert(is_array_klass(), "bad cast");
     return (ciArrayKlass*)this;
   }
+  ciValueArrayKlass*       as_value_array_klass() {
+    assert(is_value_array_klass(), "bad cast");
+    return (ciValueArrayKlass*)this;
+  }
   ciObjArrayKlass*         as_obj_array_klass() {
     assert(is_obj_array_klass(), "bad cast");
     return (ciObjArrayKlass*)this;
@@ -103,6 +109,10 @@
     assert(is_type_array_klass(), "bad cast");
     return (ciTypeArrayKlass*)this;
   }
+  ciValueKlass*            as_value_klass() {
+    assert(is_valuetype(), "bad cast");
+    return (ciValueKlass*)this;
+  }
 
   Metadata* constant_encoding() { return _metadata; }
 
--- a/src/share/vm/ci/ciMethod.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciMethod.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -578,6 +578,7 @@
 
 void ciMethod::assert_virtual_call_type_ok(int bci) {
   assert(java_code_at_bci(bci) == Bytecodes::_invokevirtual ||
+         java_code_at_bci(bci) == Bytecodes::_invokedirect ||
          java_code_at_bci(bci) == Bytecodes::_invokeinterface, "unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci)));
 }
 
--- a/src/share/vm/ci/ciMethodBlocks.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciMethodBlocks.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -239,6 +239,7 @@
       case Bytecodes::_freturn     :
       case Bytecodes::_dreturn     :
       case Bytecodes::_areturn     :
+      case Bytecodes::_vreturn     :
       case Bytecodes::_return      :
         cur_block->set_control_bci(bci);
         if (s.next_bci() < limit_bci) {
--- a/src/share/vm/ci/ciObjArrayKlass.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciObjArrayKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -43,7 +43,8 @@
   Klass* element_Klass = get_ObjArrayKlass()->bottom_klass();
   _base_element_klass = CURRENT_ENV->get_klass(element_Klass);
   assert(_base_element_klass->is_instance_klass() ||
-         _base_element_klass->is_type_array_klass(), "bad base klass");
+         _base_element_klass->is_type_array_klass() ||
+         _base_element_klass->is_value_array_klass(), "bad base klass");
   if (dimension() == 1) {
     _element_klass = _base_element_klass;
   } else {
@@ -65,7 +66,8 @@
                  dimension, T_OBJECT) {
     _base_element_klass = base_element_klass;
     assert(_base_element_klass->is_instance_klass() ||
-           _base_element_klass->is_type_array_klass(), "bad base klass");
+           _base_element_klass->is_type_array_klass() ||
+           _base_element_klass->is_value_array_klass(), "bad base klass");
     if (dimension == 1) {
       _element_klass = base_element_klass;
     } else {
--- a/src/share/vm/ci/ciObjectFactory.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciObjectFactory.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -26,6 +26,7 @@
 #include "ci/ciCallSite.hpp"
 #include "ci/ciInstance.hpp"
 #include "ci/ciInstanceKlass.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "ci/ciMemberName.hpp"
 #include "ci/ciMethod.hpp"
 #include "ci/ciMethodData.hpp"
@@ -40,6 +41,7 @@
 #include "ci/ciTypeArray.hpp"
 #include "ci/ciTypeArrayKlass.hpp"
 #include "ci/ciUtilities.hpp"
+#include "ci/ciValueArrayKlass.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
@@ -150,7 +152,8 @@
 
   for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) {
     BasicType t = (BasicType)i;
-    if (type2name(t) != NULL && t != T_OBJECT && t != T_ARRAY && t != T_NARROWOOP && t != T_NARROWKLASS) {
+    if (type2name(t) != NULL && t != T_OBJECT && t != T_ARRAY &&
+        t != T_VALUETYPE && t != T_NARROWOOP && t != T_NARROWKLASS) {
       ciType::_basic_types[t] = new (_arena) ciType(t);
       init_ident_of(ciType::_basic_types[t]);
     }
@@ -378,8 +381,12 @@
 
   if (o->is_klass()) {
     Klass* k = (Klass*)o;
-    if (k->is_instance_klass()) {
+    if (k->is_value()) {
+      return new (arena()) ciValueKlass(k);
+    } else if (k->is_instance_klass()) {
       return new (arena()) ciInstanceKlass(k);
+    } else if (k->is_valueArray_klass()) {
+      return new (arena()) ciValueArrayKlass(k);
     } else if (k->is_objArray_klass()) {
       return new (arena()) ciObjArrayKlass(k);
     } else if (k->is_typeArray_klass()) {
@@ -526,7 +533,7 @@
     int dimension = fd.dimension();
     assert(element_type != T_ARRAY, "unsuccessful decomposition");
     ciKlass* element_klass = NULL;
-    if (element_type == T_OBJECT) {
+    if (element_type == T_OBJECT || element_type == T_VALUETYPE) {
       ciEnv *env = CURRENT_THREAD_ENV;
       ciSymbol* ci_name = env->get_symbol(fd.object_key());
       element_klass =
--- a/src/share/vm/ci/ciReplay.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciReplay.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -33,6 +33,7 @@
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/macros.hpp"
 
@@ -737,6 +738,86 @@
     }
   }
 
+  class ValueTypeFieldInitializer : public FieldClosure {
+    oop _vt;
+    CompileReplay* _replay;
+  public:
+    ValueTypeFieldInitializer(oop vt, CompileReplay* replay)
+  : _vt(vt), _replay(replay) {}
+
+    void do_field(fieldDescriptor* fd) {
+      BasicType bt = fd->field_type();
+      const char* string_value = bt != T_VALUETYPE ? _replay->parse_escaped_string() : NULL;
+      switch (bt) {
+      case T_BYTE: {
+        int value = atoi(string_value);
+        _vt->byte_field_put(fd->offset(), value);
+        break;
+      }
+      case T_BOOLEAN: {
+        int value = atoi(string_value);
+        _vt->bool_field_put(fd->offset(), value);
+        break;
+      }
+      case T_SHORT: {
+        int value = atoi(string_value);
+        _vt->short_field_put(fd->offset(), value);
+        break;
+      }
+      case T_CHAR: {
+        int value = atoi(string_value);
+        _vt->char_field_put(fd->offset(), value);
+        break;
+      }
+      case T_INT: {
+        int value = atoi(string_value);
+        _vt->int_field_put(fd->offset(), value);
+        break;
+      }
+      case T_LONG: {
+        jlong value;
+        if (sscanf(string_value, JLONG_FORMAT, &value) != 1) {
+          fprintf(stderr, "Error parsing long: %s\n", string_value);
+          break;
+        }
+        _vt->long_field_put(fd->offset(), value);
+        break;
+      }
+      case T_FLOAT: {
+        float value = atof(string_value);
+        _vt->float_field_put(fd->offset(), value);
+        break;
+      }
+      case T_DOUBLE: {
+        double value = atof(string_value);
+        _vt->double_field_put(fd->offset(), value);
+        break;
+      }
+      case T_ARRAY:
+        _replay->report_error("Array in value type unsupported");
+        break;
+      case T_OBJECT:
+        _replay->report_error("Object in value type unsupported");
+        break;
+      case T_VALUETYPE: {
+        Thread* THREAD = Thread::current();
+        SignatureStream ss(fd->signature(), false);
+        InstanceKlass* holder = fd->field_holder();
+        Klass* k = ss.as_klass(Handle(THREAD, holder->class_loader()),
+                               Handle(THREAD, holder->protection_domain()),
+                               SignatureStream::ReturnNull, THREAD);
+        assert(k != NULL && !HAS_PENDING_EXCEPTION, "can resolve klass?");
+        ValueKlass* vk = ValueKlass::cast(k);
+        int field_offset = fd->offset() - vk->first_field_offset();
+        oop obj = (oop)((address)_vt + field_offset);
+        ValueTypeFieldInitializer init_fields(obj, _replay);
+        vk->do_nonstatic_fields(&init_fields);
+        break;
+      }
+      }
+    }
+  };
+
   // Initialize a class and fill in the value for a static field.
   // This is useful when the compile was dependent on the value of
   // static fields but it's impossible to properly rerun the static
@@ -807,7 +888,7 @@
       }
       java_mirror->obj_field_put(fd.offset(), value);
     } else {
-      const char* string_value = parse_escaped_string();
+      const char* string_value = field_signature[0] != 'Q' ? parse_escaped_string() : NULL;
       if (strcmp(field_signature, "I") == 0) {
         int value = atoi(string_value);
         java_mirror->int_field_put(fd.offset(), value);
@@ -843,6 +924,14 @@
         Klass* k = resolve_klass(string_value, CHECK);
         oop value = InstanceKlass::cast(k)->allocate_instance(CHECK);
         java_mirror->obj_field_put(fd.offset(), value);
+      } else if (field_signature[0] == 'Q') {
+        Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
+        Klass* kelem = resolve_klass(field_signature, CHECK);
+        ValueKlass* vk = ValueKlass::cast(kelem);
+        oop value = vk->allocate_instance(CHECK);
+        ValueTypeFieldInitializer init_fields(value, this);
+        vk->do_nonstatic_fields(&init_fields);
+        java_mirror->obj_field_put(fd.offset(), value);
       } else {
         report_error("unhandled staticfield");
       }
--- a/src/share/vm/ci/ciStreams.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciStreams.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -170,7 +170,10 @@
   case Bytecodes::_anewarray:
   case Bytecodes::_multianewarray:
   case Bytecodes::_new:
+  case Bytecodes::_vdefault:
   case Bytecodes::_newarray:
+  case Bytecodes::_vunbox:
+  case Bytecodes::_vbox:
     return get_index_u2();
   default:
     ShouldNotReachHere();
@@ -181,8 +184,8 @@
 // ------------------------------------------------------------------
 // ciBytecodeStream::get_klass
 //
-// If this bytecode is a new, newarray, multianewarray, instanceof,
-// or checkcast, get the referenced klass.
+// If this bytecode is a new, newarray, multianewarray, instanceof, vbox,
+// vunbox, or checkcast, get the referenced klass.
 ciKlass* ciBytecodeStream::get_klass(bool& will_link) {
   VM_ENTRY_MARK;
   constantPoolHandle cpool(_method->get_Method()->constants());
@@ -264,9 +267,11 @@
 // index of the referenced field.
 int ciBytecodeStream::get_field_index() {
   assert(cur_bc() == Bytecodes::_getfield ||
+         cur_bc() == Bytecodes::_vgetfield ||
          cur_bc() == Bytecodes::_putfield ||
          cur_bc() == Bytecodes::_getstatic ||
-         cur_bc() == Bytecodes::_putstatic, "wrong bc");
+         cur_bc() == Bytecodes::_putstatic ||
+         cur_bc() == Bytecodes::_vwithfield, "wrong bc");
   return get_index_u2_cpcache();
 }
 
@@ -339,6 +344,7 @@
   switch (cur_bc()) {
   case Bytecodes::_invokeinterface:
   case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokedirect:
   case Bytecodes::_invokespecial:
   case Bytecodes::_invokestatic:
   case Bytecodes::_invokedynamic:
--- a/src/share/vm/ci/ciSymbol.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciSymbol.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -46,6 +46,7 @@
   friend class ciMethod;
   friend class ciField;
   friend class ciObjArrayKlass;
+  friend class ciValueArrayKlass;
 
 private:
   const vmSymbols::SID _sid;
--- a/src/share/vm/ci/ciType.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciType.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -34,8 +34,8 @@
 
 // ciType
 //
-// This class represents either a class (T_OBJECT), array (T_ARRAY),
-// or one of the primitive types such as T_INT.
+// This class represents either a class (T_OBJECT), value (T_VALUETYPE),
+// array (T_ARRAY),or one of the primitive types such as T_INT.
 
 // ------------------------------------------------------------------
 // ciType::ciType
@@ -46,7 +46,7 @@
 }
 
 ciType::ciType(Klass* k) : ciMetadata(k) {
-  _basic_type = k->is_array_klass() ? T_ARRAY : T_OBJECT;
+  _basic_type = k->is_array_klass() ? T_ARRAY : (k->is_value() ? T_VALUETYPE : T_OBJECT);
 }
 
 
@@ -105,6 +105,7 @@
 // ciType::box_klass
 //
 ciKlass* ciType::box_klass() {
+  assert(basic_type() != T_VALUETYPE, "value type boxing not yet supported");
   if (!is_primitive_type())  return this->as_klass();  // reference types are "self boxing"
 
   // Void is "boxed" with a null.
--- a/src/share/vm/ci/ciType.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciType.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -29,8 +29,8 @@
 
 // ciType
 //
-// This class represents either a class (T_OBJECT), array (T_ARRAY),
-// or one of the primitive types such as T_INT.
+// This class represents either a class (T_OBJECT), value (T_VALUETYPE),
+// array (T_ARRAY), or one of the primitive types such as T_INT.
 class ciType : public ciMetadata {
   CI_PACKAGE_ACCESS
   friend class ciKlass;
@@ -67,7 +67,7 @@
   ciKlass*  box_klass();
 
   // Returns true if this is not a klass or array (i.e., not a reference type).
-  bool is_primitive_type() const            { return basic_type() != T_OBJECT && basic_type() != T_ARRAY; }
+  bool is_primitive_type() const            { return basic_type() != T_OBJECT && basic_type() != T_ARRAY && basic_type() != T_VALUETYPE; }
   int size() const                          { return type2size[basic_type()]; }
   bool is_void() const                      { return basic_type() == T_VOID; }
   bool is_one_word() const                  { return size() == 1; }
--- a/src/share/vm/ci/ciTypeFlow.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciTypeFlow.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -31,6 +31,7 @@
 #include "ci/ciStreams.hpp"
 #include "ci/ciTypeArrayKlass.hpp"
 #include "ci/ciTypeFlow.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "compiler/compileLog.hpp"
 #include "interpreter/bytecode.hpp"
 #include "interpreter/bytecodes.hpp"
@@ -548,12 +549,12 @@
 }
 
 // ------------------------------------------------------------------
-// ciTypeFlow::StateVector::do_aaload
-void ciTypeFlow::StateVector::do_aaload(ciBytecodeStream* str) {
+// ciTypeFlow::StateVector::do_aload
+void ciTypeFlow::StateVector::do_aload(ciBytecodeStream* str) {
   pop_int();
-  ciObjArrayKlass* array_klass = pop_objArray();
+  ciArrayKlass* array_klass = pop_objOrValueArray();
   if (array_klass == NULL) {
-    // Did aaload on a null reference; push a null and ignore the exception.
+    // Did aload on a null reference; push a null and ignore the exception.
     // This instruction will never continue normally.  All we have to do
     // is report a value that will meet correctly with any downstream
     // reference types on paths that will truly be executed.  This null type
@@ -771,6 +772,38 @@
 }
 
 // ------------------------------------------------------------------
+// ciTypeFlow::StateVector::do_vdefault
+void ciTypeFlow::StateVector::do_vdefault(ciBytecodeStream* str) {
+  bool will_link;
+  ciKlass* klass = str->get_klass(will_link);
+  assert(klass->is_valuetype(), "should be value type");
+  if (!will_link || str->is_unresolved_klass()) {
+    trap(str, klass, str->get_klass_index());
+  } else {
+    push_object(klass);
+  }
+}
+
+// ------------------------------------------------------------------
+// ciTypeFlow::StateVector::do_vwithfield
+void ciTypeFlow::StateVector::do_vwithfield(ciBytecodeStream* str) {
+  bool will_link;
+  ciField* field = str->get_field(will_link);
+  ciKlass* klass = field->holder();
+  assert(klass->is_valuetype(), "should be value type");
+  // TODO: add additional checks
+  ciType* type = pop_value();
+  ciType* field_type = field->type();
+  if (field_type->is_two_word()) {
+    ciType* type2 = pop_value();
+    assert(type2->is_two_word(), "must be 2nd half");
+    assert(type == half_type(type2), "must be 2nd half");
+  }
+  pop_object();
+  push_object(klass);
+}
+
+// ------------------------------------------------------------------
 // ciTypeFlow::StateVector::do_newarray
 void ciTypeFlow::StateVector::do_newarray(ciBytecodeStream* str) {
   pop_int();
@@ -817,6 +850,26 @@
   set_type_at(index, bottom_type());
 }
 
+void ciTypeFlow::StateVector::do_vunbox(ciBytecodeStream* str) {
+  bool will_link;
+  ciKlass* klass = str->get_klass(will_link);
+  // TODO: Handle case when class is not loaded.
+  guarantee(will_link, "Class to which the value-capable class will unbox to must be loaded for JIT compilation");
+  assert(klass->is_valuetype(), "must be value type");
+  pop_object();
+  push_object(klass->as_value_klass());
+}
+
+void ciTypeFlow::StateVector::do_vbox(ciBytecodeStream* str) {
+  bool will_link;
+  ciKlass* klass = str->get_klass(will_link);
+  // TODO: Handle case when class is not loaded.
+  guarantee(will_link, "Class to which value type will box to must be loaded for JIT compilation");
+  assert(klass->is_instance_klass(), "must be an instance class");
+  pop_object();
+  push_object(klass->as_instance_klass());
+}
+
 // ------------------------------------------------------------------
 // ciTypeFlow::StateVector::trap
 //
@@ -875,13 +928,15 @@
   }
 
   switch(str->cur_bc()) {
-  case Bytecodes::_aaload: do_aaload(str);                       break;
+  case Bytecodes::_vaload:
+  case Bytecodes::_aaload: do_aload(str);                           break;
 
+  case Bytecodes::_vastore:
   case Bytecodes::_aastore:
     {
       pop_object();
       pop_int();
-      pop_objArray();
+      pop_objOrValueArray();
       break;
     }
   case Bytecodes::_aconst_null:
@@ -889,6 +944,7 @@
       push_null();
       break;
     }
+  case Bytecodes::_vload:
   case Bytecodes::_aload:   load_local_object(str->get_index());    break;
   case Bytecodes::_aload_0: load_local_object(0);                   break;
   case Bytecodes::_aload_1: load_local_object(1);                   break;
@@ -903,11 +959,12 @@
       if (!will_link) {
         trap(str, element_klass, str->get_klass_index());
       } else {
-        push_object(ciObjArrayKlass::make(element_klass));
+        push_object(ciArrayKlass::make(element_klass));
       }
       break;
     }
   case Bytecodes::_areturn:
+  case Bytecodes::_vreturn:
   case Bytecodes::_ifnonnull:
   case Bytecodes::_ifnull:
     {
@@ -933,6 +990,7 @@
       push_int();
       break;
     }
+  case Bytecodes::_vstore:
   case Bytecodes::_astore:   store_local_object(str->get_index());  break;
   case Bytecodes::_astore_0: store_local_object(0);                 break;
   case Bytecodes::_astore_1: store_local_object(1);                 break;
@@ -1208,6 +1266,7 @@
   case Bytecodes::_fstore_2:  store_local_float(2);                  break;
   case Bytecodes::_fstore_3:  store_local_float(3);                  break;
 
+  case Bytecodes::_vgetfield:
   case Bytecodes::_getfield:  do_getfield(str);                      break;
   case Bytecodes::_getstatic: do_getstatic(str);                     break;
 
@@ -1318,6 +1377,7 @@
   case Bytecodes::_invokeinterface: do_invoke(str, true);           break;
   case Bytecodes::_invokespecial:   do_invoke(str, true);           break;
   case Bytecodes::_invokestatic:    do_invoke(str, false);          break;
+  case Bytecodes::_invokedirect:
   case Bytecodes::_invokevirtual:   do_invoke(str, true);           break;
   case Bytecodes::_invokedynamic:   do_invoke(str, false);          break;
 
@@ -1435,6 +1495,9 @@
 
   case Bytecodes::_new:      do_new(str);                           break;
 
+  case Bytecodes::_vdefault: do_vdefault(str);                      break;
+  case Bytecodes::_vwithfield: do_vwithfield(str);                  break;
+
   case Bytecodes::_newarray: do_newarray(str);                      break;
 
   case Bytecodes::_pop:
@@ -1462,6 +1525,16 @@
       push(value2);
       break;
     }
+  case Bytecodes::_vunbox:
+     {
+       do_vunbox(str);
+       break;
+     }
+     case Bytecodes::_vbox:
+     {
+       do_vbox(str);
+       break;
+     }
   case Bytecodes::_wide:
   default:
     {
@@ -1745,9 +1818,13 @@
         break;
       }
 
-      case Bytecodes::_athrow:     case Bytecodes::_ireturn:
-      case Bytecodes::_lreturn:    case Bytecodes::_freturn:
-      case Bytecodes::_dreturn:    case Bytecodes::_areturn:
+      case Bytecodes::_athrow:
+      case Bytecodes::_ireturn:
+      case Bytecodes::_lreturn:
+      case Bytecodes::_freturn:
+      case Bytecodes::_dreturn:
+      case Bytecodes::_areturn:
+      case Bytecodes::_vreturn:
       case Bytecodes::_return:
         _successors =
           new (arena) GrowableArray<Block*>(arena, 1, 0, NULL);
@@ -2185,6 +2262,7 @@
     case Bytecodes::_freturn:
     case Bytecodes::_dreturn:
     case Bytecodes::_areturn:
+    case Bytecodes::_vreturn:
     case Bytecodes::_return:
       // We can assume the monitor stack is empty in this analysis.
       return false;
--- a/src/share/vm/ci/ciTypeFlow.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/ciTypeFlow.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -341,14 +341,16 @@
              type_at_tos()->is_array_klass(), "must be array type");
       pop();
     }
-    // pop_objArray and pop_typeArray narrow the tos to ciObjArrayKlass
-    // or ciTypeArrayKlass (resp.).  In the rare case that an explicit
+    // pop_valueOrobjArray and pop_typeArray narrow the tos to ciObjArrayKlass,
+    // ciValueArrayKlass or ciTypeArrayKlass (resp.). In the rare case that an explicit
     // null is popped from the stack, we return NULL.  Caller beware.
-    ciObjArrayKlass* pop_objArray() {
+    ciArrayKlass* pop_objOrValueArray() {
       ciType* array = pop_value();
       if (array == null_type())  return NULL;
-      assert(array->is_obj_array_klass(), "must be object array type");
-      return array->as_obj_array_klass();
+      // Value type arrays may contain oop or flattened representation
+      assert(array->is_obj_array_klass() || (ValueArrayFlatten && array->is_value_array_klass()),
+          "must be value or object array type");
+      return array->as_array_klass();
     }
     ciTypeArrayKlass* pop_typeArray() {
       ciType* array = pop_value();
@@ -362,7 +364,7 @@
     void      do_null_assert(ciKlass* unloaded_klass);
 
     // Helper convenience routines.
-    void do_aaload(ciBytecodeStream* str);
+    void do_aload(ciBytecodeStream* str);
     void do_checkcast(ciBytecodeStream* str);
     void do_getfield(ciBytecodeStream* str);
     void do_getstatic(ciBytecodeStream* str);
@@ -371,10 +373,14 @@
     void do_ldc(ciBytecodeStream* str);
     void do_multianewarray(ciBytecodeStream* str);
     void do_new(ciBytecodeStream* str);
+    void do_vdefault(ciBytecodeStream* str);
+    void do_vwithfield(ciBytecodeStream* str);
     void do_newarray(ciBytecodeStream* str);
     void do_putfield(ciBytecodeStream* str);
     void do_putstatic(ciBytecodeStream* str);
     void do_ret(ciBytecodeStream* str);
+    void do_vunbox(ciBytecodeStream* str);
+    void do_vbox(ciBytecodeStream* str);
 
     void overwrite_local_double_long(int index) {
       // Invalidate the previous local if it contains first half of
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/ci/ciValueArrayKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "ci/ciInstanceKlass.hpp"
+#include "ci/ciValueArrayKlass.hpp"
+#include "ci/ciSymbol.hpp"
+#include "ci/ciUtilities.hpp"
+#include "oops/valueArrayKlass.hpp"
+
+// ciValueArrayKlass
+//
+// This class represents a Klass* in the HotSpot virtual machine
+// whose Klass part is a ValueArrayKlass.
+
+// ------------------------------------------------------------------
+// ciValueArrayKlass::ciValueArrayKlass
+//
+// Constructor for loaded value array klasses.
+ciValueArrayKlass::ciValueArrayKlass(Klass* h_k) : ciArrayKlass(h_k) {
+  assert(get_Klass()->is_valueArray_klass(), "wrong type");
+  ValueKlass* element_Klass = get_ValueArrayKlass()->element_klass();
+  _base_element_klass = CURRENT_ENV->get_klass(element_Klass);
+  assert(_base_element_klass->is_valuetype(), "bad base klass");
+  if (dimension() == 1) {
+    _element_klass = _base_element_klass;
+  } else {
+    _element_klass = NULL;
+  }
+  if (!ciObjectFactory::is_initialized()) {
+    assert(_element_klass->is_java_lang_Object(), "only arrays of object are shared");
+  }
+}
+
+// ------------------------------------------------------------------
+// ciValueArrayKlass::element_klass
+//
+// What is the one-level element type of this array?
+ciKlass* ciValueArrayKlass::element_klass() {
+  if (_element_klass == NULL) {
+    assert(dimension() > 1, "_element_klass should not be NULL");
+    // Produce the element klass.
+    if (is_loaded()) {
+      VM_ENTRY_MARK;
+      Klass* element_Klass = get_ValueArrayKlass()->element_klass();
+      _element_klass = CURRENT_THREAD_ENV->get_klass(element_Klass);
+    } else {
+      // TODO handle this
+      guarantee(false, "unloaded array klass");
+      VM_ENTRY_MARK;
+      // We are an unloaded array klass.  Attempt to fetch our
+      // element klass by name.
+      _element_klass = CURRENT_THREAD_ENV->get_klass_by_name_impl(
+                          this,
+                          constantPoolHandle(),
+                          construct_array_name(base_element_klass()->name(),
+                                               dimension() - 1),
+                          false);
+    }
+  }
+  return _element_klass;
+}
+
+// ------------------------------------------------------------------
+// ciValueArrayKlass::construct_array_name
+//
+// Build an array name from an element name and a dimension.
+ciSymbol* ciValueArrayKlass::construct_array_name(ciSymbol* element_name,
+                                                  int dimension) {
+  EXCEPTION_CONTEXT;
+  int element_len = element_name->utf8_length();
+
+  Symbol* base_name_sym = element_name->get_symbol();
+  char* name;
+
+  if (base_name_sym->byte_at(0) == '[' ||
+      (base_name_sym->byte_at(0) == 'L' &&  // watch package name 'Lxx'
+       base_name_sym->byte_at(element_len-1) == ';')) {
+
+    int new_len = element_len + dimension + 1; // for the ['s and '\0'
+    name = CURRENT_THREAD_ENV->name_buffer(new_len);
+
+    int pos = 0;
+    for ( ; pos < dimension; pos++) {
+      name[pos] = '[';
+    }
+    strncpy(name+pos, (char*)element_name->base(), element_len);
+    name[new_len-1] = '\0';
+  } else {
+    int new_len =   3                       // for L, ;, and '\0'
+                  + dimension               // for ['s
+                  + element_len;
+
+    name = CURRENT_THREAD_ENV->name_buffer(new_len);
+    int pos = 0;
+    for ( ; pos < dimension; pos++) {
+      name[pos] = '[';
+    }
+    name[pos++] = 'L';
+    strncpy(name+pos, (char*)element_name->base(), element_len);
+    name[new_len-2] = ';';
+    name[new_len-1] = '\0';
+  }
+  return ciSymbol::make(name);
+}
+
+// ------------------------------------------------------------------
+// ciValueArrayKlass::make_impl
+//
+// Implementation of make.
+ciValueArrayKlass* ciValueArrayKlass::make_impl(ciKlass* element_klass) {
+  assert(ValueArrayFlatten, "should only be used for flattened value type arrays");
+  assert(element_klass->is_valuetype(), "element type must be value type");
+  if (element_klass->is_loaded()) {
+    EXCEPTION_CONTEXT;
+    // The element klass is loaded
+    Klass* array = element_klass->get_Klass()->array_klass(THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      CLEAR_PENDING_EXCEPTION;
+      CURRENT_THREAD_ENV->record_out_of_memory_failure();
+      // TODO handle this
+      guarantee(false, "out of memory");
+      return NULL;
+    }
+    return CURRENT_THREAD_ENV->get_value_array_klass(array);
+  }
+
+  // TODO handle this
+  guarantee(false, "klass not loaded");
+  return NULL;
+}
+
+// ------------------------------------------------------------------
+// ciValueArrayKlass::make
+//
+// Make an array klass corresponding to the specified primitive type.
+ciValueArrayKlass* ciValueArrayKlass::make(ciKlass* element_klass) {
+  GUARDED_VM_ENTRY(return make_impl(element_klass);)
+}
+
+ciKlass* ciValueArrayKlass::exact_klass() {
+  ShouldNotCallThis();
+  return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/ci/ciValueArrayKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CI_CIVALUEARRAYKLASS_HPP
+#define SHARE_VM_CI_CIVALUEARRAYKLASS_HPP
+
+#include "ci/ciArrayKlass.hpp"
+
+// ciValueArrayKlass
+//
+// This class represents a Klass* in the HotSpot virtual machine
+// whose Klass part is a ValueArrayKlass.
+class ciValueArrayKlass : public ciArrayKlass {
+  CI_PACKAGE_ACCESS
+  friend class ciEnv;
+
+private:
+  ciKlass* _element_klass;
+  // TODO remove this??
+  ciKlass* _base_element_klass;
+
+protected:
+  ciValueArrayKlass(Klass* h_k);
+
+  ValueArrayKlass* get_ValueArrayKlass() {
+    return (ValueArrayKlass*)get_Klass();
+  }
+
+  static ciValueArrayKlass* make_impl(ciKlass* element_klass);
+  static ciSymbol* construct_array_name(ciSymbol* element_name,
+                                        int       dimension);
+
+  const char* type_string() { return "ciValueArrayKlass"; }
+
+  oop     loader()        { return _base_element_klass->loader(); }
+  jobject loader_handle() { return _base_element_klass->loader_handle(); }
+
+  oop     protection_domain()        { return _base_element_klass->protection_domain(); }
+  jobject protection_domain_handle() { return _base_element_klass->protection_domain_handle(); }
+
+
+public:
+  // The one-level type of the array elements.
+  ciKlass* element_klass();
+
+  // TODO refactor all of this
+  int log2_element_size() {
+    return Klass::layout_helper_log2_element_size(layout_helper());
+  }
+
+  // The innermost type of the array elements.
+  ciKlass* base_element_klass() { return _base_element_klass; }
+
+  // What kind of ciObject is this?
+  bool is_value_array_klass() const { return true; }
+
+  static ciValueArrayKlass* make(ciKlass* element_klass);
+
+  virtual ciKlass* exact_klass();
+};
+
+
+#endif // SHARE_VM_CI_CIVALUEARRAYKLASS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/ci/ciValueKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "ci/ciField.hpp"
+#include "ci/ciValueKlass.hpp"
+#include "oops/fieldStreams.hpp"
+#include "oops/valueKlass.hpp"
+
+int ciValueKlass::compute_field_index_map() {
+  assert(is_loaded(), "value class must be loaded to compute mapping of field indeces");
+  fatal("value factory attibute is not supported anymore");
+//
+//  if (_field_index_map != NULL) {
+//    return _field_index_map->length();
+//  }
+//
+//  Arena* arena = CURRENT_ENV->arena();
+//  guarantee(has_nonstatic_fields(), "value types without fields currently not supported");
+//
+//  // FIXME: Once it is possible to construct class hierarchies with value types.
+//  assert(!super()->has_nonstatic_fields(), "a value type must not inherit fields from its superclass");
+//
+//  _field_index_map = new (arena) GrowableArray<int>(arena, nof_declared_nonstatic_fields(), 0, 0);
+//  GUARDED_VM_ENTRY(
+//    ValueKlass* vklass = ValueKlass::cast(get_Klass());
+//    methodHandle factory_h(vklass->factory_method());
+//    if (factory_h.is_null()) { // Value parameter mapping not defined
+//      for (JavaFieldStream fs(vklass); !fs.done(); fs.next()) {
+//        if (fs.access_flags().is_static()) {
+//          continue;
+//        }
+//        _field_index_map->append(fs.field_descriptor().index());
+//      }
+//    } else {
+//      assert(vklass->is_initialized(), "not available until klass is initialized");
+//      int valuefactory_length = factory_h->constMethod()->valuefactory_parameter_mapping_length();
+//      assert(valuefactory_length == nof_declared_nonstatic_fields(),
+//             "value factory length must be the same as the number of nonstatic declared for the value type");
+//      for (int i = 0; i < nof_declared_nonstatic_fields(); i++) {
+//        _field_index_map->append(factory_h->constMethod()->valuefactory_parameter_mapping_start()[i].data.field_index);
+//      }
+//    }
+//  )
+//  return _field_index_map->length();
+  return 0;
+}
+
+// Number of value type fields
+int ciValueKlass::field_count() {
+  if (this == ciEnv::current()->___Value_klass()) {
+    return 0;
+  }
+  if (_field_index_map == NULL) {
+    return compute_field_index_map();
+  } else {
+    return _field_index_map->length();
+  }
+}
+
+// Size of value type fields in words
+int ciValueKlass::field_size() {
+  int size = 0;
+  for (int i = 0; i < field_count(); ++i) {
+    size += field_type_by_index(i)->size();
+  }
+  return size;
+}
+
+// Returns the index of the field with the given offset. If the field at 'offset'
+// belongs to a flattened value type field, return the index of the field
+// in the flattened value type.
+int ciValueKlass::field_index_by_offset(int offset) {
+  assert(contains_field_offset(offset), "invalid field offset");
+  int best_offset = 0;
+  int best_index = -1;
+  // Search the field with the given offset
+  for (int i = 0; i < field_count(); ++i) {
+    int field_offset = field_offset_by_index(i);
+    if (field_offset == offset) {
+      // Exact match
+      return i;
+    } else if (field_offset < offset && field_offset > best_offset) {
+      // No exact match. Save the index of the field with the closest offset that
+      // is smaller than the given field offset. This index corresponds to the
+      // flattened value type field that holds the field we are looking for.
+      best_offset = field_offset;
+      best_index = i;
+    }
+  }
+  assert(best_index >= 0, "field not found");
+  assert(best_offset == offset || field_type_by_index(best_index)->is_valuetype(), "offset should match for non-VTs");
+  return best_index;
+}
+
+// Returns the field offset of the field with the given index
+int ciValueKlass::field_offset_by_index(int index) {
+  if (_field_index_map == NULL) {
+    compute_field_index_map();
+  }
+  GUARDED_VM_ENTRY(
+    ValueKlass* vklass = ValueKlass::cast(get_Klass());
+    return vklass->field_offset(_field_index_map->at(index));
+  )
+}
+
+// Returns the field type of the field with the given index
+ciType* ciValueKlass::field_type_by_index(int index) {
+  int offset = field_offset_by_index(index);
+  VM_ENTRY_MARK;
+  return get_field_type_by_offset(offset);
+}
+
+// Offset of the first field in the value type
+int ciValueKlass::first_field_offset() const {
+  GUARDED_VM_ENTRY(
+    ValueKlass* vklass = ValueKlass::cast(get_Klass());
+    return vklass->first_field_offset();
+  )
+}
+
+bool ciValueKlass::flatten_array() const {
+  GUARDED_VM_ENTRY(
+    ValueKlass* vklass = ValueKlass::cast(get_Klass());
+    return vklass->flatten_array();
+  )
+}
+
+// When passing a value type's fields as arguments, count the number
+// of argument slots that are needed
+int ciValueKlass::value_arg_slots() {
+  int slots = nof_nonstatic_fields();
+  for (int j = 0; j < nof_nonstatic_fields(); j++) {
+    ciField* f = nonstatic_field_at(j);
+    BasicType bt = f->type()->basic_type();
+    assert(bt != T_VALUETYPE, "embedded");
+    if (bt == T_LONG || bt == T_DOUBLE) {
+      slots++;
+    }
+  }
+  return slots;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/ci/ciValueKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CI_CIVALUEKLASS_HPP
+#define SHARE_VM_CI_CIVALUEKLASS_HPP
+
+#include "ci/ciConstantPoolCache.hpp"
+#include "ci/ciFlags.hpp"
+#include "ci/ciInstanceKlass.hpp"
+#include "ci/ciSymbol.hpp"
+
+// ciValueKlass
+//
+// Specialized ciInstanceKlass for value types.
+class ciValueKlass : public ciInstanceKlass {
+  CI_PACKAGE_ACCESS
+
+private:
+  // Index fields of a value type, indeces range from 0 to the number of fields of the
+  // value type - 1.
+  // For each index constructed, _field_index_map records the field's index
+  // in InstanceKlass::_fields (i.e., _field_index_map records the value returned by
+  // fieldDescriptor::index() for each field). If the value type has a
+  // value factory mapping, indeces are as defined in the value factory mapping.
+  GrowableArray<int>* _field_index_map;
+
+protected:
+  ciValueKlass(Klass* h_k) : ciInstanceKlass(h_k), _field_index_map(NULL) {
+    assert(is_final(), "ValueKlass must be final");
+  };
+
+  const char* type_string() { return "ciValueKlass"; }
+  int compute_field_index_map();
+
+public:
+  bool      is_valuetype() const { return true; }
+  bool      flatten_array() const;
+
+  // Value type fields
+  int       field_count();
+  int       field_size();
+  int       flattened_field_count() {
+    return nof_nonstatic_fields();
+  }
+  int       field_index_by_offset(int offset);
+  int       field_offset_by_index(int index);
+  ciType*   field_type_by_index(int index);
+  int       first_field_offset() const;
+
+  int value_arg_slots();
+};
+
+#endif // SHARE_VM_CI_CIVALUEKLASS_HPP
--- a/src/share/vm/ci/compilerInterface.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/ci/compilerInterface.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -46,6 +46,7 @@
 #include "ci/ciSymbol.hpp"
 #include "ci/ciTypeArray.hpp"
 #include "ci/ciTypeArrayKlass.hpp"
+#include "ci/ciValueArrayKlass.hpp"
 
 // This is a dummy file used for including the complete
 // compiler interface.
--- a/src/share/vm/classfile/classFileParser.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/classfile/classFileParser.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -53,6 +53,7 @@
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
+#include "oops/valueKlass.hpp"
 #include "prims/jvm.h"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiThreadState.hpp"
@@ -975,6 +976,7 @@
     _jdk_internal_vm_annotation_Contended,
     _field_Stable,
     _jdk_internal_vm_annotation_ReservedStackAccess,
+    _jvm_internal_value_DeriveValueType,
     _annotation_LIMIT
   };
   const Location _location;
@@ -1010,6 +1012,8 @@
 
   void set_stable(bool stable) { set_annotation(_field_Stable); }
   bool is_stable() const { return has_annotation(_field_Stable); }
+
+  bool is_derive_value_type() const { return has_annotation(_jvm_internal_value_DeriveValueType); }
 };
 
 // This class also doubles as a holder for metadata cleanup.
@@ -1362,11 +1366,13 @@
   STATIC_SHORT,         // shorts
   STATIC_WORD,          // ints
   STATIC_DOUBLE,        // aligned long or double
+  STATIC_VALUETYPE,     // Value types
   NONSTATIC_OOP,
   NONSTATIC_BYTE,
   NONSTATIC_SHORT,
   NONSTATIC_WORD,
   NONSTATIC_DOUBLE,
+  NONSTATIC_VALUETYPE,
   MAX_FIELD_ALLOCATION_TYPE,
   BAD_ALLOCATION_TYPE = -1
 };
@@ -1386,12 +1392,13 @@
   NONSTATIC_DOUBLE,    // T_LONG        = 11,
   NONSTATIC_OOP,       // T_OBJECT      = 12,
   NONSTATIC_OOP,       // T_ARRAY       = 13,
-  BAD_ALLOCATION_TYPE, // T_VOID        = 14,
-  BAD_ALLOCATION_TYPE, // T_ADDRESS     = 15,
-  BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 16,
-  BAD_ALLOCATION_TYPE, // T_METADATA    = 17,
-  BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
-  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 19,
+  NONSTATIC_VALUETYPE, // T_VALUETYPE   = 14,
+  BAD_ALLOCATION_TYPE, // T_VOID        = 15,
+  BAD_ALLOCATION_TYPE, // T_ADDRESS     = 16,
+  BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 17,
+  BAD_ALLOCATION_TYPE, // T_METADATA    = 18,
+  BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 19,
+  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 20,
   BAD_ALLOCATION_TYPE, // 0
   BAD_ALLOCATION_TYPE, // 1
   BAD_ALLOCATION_TYPE, // 2
@@ -1406,12 +1413,13 @@
   STATIC_DOUBLE,       // T_LONG        = 11,
   STATIC_OOP,          // T_OBJECT      = 12,
   STATIC_OOP,          // T_ARRAY       = 13,
-  BAD_ALLOCATION_TYPE, // T_VOID        = 14,
-  BAD_ALLOCATION_TYPE, // T_ADDRESS     = 15,
-  BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 16,
-  BAD_ALLOCATION_TYPE, // T_METADATA    = 17,
-  BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
-  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 19,
+  STATIC_VALUETYPE,    // T_VALUETYPE   = 14,
+  BAD_ALLOCATION_TYPE, // T_VOID        = 15,
+  BAD_ALLOCATION_TYPE, // T_ADDRESS     = 16,
+  BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 17,
+  BAD_ALLOCATION_TYPE, // T_METADATA    = 18,
+  BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 19,
+  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 20,
 };
 
 static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) {
@@ -2057,6 +2065,12 @@
       if (RestrictReservedStack && !privileged) break; // honor privileges
       return _jdk_internal_vm_annotation_ReservedStackAccess;
     }
+    case vmSymbols::VM_SYMBOL_ENUM_NAME(jvm_internal_value_DeriveValueType_signature) : {
+      if (_location != _in_class) {
+        break;
+      }
+      return _jvm_internal_value_DeriveValueType;
+    }
     default: {
       break;
     }
@@ -3552,7 +3566,8 @@
   const InstanceKlass* super_klass = NULL;
 
   if (super_class_index == 0) {
-    check_property(_class_name == vmSymbols::java_lang_Object(),
+    check_property(_class_name == vmSymbols::java_lang_Object()
+                   || (_access_flags.get_flags() & JVM_ACC_VALUE),
                    "Invalid superclass index %u in class file %s",
                    super_class_index,
                    CHECK_NULL);
@@ -3579,39 +3594,6 @@
   return super_klass;
 }
 
-static unsigned int compute_oop_map_count(const InstanceKlass* super,
-                                          unsigned int nonstatic_oop_map_count,
-                                          int first_nonstatic_oop_offset) {
-
-  unsigned int map_count =
-    NULL == super ? 0 : super->nonstatic_oop_map_count();
-  if (nonstatic_oop_map_count > 0) {
-    // We have oops to add to map
-    if (map_count == 0) {
-      map_count = nonstatic_oop_map_count;
-    }
-    else {
-      // Check whether we should add a new map block or whether the last one can
-      // be extended
-      const OopMapBlock* const first_map = super->start_of_nonstatic_oop_maps();
-      const OopMapBlock* const last_map = first_map + map_count - 1;
-
-      const int next_offset = last_map->offset() + last_map->count() * heapOopSize;
-      if (next_offset == first_nonstatic_oop_offset) {
-        // There is no gap bettwen superklass's last oop field and first
-        // local oop field, merge maps.
-        nonstatic_oop_map_count -= 1;
-      }
-      else {
-        // Superklass didn't end with a oop field, add extra maps
-        assert(next_offset < first_nonstatic_oop_offset, "just checking");
-      }
-      map_count += nonstatic_oop_map_count;
-    }
-  }
-  return map_count;
-}
-
 #ifndef PRODUCT
 static void print_field_layout(const Symbol* name,
                                Array<u2>* fields,
@@ -3652,16 +3634,158 @@
 // Values needed for oopmap and InstanceKlass creation
 class ClassFileParser::FieldLayoutInfo : public ResourceObj {
  public:
-  int*          nonstatic_oop_offsets;
-  unsigned int* nonstatic_oop_counts;
-  unsigned int  nonstatic_oop_map_count;
-  unsigned int  total_oop_map_count;
+  OopMapBlocksBuilder* oop_map_blocks;
   int           instance_size;
   int           nonstatic_field_size;
   int           static_field_size;
   bool          has_nonstatic_fields;
 };
 
+// Utility to collect and compact oop maps during layout
+class ClassFileParser::OopMapBlocksBuilder : public ResourceObj {
+ public:
+  OopMapBlock*  nonstatic_oop_maps;
+  unsigned int  nonstatic_oop_map_count;
+  unsigned int  max_nonstatic_oop_maps;
+
+ public:
+  OopMapBlocksBuilder(unsigned int  max_blocks, TRAPS) {
+    max_nonstatic_oop_maps = max_blocks;
+    nonstatic_oop_map_count = 0;
+    if (max_blocks == 0) {
+      nonstatic_oop_maps = NULL;
+    } else {
+      nonstatic_oop_maps = NEW_RESOURCE_ARRAY_IN_THREAD(
+        THREAD, OopMapBlock, max_nonstatic_oop_maps);
+      memset(nonstatic_oop_maps, 0, sizeof(OopMapBlock) * max_blocks);
+    }
+  }
+
+  OopMapBlock* last_oop_map() const {
+    assert(nonstatic_oop_map_count > 0, "Has no oop maps");
+    return nonstatic_oop_maps + (nonstatic_oop_map_count - 1);
+  }
+
+  // addition of super oop maps
+  void initialize_inherited_blocks(OopMapBlock* blocks, unsigned int nof_blocks) {
+    assert(nof_blocks && nonstatic_oop_map_count == 0 &&
+        nof_blocks <= max_nonstatic_oop_maps, "invariant");
+
+    memcpy(nonstatic_oop_maps, blocks, sizeof(OopMapBlock) * nof_blocks);
+    nonstatic_oop_map_count += nof_blocks;
+  }
+
+  // collection of oops
+  void add(int offset, int count) {
+    if (nonstatic_oop_map_count == 0) {
+      nonstatic_oop_map_count++;
+    }
+    OopMapBlock*  nonstatic_oop_map = last_oop_map();
+    if (nonstatic_oop_map->count() == 0) {  // Unused map, set it up
+      nonstatic_oop_map->set_offset(offset);
+      nonstatic_oop_map->set_count(count);
+    } else if (nonstatic_oop_map->is_contiguous(offset)) { // contiguous, add
+      nonstatic_oop_map->increment_count(count);
+    } else { // Need a new one...
+      nonstatic_oop_map_count++;
+      assert(nonstatic_oop_map_count <= max_nonstatic_oop_maps, "range check");
+      nonstatic_oop_map = last_oop_map();
+      nonstatic_oop_map->set_offset(offset);
+      nonstatic_oop_map->set_count(count);
+    }
+  }
+
+  // general purpose copy, e.g. into allocated instanceKlass
+  void copy(OopMapBlock* dst) {
+    if (nonstatic_oop_map_count != 0) {
+      memcpy(dst, nonstatic_oop_maps, sizeof(OopMapBlock) * nonstatic_oop_map_count);
+    }
+  }
+
+  // Sort and compact adjacent blocks
+  void compact(TRAPS) {
+    if (nonstatic_oop_map_count <= 1) {
+      return;
+    }
+    /*
+     * Since field layout sneeks in oops before values, we will be able to condense
+     * blocks. There is potential to compact between super, own refs and values
+     * containing refs.
+     *
+     * Currently compaction is slightly limited due to values being 8 byte aligned.
+     * This may well change: FixMe if doesn't, the code below is fairly general purpose
+     * and maybe it doesn't need to be.
+     */
+    qsort(nonstatic_oop_maps, nonstatic_oop_map_count, sizeof(OopMapBlock),
+        (_sort_Fn)OopMapBlock::compare_offset);
+    if (nonstatic_oop_map_count < 2) {
+      return;
+    }
+
+     //Make a temp copy, and iterate through and copy back into the orig
+    ResourceMark rm(THREAD);
+    OopMapBlock* oop_maps_copy = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, OopMapBlock,
+        nonstatic_oop_map_count);
+    OopMapBlock* oop_maps_copy_end = oop_maps_copy + nonstatic_oop_map_count;
+    copy(oop_maps_copy);
+    OopMapBlock*  nonstatic_oop_map = nonstatic_oop_maps;
+    unsigned int new_count = 1;
+    oop_maps_copy++;
+    while(oop_maps_copy < oop_maps_copy_end) {
+      assert(nonstatic_oop_map->offset() < oop_maps_copy->offset(), "invariant");
+      if (nonstatic_oop_map->is_contiguous(oop_maps_copy->offset())) {
+        nonstatic_oop_map->increment_count(oop_maps_copy->count());
+      } else {
+        nonstatic_oop_map++;
+        new_count++;
+        nonstatic_oop_map->set_offset(oop_maps_copy->offset());
+        nonstatic_oop_map->set_count(oop_maps_copy->count());
+      }
+      oop_maps_copy++;
+    }
+    assert(new_count <= nonstatic_oop_map_count, "end up with more maps after compact() ?");
+    nonstatic_oop_map_count = new_count;
+  }
+
+  void print_on(outputStream* st) const {
+    st->print_cr("  OopMapBlocks: %3d  /%3d", nonstatic_oop_map_count, max_nonstatic_oop_maps);
+    if (nonstatic_oop_map_count > 0) {
+      OopMapBlock* map = nonstatic_oop_maps;
+      OopMapBlock* last_map = last_oop_map();
+      assert(map <= last_map, "Last less than first");
+      while (map <= last_map) {
+        st->print_cr("    Offset: %3d  -%3d Count: %3d", map->offset(),
+            map->offset() + map->offset_span() - heapOopSize, map->count());
+        map++;
+      }
+    }
+  }
+
+  void print_value_on(outputStream* st) const {
+    print_on(st);
+  }
+
+};
+
+void ClassFileParser::throwValueTypeLimitation(THREAD_AND_LOCATION_DECL,
+                                               const char* msg,
+                                               const Symbol* name,
+                                               const Symbol* sig) const {
+
+  ResourceMark rm(THREAD);
+  if (name == NULL || sig == NULL) {
+    Exceptions::fthrow(THREAD_AND_LOCATION_ARGS,
+        vmSymbols::java_lang_ClassFormatError(),
+        "class: %s - %s", _class_name->as_C_string(), msg);
+  }
+  else {
+    Exceptions::fthrow(THREAD_AND_LOCATION_ARGS,
+        vmSymbols::java_lang_ClassFormatError(),
+        "\"%s\" sig: \"%s\" class: %s - %s", name->as_C_string(), sig->as_C_string(),
+        _class_name->as_C_string(), msg);
+  }
+}
+
 // Layout fields and fill in FieldLayoutInfo.  Could use more refactoring!
 void ClassFileParser::layout_fields(ConstantPool* cp,
                                     const FieldAllocationCount* fac,
@@ -3674,6 +3798,12 @@
   // Field size and offset computation
   int nonstatic_field_size = _super_klass == NULL ? 0 :
                                _super_klass->nonstatic_field_size();
+  int next_nonstatic_valuetype_offset = 0;
+  int first_nonstatic_valuetype_offset = 0;
+
+  // Fields that are value types are handled differently depending if they are static or not:
+  // - static fields are oops
+  // - non-static fields are embedded
 
   // Count the contended fields by type.
   //
@@ -3694,8 +3824,9 @@
 
   // Calculate the starting byte offsets
   int next_static_oop_offset    = InstanceMirrorKlass::offset_of_static_fields();
+  // Value types in static fields are nor embedded, they are handled with oops
   int next_static_double_offset = next_static_oop_offset +
-                                      ((fac->count[STATIC_OOP]) * heapOopSize);
+                                  ((fac->count[STATIC_OOP] + fac->count[STATIC_VALUETYPE]) * heapOopSize);
   if ( fac->count[STATIC_DOUBLE] &&
        (Universe::field_type_should_be_aligned(T_DOUBLE) ||
         Universe::field_type_should_be_aligned(T_LONG)) ) {
@@ -3712,6 +3843,16 @@
   int nonstatic_fields_start  = instanceOopDesc::base_offset_in_bytes() +
                                 nonstatic_field_size * heapOopSize;
 
+  // First field of value types is aligned on a long boundary in order to ease
+  // in-lining of value types (with header removal) in packed arrays and
+  // flatten value types
+  int initial_value_type_padding = 0;
+  if (is_value_type() || is_derive_value_type()) {
+    int old = nonstatic_fields_start;
+    nonstatic_fields_start = align_size_up(nonstatic_fields_start, BytesPerLong);
+    initial_value_type_padding = nonstatic_fields_start - old;
+  }
+
   int next_nonstatic_field_offset = nonstatic_fields_start;
 
   const bool is_contended_class     = parsed_annotations->is_contended();
@@ -3721,6 +3862,14 @@
     next_nonstatic_field_offset += ContendedPaddingWidth;
   }
 
+  // Temporary value types restrictions
+  if (is_value_type() || is_derive_value_type()) {
+    if (is_contended_class) {
+      throwValueTypeLimitation(THREAD_AND_LOCATION, "Value Types do not support @Contended annotation yet");
+      return;
+    }
+  }
+
   // Compute the non-contended fields count.
   // The packing code below relies on these counts to determine if some field
   // can be squeezed into the alignment gap. Contended fields are obviously
@@ -3731,16 +3880,53 @@
   unsigned int nonstatic_byte_count   = fac->count[NONSTATIC_BYTE]   - fac_contended.count[NONSTATIC_BYTE];
   unsigned int nonstatic_oop_count    = fac->count[NONSTATIC_OOP]    - fac_contended.count[NONSTATIC_OOP];
 
+  int static_value_type_count = 0;
+  int nonstatic_value_type_count = 0;
+  int* nonstatic_value_type_indexes = NULL;
+  Klass** nonstatic_value_type_klasses = NULL;
+  unsigned int value_type_oop_map_count = 0;
+
+  int max_nonstatic_value_type = fac->count[NONSTATIC_VALUETYPE] + 1;
+
+  nonstatic_value_type_indexes = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, int,
+                                                              max_nonstatic_value_type);
+  for (int i = 0; i < max_nonstatic_value_type; i++) {
+    nonstatic_value_type_indexes[i] = -1;
+  }
+  nonstatic_value_type_klasses = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, Klass*,
+                                                              max_nonstatic_value_type);
+
+  for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+    if (fs.allocation_type() == STATIC_VALUETYPE) {
+      static_value_type_count++;
+    } else if (fs.allocation_type() == NONSTATIC_VALUETYPE) {
+      Symbol* signature = fs.signature();
+      Klass* klass = SystemDictionary::resolve_or_fail(signature,
+                                                       Handle(THREAD, _loader_data->class_loader()),
+                                                       _protection_domain, true, CHECK);
+      assert(klass != NULL, "Sanity check");
+      assert(klass->access_flags().is_value_type(), "Value type expected");
+      nonstatic_value_type_indexes[nonstatic_value_type_count] = fs.index();
+      nonstatic_value_type_klasses[nonstatic_value_type_count] = klass;
+      nonstatic_value_type_count++;
+
+      ValueKlass* vklass = ValueKlass::cast(klass);
+      if (vklass->contains_oops()) {
+        value_type_oop_map_count += vklass->nonstatic_oop_map_count();
+      }
+    }
+  }
+
   // Total non-static fields count, including every contended field
   unsigned int nonstatic_fields_count = fac->count[NONSTATIC_DOUBLE] + fac->count[NONSTATIC_WORD] +
                                         fac->count[NONSTATIC_SHORT] + fac->count[NONSTATIC_BYTE] +
-                                        fac->count[NONSTATIC_OOP];
+                                        fac->count[NONSTATIC_OOP] + fac->count[NONSTATIC_VALUETYPE];
 
   const bool super_has_nonstatic_fields =
           (_super_klass != NULL && _super_klass->has_nonstatic_fields());
   const bool has_nonstatic_fields =
     super_has_nonstatic_fields || (nonstatic_fields_count != 0);
-
+  const bool has_nonstatic_value_fields = nonstatic_value_type_count > 0;
 
   // Prepare list of oops for oop map generation.
   //
@@ -3750,15 +3936,17 @@
   // we pessimistically allocate the maps to fit all the oops into the
   // distinct regions.
   //
-  // TODO: We add +1 to always allocate non-zero resource arrays; we need
-  // to figure out if we still need to do this.
-  unsigned int nonstatic_oop_map_count = 0;
-  unsigned int max_nonstatic_oop_maps  = fac->count[NONSTATIC_OOP] + 1;
-
-  int* nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
-            THREAD, int, max_nonstatic_oop_maps);
-  unsigned int* const nonstatic_oop_counts  = NEW_RESOURCE_ARRAY_IN_THREAD(
-            THREAD, unsigned int, max_nonstatic_oop_maps);
+  int super_oop_map_count = (_super_klass == NULL) ? 0 :_super_klass->nonstatic_oop_map_count();
+  int max_oop_map_count =
+      super_oop_map_count +
+      fac->count[NONSTATIC_OOP] +
+      value_type_oop_map_count;
+
+  OopMapBlocksBuilder* nonstatic_oop_maps = new OopMapBlocksBuilder(max_oop_map_count, THREAD);
+  if (super_oop_map_count > 0) {
+    nonstatic_oop_maps->initialize_inherited_blocks(_super_klass->start_of_nonstatic_oop_maps(),
+                                                    _super_klass->nonstatic_oop_map_count());
+  }
 
   int first_nonstatic_oop_offset = 0; // will be set for first oop field
 
@@ -3807,13 +3995,8 @@
     next_nonstatic_double_offset = next_nonstatic_field_offset;
   } else if( allocation_style == 2 ) {
     // Fields allocation: oops fields in super and sub classes are together.
-    if( nonstatic_field_size > 0 && _super_klass != NULL &&
-        _super_klass->nonstatic_oop_map_size() > 0 ) {
-      const unsigned int map_count = _super_klass->nonstatic_oop_map_count();
-      const OopMapBlock* const first_map = _super_klass->start_of_nonstatic_oop_maps();
-      const OopMapBlock* const last_map = first_map + map_count - 1;
-      const int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
-      if (next_offset == next_nonstatic_field_offset) {
+    if( nonstatic_field_size > 0 && super_oop_map_count > 0 ) {
+      if (next_nonstatic_field_offset == nonstatic_oop_maps->last_oop_map()->end_offset()) {
         allocation_style = 0;   // allocate oops first
         next_nonstatic_oop_offset    = next_nonstatic_field_offset;
         next_nonstatic_double_offset = next_nonstatic_oop_offset +
@@ -3896,6 +4079,16 @@
     next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize);
   }
 
+  // Aligning embedded value types
+  // bug below, the current algorithm to layout embedded value types always put them at the
+  // end of the layout, which doesn't match the different allocation policies the VM is
+  // supposed to provide => FixMe
+  // Note also that the current alignment policy is to make each value type starting on a
+  // 64 bits boundary. This could be optimized later. For instance, it could be nice to
+  // align value types according to their most constrained internal type.
+  next_nonstatic_valuetype_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong);
+  int next_value_type_index = 0;
+
   // Iterate over fields again and compute correct offsets.
   // The field allocation type was temporarily stored in the offset slot.
   // oop fields are located before non-oop fields (static and non-static).
@@ -3912,6 +4105,8 @@
 
     // pack the rest of the fields
     switch (atype) {
+      // Value types in static fields are handled with oops
+      case STATIC_VALUETYPE:   // Fallthrough
       case STATIC_OOP:
         real_offset = next_static_oop_offset;
         next_static_oop_offset += heapOopSize;
@@ -3932,6 +4127,29 @@
         real_offset = next_static_double_offset;
         next_static_double_offset += BytesPerLong;
         break;
+      case NONSTATIC_VALUETYPE:
+      {
+        Klass* klass = nonstatic_value_type_klasses[next_value_type_index];
+        assert(klass != NULL, "Klass should have been loaded and resolved earlier");
+        assert(klass->access_flags().is_value_type(),"Must be a value type");
+        ValueKlass* vklass = ValueKlass::cast(klass);
+        real_offset = next_nonstatic_valuetype_offset;
+        next_nonstatic_valuetype_offset += (vklass->size_helper()) * wordSize - vklass->first_field_offset();
+        // aligning next value type on a 64 bits boundary
+        next_nonstatic_valuetype_offset = align_size_up(next_nonstatic_valuetype_offset, BytesPerLong);
+        next_value_type_index += 1;
+
+        if (vklass->contains_oops()) { // add flatten oop maps
+          int diff = real_offset - vklass->first_field_offset();
+          const OopMapBlock* map = vklass->start_of_nonstatic_oop_maps();
+          const OopMapBlock* const last_map = map + vklass->nonstatic_oop_map_count();
+          while (map < last_map) {
+            nonstatic_oop_maps->add(map->offset() + diff, map->count());
+            map++;
+          }
+        }
+      }
+      break;
       case NONSTATIC_OOP:
         if( nonstatic_oop_space_count > 0 ) {
           real_offset = nonstatic_oop_space_offset;
@@ -3941,26 +4159,7 @@
           real_offset = next_nonstatic_oop_offset;
           next_nonstatic_oop_offset += heapOopSize;
         }
-
-        // Record this oop in the oop maps
-        if( nonstatic_oop_map_count > 0 &&
-            nonstatic_oop_offsets[nonstatic_oop_map_count - 1] ==
-            real_offset -
-            int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) *
-            heapOopSize ) {
-          // This oop is adjacent to the previous one, add to current oop map
-          assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check");
-          nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1;
-        } else {
-          // This oop is not adjacent to the previous one, create new oop map
-          assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check");
-          nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset;
-          nonstatic_oop_counts [nonstatic_oop_map_count] = 1;
-          nonstatic_oop_map_count += 1;
-          if( first_nonstatic_oop_offset == 0 ) { // Undefined
-            first_nonstatic_oop_offset = real_offset;
-          }
-        }
+        nonstatic_oop_maps->add(real_offset, 1);
         break;
       case NONSTATIC_BYTE:
         if( nonstatic_byte_space_count > 0 ) {
@@ -4069,30 +4268,17 @@
             next_nonstatic_padded_offset += BytesPerLong;
             break;
 
+            // Value types in static fields are handled with oops
+          case NONSTATIC_VALUETYPE:
+            throwValueTypeLimitation(THREAD_AND_LOCATION,
+                                     "@Contended annotation not supported for value types yet", fs.name(), fs.signature());
+            return;
+
           case NONSTATIC_OOP:
             next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize);
             real_offset = next_nonstatic_padded_offset;
             next_nonstatic_padded_offset += heapOopSize;
-
-            // Record this oop in the oop maps
-            if( nonstatic_oop_map_count > 0 &&
-                nonstatic_oop_offsets[nonstatic_oop_map_count - 1] ==
-                real_offset -
-                int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) *
-                heapOopSize ) {
-              // This oop is adjacent to the previous one, add to current oop map
-              assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check");
-              nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1;
-            } else {
-              // This oop is not adjacent to the previous one, create new oop map
-              assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check");
-              nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset;
-              nonstatic_oop_counts [nonstatic_oop_map_count] = 1;
-              nonstatic_oop_map_count += 1;
-              if( first_nonstatic_oop_offset == 0 ) { // Undefined
-                first_nonstatic_oop_offset = real_offset;
-              }
-            }
+            nonstatic_oop_maps->add(real_offset, 1);
             break;
 
           default:
@@ -4127,12 +4313,24 @@
   // This helps to alleviate memory contention effects for subclass fields
   // and/or adjacent object.
   if (is_contended_class) {
+    assert(!is_value_type() && !is_derive_value_type(), "@Contended not supported for value types yet");
     next_nonstatic_padded_offset += ContendedPaddingWidth;
   }
 
-  int notaligned_nonstatic_fields_end = next_nonstatic_padded_offset;
-
-  int nonstatic_fields_end      = align_size_up(notaligned_nonstatic_fields_end, heapOopSize);
+  int notaligned_nonstatic_fields_end;
+  if (nonstatic_value_type_count != 0) {
+    notaligned_nonstatic_fields_end = next_nonstatic_valuetype_offset;
+  } else {
+    notaligned_nonstatic_fields_end = next_nonstatic_padded_offset;
+  }
+
+  int nonstatic_field_sz_align = heapOopSize;
+  if (is_value_type() || is_derive_value_type()) {
+    if ((notaligned_nonstatic_fields_end - nonstatic_fields_start) > heapOopSize) {
+      nonstatic_field_sz_align = BytesPerLong; // value copy of fields only uses jlong copy
+    }
+  }
+  int nonstatic_fields_end      = align_size_up(notaligned_nonstatic_fields_end, nonstatic_field_sz_align);
   int instance_end              = align_size_up(notaligned_nonstatic_fields_end, wordSize);
   int static_fields_end         = align_size_up(next_static_byte_offset, wordSize);
 
@@ -4144,8 +4342,9 @@
   int instance_size             = align_object_size(instance_end / wordSize);
 
   assert(instance_size == align_object_size(align_size_up(
-         (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize),
-          wordSize) / wordSize), "consistent layout helper value");
+         (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize)
+         + initial_value_type_padding, wordSize) / wordSize), "consistent layout helper value");
+
 
   // Invariant: nonstatic_field end/start should only change if there are
   // nonstatic fields in the class, or if the class is contended. We compare
@@ -4156,12 +4355,11 @@
          (nonstatic_fields_count > 0), "double-check nonstatic start/end");
 
   // Number of non-static oop map blocks allocated at end of klass.
-  const unsigned int total_oop_map_count =
-    compute_oop_map_count(_super_klass, nonstatic_oop_map_count,
-                          first_nonstatic_oop_offset);
+  nonstatic_oop_maps->compact(THREAD);
 
 #ifndef PRODUCT
-  if (PrintFieldLayout) {
+  if ((PrintFieldLayout && !is_value_type()) ||
+      (PrintValueLayout && (is_value_type() || has_nonstatic_value_fields))) {
     print_field_layout(_class_name,
           _fields,
           cp,
@@ -4169,62 +4367,19 @@
           nonstatic_fields_start,
           nonstatic_fields_end,
           static_fields_end);
+    nonstatic_oop_maps->print_on(tty);
+    tty->print("\n");
   }
 
 #endif
   // Pass back information needed for InstanceKlass creation
-  info->nonstatic_oop_offsets = nonstatic_oop_offsets;
-  info->nonstatic_oop_counts = nonstatic_oop_counts;
-  info->nonstatic_oop_map_count = nonstatic_oop_map_count;
-  info->total_oop_map_count = total_oop_map_count;
+  info->oop_map_blocks = nonstatic_oop_maps;
   info->instance_size = instance_size;
   info->static_field_size = static_field_size;
   info->nonstatic_field_size = nonstatic_field_size;
   info->has_nonstatic_fields = has_nonstatic_fields;
 }
 
-static void fill_oop_maps(const InstanceKlass* k,
-                          unsigned int nonstatic_oop_map_count,
-                          const int* nonstatic_oop_offsets,
-                          const unsigned int* nonstatic_oop_counts) {
-
-  assert(k != NULL, "invariant");
-
-  OopMapBlock* this_oop_map = k->start_of_nonstatic_oop_maps();
-  const InstanceKlass* const super = k->superklass();
-  const unsigned int super_count = super ? super->nonstatic_oop_map_count() : 0;
-  if (super_count > 0) {
-    // Copy maps from superklass
-    OopMapBlock* super_oop_map = super->start_of_nonstatic_oop_maps();
-    for (unsigned int i = 0; i < super_count; ++i) {
-      *this_oop_map++ = *super_oop_map++;
-    }
-  }
-
-  if (nonstatic_oop_map_count > 0) {
-    if (super_count + nonstatic_oop_map_count > k->nonstatic_oop_map_count()) {
-      // The counts differ because there is no gap between superklass's last oop
-      // field and the first local oop field.  Extend the last oop map copied
-      // from the superklass instead of creating new one.
-      nonstatic_oop_map_count--;
-      nonstatic_oop_offsets++;
-      this_oop_map--;
-      this_oop_map->set_count(this_oop_map->count() + *nonstatic_oop_counts++);
-      this_oop_map++;
-    }
-
-    // Add new map blocks, fill them
-    while (nonstatic_oop_map_count-- > 0) {
-      this_oop_map->set_offset(*nonstatic_oop_offsets++);
-      this_oop_map->set_count(*nonstatic_oop_counts++);
-      this_oop_map++;
-    }
-    assert(k->start_of_nonstatic_oop_maps() + k->nonstatic_oop_map_count() ==
-           this_oop_map, "sanity");
-  }
-}
-
-
 void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) {
   assert(ik != NULL, "invariant");
 
@@ -4912,7 +5067,8 @@
     case JVM_SIGNATURE_LONG:
     case JVM_SIGNATURE_DOUBLE:
       return signature + 1;
-    case JVM_SIGNATURE_CLASS: {
+    case JVM_SIGNATURE_CLASS:
+    case JVM_SIGNATURE_VALUE_CLASS: {
       if (_major_version < JAVA_1_5_VERSION) {
         // Skip over the class name if one is there
         const char* const p = skip_over_field_name(signature + 1, true, --length);
@@ -5162,7 +5318,7 @@
 
 int ClassFileParser::total_oop_map_count() const {
   assert(_field_info != NULL, "invariant");
-  return _field_info->total_oop_map_count;
+  return _field_info->oop_map_blocks->nonstatic_oop_map_count;
 }
 
 jint ClassFileParser::layout_size() const {
@@ -5296,7 +5452,7 @@
 
   assert(_field_info != NULL, "invariant");
   assert(ik->static_field_size() == _field_info->static_field_size, "sanity");
-  assert(ik->nonstatic_oop_map_count() == _field_info->total_oop_map_count,
+  assert(ik->nonstatic_oop_map_count() == _field_info->oop_map_blocks->nonstatic_oop_map_count,
     "sanity");
 
   assert(ik->is_instance_klass(), "sanity");
@@ -5310,7 +5466,7 @@
   ik->set_nonstatic_field_size(_field_info->nonstatic_field_size);
   ik->set_has_nonstatic_fields(_field_info->has_nonstatic_fields);
   assert(_fac != NULL, "invariant");
-  ik->set_static_oop_field_count(_fac->count[STATIC_OOP]);
+  ik->set_static_oop_field_count(_fac->count[STATIC_OOP] + _fac->count[STATIC_VALUETYPE]);
 
   // this transfers ownership of a lot of arrays from
   // the parser onto the InstanceKlass*
@@ -5390,10 +5546,10 @@
 
   // Compute transitive closure of interfaces this class implements
   // Do final class setup
-  fill_oop_maps(ik,
-                _field_info->nonstatic_oop_map_count,
-                _field_info->nonstatic_oop_offsets,
-                _field_info->nonstatic_oop_counts);
+  OopMapBlocksBuilder* oop_map_blocks = _field_info->oop_map_blocks;
+  if (oop_map_blocks->nonstatic_oop_map_count > 0) {
+    oop_map_blocks->copy(ik->start_of_nonstatic_oop_maps());
+  }
 
   // Fill in has_finalizer, has_vanilla_constructor, and layout_helper
   set_precomputed_flags(ik);
@@ -5437,6 +5593,12 @@
                                              CHECK);
   }
 
+  // Valhalla shady value type conversion
+  if (_parsed_annotations->is_derive_value_type()) {
+    ik->create_derive_value_type(Handle(THREAD, _loader_data->class_loader()),
+                                 _protection_domain, CHECK);
+  }
+
   // Add read edges to the unnamed modules of the bootstrap and app class loaders.
   if (changed_by_loadhook && !module_handle.is_null() && module_entry->is_named() &&
       !module_entry->has_default_read_edges()) {
@@ -6021,7 +6183,9 @@
       return;
     }
     // Make sure super class is not final
-    if (_super_klass->is_final()) {
+    if (_super_klass->is_final()
+        && !(_super_klass->name() == vmSymbols::java_lang____Value()
+        && (_access_flags.get_flags() & JVM_ACC_VALUE))) {
       THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
     }
   }
@@ -6097,6 +6261,11 @@
 
   return _stream->clone();
 }
+
+bool ClassFileParser::is_derive_value_type() const {
+  return _parsed_annotations->is_derive_value_type();
+}
+
 // ----------------------------------------------------------------------------
 // debugging
 
--- a/src/share/vm/classfile/classFileParser.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/classfile/classFileParser.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -55,6 +55,7 @@
  class FieldAllocationCount;
  class FieldAnnotationCollector;
  class FieldLayoutInfo;
+ class OopMapBlocksBuilder;
 
  public:
   // The ClassFileParser has an associated "publicity" level
@@ -386,6 +387,11 @@
                              const Symbol* sig,
                              TRAPS) const;
 
+  void throwValueTypeLimitation(THREAD_AND_LOCATION_DECL,
+                                const char* msg,
+                                const Symbol* name = NULL,
+                                const Symbol* sig  = NULL) const;
+
   void verify_constantvalue(const ConstantPool* const cp,
                             int constantvalue_index,
                             int signature_index,
@@ -517,6 +523,8 @@
 
   bool is_anonymous() const { return _host_klass != NULL; }
   bool is_interface() const { return _access_flags.is_interface(); }
+  bool is_value_type() const { return _access_flags.is_value_type(); }
+  bool is_derive_value_type() const;
 
   const InstanceKlass* host_klass() const { return _host_klass; }
   const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
--- a/src/share/vm/classfile/classLoader.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/classfile/classLoader.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -209,7 +209,7 @@
     // Set bad_class_name to true to indicate that the package name
     // could not be obtained due to an error condition.
     // In this situation, is_same_class_package returns false.
-    if (*class_name_ptr == 'L') {
+    if (*class_name_ptr == 'L' || *class_name_ptr == 'Q') {
       if (bad_class_name != NULL) {
         *bad_class_name = true;
       }
--- a/src/share/vm/classfile/javaClasses.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/classfile/javaClasses.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -45,6 +45,7 @@
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayOop.hpp"
+#include "oops/valueArrayKlass.hpp"
 #include "runtime/fieldDescriptor.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/interfaceSupport.hpp"
@@ -843,7 +844,11 @@
     // It might also have a component mirror.  This mirror must already exist.
     if (k->is_array_klass()) {
       oop comp_mirror;
-      if (k->is_typeArray_klass()) {
+      if (k->is_valueArray_klass()) {
+        Klass* element_klass = (Klass*) ValueArrayKlass::cast(k)->element_klass();
+        comp_mirror = element_klass->java_mirror();
+      }
+      else if (k->is_typeArray_klass()) {
         BasicType type = TypeArrayKlass::cast(k)->element_type();
         comp_mirror = Universe::java_mirror(type);
       } else {
@@ -1016,18 +1021,26 @@
   assert(java_lang_Class::is_instance(java_class), "must be a Class object");
   Symbol* name = NULL;
   bool is_instance = false;
+  bool is_value = false;
   if (is_primitive(java_class)) {
     name = vmSymbols::type_signature(primitive_type(java_class));
   } else {
     Klass* k = as_Klass(java_class);
     is_instance = k->is_instance_klass();
+    is_value = k->is_value();
     name = k->name();
   }
   if (name == NULL) {
     st->print("<null>");
     return;
   }
-  if (is_instance)  st->print("L");
+  if (is_instance)  {
+    if (is_value) {
+      st->print("Q");
+    } else {
+      st->print("L");
+    }
+  }
   st->write((char*) name->base(), (int) name->utf8_length());
   if (is_instance)  st->print(";");
 }
--- a/src/share/vm/classfile/systemDictionary.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/classfile/systemDictionary.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -66,6 +66,7 @@
 #include "runtime/javaCalls.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/orderAccess.inline.hpp"
+#include "runtime/os.hpp"
 #include "runtime/signature.hpp"
 #include "services/classLoadingService.hpp"
 #include "services/threadService.hpp"
@@ -237,9 +238,9 @@
          class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string());
   if (FieldType::is_array(class_name)) {
     return resolve_array_class_or_null(class_name, class_loader, protection_domain, THREAD);
-  } else if (FieldType::is_obj(class_name)) {
+  } else if (FieldType::is_obj(class_name) || FieldType::is_valuetype(class_name)) {
     ResourceMark rm(THREAD);
-    // Ignore wrapping L and ;.
+    // Ignore wrapping L and ;. (and Q and ; for value types);
     TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1,
                                    class_name->utf8_length() - 2, CHECK_NULL);
     return resolve_instance_class_or_null(name, class_loader, protection_domain, THREAD);
@@ -264,7 +265,7 @@
   // dimension and object_key in FieldArrayInfo are assigned as a side-effect
   // of this call
   BasicType t = FieldType::get_array_info(class_name, fd, CHECK_NULL);
-  if (t == T_OBJECT) {
+  if (t == T_OBJECT  || t == T_VALUETYPE) {
     // naked oop "k" is OK here -- we assign back into it
     k = SystemDictionary::resolve_instance_class_or_null(fd.object_key(),
                                                          class_loader,
@@ -648,7 +649,7 @@
                                                         Handle protection_domain,
                                                         TRAPS) {
   assert(name != NULL && !FieldType::is_array(name) &&
-         !FieldType::is_obj(name), "invalid class name");
+         !FieldType::is_obj(name)  && !FieldType::is_valuetype(name), "invalid class name");
 
   Ticks class_load_start_time = Ticks::now();
 
@@ -994,7 +995,7 @@
     // side-effect of this call
     FieldArrayInfo fd;
     BasicType t = FieldType::get_array_info(class_name, fd, CHECK_(NULL));
-    if (t != T_OBJECT) {
+    if (t != T_OBJECT  && t != T_VALUETYPE) {
       k = Universe::typeArrayKlassObj(t);
     } else {
       k = SystemDictionary::find(fd.object_key(), class_loader, protection_domain, THREAD);
@@ -2097,6 +2098,20 @@
     must_load = (init_opt < SystemDictionary::Opt);
   }
 
+  if (init_opt == SystemDictionary::ValhallaClasses) {
+    if (EnableValhalla || EnableMVT) {
+      must_load = true;
+    } else {
+      return false;
+    }
+  } else if (init_opt == SystemDictionary::MVTClasses) {
+    if (EnableMVT) {
+      must_load = true;
+    } else {
+      return false;
+    }
+  }
+
   if ((*klassp) == NULL) {
     Klass* k;
     if (must_load) {
@@ -2348,7 +2363,7 @@
     // constraint table. The element Klass*s are.
     FieldArrayInfo fd;
     BasicType t = FieldType::get_array_info(class_name, fd, CHECK_(NULL));
-    if (t != T_OBJECT) {
+    if (t != T_OBJECT && t != T_VALUETYPE) {
       klass = Universe::typeArrayKlassObj(t);
     } else {
       MutexLocker mu(SystemDictionary_lock, THREAD);
--- a/src/share/vm/classfile/systemDictionary.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/classfile/systemDictionary.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -181,6 +181,10 @@
   do_klass(CodeSource_klass,                            java_security_CodeSource,                  Pre                 ) \
   do_klass(ParseUtil_klass,                             sun_net_www_ParseUtil,                     Pre                 ) \
                                                                                                                          \
+  /* support for valhalla "shady" value type bytecode transformer */                                                     \
+  do_klass(DeriveValueType_klass,                       jvm_internal_value_DeriveValueType,        MVTClasses          ) \
+  do_klass(Valhalla_MVT1_0_klass,                       valhalla_shady_MVT1_0,                     MVTClasses          ) \
+                                                                                                                         \
   do_klass(StackTraceElement_klass,                     java_lang_StackTraceElement,               Opt                 ) \
                                                                                                                          \
   /* It's okay if this turns out to be NULL in non-1.4 JDKs. */                                                          \
@@ -202,6 +206,8 @@
   do_klass(Integer_klass,                               java_lang_Integer,                         Pre                 ) \
   do_klass(Long_klass,                                  java_lang_Long,                            Pre                 ) \
                                                                                                                          \
+  do_klass(___Value_klass,                              java_lang____Value,                        ValhallaClasses     ) \
+                                                                                                                         \
   /* Extensions */                                                                                                       \
   WK_KLASSES_DO_EXT(do_klass)                                                                                            \
   /* JVMCI classes. These are loaded on-demand. */                                                                       \
@@ -243,8 +249,10 @@
 #if INCLUDE_JVMCI
     Jvmci,                      // preload tried; error if not present if JVMCI enabled
 #endif
+    ValhallaClasses,            // loaded if Valhalla enabled
+    MVTClasses,                 // loaded if MVT enabled
     OPTION_LIMIT,
-    CEIL_LG_OPTION_LIMIT = 2    // OPTION_LIMIT <= (1<<CEIL_LG_OPTION_LIMIT)
+    CEIL_LG_OPTION_LIMIT = 3    // OPTION_LIMIT <= (1<<CEIL_LG_OPTION_LIMIT)
   };
 
 
@@ -425,6 +433,8 @@
 
   static InstanceKlass* check_klass_Pre(InstanceKlass* k) { return check_klass(k); }
   static InstanceKlass* check_klass_Opt(InstanceKlass* k) { return k; }
+  static InstanceKlass* check_klass_ValhallaClasses(InstanceKlass* k) { return k; }
+  static InstanceKlass* check_klass_MVTClasses(InstanceKlass* k) { return k; }
 
   JVMCI_ONLY(static InstanceKlass* check_klass_Jvmci(InstanceKlass* k) { return k; })
 
--- a/src/share/vm/classfile/vmSymbols.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/classfile/vmSymbols.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -196,7 +196,11 @@
       return (BasicType)i;
     }
   }
-  return T_OBJECT;
+  if (s->byte_at(0) =='Q') {
+    return T_VALUETYPE;
+  } else {
+    return T_OBJECT;
+  }
 }
 
 
--- a/src/share/vm/classfile/vmSymbols.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/classfile/vmSymbols.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -123,6 +123,7 @@
   template(getBootClassPathEntryForClass_name,        "getBootClassPathEntryForClass")            \
   template(jdk_internal_vm_PostVMInitHook,            "jdk/internal/vm/PostVMInitHook")           \
   template(sun_net_www_ParseUtil,                     "sun/net/www/ParseUtil")                    \
+  template(java_lang____Value,                        "java/lang/__Value")                        \
                                                                                                   \
   template(jdk_internal_loader_ClassLoaders_AppClassLoader,      "jdk/internal/loader/ClassLoaders$AppClassLoader")      \
   template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \
@@ -315,6 +316,14 @@
   template(DEFAULT_CONTEXT_name,                      "DEFAULT_CONTEXT")                          \
   NOT_LP64(  do_alias(intptr_signature,               int_signature)  )                           \
   LP64_ONLY( do_alias(intptr_signature,               long_signature) )                           \
+                                                                                                  \
+ /* support for valhalla "shady" value types */                                                   \
+  template(jvm_internal_value_DeriveValueType,           "jvm/internal/value/DeriveValueType")    \
+  template(jvm_internal_value_DeriveValueType_signature, "Ljvm/internal/value/DeriveValueType;")  \
+  template(valhalla_shady_MVT1_0,                        "valhalla/shady/MinimalValueTypes_1_0")  \
+  template(valhalla_shady_MVT1_0_createDerivedValueType,           "createDerivedValueType")      \
+  template(valhalla_shady_MVT1_0_createDerivedValueType_signature, "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/security/ProtectionDomain;[Ljava/lang/String;[I)Ljava/lang/String;") \
+                                                                                                  \
                                                                                                                                       \
   /* Support for JVMCI */                                                                                                             \
   JVMCI_VM_SYMBOLS_DO(template, do_alias)                                                         \
--- a/src/share/vm/gc/parallel/psCompactionManager.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/gc/parallel/psCompactionManager.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -38,6 +38,7 @@
 #include "oops/instanceMirrorKlass.inline.hpp"
 #include "oops/objArrayKlass.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueArrayKlass.inline.hpp"
 #include "runtime/atomic.hpp"
 
 PSOldGen*            ParCompactionManager::_old_gen = NULL;
@@ -236,6 +237,15 @@
   // know that Universe::TypeArrayKlass never moves.
 }
 
+void ValueArrayKlass::oop_pc_follow_contents(oop obj, ParCompactionManager* cm) {
+  assert(obj->is_valueArray(),"must be a value array");
+  cm->follow_klass(this);
+  if (contains_oops()) { // CMH: parallel version (like objArrayTask) missing, treat as single obj for now
+    ParCompactionManager::MarkAndPushClosure cl(cm);
+    ValueArrayKlass::oop_oop_iterate_elements<true>(valueArrayOop(obj), &cl);
+  }
+}
+
 void ParCompactionManager::follow_marking_stacks() {
   do {
     // Drain the overflow stack first, to allow stealing from the marking stack.
--- a/src/share/vm/gc/parallel/psParallelCompact.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/gc/parallel/psParallelCompact.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -58,6 +58,7 @@
 #include "oops/methodData.hpp"
 #include "oops/objArrayKlass.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueArrayKlass.inline.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/fprofiler.hpp"
 #include "runtime/safepoint.hpp"
@@ -3107,6 +3108,14 @@
   assert(obj->is_typeArray(),"must be a type array");
 }
 
+void ValueArrayKlass::oop_pc_update_pointers(oop obj, ParCompactionManager* cm) {
+  assert(obj->is_valueArray(),"must be a value array");
+  if (contains_oops()) {
+    PSParallelCompact::AdjustPointerClosure closure(cm);
+    oop_oop_iterate_elements<true>(valueArrayOop(obj), &closure);
+  }
+}
+
 ParMarkBitMapClosure::IterationStatus
 MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) {
   assert(destination() != NULL, "sanity");
--- a/src/share/vm/gc/parallel/psPromotionManager.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/gc/parallel/psPromotionManager.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -41,6 +41,7 @@
 #include "oops/instanceMirrorKlass.inline.hpp"
 #include "oops/objArrayKlass.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueArrayKlass.inline.hpp"
 
 PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = NULL;
 OopStarTaskQueueSet*           PSPromotionManager::_stack_array_depth = NULL;
@@ -481,6 +482,14 @@
   ShouldNotReachHere();
 }
 
+void ValueArrayKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) {
+  assert(obj->is_valueArray(),"must be a value array");
+  if (contains_oops()) {
+    PushContentsClosure cl(pm);
+    oop_oop_iterate_elements<true>(valueArrayOop(obj), &cl);
+  }
+}
+
 oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) {
   assert(_old_gen_is_full || PromotionFailureALot, "Sanity");
 
--- a/src/share/vm/gc/serial/markSweep.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/gc/serial/markSweep.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -36,6 +36,7 @@
 #include "oops/instanceRefKlass.inline.hpp"
 #include "oops/methodData.hpp"
 #include "oops/objArrayKlass.inline.hpp"
+#include "oops/valueArrayKlass.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/typeArrayOop.inline.hpp"
 #include "utilities/macros.hpp"
@@ -354,5 +355,13 @@
   return t->object_size();
 }
 
+int ValueArrayKlass::oop_ms_adjust_pointers(oop obj) {
+  assert(obj->is_valueArray(), "must be value array");
+  valueArrayOop v = valueArrayOop(obj);
+  int size = v->object_size();
+  oop_oop_iterate_elements<true>(v, &MarkSweep::adjust_pointer_closure);
+  return size;
+}
+
 // Generate MS specialized oop_oop_iterate functions.
 SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(ALL_KLASS_OOP_OOP_ITERATE_DEFN)
--- a/src/share/vm/interpreter/abstractInterpreter.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/abstractInterpreter.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -318,6 +318,7 @@
 
   switch (code) {
     case Bytecodes::_invokevirtual  :
+    case Bytecodes::_invokedirect   :
     case Bytecodes::_invokespecial  :
     case Bytecodes::_invokestatic   :
     case Bytecodes::_invokeinterface: {
--- a/src/share/vm/interpreter/abstractInterpreter.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/abstractInterpreter.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -101,7 +101,7 @@
   }
 
   enum SomeConstants {
-    number_of_result_handlers = 10                              // number of result handlers for native calls
+    number_of_result_handlers = 11                              // number of result handlers for native calls
   };
 
  protected:
--- a/src/share/vm/interpreter/bytecode.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/bytecode.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -214,6 +214,7 @@
   // Testers
   bool is_invokeinterface() const                { return invoke_code() == Bytecodes::_invokeinterface; }
   bool is_invokevirtual() const                  { return invoke_code() == Bytecodes::_invokevirtual; }
+  bool is_invokedirect() const                   { return invoke_code() == Bytecodes::_invokedirect; }
   bool is_invokestatic() const                   { return invoke_code() == Bytecodes::_invokestatic; }
   bool is_invokespecial() const                  { return invoke_code() == Bytecodes::_invokespecial; }
   bool is_invokedynamic() const                  { return invoke_code() == Bytecodes::_invokedynamic; }
@@ -223,6 +224,7 @@
 
   bool is_valid() const                          { return is_invokeinterface() ||
                                                           is_invokevirtual()   ||
+                                                          is_invokedirect()    ||
                                                           is_invokestatic()    ||
                                                           is_invokespecial()   ||
                                                           is_invokedynamic()   ||
--- a/src/share/vm/interpreter/bytecodeTracer.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/bytecodeTracer.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -431,11 +431,13 @@
     case Bytecodes::_fload:
     case Bytecodes::_dload:
     case Bytecodes::_aload:
+    case Bytecodes::_vload:
     case Bytecodes::_istore:
     case Bytecodes::_lstore:
     case Bytecodes::_fstore:
     case Bytecodes::_dstore:
     case Bytecodes::_astore:
+    case Bytecodes::_vstore:
       st->print_cr(" #%d", get_index_special());
       break;
 
@@ -544,10 +546,13 @@
     case Bytecodes::_getstatic:
     case Bytecodes::_putfield:
     case Bytecodes::_getfield:
+    case Bytecodes::_vgetfield:
+    case Bytecodes::_vwithfield:
       print_field_or_method(get_index_u2_cpcache(), st);
       break;
 
     case Bytecodes::_invokevirtual:
+    case Bytecodes::_invokedirect:
     case Bytecodes::_invokespecial:
     case Bytecodes::_invokestatic:
       print_field_or_method(get_index_u2_cpcache(), st);
@@ -568,6 +573,9 @@
     case Bytecodes::_new:
     case Bytecodes::_checkcast:
     case Bytecodes::_instanceof:
+    case Bytecodes::_vbox:
+    case Bytecodes::_vunbox:
+    case Bytecodes::_vdefault:
       { int i = get_index_u2();
         ConstantPool* constants = method()->constants();
         Symbol* name = constants->klass_name_at(i);
--- a/src/share/vm/interpreter/bytecodes.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/bytecodes.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -481,11 +481,23 @@
   def(_goto_w              , "goto_w"              , "boooo", NULL    , T_VOID   ,  0, false);
   def(_jsr_w               , "jsr_w"               , "boooo", NULL    , T_INT    ,  0, false);
   def(_breakpoint          , "breakpoint"          , ""     , NULL    , T_VOID   ,  0, true);
+  def(_vload               , "vload"               , "bi"   , "wbii"  , T_VALUETYPE,1, false);
+  def(_vstore              , "vstore"              , "bi"   , "wbii"  , T_VOID   , -1, false);
+  def(_vaload              , "vaload"              , "b"    , NULL    , T_VALUETYPE, -1, true);
+  def(_vastore             , "vastore"             , "b"    , NULL    , T_VOID   , -3, true );
+  def(_vreturn             , "vreturn"             , "b"    , NULL    , T_VALUETYPE, -1, true);
+  def(_vgetfield           , "vgetfield"           , "bJJ"  , NULL    , T_ILLEGAL,  0, true );
+  def(_invokedirect        , "invokedirect"        , "bJJ"  , NULL    , T_ILLEGAL, -1, true);
+  def(_vbox                , "vbox"                , "bkk"  , NULL    , T_OBJECT ,  0, true );
+  def(_vunbox              , "vunbox"              , "bkk"  , NULL    , T_VALUETYPE,0, true );
+  def(_vdefault            , "vdefault"            , "bkk"  , NULL    , T_VALUETYPE, 1, true);
+  def(_vwithfield          , "vwithfield"          , "bJJ"  , NULL    , T_VALUETYPE, -1, true );
 
   //  JVM bytecodes
   //  bytecode               bytecode name           format   wide f.   result tp  stk traps  std code
 
   def(_fast_agetfield      , "fast_agetfield"      , "bJJ"  , NULL    , T_OBJECT ,  0, true , _getfield       );
+  def(_fast_qgetfield      , "fast_qgetfield"      , "bJJ"  , NULL    , T_VALUETYPE, 0, true, _getfield       );
   def(_fast_bgetfield      , "fast_bgetfield"      , "bJJ"  , NULL    , T_INT    ,  0, true , _getfield       );
   def(_fast_cgetfield      , "fast_cgetfield"      , "bJJ"  , NULL    , T_CHAR   ,  0, true , _getfield       );
   def(_fast_dgetfield      , "fast_dgetfield"      , "bJJ"  , NULL    , T_DOUBLE ,  0, true , _getfield       );
@@ -495,6 +507,7 @@
   def(_fast_sgetfield      , "fast_sgetfield"      , "bJJ"  , NULL    , T_SHORT  ,  0, true , _getfield       );
 
   def(_fast_aputfield      , "fast_aputfield"      , "bJJ"  , NULL    , T_OBJECT ,  0, true , _putfield       );
+  def(_fast_qputfield      , "fast_qputfield"      , "bJJ"  , NULL    , T_VALUETYPE, 0, true, _putfield       );
   def(_fast_bputfield      , "fast_bputfield"      , "bJJ"  , NULL    , T_INT    ,  0, true , _putfield       );
   def(_fast_zputfield      , "fast_zputfield"      , "bJJ"  , NULL    , T_INT    ,  0, true , _putfield       );
   def(_fast_cputfield      , "fast_cputfield"      , "bJJ"  , NULL    , T_CHAR   ,  0, true , _putfield       );
--- a/src/share/vm/interpreter/bytecodes.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/bytecodes.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -243,10 +243,24 @@
     _jsr_w                = 201, // 0xc9
     _breakpoint           = 202, // 0xca
 
+    // value-type bytecodes
+    _vload                = 203, // 0xcb
+    _vstore               = 204, // 0xcc
+    _vaload               = 205, // 0xcd
+    _vastore              = 206, // 0xce
+    _vreturn              = 210, // 0xd2
+    _vgetfield            = 211, // 0xd3
+    _invokedirect         = 213, // 0xd5
+    _vdefault             = 214, // 0xd6
+    _vwithfield           = 215, // 0xd7
+    _vbox                 = 216, // 0xd6
+    _vunbox               = 217, // 0xd7
+
     number_of_java_codes,
 
     // JVM bytecodes
     _fast_agetfield       = number_of_java_codes,
+    _fast_qgetfield       ,
     _fast_bgetfield       ,
     _fast_cgetfield       ,
     _fast_dgetfield       ,
@@ -256,6 +270,7 @@
     _fast_sgetfield       ,
 
     _fast_aputfield       ,
+    _fast_qputfield       ,
     _fast_bputfield       ,
     _fast_zputfield       ,
     _fast_cputfield       ,
@@ -422,8 +437,9 @@
   static bool        is_zero_const  (Code code)    { return (code == _aconst_null || code == _iconst_0
                                                            || code == _fconst_0 || code == _dconst_0); }
   static bool        is_return      (Code code)    { return (_ireturn <= code && code <= _return); }
-  static bool        is_invoke      (Code code)    { return (_invokevirtual <= code && code <= _invokedynamic); }
+  static bool        is_invoke      (Code code)    { return (_invokevirtual <= code && code <= _invokedynamic) || code == _invokedirect; }
   static bool        has_receiver   (Code code)    { assert(is_invoke(code), "");  return code == _invokevirtual ||
+                                                                                          code == _invokedirect  ||
                                                                                           code == _invokespecial ||
                                                                                           code == _invokeinterface; }
   static bool        has_optional_appendix(Code code) { return code == _invokedynamic || code == _invokehandle; }
--- a/src/share/vm/interpreter/interpreterRuntime.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -45,6 +45,9 @@
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
+#include "oops/valueKlass.hpp"
+#include "oops/valueArrayKlass.hpp"
+#include "oops/valueArrayOop.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/nativeLookup.hpp"
 #include "runtime/atomic.hpp"
@@ -63,6 +66,7 @@
 #include "runtime/synchronizer.hpp"
 #include "runtime/threadCritical.hpp"
 #include "utilities/events.hpp"
+#include "utilities/globalDefinitions.hpp"
 #ifdef COMPILER2
 #include "opto/runtime.hpp"
 #endif
@@ -165,6 +169,211 @@
   thread->set_vm_result(obj);
 IRT_END
 
+void copy_primitive_argument(intptr_t* addr, Handle instance, int offset, BasicType type) {
+  switch (type) {
+  case T_BOOLEAN:
+    instance()->bool_field_put(offset, (jboolean)*((int*)addr));
+    break;
+  case T_CHAR:
+    instance()->char_field_put(offset, (jchar) *((int*)addr));
+    break;
+  case T_FLOAT:
+    instance()->float_field_put(offset, (jfloat)*((float*)addr));
+    break;
+  case T_DOUBLE:
+    instance()->double_field_put(offset, (jdouble)*((double*)addr));
+    break;
+  case T_BYTE:
+    instance()->byte_field_put(offset, (jbyte)*((int*)addr));
+    break;
+  case T_SHORT:
+    instance()->short_field_put(offset, (jshort)*((int*)addr));
+    break;
+  case T_INT:
+    instance()->int_field_put(offset, (jint)*((int*)addr));
+    break;
+  case T_LONG:
+    instance()->long_field_put(offset, (jlong)*((long*)addr)); // Is it correct on 32 and 64 bits?
+    break;
+  case T_OBJECT:
+  case T_ARRAY:
+  case T_VALUETYPE:
+    fatal("Should not be handled with this method");
+    break;
+  default:
+    fatal("Unsupported BasicType");
+  }
+}
+
+IRT_ENTRY(void, InterpreterRuntime::vdefault(JavaThread* thread, ConstantPool* pool, int index))
+  // Getting the ValueKlass
+  Klass* k = pool->klass_at(index, CHECK);
+  assert(k->is_value(), "vdefault argument must be the value type class");
+  ValueKlass* vklass = ValueKlass::cast(k);
+
+  vklass->initialize(THREAD);
+
+  // Creating value
+  instanceOop value = vklass->allocate_instance(CHECK);
+  Handle value_h = Handle(THREAD, value);
+
+  // Zeroing, already performed by allocate_instance() when allocating in the Java Heap
+  // Might need to be performed manually for off-heap allocations
+  // memset(((char*)(oopDesc*)value) + vklass_h->first_field_offset(), 0,
+  //        vklass_h->size_helper() * wordSize - vklass_h->first_field_offset());
+
+  thread->set_vm_result(value_h());
+IRT_END
+
+IRT_ENTRY(int, InterpreterRuntime::vwithfield(JavaThread* thread, ConstantPoolCache* cp_cache))
+  // Getting the ValueKlass
+  int index = ConstantPool::decode_cpcache_index(get_index_u2_cpcache(thread, Bytecodes::_vwithfield));
+  ConstantPoolCacheEntry* cp_entry = cp_cache->entry_at(index);
+  assert(cp_entry->is_resolved(Bytecodes::_vwithfield), "Should have been resolved");
+  Klass* klass = cp_entry->f1_as_klass();
+  assert(klass->is_value(), "vwithfield only applies to value types");
+  ValueKlass* vklass = ValueKlass::cast(klass);
+
+  // Getting Field information
+  int offset = cp_entry->f2_as_index();
+  fieldDescriptor fd;
+  vklass->find_field_from_offset(offset, false, &fd);
+  Symbol* field_signature = fd.signature();
+  const char* signature = (const char *) field_signature->as_utf8();
+  BasicType field_type = char2type(signature[0]);
+
+  // Getting old value
+  intptr_t* arg = last_frame(thread).sp();
+  int offset2 = type2size[field_type];
+  oop old_value = *(oop*)(&arg[type2size[field_type]]);
+  int arg_size = (type2size[field_type]) * AbstractInterpreter::stackElementSize;
+  assert(old_value->is_oop(),"Verify pointer arithmetic above is correct");
+  Handle old_value_h(THREAD, old_value);
+
+  // Creating new value by copying the one passed in argument
+  instanceOop new_value = vklass->allocate_instance(CHECK_0);
+  Handle new_value_h = Handle(THREAD, new_value);
+  int first_offset = vklass->first_field_offset();
+  vklass->value_store(((char*)(oopDesc*)old_value_h()) + first_offset,
+      ((char*)(oopDesc*)new_value_h()) + first_offset, true, false);
+
+  // Updating the field specified in arguments
+  if (field_type == T_OBJECT || field_type == T_ARRAY) {
+    oop aoop = *((oop*)arg);
+    assert(aoop->is_oop() && (!aoop->is_value()),"value type argument should be oop");
+    new_value_h()->obj_field_put(fd.offset(), aoop);
+  } else if (field_type == T_VALUETYPE) {
+    ResourceMark rm(THREAD);
+    Symbol* field_klassname = SignatureStream(field_signature, false).as_symbol(CHECK_(arg_size));
+    // It would be better to have another way to retrieve the field klass
+    // than doing a lookup in the SystemDictionary
+    Klass* field_k = SystemDictionary::resolve_or_null(field_klassname,
+        Handle(THREAD, vklass->class_loader()), Handle(THREAD, vklass->protection_domain()), CHECK_(arg_size));
+    if (field_k == NULL) {
+      ResourceMark rm(THREAD);
+      THROW_MSG_(vmSymbols::java_lang_NoSuchFieldError(), fd.name()->as_C_string(), arg_size);
+    }
+    ValueKlass* field_vk = ValueKlass::cast(field_k);
+    oop vt_oop = *(oop*)arg;
+    assert(vt_oop->is_oop(),"value type argument should be oop");
+    assert(field_vk == vt_oop->klass(), "Must match");
+    field_vk->value_store(((char*)(oopDesc*)vt_oop + field_vk->first_field_offset()),
+            ((char*)(oopDesc*)new_value_h()) + fd.offset(), true, false);
+  } else {
+    copy_primitive_argument(arg, new_value_h, fd.offset(), field_type);
+  }
+
+  // returning result
+  thread->set_vm_result(new_value_h());
+  return arg_size;
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::vbox(JavaThread* thread, ConstantPool* pool, int index, oopDesc* value))
+  if (value == NULL) {
+    THROW(vmSymbols::java_lang_NullPointerException());
+  }
+
+  // Since the verifier is probably disabled, a few extra type check
+  Klass* target_klass = pool->klass_at(index, CHECK);
+  if (target_klass->is_value()) {
+    THROW_MSG(vmSymbols::java_lang_ClassCastException(), "vbox target is value type");
+  }
+  Klass* klass = value->klass();
+  if (!klass->is_value()) {
+    THROW_MSG(vmSymbols::java_lang_ClassCastException(), "vbox not from value type");
+  }
+  ValueKlass* vtklass = ValueKlass::cast(klass);
+  if (vtklass->derive_value_type_klass() != target_klass) {
+    THROW_MSG(vmSymbols::java_lang_ClassCastException(), "vbox target is not derive value type box");
+  }
+
+  oop boxed = vtklass->derive_value_type_copy(Handle(THREAD, value),
+                                              InstanceKlass::cast(target_klass),
+                                              CHECK);
+  thread->set_vm_result(boxed);
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::vunbox(JavaThread* thread, ConstantPool* pool, int index, oopDesc* obj))
+  if (obj == NULL) {
+    THROW(vmSymbols::java_lang_NullPointerException());
+  }
+  Klass* target_klass = pool->klass_at(index, CHECK);
+  if (!target_klass->is_value()) {
+    THROW_MSG(vmSymbols::java_lang_ClassCastException(), "vunbox target is not value type");
+  }
+  Klass* klass = obj->klass();
+  if ((!klass->is_instance_klass()) || klass->is_value()) {
+    THROW_MSG(vmSymbols::java_lang_ClassCastException(), "vunbox source is not an instance");
+  }
+  InstanceKlass* dvtklass = InstanceKlass::cast(klass)->derive_value_type_klass();
+  if (dvtklass != target_klass) {
+    THROW_MSG(vmSymbols::java_lang_ClassCastException(), "vunbox target is not derive value type");
+  }
+  oop value = ValueKlass::cast(dvtklass)->derive_value_type_copy(Handle(THREAD, obj),
+                                                                 InstanceKlass::cast(target_klass),
+                                                                 CHECK);
+  thread->set_vm_result(value);
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::qgetfield(JavaThread* thread, oopDesc* value, int offset))
+  Handle value_h(THREAD, value);
+  InstanceKlass* klass = InstanceKlass::cast(value->klass());
+
+  fieldDescriptor fd;
+  klass->find_field_from_offset(offset, false, &fd);
+  Symbol* field_signature = fd.signature();
+  ResourceMark rm(thread);
+  Symbol* field_klassname = SignatureStream(field_signature, false).as_symbol(CHECK);
+  // It would be better to have another way to retrieve the field klass
+  // than doing a lookup in the SystemDictionary
+  Klass* field_k = SystemDictionary::resolve_or_null(field_klassname,
+    Handle(THREAD, klass->class_loader()), Handle(THREAD, klass->protection_domain()), CHECK);
+  if (field_k == NULL) {
+    ResourceMark rm(THREAD);
+    THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), fd.name()->as_C_string());
+  }
+  ValueKlass* field_vklass = ValueKlass::cast(field_k);
+  // allocate instance
+  instanceOop res = field_vklass->allocate_instance(CHECK);
+  // copy value
+  int size = field_vklass->layout_helper_size_in_bytes(field_vklass->layout_helper());
+  field_vklass->value_store(((char*)(oopDesc*)value_h()) + offset,
+    ((char*)(oopDesc*)res) + field_vklass->first_field_offset(),true, false);
+  thread->set_vm_result(res);
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::qputfield(JavaThread* thread, oopDesc* obj, oopDesc* value, int offset))
+  Handle value_h(THREAD, value);
+  Handle obj_h(THREAD, obj);
+
+  InstanceKlass* klass_h = InstanceKlass::cast(obj->klass());
+  ValueKlass* field_vklass = ValueKlass::cast(value->klass());
+
+  // copy value
+  int size = field_vklass->layout_helper_size_in_bytes(field_vklass->layout_helper());
+  field_vklass->value_store(((char*)(oopDesc*)value_h()) + field_vklass->first_field_offset(),
+                            ((char*)(oopDesc*)obj_h()) + offset, true, false);
+IRT_END
 
 IRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* thread, BasicType type, jint size))
   oop obj = oopFactory::new_typeArray(type, size, CHECK);
@@ -174,10 +383,48 @@
 
 IRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* thread, ConstantPool* pool, int index, jint size))
   Klass*    klass = pool->klass_at(index, CHECK);
-  objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
+  if (klass->is_value()) { // Logically creates elements, ensure klass init
+    klass->initialize(CHECK);
+  }
+  arrayOop obj = oopFactory::new_array(klass, size, CHECK);
   thread->set_vm_result(obj);
 IRT_END
 
+IRT_ENTRY(void, InterpreterRuntime::value_array_load(JavaThread* thread, arrayOopDesc* array, int index))
+  Klass* klass = array->klass();
+  assert(klass->is_valueArray_klass() || klass->is_objArray_klass(), "expected value or object array oop");
+
+  if (klass->is_objArray_klass()) {
+    thread->set_vm_result(((objArrayOop) array)->obj_at(index));
+  }
+  else {
+    // Early prototype: we don't have valorind support...just allocate aref and copy
+    ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
+    ValueKlass* vklass = vaklass->element_klass();
+    arrayHandle ah(THREAD, array);
+    instanceOop value_holder = vklass->allocate_instance(CHECK);
+    void* src = ((valueArrayOop)ah())->value_at_addr(index, vaklass->layout_helper());
+    vklass->value_store(src, vklass->data_for_oop(value_holder),
+                          vaklass->element_value_store_size(), true, true);
+    thread->set_vm_result(value_holder);
+  }
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::value_array_store(JavaThread* thread, arrayOopDesc* array, int index, void* val))
+  Klass* klass = array->klass();
+  assert(klass->is_valueArray_klass() || klass->is_objArray_klass(), "expected value or object array oop");
+  if (klass->is_objArray_klass()) {
+    ((objArrayOop) array)->obj_at_put(index, (oop)val);
+  }
+  else {
+    valueArrayOop varray = (valueArrayOop)array;
+    ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
+    ValueKlass* vklass = vaklass->element_klass();
+    const int lh = vaklass->layout_helper();
+    vklass->value_store(vklass->data_for_oop((oop)val), varray->value_at_addr(index, lh),
+                        vaklass->element_value_store_size(), true, false);
+  }
+IRT_END
 
 IRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* thread, jint* first_size_address))
   // We may want to pass in more arguments - could make this slightly faster
@@ -188,6 +435,10 @@
   assert(klass->is_klass(), "not a class");
   assert(nof_dims >= 1, "multianewarray rank must be nonzero");
 
+  if (klass->is_value()) { // Logically creates elements, ensure klass init
+    klass->initialize(CHECK);
+  }
+
   // We must create an array of jints to pass to multi_allocate.
   ResourceMark rm(thread);
   const int small_dims = 10;
@@ -559,8 +810,9 @@
   constantPoolHandle pool(thread, method(thread)->constants());
   methodHandle m(thread, method(thread));
   bool is_put    = (bytecode == Bytecodes::_putfield  || bytecode == Bytecodes::_nofast_putfield ||
-                    bytecode == Bytecodes::_putstatic);
+                    bytecode == Bytecodes::_putstatic || bytecode == Bytecodes::_vwithfield);
   bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
+  bool is_value  = (bytecode == Bytecodes::_vgetfield || bytecode == Bytecodes::_vwithfield);
 
   {
     JvmtiHideSingleStepping jhss(thread);
@@ -604,9 +856,15 @@
   Bytecodes::Code get_code = (Bytecodes::Code)0;
   Bytecodes::Code put_code = (Bytecodes::Code)0;
   if (!uninitialized_static) {
-    get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);
-    if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) {
-      put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
+    if (is_static) {
+      get_code = Bytecodes::_getstatic;
+    } else {
+      get_code = ((is_value) ? Bytecodes::_vgetfield : Bytecodes::_getfield);
+    }
+    if (is_put && is_value) {
+        put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_vwithfield);
+    } else if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) {
+        put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
     }
   }
 
@@ -720,7 +978,9 @@
   Thread* THREAD = thread;
   // extract receiver from the outgoing argument list if necessary
   Handle receiver(thread, NULL);
-  if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) {
+  if (bytecode == Bytecodes::_invokevirtual ||
+      bytecode == Bytecodes::_invokeinterface ||
+      bytecode == Bytecodes::_invokedirect) {
     ResourceMark rm(thread);
     methodHandle m (thread, method(thread));
     Bytecode_invoke call(m, bci(thread));
@@ -759,6 +1019,9 @@
     }
   } // end JvmtiHideSingleStepping
 
+  assert(!(bytecode == Bytecodes::_invokedirect && info.call_kind() != CallInfo::direct_call),
+         "the target of a invokedirect bytecode must be a direct call");
+
   // check if link resolution caused cpCache to be updated
   ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread);
   if (cp_cache_entry->is_resolved(bytecode)) return;
@@ -861,9 +1124,12 @@
   case Bytecodes::_putstatic:
   case Bytecodes::_getfield:
   case Bytecodes::_putfield:
+  case Bytecodes::_vgetfield:
+  case Bytecodes::_vwithfield:
     resolve_get_put(thread, bytecode);
     break;
   case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokedirect:
   case Bytecodes::_invokespecial:
   case Bytecodes::_invokestatic:
   case Bytecodes::_invokeinterface:
--- a/src/share/vm/interpreter/interpreterRuntime.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/interpreterRuntime.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -87,6 +87,19 @@
   static void    anewarray     (JavaThread* thread, ConstantPool* pool, int index, jint size);
   static void    multianewarray(JavaThread* thread, jint* first_size_address);
   static void    register_finalizer(JavaThread* thread, oopDesc* obj);
+  static void    vdefault      (JavaThread* thread, ConstantPool* pool, int index);
+  static int     vwithfield    (JavaThread* thread, ConstantPoolCache* cp_cache);
+  static void    qgetfield     (JavaThread* thread, oopDesc* value, int offset);
+  static void    qputfield     (JavaThread* thread, oopDesc* obj, oopDesc* value, int offset);
+
+  // vaload/vastore
+  static void value_array_load(JavaThread* thread, arrayOopDesc* array, int index);
+  static void value_array_store(JavaThread* thread, arrayOopDesc* array, int index, void* val);
+
+  // Valhalla MVT VCC<->DVT
+  static void    vbox  (JavaThread* thread, ConstantPool* pool, int index, oopDesc* value);
+  static void    vunbox(JavaThread* thread, ConstantPool* pool, int index, oopDesc* obj);
+
 
   // Quicken instance-of and check-cast bytecodes
   static void    quicken_io_cc(JavaThread* thread);
--- a/src/share/vm/interpreter/linkResolver.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/linkResolver.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -904,11 +904,13 @@
                                  TRAPS) {
   assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic ||
          byte == Bytecodes::_getfield  || byte == Bytecodes::_putfield  ||
+         byte == Bytecodes::_vgetfield || byte == Bytecodes::_vwithfield ||
          byte == Bytecodes::_nofast_getfield  || byte == Bytecodes::_nofast_putfield  ||
          (byte == Bytecodes::_nop && !link_info.check_access()), "bad field access bytecode");
 
   bool is_static = (byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic);
-  bool is_put    = (byte == Bytecodes::_putfield  || byte == Bytecodes::_putstatic || byte == Bytecodes::_nofast_putfield);
+  bool is_put    = (byte == Bytecodes::_putfield  || byte == Bytecodes::_putstatic || byte == Bytecodes::_nofast_putfield
+                    || byte == Bytecodes::_vwithfield);
   // Check if there's a resolved klass containing the field
   Klass* resolved_klass = link_info.resolved_klass();
   Symbol* field = link_info.name();
@@ -1532,6 +1534,7 @@
     case Bytecodes::_invokestatic   : resolve_invokestatic   (result,       pool, index, CHECK); break;
     case Bytecodes::_invokespecial  : resolve_invokespecial  (result,       pool, index, CHECK); break;
     case Bytecodes::_invokevirtual  : resolve_invokevirtual  (result, recv, pool, index, CHECK); break;
+    case Bytecodes::_invokedirect   : resolve_invokespecial  (result,       pool, index, CHECK); break; // temp hack
     case Bytecodes::_invokehandle   : resolve_invokehandle   (result,       pool, index, CHECK); break;
     case Bytecodes::_invokedynamic  : resolve_invokedynamic  (result,       pool, index, CHECK); break;
     case Bytecodes::_invokeinterface: resolve_invokeinterface(result, recv, pool, index, CHECK); break;
--- a/src/share/vm/interpreter/oopMapCache.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/oopMapCache.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -241,6 +241,7 @@
   void pass_float()                              { /* ignore */ }
   void pass_double()                             { /* ignore */ }
   void pass_object()                             { set_one(offset()); }
+  void pass_valuetype()                          { set_one(offset()); }
 
   MaskFillerForNative(methodHandle method, uintptr_t* mask, int size) : NativeSignatureIterator(method) {
     _mask   = mask;
@@ -267,7 +268,7 @@
 
   for(int i = 0; i < max_locals; i++) {
     bool v1 = is_oop(i)               ? true : false;
-    bool v2 = vars[i].is_reference()  ? true : false;
+    bool v2 = vars[i].is_reference() || vars[i].is_valuetype() ? true : false;
     assert(v1 == v2, "locals oop mask generation error");
     if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0);
   }
@@ -275,7 +276,7 @@
   if (TraceOopMapGeneration && Verbose) { tty->cr(); tty->print("Stack (%d): ", stack_top); }
   for(int j = 0; j < stack_top; j++) {
     bool v1 = is_oop(max_locals + j)  ? true : false;
-    bool v2 = stack[j].is_reference() ? true : false;
+    bool v2 = stack[j].is_reference() || stack[j].is_valuetype( )? true : false;
     assert(v1 == v2, "stack oop mask generation error");
     if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0);
   }
@@ -357,14 +358,15 @@
     }
 
     // set oop bit
-    if ( cell->is_reference()) {
+    // Note: the interpreter handles value types with oops too
+    if ( cell->is_reference() || cell->is_valuetype()) {
       value |= (mask << oop_bit_number );
     }
 
     // set dead bit
     if (!cell->is_live()) {
       value |= (mask << dead_bit_number);
-      assert(!cell->is_reference(), "dead value marked as oop");
+      assert(!cell->is_reference() && !cell->is_valuetype(), "dead value marked as oop");
     }
   }
 
--- a/src/share/vm/interpreter/rewriter.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/rewriter.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -443,7 +443,10 @@
         // fall through
         case Bytecodes::_getstatic      : // fall through
         case Bytecodes::_getfield       : // fall through
+        case Bytecodes::_vgetfield      : // fall through
+        case Bytecodes::_vwithfield     : // fall through but may require more checks for correctness
         case Bytecodes::_invokevirtual  : // fall through
+        case Bytecodes::_invokedirect   : // fall through
         case Bytecodes::_invokestatic   :
         case Bytecodes::_invokeinterface:
         case Bytecodes::_invokehandle   : // if reverse=true
--- a/src/share/vm/interpreter/templateInterpreter.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/templateInterpreter.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -69,7 +69,7 @@
 // Implementation of EntryPoint
 
 EntryPoint::EntryPoint() {
-  assert(number_of_states == 10, "check the code below");
+  assert(number_of_states == 11, "check the code below");
   _entry[btos] = NULL;
   _entry[ztos] = NULL;
   _entry[ctos] = NULL;
@@ -79,12 +79,13 @@
   _entry[ltos] = NULL;
   _entry[ftos] = NULL;
   _entry[dtos] = NULL;
+  _entry[qtos] = NULL;
   _entry[vtos] = NULL;
 }
 
 
-EntryPoint::EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry) {
-  assert(number_of_states == 10, "check the code below");
+EntryPoint::EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address qentry, address ventry) {
+  assert(number_of_states == 11, "check the code below");
   _entry[btos] = bentry;
   _entry[ztos] = zentry;
   _entry[ctos] = centry;
@@ -94,6 +95,7 @@
   _entry[ltos] = lentry;
   _entry[ftos] = fentry;
   _entry[dtos] = dentry;
+  _entry[qtos] = qentry;
   _entry[vtos] = ventry;
 }
 
@@ -145,6 +147,7 @@
       _table[ltos][i],
       _table[ftos][i],
       _table[dtos][i],
+      _table[qtos][i],
       _table[vtos][i]
     );
 }
@@ -152,7 +155,7 @@
 
 void DispatchTable::set_entry(int i, EntryPoint& entry) {
   assert(0 <= i && i < length, "index out of bounds");
-  assert(number_of_states == 10, "check the code below");
+  assert(number_of_states == 11, "check the code below");
   _table[btos][i] = entry.entry(btos);
   _table[ztos][i] = entry.entry(ztos);
   _table[ctos][i] = entry.entry(ctos);
@@ -162,6 +165,7 @@
   _table[ltos][i] = entry.entry(ltos);
   _table[ftos][i] = entry.entry(ftos);
   _table[dtos][i] = entry.entry(dtos);
+  _table[qtos][i] = entry.entry(qtos);
   _table[vtos][i] = entry.entry(vtos);
 }
 
@@ -216,6 +220,7 @@
   case Bytecodes::_invokestatic:
   case Bytecodes::_invokespecial:
   case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokedirect:
   case Bytecodes::_invokehandle:
     return Interpreter::invoke_return_entry_table();
   case Bytecodes::_invokeinterface:
@@ -238,6 +243,7 @@
   case Bytecodes::_invokestatic:
   case Bytecodes::_invokespecial:
   case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokedirect:
   case Bytecodes::_invokehandle:
     return _invoke_return_entry[index];
   case Bytecodes::_invokeinterface:
--- a/src/share/vm/interpreter/templateInterpreter.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/templateInterpreter.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -47,7 +47,7 @@
  public:
   // Construction
   EntryPoint();
-  EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry);
+  EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address qentry, address ventry);
 
   // Attributes
   address entry(TosState state) const;                // return target address for a given tosca state
--- a/src/share/vm/interpreter/templateInterpreterGenerator.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/templateInterpreterGenerator.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -50,7 +50,8 @@
   T_VOID   ,
   T_FLOAT  ,
   T_DOUBLE ,
-  T_OBJECT
+  T_OBJECT ,
+  T_VALUETYPE
 };
 
 void TemplateInterpreterGenerator::generate_all() {
@@ -77,6 +78,7 @@
                  generate_trace_code(ltos),
                  generate_trace_code(ftos),
                  generate_trace_code(dtos),
+                 generate_trace_code(qtos),
                  generate_trace_code(vtos)
                  );
   }
@@ -96,6 +98,7 @@
                    generate_return_entry_for(ltos, i, index_size),
                    generate_return_entry_for(ftos, i, index_size),
                    generate_return_entry_for(dtos, i, index_size),
+                   generate_return_entry_for(qtos, i, index_size),
                    generate_return_entry_for(vtos, i, index_size)
                    );
     }
@@ -104,7 +107,7 @@
   { CodeletMark cm(_masm, "invoke return entry points");
     // These states are in order specified in TosState, except btos/ztos/ctos/stos are
     // really the same as itos since there is no top of stack optimization for these types
-    const TosState states[] = {itos, itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos, ilgl};
+    const TosState states[] = {itos, itos, itos, itos, itos, ltos, ftos, dtos, atos, qtos, vtos, ilgl};
     const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic);
     const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface);
     const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic);
@@ -130,6 +133,7 @@
                  generate_earlyret_entry_for(ltos),
                  generate_earlyret_entry_for(ftos),
                  generate_earlyret_entry_for(dtos),
+                 generate_earlyret_entry_for(qtos),
                  generate_earlyret_entry_for(vtos)
                  );
   }
@@ -147,6 +151,7 @@
                    generate_deopt_entry_for(ltos, i),
                    generate_deopt_entry_for(ftos, i),
                    generate_deopt_entry_for(dtos, i),
+                   generate_deopt_entry_for(qtos, i),
                    generate_deopt_entry_for(vtos, i)
                    );
     }
@@ -178,6 +183,7 @@
                  generate_safept_entry_for(ltos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
                  generate_safept_entry_for(ftos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
                  generate_safept_entry_for(dtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
+                 generate_safept_entry_for(qtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
                  generate_safept_entry_for(vtos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint))
                  );
   }
@@ -285,7 +291,7 @@
 
 void TemplateInterpreterGenerator::set_unimplemented(int i) {
   address e = _unimplemented_bytecode;
-  EntryPoint entry(e, e, e, e, e, e, e, e, e, e);
+  EntryPoint entry(e, e, e, e, e, e, e, e, e, e, e);
   Interpreter::_normal_table.set_entry(i, entry);
   Interpreter::_wentry_point[i] = _unimplemented_bytecode;
 }
@@ -305,13 +311,14 @@
   address lep = _illegal_bytecode_sequence;
   address fep = _illegal_bytecode_sequence;
   address dep = _illegal_bytecode_sequence;
+  address qep = _illegal_bytecode_sequence;
   address vep = _unimplemented_bytecode;
   address wep = _unimplemented_bytecode;
   // code for short & wide version of bytecode
   if (Bytecodes::is_defined(code)) {
     Template* t = TemplateTable::template_for(code);
     assert(t->is_valid(), "just checking");
-    set_short_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep);
+    set_short_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, qep, vep);
   }
   if (Bytecodes::wide_is_defined(code)) {
     Template* t = TemplateTable::template_for_wide(code);
@@ -319,7 +326,7 @@
     set_wide_entry_point(t, wep);
   }
   // set entry points
-  EntryPoint entry(bep, zep, cep, sep, aep, iep, lep, fep, dep, vep);
+  EntryPoint entry(bep, zep, cep, sep, aep, iep, lep, fep, dep, qep, vep);
   Interpreter::_normal_table.set_entry(code, entry);
   Interpreter::_wentry_point[code] = wep;
 }
@@ -332,7 +339,7 @@
 }
 
 
-void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) {
+void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& qep, address& vep) {
   assert(t->is_valid(), "template must exist");
   switch (t->tos_in()) {
     case btos:
@@ -346,7 +353,8 @@
     case ltos: vep = __ pc(); __ pop(ltos); lep = __ pc(); generate_and_dispatch(t); break;
     case ftos: vep = __ pc(); __ pop(ftos); fep = __ pc(); generate_and_dispatch(t); break;
     case dtos: vep = __ pc(); __ pop(dtos); dep = __ pc(); generate_and_dispatch(t); break;
-    case vtos: set_vtos_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, vep);     break;
+    case qtos: vep = __ pc(); __ pop(qtos); qep = __ pc(); generate_and_dispatch(t); break;
+    case vtos: set_vtos_entry_points(t, bep, cep, sep, aep, iep, lep, fep, dep, qep, vep);     break;
     default  : ShouldNotReachHere();                                                 break;
   }
 }
--- a/src/share/vm/interpreter/templateInterpreterGenerator.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -64,8 +64,8 @@
 
   // Instruction generation
   void generate_and_dispatch (Template* t, TosState tos_out = ilgl);
-  void set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep);
-  void set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep);
+  void set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& qep, address& vep);
+  void set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& qep, address& vep);
   void set_wide_entry_point  (Template* t, address& wep);
 
   void set_entry_points(Bytecodes::Code code);
--- a/src/share/vm/interpreter/templateTable.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/templateTable.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -460,6 +460,18 @@
   def(Bytecodes::_ifnonnull           , ubcp|____|clvm|____, atos, vtos, if_nullcmp          , not_equal    );
   def(Bytecodes::_goto_w              , ubcp|____|clvm|____, vtos, vtos, goto_w              ,  _           );
   def(Bytecodes::_jsr_w               , ubcp|____|____|____, vtos, vtos, jsr_w               ,  _           );
+  def(Bytecodes::_breakpoint          , ubcp|disp|clvm|____, vtos, vtos, _breakpoint         ,  _           );
+  def(Bytecodes::_vload               , ubcp|____|clvm|____, vtos, qtos, vload               ,  _           );
+  def(Bytecodes::_vstore              , ubcp|____|clvm|____, vtos, vtos, vstore              ,  _           );
+  def(Bytecodes::_vaload              , ____|____|clvm|____, itos, qtos, vaload              ,  _           );
+  def(Bytecodes::_vastore             , ____|____|clvm|____, vtos, vtos, vastore             ,  _           );
+  def(Bytecodes::_vreturn             , ____|disp|clvm|____, qtos, qtos, _return             , qtos         );
+  def(Bytecodes::_vgetfield           , ubcp|____|clvm|____, vtos, vtos, vgetfield           , _            );
+  def(Bytecodes::_invokedirect        , ubcp|disp|clvm|____, vtos, vtos, invokedirect        , f2_byte      );
+  def(Bytecodes::_vdefault            , ubcp|____|clvm|____, vtos, qtos, vdefault            , _            );
+  def(Bytecodes::_vwithfield          , ubcp|____|clvm|____, vtos, qtos, vwithfield          , _            );
+  def(Bytecodes::_vbox                , ubcp|____|clvm|____, qtos, atos, _vbox               , _            );
+  def(Bytecodes::_vunbox              , ubcp|____|clvm|____, atos, qtos, _vunbox             , _            );
 
   // wide Java spec bytecodes
   def(Bytecodes::_iload               , ubcp|____|____|iswd, vtos, itos, wide_iload          ,  _           );
@@ -467,17 +479,20 @@
   def(Bytecodes::_fload               , ubcp|____|____|iswd, vtos, ftos, wide_fload          ,  _           );
   def(Bytecodes::_dload               , ubcp|____|____|iswd, vtos, dtos, wide_dload          ,  _           );
   def(Bytecodes::_aload               , ubcp|____|____|iswd, vtos, atos, wide_aload          ,  _           );
+  def(Bytecodes::_vload               , ubcp|____|____|iswd, vtos, qtos, wide_vload          ,  _           );
   def(Bytecodes::_istore              , ubcp|____|____|iswd, vtos, vtos, wide_istore         ,  _           );
   def(Bytecodes::_lstore              , ubcp|____|____|iswd, vtos, vtos, wide_lstore         ,  _           );
   def(Bytecodes::_fstore              , ubcp|____|____|iswd, vtos, vtos, wide_fstore         ,  _           );
   def(Bytecodes::_dstore              , ubcp|____|____|iswd, vtos, vtos, wide_dstore         ,  _           );
   def(Bytecodes::_astore              , ubcp|____|____|iswd, vtos, vtos, wide_astore         ,  _           );
+  def(Bytecodes::_vstore              , ubcp|____|____|iswd, vtos, vtos, wide_vstore         ,  _           );
   def(Bytecodes::_iinc                , ubcp|____|____|iswd, vtos, vtos, wide_iinc           ,  _           );
   def(Bytecodes::_ret                 , ubcp|disp|____|iswd, vtos, vtos, wide_ret            ,  _           );
   def(Bytecodes::_breakpoint          , ubcp|disp|clvm|____, vtos, vtos, _breakpoint         ,  _           );
 
   // JVM bytecodes
   def(Bytecodes::_fast_agetfield      , ubcp|____|____|____, atos, atos, fast_accessfield    ,  atos        );
+  def(Bytecodes::_fast_qgetfield      , ubcp|____|____|____, atos, qtos, fast_accessfield    ,  qtos        );
   def(Bytecodes::_fast_bgetfield      , ubcp|____|____|____, atos, itos, fast_accessfield    ,  itos        );
   def(Bytecodes::_fast_cgetfield      , ubcp|____|____|____, atos, itos, fast_accessfield    ,  itos        );
   def(Bytecodes::_fast_dgetfield      , ubcp|____|____|____, atos, dtos, fast_accessfield    ,  dtos        );
@@ -487,6 +502,7 @@
   def(Bytecodes::_fast_sgetfield      , ubcp|____|____|____, atos, itos, fast_accessfield    ,  itos        );
 
   def(Bytecodes::_fast_aputfield      , ubcp|____|____|____, atos, vtos, fast_storefield ,   atos        );
+  def(Bytecodes::_fast_qputfield      , ubcp|____|____|____, qtos, vtos, fast_storefield ,   qtos        );
   def(Bytecodes::_fast_bputfield      , ubcp|____|____|____, itos, vtos, fast_storefield ,   itos        );
   def(Bytecodes::_fast_zputfield      , ubcp|____|____|____, itos, vtos, fast_storefield ,   itos        );
   def(Bytecodes::_fast_cputfield      , ubcp|____|____|____, itos, vtos, fast_storefield  ,  itos        );
--- a/src/share/vm/interpreter/templateTable.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/interpreter/templateTable.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -144,6 +144,7 @@
   static void fload();
   static void dload();
   static void aload();
+  static void vload();
 
   static void locals_index_wide(Register reg);
   static void wide_iload();
@@ -151,12 +152,14 @@
   static void wide_fload();
   static void wide_dload();
   static void wide_aload();
+  static void wide_vload();
 
   static void iaload();
   static void laload();
   static void faload();
   static void daload();
   static void aaload();
+  static void vaload();
   static void baload();
   static void caload();
   static void saload();
@@ -177,18 +180,21 @@
   static void fstore();
   static void dstore();
   static void astore();
+  static void vstore();
 
   static void wide_istore();
   static void wide_lstore();
   static void wide_fstore();
   static void wide_dstore();
   static void wide_astore();
+  static void wide_vstore();
 
   static void iastore();
   static void lastore();
   static void fastore();
   static void dastore();
   static void aastore();
+  static void vastore();
   static void bastore();
   static void castore();
   static void sastore();
@@ -278,6 +284,7 @@
                                         Register flags,
                                         bool is_static);
   static void invokevirtual(int byte_no);
+  static void invokedirect(int byte_no);
   static void invokespecial(int byte_no);
   static void invokestatic(int byte_no);
   static void invokeinterface(int byte_no);
@@ -285,7 +292,7 @@
   static void invokehandle(int byte_no);
   static void fast_invokevfinal(int byte_no);
 
-  static void getfield_or_static(int byte_no, bool is_static, RewriteControl rc = may_rewrite);
+  static void getfield_or_static(int byte_no, bool is_static, RewriteControl rc = may_rewrite, bool is_vgetfield = false);
   static void putfield_or_static(int byte_no, bool is_static, RewriteControl rc = may_rewrite);
 
   static void getfield(int byte_no);
@@ -295,14 +302,20 @@
   static void getstatic(int byte_no);
   static void putstatic(int byte_no);
   static void pop_and_check_object(Register obj);
+  static void vgetfield();
+  static void vwithfield();
 
   static void _new();
+  static void vdefault();
   static void newarray();
   static void anewarray();
   static void arraylength();
   static void checkcast();
   static void instanceof();
 
+  static void _vbox();
+  static void _vunbox();
+
   static void athrow();
 
   static void monitorenter();
--- a/src/share/vm/jvmci/jvmciCompilerToVM.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/jvmci/jvmciCompilerToVM.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -202,6 +202,7 @@
 
   inline void do_object() { _jca->push_oop(next_arg(T_OBJECT)); }
   inline void do_object(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); }
+  inline void do_valuetype(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_VALUETYPE)); }
   inline void do_array(int begin, int end)  { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); }
   inline void do_void()                     { }
 };
--- a/src/share/vm/memory/iterator.inline.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/memory/iterator.inline.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -34,6 +34,7 @@
 #include "oops/instanceRefKlass.inline.hpp"
 #include "oops/objArrayKlass.inline.hpp"
 #include "oops/typeArrayKlass.inline.hpp"
+#include "oops/valueArrayKlass.inline.hpp"
 #include "utilities/debug.hpp"
 
 inline void MetadataAwareOopClosure::do_cld_nv(ClassLoaderData* cld) {
@@ -113,6 +114,7 @@
   ALL_INSTANCE_MIRROR_KLASS_OOP_OOP_ITERATE_DEFN(      OopClosureType, nv_suffix)  \
   ALL_INSTANCE_CLASS_LOADER_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)  \
   ALL_OBJ_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(            OopClosureType, nv_suffix)  \
-  ALL_TYPE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(           OopClosureType, nv_suffix)
+  ALL_TYPE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(           OopClosureType, nv_suffix)  \
+  ALL_VALUE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(          OopClosureType, nv_suffix)
 
 #endif // SHARE_VM_MEMORY_ITERATOR_INLINE_HPP
--- a/src/share/vm/memory/oopFactory.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/memory/oopFactory.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -33,8 +33,11 @@
 #include "memory/universe.inline.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/instanceOop.hpp"
+#include "oops/objArrayOop.inline.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
+#include "oops/valueArrayKlass.hpp"
 
 
 typeArrayOop oopFactory::new_charArray(const char* utf8_str, TRAPS) {
@@ -79,6 +82,8 @@
 
 objArrayOop oopFactory::new_objArray(Klass* klass, int length, TRAPS) {
   assert(klass->is_klass(), "must be instance class");
+  assert(!klass->is_value() || (!ValueKlass::cast(klass)->flatten_array()),
+           "Did not expect flatten array of value klass");
   if (klass->is_array_klass()) {
     return ArrayKlass::cast(klass)->allocate_arrayArray(1, length, THREAD);
   } else {
@@ -86,6 +91,36 @@
   }
 }
 
+arrayOop oopFactory::new_valueArray(Klass* klass, int length, TRAPS) {
+  assert(klass->is_value(), "Klass must be value type");
+  Klass* array_klass = klass->array_klass(CHECK_NULL); // Flat value array or object array ?
+  assert(array_klass->is_valueArray_klass() || array_klass->is_objArray_klass(),
+         "Expect an array class here");
+
+  if (array_klass->is_valueArray_klass()) {
+    return (arrayOop) ValueArrayKlass::cast(array_klass)->allocate(length, true, THREAD);
+  }
+
+  ValueKlass* vklass = ValueKlass::cast(klass);
+  objArrayOop array = oopFactory::new_objArray(klass, length, CHECK_NULL);
+  if (length == 0) {
+    return array;
+  }
+
+  // Populate default values...
+  objArrayHandle array_h(THREAD, array);
+  instanceOop value = vklass->allocate_instance(CHECK_NULL);
+  for (int i = 0; i < length; i++) {
+    array_h->obj_at_put(i, value);
+  }
+  return array_h();
+}
+
+arrayOop oopFactory::new_array(Klass* klass, int length, TRAPS) {
+  return (klass->is_value()) ? new_valueArray(klass, length, THREAD) :
+      (arrayOop)new_objArray(klass, length, THREAD);
+}
+
 objArrayHandle oopFactory::new_objArray_handle(Klass* klass, int length, TRAPS) {
   objArrayOop obj = new_objArray(klass, length, CHECK_(objArrayHandle()));
   return objArrayHandle(THREAD, obj);
--- a/src/share/vm/memory/oopFactory.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/memory/oopFactory.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -67,6 +67,12 @@
   // Regular object arrays
   static objArrayOop     new_objArray(Klass* klass, int length, TRAPS);
 
+  // Value arrays
+  static arrayOop        new_valueArray(Klass* klass, int length, TRAPS);
+
+  // Object/Value array for klass
+  static arrayOop        new_array(Klass* klass, int length, TRAPS);
+
   // Helpers that return handles
   static objArrayHandle  new_objArray_handle(Klass* klass, int length, TRAPS);
   static typeArrayHandle new_byteArray_handle(int length, TRAPS);
--- a/src/share/vm/memory/universe.inline.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/memory/universe.inline.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -32,7 +32,7 @@
 // strongly.
 
 inline bool Universe::element_type_should_be_aligned(BasicType type) {
-  return type == T_DOUBLE || type == T_LONG;
+  return type == T_DOUBLE || type == T_LONG  || type == T_VALUETYPE;
 }
 
 // Check whether an object field (static/non-static) of the given type must be aligned 0 mod 8.
--- a/src/share/vm/oops/arrayKlass.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/arrayKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/javaClasses.hpp"
+#include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
@@ -32,6 +33,7 @@
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
 #include "oops/arrayKlass.hpp"
+#include "oops/objArrayKlass.hpp"
 #include "oops/arrayOop.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/objArrayOop.hpp"
@@ -93,6 +95,41 @@
     TRACE_INIT_ID(this);
 }
 
+Symbol* ArrayKlass::create_element_klass_array_name(Klass* element_klass, TRAPS) {
+  Symbol* name = NULL;
+  if (!element_klass->is_instance_klass() ||
+      (name = InstanceKlass::cast(element_klass)->array_name()) == NULL) {
+
+    ResourceMark rm(THREAD);
+    char *name_str = element_klass->name()->as_C_string();
+    int len = element_klass->name()->utf8_length();
+    char *new_str = NEW_RESOURCE_ARRAY(char, len + 4);
+    int idx = 0;
+    new_str[idx++] = '[';
+    if (element_klass->is_instance_klass()) { // it could be an array or simple type
+      // Temporary hack, for arrays of value types, this code should be removed
+      // once value types have their own array types
+      if (element_klass->is_value()) {
+        new_str[idx++] = 'Q';
+      } else {
+        new_str[idx++] = 'L';
+      }
+    }
+    memcpy(&new_str[idx], name_str, len * sizeof(char));
+    idx += len;
+    if (element_klass->is_instance_klass()) {
+      new_str[idx++] = ';';
+    }
+    new_str[idx++] = '\0';
+    name = SymbolTable::new_permanent_symbol(new_str, CHECK_NULL);
+    if (element_klass->is_instance_klass() || element_klass->is_value()) {
+      InstanceKlass* ik = InstanceKlass::cast(element_klass);
+      ik->set_array_name(name);
+    }
+  }
+
+  return name;
+}
 
 // Initialization of vtables and mirror object is done separatly from base_create_array_klass,
 // since a GC can happen. At this point all instance variables of the ArrayKlass must be setup.
--- a/src/share/vm/oops/arrayKlass.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/arrayKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -47,6 +47,9 @@
   ArrayKlass(Symbol* name);
   ArrayKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for cds"); }
 
+  // Create array_name for element klass, creates a permanent symbol, returns result
+  static Symbol* create_element_klass_array_name(Klass* element_klass, TRAPS);
+
  public:
   // Testing operation
   DEBUG_ONLY(bool is_array_klass_slow() const { return true; })
--- a/src/share/vm/oops/arrayOop.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/arrayOop.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -44,7 +44,7 @@
   friend class arrayOopDescTest;
 
   // Interpreter/Compiler offsets
-
+protected:
   // Header size computation.
   // The header is considered the oop part of this type plus the length.
   // Returns the aligned header_size_in_bytes.  This is not equivalent to
@@ -103,6 +103,21 @@
       : typesize_in_bytes/HeapWordSize);
   }
 
+  static int32_t max_array_length(int header_size, int elembytes) {
+    const size_t max_element_words_per_size_t =
+        align_size_down((SIZE_MAX/HeapWordSize - header_size), MinObjAlignment);
+    const size_t max_elements_per_size_t =
+        HeapWordSize * max_element_words_per_size_t / elembytes;
+    if ((size_t)max_jint < max_elements_per_size_t) {
+      // It should be ok to return max_jint here, but parts of the code
+      // (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for
+      // passing around the size (in words) of an object. So, we need to avoid
+      // overflowing an int when we add the header. See CRs 4718400 and 7110613.
+      return align_size_down(max_jint - header_size, MinObjAlignment);
+    }
+    return (int32_t)max_elements_per_size_t;
+  }
+
   // Return the maximum length of an array of BasicType.  The length can passed
   // to typeArrayOop::object_size(scale, length, header_size) without causing an
   // overflow. We also need to make sure that this will not overflow a size_t on
--- a/src/share/vm/oops/cpCache.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/cpCache.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -158,6 +158,7 @@
 
       // ...and fall through as if we were handling invokevirtual:
     case Bytecodes::_invokevirtual:
+    case Bytecodes::_invokedirect:
       {
         if (!is_vtable_call) {
           assert(method->can_be_statically_bound(), "");
@@ -223,11 +224,13 @@
       // Otherwise, the method needs to be reresolved with caller for each
       // interface call.
       if (method->is_public()) set_bytecode_1(invoke_code);
+      invoke_code = Bytecodes::_invokevirtual;
     } else {
-      assert(invoke_code == Bytecodes::_invokevirtual, "");
+      assert(invoke_code == Bytecodes::_invokevirtual ||
+             invoke_code == Bytecodes::_invokedirect, "");
     }
     // set up for invokevirtual, even if linking for invokeinterface also:
-    set_bytecode_2(Bytecodes::_invokevirtual);
+    set_bytecode_2(invoke_code);
   } else {
     ShouldNotReachHere();
   }
@@ -388,6 +391,7 @@
   if (invoke_code != (Bytecodes::Code)0) {
     switch (invoke_code) {
     case Bytecodes::_invokevirtual:
+    case Bytecodes::_invokedirect:
       if (is_vfinal()) {
         // invokevirtual
         Method* m = f2_as_vfinal_method();
--- a/src/share/vm/oops/cpCache.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/cpCache.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -89,7 +89,8 @@
 // ftos: 6
 // dtos: 7
 // atos: 8
-// vtos: 9
+// qtos: 9
+// vtos: 10
 //
 // Entry specific: field entries:
 // _indices = get (b1 section) and put (b2 section) bytecodes, original constant pool index
@@ -304,6 +305,7 @@
     switch (code) {
       case Bytecodes::_getstatic       :    // fall through
       case Bytecodes::_getfield        :    // fall through
+      case Bytecodes::_vgetfield       :    // fall through
       case Bytecodes::_invokespecial   :    // fall through
       case Bytecodes::_invokestatic    :    // fall through
       case Bytecodes::_invokehandle    :    // fall through
@@ -311,6 +313,8 @@
       case Bytecodes::_invokeinterface : return 1;
       case Bytecodes::_putstatic       :    // fall through
       case Bytecodes::_putfield        :    // fall through
+      case Bytecodes::_vwithfield      :    // fall through
+      case Bytecodes::_invokedirect    :    // fall through
       case Bytecodes::_invokevirtual   : return 2;
       default                          : break;
     }
@@ -343,6 +347,7 @@
   bool      is_f1_null() const                   { Metadata* f1 = f1_ord(); return f1 == NULL; }  // classifies a CPC entry as unbound
   int       f2_as_index() const                  { assert(!is_vfinal(), ""); return (int) _f2; }
   Method*   f2_as_vfinal_method() const          { assert(is_vfinal(), ""); return (Method*)_f2; }
+  int       f2_as_offset() const                 { assert(is_field_entry(),  ""); return (int)_f2; }
   int  field_index() const                       { assert(is_field_entry(),  ""); return (_flags & field_index_mask); }
   int  parameter_size() const                    { assert(is_method_entry(), ""); return (_flags & parameter_size_mask); }
   bool is_volatile() const                       { return (_flags & (1 << is_volatile_shift))       != 0; }
@@ -355,6 +360,7 @@
   bool is_field_entry() const                    { return (_flags & (1 << is_field_entry_shift))    != 0; }
   bool is_long() const                           { return flag_state() == ltos; }
   bool is_double() const                         { return flag_state() == dtos; }
+  bool is_valuetype() const                      { return flag_state() == qtos; }
   TosState flag_state() const                    { assert((uint)number_of_states <= (uint)tos_state_mask+1, "");
                                                    return (TosState)((_flags >> tos_state_shift) & tos_state_mask); }
 
--- a/src/share/vm/oops/generateOopMap.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/generateOopMap.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -119,6 +119,7 @@
   virtual void do_int   ()              { set(CellTypeState::value); };
   virtual void do_void  ()              { set(CellTypeState::bottom);};
   virtual void do_object(int begin, int end)  { set(CellTypeState::ref); };
+  virtual void do_valuetype (int begin, int end)  { set(CellTypeState::valuetype); };
   virtual void do_array (int begin, int end)  { set(CellTypeState::ref); };
 
   void do_double()                      { set(CellTypeState::value);
@@ -130,12 +131,16 @@
   ComputeCallStack(Symbol* signature) : SignatureIterator(signature) {};
 
   // Compute methods
-  int compute_for_parameters(bool is_static, CellTypeState *effect) {
+  int compute_for_parameters(bool is_static, bool is_direct, CellTypeState *effect) {
     _idx    = 0;
     _effect = effect;
 
-    if (!is_static)
+    if (is_direct) {
+      effect[_idx++] = CellTypeState::valuetype;
+    }
+    else if (!is_static) {
       effect[_idx++] = CellTypeState::ref;
+    }
 
     iterate_parameters();
 
@@ -174,6 +179,7 @@
   virtual void do_void  ()              { set(CellTypeState::bottom);};
   virtual void do_object(int begin, int end)  { set(CellTypeState::make_slot_ref(_idx)); }
   virtual void do_array (int begin, int end)  { set(CellTypeState::make_slot_ref(_idx)); }
+  virtual void do_valuetype(int begin, int end)  { set(CellTypeState::make_slot_valuetype(_idx)); }
 
   void do_double()                      { set(CellTypeState::value);
                                           set(CellTypeState::value); }
@@ -287,6 +293,7 @@
 CellTypeState CellTypeState::uninit      = CellTypeState::make_any(uninit_value);
 CellTypeState CellTypeState::ref         = CellTypeState::make_any(ref_conflict);
 CellTypeState CellTypeState::value       = CellTypeState::make_any(val_value);
+CellTypeState CellTypeState::valuetype   = CellTypeState::make_any(valuetype_conflict);
 CellTypeState CellTypeState::refUninit   = CellTypeState::make_any(ref_conflict | uninit_value);
 CellTypeState CellTypeState::top         = CellTypeState::make_top();
 CellTypeState CellTypeState::addr        = CellTypeState::make_any(addr_conflict);
@@ -295,12 +302,15 @@
 static CellTypeState epsilonCTS[1] = { CellTypeState::bottom };
 static CellTypeState   refCTS   = CellTypeState::ref;
 static CellTypeState   valCTS   = CellTypeState::value;
+static CellTypeState valuetypeCTS = CellTypeState::valuetype;
 static CellTypeState    vCTS[2] = { CellTypeState::value, CellTypeState::bottom };
 static CellTypeState    rCTS[2] = { CellTypeState::ref,   CellTypeState::bottom };
+static CellTypeState    qCTS[2] = { CellTypeState::valuetype, CellTypeState::bottom };
 static CellTypeState   rrCTS[3] = { CellTypeState::ref,   CellTypeState::ref,   CellTypeState::bottom };
 static CellTypeState   vrCTS[3] = { CellTypeState::value, CellTypeState::ref,   CellTypeState::bottom };
 static CellTypeState   vvCTS[3] = { CellTypeState::value, CellTypeState::value, CellTypeState::bottom };
 static CellTypeState  rvrCTS[4] = { CellTypeState::ref,   CellTypeState::value, CellTypeState::ref,   CellTypeState::bottom };
+static CellTypeState  qvrCTS[4] = { CellTypeState::valuetype, CellTypeState::value, CellTypeState::ref, CellTypeState::bottom };
 static CellTypeState  vvrCTS[4] = { CellTypeState::value, CellTypeState::value, CellTypeState::ref,   CellTypeState::bottom };
 static CellTypeState  vvvCTS[4] = { CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::bottom };
 static CellTypeState vvvrCTS[5] = { CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::ref,   CellTypeState::bottom };
@@ -308,10 +318,15 @@
 
 char CellTypeState::to_char() const {
   if (can_be_reference()) {
+    if (can_be_value() || can_be_address() || can_be_valuetype())
+      return '#';    // Conflict that needs to be rewritten
+    else
+      return 'r';
+  } else if (can_be_valuetype()) {
     if (can_be_value() || can_be_address())
       return '#';    // Conflict that needs to be rewritten
     else
-      return 'r';
+      return 'q';
   } else if (can_be_value())
     return 'v';
   else if (can_be_address())
@@ -342,6 +357,11 @@
   } else {
     os->print(" ");
   }
+  if (can_be_valuetype()) {
+    os->print("q");
+  } else {
+    os->print(" ");
+  }
   if (can_be_uninit()) {
     os->print("u|");
   } else {
@@ -576,6 +596,7 @@
     case Bytecodes::_freturn:
     case Bytecodes::_dreturn:
     case Bytecodes::_areturn:
+    case Bytecodes::_vreturn:
     case Bytecodes::_return:
     case Bytecodes::_ret:
       break;
@@ -687,13 +708,15 @@
 
   // If the top bit is set, we don't need to do any more work.
   if (!result.is_info_top()) {
-    assert((result.can_be_address() || result.can_be_reference()),
+    assert((result.can_be_address() || result.can_be_reference() || result.can_be_valuetype()),
            "only addresses and references have non-top info");
 
     if (!equal(cts)) {
       // The two values being merged are different.  Raise to top.
       if (result.is_reference()) {
         result = CellTypeState::make_slot_ref(slot);
+      } else if (result.is_valuetype()) {
+        result = CellTypeState::make_slot_valuetype(slot);
       } else {
         result._state |= info_conflict;
       }
@@ -816,7 +839,7 @@
 }
 
 void GenerateOopMap::set_var(int localNo, CellTypeState cts) {
-  assert(cts.is_reference() || cts.is_value() || cts.is_address(),
+  assert(cts.is_reference() || cts.is_value() || cts.is_address() || cts.is_valuetype(),
          "wrong celltypestate");
   if (localNo < 0 || localNo > _max_locals) {
     verify_error("variable write error: r%d", localNo);
@@ -1275,6 +1298,7 @@
     os->print("    %s", Bytecodes::name(currentBC->code()));
     switch(currentBC->code()) {
       case Bytecodes::_invokevirtual:
+      case Bytecodes::_invokedirect:
       case Bytecodes::_invokespecial:
       case Bytecodes::_invokestatic:
       case Bytecodes::_invokedynamic:
@@ -1307,6 +1331,7 @@
     }
     switch(currentBC->code()) {
       case Bytecodes::_invokevirtual:
+      case Bytecodes::_invokedirect:
       case Bytecodes::_invokespecial:
       case Bytecodes::_invokestatic:
       case Bytecodes::_invokedynamic:
@@ -1361,6 +1386,9 @@
     case Bytecodes::_new:               ppush1(CellTypeState::make_line_ref(itr->bci()));
                                         break;
 
+    case Bytecodes::_vdefault:          ppush1(CellTypeState::make_line_valuetype(itr->bci())); break;
+    case Bytecodes::_vwithfield:        do_vwithfield(itr->get_index_u2_cpcache(), itr->bci()); break;
+
     case Bytecodes::_iconst_m1:
     case Bytecodes::_iconst_0:
     case Bytecodes::_iconst_1:
@@ -1392,6 +1420,8 @@
 
     case Bytecodes::_aload:             ppload(rCTS, itr->get_index()); break;
 
+    case Bytecodes::_vload:             ppload(qCTS, itr->get_index()); break;
+
     case Bytecodes::_iload_0:
     case Bytecodes::_fload_0:           ppload(vCTS, 0);            break;
     case Bytecodes::_iload_1:
@@ -1425,6 +1455,7 @@
     case Bytecodes::_daload:            pp(vrCTS, vvCTS); break;
 
     case Bytecodes::_aaload:            pp_new_ref(vrCTS, itr->bci()); break;
+    case Bytecodes::_vaload:            pp_new_valuetype(vrCTS, itr->bci()); break;
 
     case Bytecodes::_istore:
     case Bytecodes::_fstore:            ppstore(vCTS, itr->get_index()); break;
@@ -1433,6 +1464,7 @@
     case Bytecodes::_dstore:            ppstore(vvCTS, itr->get_index()); break;
 
     case Bytecodes::_astore:            do_astore(itr->get_index());     break;
+    case Bytecodes::_vstore:            do_vstore(itr->get_index()); break;
 
     case Bytecodes::_istore_0:
     case Bytecodes::_fstore_0:          ppstore(vCTS, 0);           break;
@@ -1465,6 +1497,7 @@
     case Bytecodes::_lastore:
     case Bytecodes::_dastore:           ppop(vvvrCTS);              break;
     case Bytecodes::_aastore:           ppop(rvrCTS);               break;
+    case Bytecodes::_vastore:           ppop(qvrCTS);               break;
 
     case Bytecodes::_pop:               ppop_any(1);                break;
     case Bytecodes::_pop2:              ppop_any(2);                break;
@@ -1574,16 +1607,20 @@
     case Bytecodes::_jsr:               do_jsr(itr->dest());         break;
     case Bytecodes::_jsr_w:             do_jsr(itr->dest_w());       break;
 
-    case Bytecodes::_getstatic:         do_field(true,  true,  itr->get_index_u2_cpcache(), itr->bci()); break;
-    case Bytecodes::_putstatic:         do_field(false, true,  itr->get_index_u2_cpcache(), itr->bci()); break;
-    case Bytecodes::_getfield:          do_field(true,  false, itr->get_index_u2_cpcache(), itr->bci()); break;
-    case Bytecodes::_putfield:          do_field(false, false, itr->get_index_u2_cpcache(), itr->bci()); break;
 
+
+    case Bytecodes::_getstatic:         do_field(true,  true,  false, itr->get_index_u2_cpcache(), itr->bci()); break;
+    case Bytecodes::_putstatic:         do_field(false, true,  false, itr->get_index_u2_cpcache(), itr->bci()); break;
+    case Bytecodes::_getfield:          do_field(true,  false, false, itr->get_index_u2_cpcache(), itr->bci()); break;
+    case Bytecodes::_putfield:          do_field(false, false, false, itr->get_index_u2_cpcache(), itr->bci()); break;
+    case Bytecodes::_vgetfield:         do_field(true,  false, true , itr->get_index_u2_cpcache(), itr->bci()); break;
+
+    case Bytecodes::_invokeinterface:
     case Bytecodes::_invokevirtual:
     case Bytecodes::_invokespecial:     do_method(false, false, itr->get_index_u2_cpcache(), itr->bci()); break;
+    case Bytecodes::_invokedirect:      do_method(false, true , itr->get_index_u2_cpcache(), itr->bci()); break;
     case Bytecodes::_invokestatic:      do_method(true,  false, itr->get_index_u2_cpcache(), itr->bci()); break;
     case Bytecodes::_invokedynamic:     do_method(true,  false, itr->get_index_u4(),         itr->bci()); break;
-    case Bytecodes::_invokeinterface:   do_method(false, true,  itr->get_index_u2_cpcache(), itr->bci()); break;
     case Bytecodes::_newarray:
     case Bytecodes::_anewarray:         pp_new_ref(vCTS, itr->bci()); break;
     case Bytecodes::_checkcast:         do_checkcast(); break;
@@ -1603,10 +1640,18 @@
     case Bytecodes::_areturn:           do_return_monitor_check();
                                         ppop1(refCTS);
                                         break;
+
+    case Bytecodes::_vreturn:           do_return_monitor_check();
+                                        ppop1(valuetypeCTS);
+                                        break;
+
     case Bytecodes::_ifnull:
     case Bytecodes::_ifnonnull:         ppop1(refCTS); break;
     case Bytecodes::_multianewarray:    do_multianewarray(*(itr->bcp()+3), itr->bci()); break;
 
+    case Bytecodes::_vbox:              pp_new_ref(qCTS, itr->bci());       break;
+    case Bytecodes::_vunbox:            pp_new_valuetype(rCTS, itr->bci()); break;
+
     case Bytecodes::_wide:              fatal("Iterator should skip this bytecode"); break;
     case Bytecodes::_ret:                                           break;
 
@@ -1640,7 +1685,7 @@
   while(!(*out).is_bottom()) {
     CellTypeState out1 = *out++;
     CellTypeState vcts = get_var(loc_no);
-    assert(out1.can_be_reference() || out1.can_be_value(),
+    assert(out1.can_be_reference() || out1.can_be_value() || out1.can_be_valuetype(),
            "can only load refs. and values.");
     if (out1.is_reference()) {
       assert(loc_no>=0, "sanity check");
@@ -1709,7 +1754,7 @@
 }
 
 void GenerateOopMap::ppush1(CellTypeState in) {
-  assert(in.is_reference() | in.is_value(), "sanity check");
+  assert(in.is_reference() || in.is_value() || in.is_valuetype(), "sanity check");
   push(in);
 }
 
@@ -1729,6 +1774,11 @@
   ppush1(CellTypeState::make_line_ref(bci));
 }
 
+void GenerateOopMap::pp_new_valuetype(CellTypeState *in, int bci) {
+  ppop(in);
+  ppush1(CellTypeState::make_line_valuetype(bci));
+}
+
 void GenerateOopMap::ppop_any(int poplen) {
   if (_stack_top >= poplen) {
     _stack_top -= poplen;
@@ -1895,6 +1945,15 @@
   set_var(idx, r_or_p);
 }
 
+void GenerateOopMap::do_vstore(int idx) {
+  CellTypeState q = pop();
+  if (!q.is_valuetype()) {
+    verify_error("wrong type on stack (found: %c, expected: {q})", q.to_char());
+    return;
+  }
+  set_var(idx, q);
+}
+
 // Copies bottom/zero terminated CTS string from "src" into "dst".
 //   Does NOT terminate with a bottom. Returns the number of cells copied.
 int GenerateOopMap::copy_cts(CellTypeState *dst, CellTypeState *src) {
@@ -1906,7 +1965,8 @@
   return idx;
 }
 
-void GenerateOopMap::do_field(int is_get, int is_static, int idx, int bci) {
+void GenerateOopMap::do_field(int is_get, int is_static, int is_valuetype, int idx, int bci) {
+  assert(!(!is_get && is_valuetype), "Invalid configuration: vputfield doesn't exist");
   // Dig up signature for field in constant pool
   ConstantPool* cp     = method()->constants();
   int nameAndTypeIdx     = cp->name_and_type_ref_index_at(idx);
@@ -1930,13 +1990,19 @@
     out = epsilonCTS;
     i   = copy_cts(in, eff);
   }
-  if (!is_static) in[i++] = CellTypeState::ref;
+  if (!is_static) {
+    if (is_valuetype) {
+      in[i++] = CellTypeState::valuetype;
+    } else {
+      in[i++] = CellTypeState::ref;
+    }
+  }
   in[i] = CellTypeState::bottom;
   assert(i<=3, "sanity check");
   pp(in, out);
 }
 
-void GenerateOopMap::do_method(int is_static, int is_interface, int idx, int bci) {
+void GenerateOopMap::do_method(int is_static, int is_direct, int idx, int bci) {
  // Dig up signature for field in constant pool
   ConstantPool* cp  = _method->constants();
   Symbol* signature   = cp->signature_ref_at(idx);
@@ -1957,7 +2023,7 @@
   assert(res_length<=4, "max value should be vv");
 
   // Compute arguments
-  int arg_length = cse.compute_for_parameters(is_static != 0, in);
+  int arg_length = cse.compute_for_parameters(is_static != 0, is_direct != 0, in);
   assert(arg_length<=MAXARGSIZE, "too many locals");
 
   // Pop arguments
@@ -1973,6 +2039,34 @@
   ppush(out);
 }
 
+void GenerateOopMap::do_vwithfield(int idx, int bci) {
+  // Dig up signature for field in constant pool
+  ConstantPool* cp = method()->constants();
+  int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx);
+  int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx);
+  Symbol* signature = cp->symbol_at(signatureIdx);
+
+  // Parse signature (especially simple for fields)
+  assert(signature->utf8_length() > 0,
+      "field signatures cannot have zero length");
+  // The signature is UFT8 encoded, but the first char is always ASCII for signatures.
+  char sigch = (char) *(signature->base());
+  CellTypeState temp[4];
+  CellTypeState *eff = sigchar_to_effect(sigch, bci, temp);
+
+  CellTypeState in[4];
+  int i = copy_cts(in, eff);
+  in[i++] = CellTypeState::valuetype;
+  in[i] = CellTypeState::bottom;
+  assert(i <= 3, "sanity check");
+
+  CellTypeState out[2];
+  out[0] = CellTypeState::valuetype;
+  out[1] = CellTypeState::bottom;
+
+  pp(in, out);
+}
+
 // This is used to parse the signature for fields, since they are very simple...
 CellTypeState *GenerateOopMap::sigchar_to_effect(char sigch, int bci, CellTypeState *out) {
   // Object and array
@@ -1981,6 +2075,11 @@
     out[1] = CellTypeState::bottom;
     return out;
   }
+  if (sigch == 'Q') {
+    out[0] = CellTypeState::make_line_valuetype(bci);
+    out[1] = CellTypeState::bottom;
+    return out;
+  }
   if (sigch == 'J' || sigch == 'D' ) return vvCTS;  // Long and Double
   if (sigch == 'V' ) return epsilonCTS;             // Void
   return vCTS;                                      // Otherwise
--- a/src/share/vm/oops/generateOopMap.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/generateOopMap.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -91,7 +91,7 @@
   unsigned int _state;
 
   // Masks for separating the BITS and INFO portions of a CellTypeState
-  enum { info_mask            = right_n_bits(28),
+  enum { info_mask            = right_n_bits(27),
          bits_mask            = (int)(~info_mask) };
 
   // These constant are used for manipulating the BITS portion of a
@@ -100,22 +100,28 @@
          ref_bit              = nth_bit(30),
          val_bit              = nth_bit(29),
          addr_bit             = nth_bit(28),
+         valuetype_bit        = nth_bit(27),
          live_bits_mask       = (int)(bits_mask & ~uninit_bit) };
 
   // These constants are used for manipulating the INFO portion of a
   // CellTypeState
-  enum { top_info_bit         = nth_bit(27),
-         not_bottom_info_bit  = nth_bit(26),
-         info_data_mask       = right_n_bits(26),
+  enum { top_info_bit         = nth_bit(26),
+         not_bottom_info_bit  = nth_bit(25),
+         info_data_mask       = right_n_bits(25),
          info_conflict        = info_mask };
 
   // Within the INFO data, these values are used to distinguish different
   // kinds of references.
-  enum { ref_not_lock_bit     = nth_bit(25),  // 0 if this reference is locked as a monitor
-         ref_slot_bit         = nth_bit(24),  // 1 if this reference is a "slot" reference,
+  enum { ref_not_lock_bit     = nth_bit(24),  // 0 if this reference is locked as a monitor
+         ref_slot_bit         = nth_bit(23),  // 1 if this reference is a "slot" reference,
                                               // 0 if it is a "line" reference.
-         ref_data_mask        = right_n_bits(24) };
+         ref_data_mask        = right_n_bits(23) };
 
+  // Within the INFO data, these values are used to distinguish different
+  // kinds of value types.
+  enum { valuetype_slot_bit   = nth_bit(24),  // 1 if this reference is a "slot" value type,
+    // 0 if it is a "line" value type.
+    valuetype_data_mask  = right_n_bits(24) };
 
   // These values are used to initialize commonly used CellTypeState
   // constants.
@@ -124,6 +130,7 @@
          ref_value            = ref_bit,
          ref_conflict         = ref_bit | info_conflict,
          val_value            = val_bit | info_conflict,
+         valuetype_conflict   = valuetype_bit | info_conflict,
          addr_value           = addr_bit,
          addr_conflict        = addr_bit | info_conflict };
 
@@ -175,6 +182,19 @@
     return make_any(ref_bit | not_bottom_info_bit | (bci & ref_data_mask));
   }
 
+
+  static CellTypeState make_slot_valuetype(int slot_num) {
+    assert(slot_num >= 0 && slot_num < valuetype_data_mask, "slot out of range");
+    return make_any(valuetype_bit | not_bottom_info_bit | valuetype_slot_bit |
+        (slot_num & valuetype_data_mask));
+  }
+
+  static CellTypeState make_line_valuetype(int bci) {
+    assert(bci >= 0 && bci < valuetype_data_mask, "line out of range");
+    return make_any(valuetype_bit | not_bottom_info_bit |
+        (bci & valuetype_data_mask));
+  }
+
   // Query methods:
   bool is_bottom() const                { return _state == 0; }
   bool is_live() const                  { return ((_state & live_bits_mask) != 0); }
@@ -197,11 +217,13 @@
   bool is_address() const               { return ((_state & bits_mask) == addr_bit); }
   bool is_reference() const             { return ((_state & bits_mask) == ref_bit); }
   bool is_value() const                 { return ((_state & bits_mask) == val_bit); }
+  bool is_valuetype() const             { return ((_state & bits_mask) == valuetype_bit); }
   bool is_uninit() const                { return ((_state & bits_mask) == (uint)uninit_bit); }
 
   bool can_be_address() const           { return ((_state & addr_bit) != 0); }
   bool can_be_reference() const         { return ((_state & ref_bit) != 0); }
   bool can_be_value() const             { return ((_state & val_bit) != 0); }
+  bool can_be_valuetype() const         { return ((_state & valuetype_bit) != 0); }
   bool can_be_uninit() const            { return ((_state & uninit_bit) != 0); }
 
   bool is_info_bottom() const           { return ((_state & not_bottom_info_bit) == 0); }
@@ -238,6 +260,7 @@
   static CellTypeState uninit;
   static CellTypeState ref;
   static CellTypeState value;
+  static CellTypeState valuetype;
   static CellTypeState refUninit;
   static CellTypeState varUninit;
   static CellTypeState top;
@@ -397,12 +420,15 @@
   void  ppop_any                            (int poplen);
   void  pp                                  (CellTypeState *in, CellTypeState *out);
   void  pp_new_ref                          (CellTypeState *in, int bci);
+  void  pp_new_valuetype                    (CellTypeState *in, int bci);
   void  ppdupswap                           (int poplen, const char *out);
   void  do_ldc                              (int bci);
   void  do_astore                           (int idx);
+  void  do_vstore                           (int idx);
   void  do_jsr                              (int delta);
-  void  do_field                            (int is_get, int is_static, int idx, int bci);
-  void  do_method                           (int is_static, int is_interface, int idx, int bci);
+  void  do_field                            (int is_get, int is_static, int is_valuetype, int idx, int bci);
+  void  do_method                           (int is_static, int is_direct, int idx, int bci);
+  void  do_vwithfield                       (int idx, int bci);
   void  do_multianewarray                   (int dims, int bci);
   void  do_monitorenter                     (int bci);
   void  do_monitorexit                      (int bci);
--- a/src/share/vm/oops/instanceKlass.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/instanceKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -56,6 +56,7 @@
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
+#include "oops/valueKlass.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
 #include "prims/jvmtiThreadState.hpp"
@@ -166,8 +167,10 @@
     else if (is_class_loader(class_name, parser)) {
       // class loader
       ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
-    }
-    else {
+    } else if (parser.is_value_type()) {
+      // value type
+      ik = new (loader_data, size, THREAD) ValueKlass(parser);
+    } else {
       // normal
       ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_misc_kind_other);
     }
@@ -186,6 +189,13 @@
   assert(ik != NULL, "invariant");
 
   const bool publicize = !parser.is_internal();
+#ifdef ASSERT
+  assert(ik->size() == size, "");
+  ik->bounds_check((address) ik->start_of_vtable(), false, size);
+  ik->bounds_check((address) ik->start_of_itable(), false, size);
+  ik->bounds_check((address) ik->end_of_itable(), true, size);
+  ik->bounds_check((address) ik->end_of_nonstatic_oop_maps(), true, size);
+#endif //ASSERT
 
   // Add all classes to our internal class loader list here,
   // including classes in the bootstrap (NULL) class loader.
@@ -195,6 +205,29 @@
   return ik;
 }
 
+#ifndef PRODUCT
+bool InstanceKlass::bounds_check(address addr, bool edge_ok, intptr_t size_in_bytes) const {
+  const char* bad = NULL;
+  address end = NULL;
+  if (addr < (address)this) {
+    bad = "before";
+  } else if (addr == (address)this) {
+    if (edge_ok)  return true;
+    bad = "just before";
+  } else if (addr == (end = (address)this + sizeof(intptr_t) * (size_in_bytes < 0 ? size() : size_in_bytes))) {
+    if (edge_ok)  return true;
+    bad = "just after";
+  } else if (addr > end) {
+    bad = "after";
+  } else {
+    return true;
+  }
+  tty->print_cr("%s object bounds: " INTPTR_FORMAT " [" INTPTR_FORMAT ".." INTPTR_FORMAT "]",
+      bad, (intptr_t)addr, (intptr_t)this, (intptr_t)end);
+  Verbose = WizardMode = true; this->print(); //@@
+  return false;
+}
+#endif //PRODUCT
 
 // copy method ordering from resource area to Metaspace
 void InstanceKlass::copy_method_ordering(const intArray* m, TRAPS) {
@@ -561,6 +594,61 @@
     interk->link_class_impl(throw_verifyerror, CHECK_false);
   }
 
+  // If a value type is referenced by a class (either as a field type or a
+  // method argument or return type) this value type must be loaded during
+  // the linking of this class because size and properties of the value type
+  // must be known in order to be able to perform value type optimizations
+
+  // Note: circular dependencies between value types are not handled yet
+
+  // Note: one case is not handled yet: arrays of value types => FixMe
+
+  // Note: the current implementation is not optimized because the search for
+  // value types is performed on all classes. It would be more efficient to
+  // detect value types during verification and 'tag' the classes for which
+  // value type loading is required. However, this optimization won't be
+  // applicable to classes that are not verified
+
+  // First step: fields
+  for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
+    ResourceMark rm(THREAD);
+    if (fs.field_descriptor().field_type() == T_VALUETYPE) {
+      Symbol* signature = fs.field_descriptor().signature();
+      // Get current loader and protection domain first.
+      oop loader = class_loader();
+      oop prot_domain = protection_domain();
+      Klass* klass = SystemDictionary::resolve_or_fail(signature,
+          Handle(THREAD, loader), Handle(THREAD, prot_domain), true,
+          THREAD);
+      if (klass == NULL) {
+        THROW_(vmSymbols::java_lang_LinkageError(), false);
+      }
+    }
+  }
+
+  // Second step: methods arguments and return types
+  //  for (int i = 0; i < this_k->constants()->length(); i++) {
+  //    if (this_k->constants()->tag_at(i).is_method()) {
+  //      Symbol* signature = this_k->constants()->signature_ref_at(i);
+  //      ResourceMark rm(THREAD);
+  //      for (SignatureStream ss(signature); !ss.is_done(); ss.next()) {
+  //        if (ss.type() == T_VALUETYPE) {
+  //          Symbol* sig = ss.as_symbol(THREAD);
+  //          // Get current loader and protection domain first.
+  //          oop loader = this_k->class_loader();
+  //          oop protection_domain = this_k->protection_domain();
+  //
+  //          bool ok = SystemDictionary::resolve_or_fail(sig,
+  //              Handle(THREAD, loader), Handle(THREAD, protection_domain), true,
+  //              THREAD);
+  //          if (!ok) {
+  //            THROW_(vmSymbols::java_lang_LinkageError(), false);
+  //          }
+  //        }
+  //      }
+  //    }
+  //  }
+
   // in case the class is linked in the process of linking its superclasses
   if (is_linked()) {
     return true;
@@ -632,6 +720,13 @@
         // itable()->verify(tty, true);
       }
 #endif
+      // DVT/VCC linking implies linking it's partner
+      if (is_derive_value_type()) {
+        // Simple state check to prevent infinite link calls
+        if (!derive_value_type_klass()->is_rewritten()) {
+          derive_value_type_klass()->link_class(CHECK_false);
+        }
+      }
       set_init_state(linked);
       if (JvmtiExport::should_post_class_prepare()) {
         Thread *thread = THREAD;
@@ -694,6 +789,11 @@
 void InstanceKlass::initialize_impl(TRAPS) {
   HandleMark hm(THREAD);
 
+  // ensure outer VCC is initialized, possible some crafty code referred to VT 1st
+  if (is_derive_value_type() && is_value()) {
+    derive_value_type_klass()->initialize(CHECK);
+  }
+
   // Make sure klass is linked (verified) before initialization
   // A class could already be verified, since it has been reflected upon.
   link_class(CHECK);
@@ -2215,7 +2315,7 @@
 
   // Add L as type indicator
   int dest_index = 0;
-  dest[dest_index++] = 'L';
+  dest[dest_index++] = is_value_type_klass() ? 'Q' : 'L';
 
   // Add the actual class name
   for (int src_index = 0; src_index < src_length; ) {
@@ -2800,20 +2900,55 @@
   "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
 };
 
-static void print_vtable(intptr_t* start, int len, outputStream* st) {
+static void print_vtable(address self, intptr_t* start, int len, outputStream* st) {
+  ResourceMark rm;
+  int* forward_refs = NEW_RESOURCE_ARRAY(int, len);
+  for (int i = 0; i < len; i++)  forward_refs[i] = 0;
   for (int i = 0; i < len; i++) {
     intptr_t e = start[i];
     st->print("%d : " INTPTR_FORMAT, i, e);
+    if (forward_refs[i] != 0) {
+      int from = forward_refs[i];
+      int off = (int) start[from];
+      st->print(" (offset %d <= [%d])", off, from);
+    }
     if (e != 0 && ((Metadata*)e)->is_metaspace_object()) {
       st->print(" ");
       ((Metadata*)e)->print_value_on(st);
+    } else if (self != NULL && e > 0 && e < 0x10000) {
+      address location = self + e;
+      int index = (int)((intptr_t*)location - start);
+      st->print(" (offset %d => [%d])", (int)e, index);
+      if (index >= 0 && index < len)
+        forward_refs[index] = i;
     }
     st->cr();
   }
 }
 
 static void print_vtable(vtableEntry* start, int len, outputStream* st) {
-  return print_vtable(reinterpret_cast<intptr_t*>(start), len, st);
+  return print_vtable(NULL, reinterpret_cast<intptr_t*>(start), len, st);
+}
+
+template<typename T>
+ static void print_array_on(outputStream* st, Array<T>* array) {
+   if (array == NULL) { st->print_cr("NULL"); return; }
+   array->print_value_on(st); st->cr();
+   if (Verbose || WizardMode) {
+     for (int i = 0; i < array->length(); i++) {
+       st->print("%d : ", i); array->at(i)->print_value_on(st); st->cr();
+     }
+   }
+ }
+
+static void print_array_on(outputStream* st, Array<int>* array) {
+  if (array == NULL) { st->print_cr("NULL"); return; }
+  array->print_value_on(st); st->cr();
+  if (Verbose || WizardMode) {
+    for (int i = 0; i < array->length(); i++) {
+      st->print("%d : %d", i, array->at(i)); st->cr();
+    }
+  }
 }
 
 void InstanceKlass::print_on(outputStream* st) const {
@@ -2823,6 +2958,7 @@
   st->print(BULLET"instance size:     %d", size_helper());                        st->cr();
   st->print(BULLET"klass size:        %d", size());                               st->cr();
   st->print(BULLET"access:            "); access_flags().print_on(st);            st->cr();
+  st->print(BULLET"misc flags:        0x%x", _misc_flags);                        st->cr();
   st->print(BULLET"state:             "); st->print_cr("%s", state_names[_init_state]);
   st->print(BULLET"name:              "); name()->print_value_on(st);             st->cr();
   st->print(BULLET"super:             "); super()->print_value_on_maybe_null(st); st->cr();
@@ -2849,26 +2985,14 @@
   }
 
   st->print(BULLET"arrays:            "); array_klasses()->print_value_on_maybe_null(st); st->cr();
-  st->print(BULLET"methods:           "); methods()->print_value_on(st);                  st->cr();
-  if (Verbose || WizardMode) {
-    Array<Method*>* method_array = methods();
-    for (int i = 0; i < method_array->length(); i++) {
-      st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
-    }
+  st->print(BULLET"methods:           "); print_array_on(st, methods());
+  st->print(BULLET"method ordering:   "); print_array_on(st, method_ordering());
+  st->print(BULLET"default_methods:   "); print_array_on(st, default_methods());
+  if (default_vtable_indices() != NULL) {
+    st->print(BULLET"default vtable indices:   "); print_array_on(st, default_vtable_indices());
   }
-  st->print(BULLET"method ordering:   "); method_ordering()->print_value_on(st);      st->cr();
-  st->print(BULLET"default_methods:   "); default_methods()->print_value_on(st);      st->cr();
-  if (Verbose && default_methods() != NULL) {
-    Array<Method*>* method_array = default_methods();
-    for (int i = 0; i < method_array->length(); i++) {
-      st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
-    }
-  }
-  if (default_vtable_indices() != NULL) {
-    st->print(BULLET"default vtable indices:   "); default_vtable_indices()->print_value_on(st);       st->cr();
-  }
-  st->print(BULLET"local interfaces:  "); local_interfaces()->print_value_on(st);      st->cr();
-  st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr();
+  st->print(BULLET"local interfaces:  "); print_array_on(st, local_interfaces());
+  st->print(BULLET"trans. interfaces: "); print_array_on(st, transitive_interfaces());
   st->print(BULLET"constants:         "); constants()->print_value_on(st);         st->cr();
   if (class_loader_data() != NULL) {
     st->print(BULLET"class loader data:  ");
@@ -2914,7 +3038,7 @@
   st->print(BULLET"vtable length      %d  (start addr: " INTPTR_FORMAT ")", vtable_length(), p2i(start_of_vtable())); st->cr();
   if (vtable_length() > 0 && (Verbose || WizardMode))  print_vtable(start_of_vtable(), vtable_length(), st);
   st->print(BULLET"itable length      %d (start addr: " INTPTR_FORMAT ")", itable_length(), p2i(start_of_itable())); st->cr();
-  if (itable_length() > 0 && (Verbose || WizardMode))  print_vtable(start_of_itable(), itable_length(), st);
+  if (itable_length() > 0 && (Verbose || WizardMode))  print_vtable(NULL, start_of_itable(), itable_length(), st);
   st->print_cr(BULLET"---- static fields (%d words):", static_field_size());
   FieldPrinter print_static_field(st);
   ((InstanceKlass*)this)->do_local_static_fields(&print_static_field);
@@ -3708,3 +3832,105 @@
 }
 #endif
 #endif
+
+#define THROW_DVT_ERROR(s) \
+  Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_InternalError(), \
+      "DeriveValueType class '%s' %s", external_name(),(s)); \
+      return
+
+void InstanceKlass::create_derive_value_type(Handle class_loader, Handle protection_domain, TRAPS) {
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+
+  if (!ValhallaMVT1_0) {
+    return; // Silent fail
+  }
+  // Validate VCC...
+  if (!has_nonstatic_fields()) {
+    THROW_DVT_ERROR("has no instance fields");
+  }
+  if (is_value()) {
+    THROW_DVT_ERROR("is already a value type");
+  }
+  if (!access_flags().is_final()) {
+    THROW_DVT_ERROR("is not a final class");
+  }
+  if (super() != SystemDictionary::Object_klass()) {
+    THROW_DVT_ERROR("does not derive from Object only");
+  }
+
+  // All non-static are final
+  GrowableArray<Handle>* fields = new GrowableArray<Handle>(THREAD, java_fields_count()*2);
+  GrowableArray<jint>* fields_access = new GrowableArray<jint>(THREAD, java_fields_count()*2);
+  for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
+    AccessFlags access_flags = fs.access_flags();
+    if (access_flags.is_static()) {
+      continue;
+    }
+    if (!access_flags.is_final()) {
+      THROW_DVT_ERROR("contains non-final instance field");
+    }
+    jint flags = access_flags.get_flags();
+    // Remember the field name, signature, access modifiers
+    Handle h = java_lang_String::create_from_symbol(fs.name(), CHECK);
+    fields->append(h);
+    h = java_lang_String::create_from_symbol(fs.signature(), CHECK);
+    fields->append(h);
+    fields_access->append(access_flags.get_flags());
+  }
+
+  // Generate DVT...
+  log_debug(load)("Cooking DVT for VCC %s", external_name());
+  const char*  this_name     = name()->as_C_string();
+
+  // Assemble the Java args...field descriptor array
+  objArrayOop fdarr_oop = oopFactory::new_objectArray(fields->length(), CHECK);
+  objArrayHandle fdarr(THREAD, fdarr_oop);
+  for (int i = 0; i < fields->length(); i++) {
+    fdarr->obj_at_put(i, fields->at(i)());
+  }
+  //...field access modifiers array
+  typeArrayOop faarr_oop = oopFactory::new_intArray(fields_access->length(), CHECK);
+  typeArrayHandle faarr(THREAD, faarr_oop);
+  for (int i = 0; i < fields_access->length(); i++) {
+    faarr->int_at_put(i, fields_access->at(i));
+  }
+
+  Handle vcc_name_h = java_lang_String::create_from_symbol(name(), CHECK);
+  // Upcall to our Java helper...
+  JavaValue result(T_OBJECT);
+  JavaCallArguments args(5);
+  args.push_oop(vcc_name_h);
+  args.push_oop(class_loader);
+  args.push_oop(protection_domain);
+  args.push_oop(fdarr);
+  args.push_oop(faarr);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::Valhalla_MVT1_0_klass(),
+                         vmSymbols::valhalla_shady_MVT1_0_createDerivedValueType(),
+                         vmSymbols::valhalla_shady_MVT1_0_createDerivedValueType_signature(),
+                         &args,
+                         CHECK);
+  Handle returned(THREAD, (oop) result.get_jobject());
+  if (returned.is_null()) {
+    THROW_DVT_ERROR("unknown error deriving value type");
+  }
+  TempNewSymbol dvt_name_sym = java_lang_String::as_symbol(returned(), CHECK);
+
+  Klass* dvt_klass = SystemDictionary::resolve_or_null(dvt_name_sym,
+                                                       class_loader,
+                                                       protection_domain,
+                                                       CHECK);
+  if (!dvt_klass->is_value()) {
+    THROW_DVT_ERROR("failed to resolve derived value type");
+  }
+  /**
+   * Found it, let's point to each other to denote "is_derive_vt()"...
+   */
+  ValueKlass* vt_klass = ValueKlass::cast(dvt_klass);
+  assert(vt_klass->class_loader() == class_loader(), "DVT Not the same class loader as VCC");
+  _derive_value_type_klass = vt_klass;
+  vt_klass->_derive_value_type_klass = this;
+  log_debug(load)("Cooked DVT %s for VCC %s", vt_klass->external_name(), external_name());
+}
+
--- a/src/share/vm/oops/instanceKlass.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/instanceKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -101,12 +101,28 @@
   uint count() const         { return _count; }
   void set_count(uint count) { _count = count; }
 
+  void increment_count(int diff)     { _count += diff; }
+
+  int offset_span() const { return _count * heapOopSize; }
+
+  int end_offset() const {
+    return offset() + offset_span();
+  }
+
+  bool is_contiguous(int another_offset) const {
+    return another_offset == end_offset();
+  }
+
   // sizeof(OopMapBlock) in words.
   static const int size_in_words() {
     return align_size_up(int(sizeof(OopMapBlock)), wordSize) >>
       LogBytesPerWord;
   }
 
+  static int compare_offset(const OopMapBlock* a, const OopMapBlock* b) {
+    return a->offset() - b->offset();
+  }
+
  private:
   int  _offset;
   uint _count;
@@ -193,11 +209,11 @@
   bool            _is_marked_dependent;  // used for marking during flushing and deoptimization
   bool            _is_being_redefined;   // used for locking redefinition
 
-  // The low two bits of _misc_flags contains the kind field.
-  // This can be used to quickly discriminate among the four kinds of
+  // The low three bits of _misc_flags contains the kind field.
+  // This can be used to quickly discriminate among the five kinds of
   // InstanceKlass.
 
-  static const unsigned _misc_kind_field_size = 2;
+  static const unsigned _misc_kind_field_size = 3;
   static const unsigned _misc_kind_field_pos  = 0;
   static const unsigned _misc_kind_field_mask = (1u << _misc_kind_field_size) - 1u;
 
@@ -205,23 +221,24 @@
   static const unsigned _misc_kind_reference    = 1; // InstanceRefKlass
   static const unsigned _misc_kind_class_loader = 2; // InstanceClassLoaderKlass
   static const unsigned _misc_kind_mirror       = 3; // InstanceMirrorKlass
+  static const unsigned _misc_kind_value_type   = 4; // ValueKlass
 
   // Start after _misc_kind field.
   enum {
-    _misc_rewritten                           = 1 << 2,  // methods rewritten.
-    _misc_has_nonstatic_fields                = 1 << 3,  // for sizing with UseCompressedOops
-    _misc_should_verify_class                 = 1 << 4,  // allow caching of preverification
-    _misc_is_anonymous                        = 1 << 5,  // has embedded _host_klass field
-    _misc_is_contended                        = 1 << 6,  // marked with contended annotation
-    _misc_has_nonstatic_concrete_methods      = 1 << 7,  // class/superclass/implemented interfaces has non-static, concrete methods
-    _misc_declares_nonstatic_concrete_methods = 1 << 8,  // directly declares non-static, concrete methods
-    _misc_has_been_redefined                  = 1 << 9,  // class has been redefined
-    _misc_has_passed_fingerprint_check        = 1 << 10, // when this class was loaded, the fingerprint computed from its
+    _misc_rewritten                           = 1 << 3,  // methods rewritten.
+    _misc_has_nonstatic_fields                = 1 << 4,  // for sizing with UseCompressedOops
+    _misc_should_verify_class                 = 1 << 5,  // allow caching of preverification
+    _misc_is_anonymous                        = 1 << 6,  // has embedded _host_klass field
+    _misc_is_contended                        = 1 << 7,  // marked with contended annotation
+    _misc_has_nonstatic_concrete_methods      = 1 << 8,  // class/superclass/implemented interfaces has non-static, concrete methods
+    _misc_declares_nonstatic_concrete_methods = 1 << 9,  // directly declares non-static, concrete methods
+    _misc_has_been_redefined                  = 1 << 10,  // class has been redefined
+    _misc_has_passed_fingerprint_check        = 1 << 11, // when this class was loaded, the fingerprint computed from its
                                                          // code source was found to be matching the value recorded by AOT.
-    _misc_is_scratch_class                    = 1 << 11, // class is the redefined scratch class
-    _misc_is_shared_boot_class                = 1 << 12, // defining class loader is boot class loader
-    _misc_is_shared_platform_class            = 1 << 13, // defining class loader is platform class loader
-    _misc_is_shared_app_class                 = 1 << 14  // defining class loader is app class loader
+    _misc_is_scratch_class                    = 1 << 12, // class is the redefined scratch class
+    _misc_is_shared_boot_class                = 1 << 13, // defining class loader is boot class loader
+    _misc_is_shared_platform_class            = 1 << 14, // defining class loader is platform class loader
+    _misc_is_shared_app_class                 = 1 << 15  // defining class loader is app class loader
   };
   u2 loader_type_bits() {
     return _misc_is_shared_boot_class|_misc_is_shared_platform_class|_misc_is_shared_app_class;
@@ -287,6 +304,8 @@
   //     [generic signature index]
   //     ...
   Array<u2>*      _fields;
+  // Valhalla shady value type
+  InstanceKlass*  _derive_value_type_klass;
 
   // embedded Java vtable follows here
   // embedded Java itables follows here
@@ -538,7 +557,7 @@
 
   // find a non-static or static field given its offset within the class.
   bool contains_field_offset(int offset) {
-    return instanceOopDesc::contains_field_offset(offset, nonstatic_field_size());
+    return instanceOopDesc::contains_field_offset(offset, nonstatic_field_size(), is_value());
   }
 
   bool find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
@@ -770,6 +789,7 @@
   bool is_reference_instance_klass() const    { return is_kind(_misc_kind_reference); }
   bool is_mirror_instance_klass() const       { return is_kind(_misc_kind_mirror); }
   bool is_class_loader_instance_klass() const { return is_kind(_misc_kind_class_loader); }
+  bool is_value_type_klass()            const { return is_kind(_misc_kind_value_type); }
 
 #if INCLUDE_JVMTI
 
@@ -1063,6 +1083,8 @@
 
   address static_field_addr(int offset);
 
+  bool bounds_check(address addr, bool edge_ok = false, intptr_t size_in_bytes = -1) const PRODUCT_RETURN0;
+
   OopMapBlock* start_of_nonstatic_oop_maps() const {
     return (OopMapBlock*)(start_of_itable() + itable_length());
   }
@@ -1112,7 +1134,7 @@
   }
 
   // Use this to return the size of an instance in heap words:
-  int size_helper() const {
+  virtual int size_helper() const {
     return layout_helper_to_size_helper(layout_helper());
   }
 
@@ -1301,12 +1323,14 @@
   void eager_initialize_impl                     ();
   /* jni_id_for_impl for jfieldID only */
   JNIid* jni_id_for_impl                         (int offset);
-
+protected:
   // Returns the array class for the n'th dimension
-  Klass* array_klass_impl(bool or_null, int n, TRAPS);
+  virtual Klass* array_klass_impl(bool or_null, int n, TRAPS);
 
   // Returns the array class with this class as element type
-  Klass* array_klass_impl(bool or_null, TRAPS);
+  virtual Klass* array_klass_impl(bool or_null, TRAPS);
+
+private:
 
   // find a local method (returns NULL if not found)
   Method* find_method_impl(const Symbol* name,
@@ -1343,6 +1367,15 @@
   void set_member_names(MemberNameTable* member_names) { _member_names = member_names; }
   oop add_member_name(Handle member_name, bool intern);
 
+  //Valhalla prototype DeriveValueType
+  void create_derive_value_type(Handle class_loader, Handle protection_domain, TRAPS);
+  bool is_derive_value_type() const {
+    return _derive_value_type_klass != NULL;
+  }
+  InstanceKlass* derive_value_type_klass() const {
+    return _derive_value_type_klass;
+  }
+
 public:
   // JVMTI support
   jint jvmti_class_status() const;
--- a/src/share/vm/oops/instanceKlass.inline.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/instanceKlass.inline.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -166,6 +166,9 @@
 ALWAYSINLINE int InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
   if (Devirtualizer<nv>::do_metadata(closure)) {
     Devirtualizer<nv>::do_klass(closure, this);
+    if (is_derive_value_type()) {
+      Devirtualizer<nv>::do_klass(closure, derive_value_type_klass());
+    }
   }
 
   oop_oop_iterate_oop_maps<nv>(obj, closure);
@@ -190,6 +193,9 @@
   if (Devirtualizer<nv>::do_metadata(closure)) {
     if (mr.contains(obj)) {
       Devirtualizer<nv>::do_klass(closure, this);
+      if (is_derive_value_type()) {
+        Devirtualizer<nv>::do_klass(closure, derive_value_type_klass());
+      }
     }
   }
 
--- a/src/share/vm/oops/instanceOop.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/instanceOop.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -44,8 +44,12 @@
              sizeof(instanceOopDesc);
   }
 
-  static bool contains_field_offset(int offset, int nonstatic_field_size) {
+  static bool contains_field_offset(int offset, int nonstatic_field_size, bool is_value) {
     int base_in_bytes = base_offset_in_bytes();
+    if (is_value) {
+      // The first field of value types is aligned on a long boundary
+      base_in_bytes = align_size_up(base_in_bytes, BytesPerLong);
+    }
     return (offset >= base_in_bytes &&
             (offset-base_in_bytes) < nonstatic_field_size * heapOopSize);
   }
--- a/src/share/vm/oops/klass.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/klass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -81,7 +81,7 @@
   // distinct bytes, as follows:
   //    MSB:[tag, hsz, ebt, log2(esz)]:LSB
   // where:
-  //    tag is 0x80 if the elements are oops, 0xC0 if non-oops
+  //    tag is 0x80 if the elements are oops, 0xC0 if non-oops, 0xA0 if value types
   //    hsz is array header size in bytes (i.e., offset of first element)
   //    ebt is the BasicType of the elements
   //    esz is the element size in bytes
@@ -307,13 +307,13 @@
     _lh_element_type_mask       = right_n_bits(BitsPerByte),  // shifted mask
     _lh_header_size_shift       = BitsPerByte*2,
     _lh_header_size_mask        = right_n_bits(BitsPerByte),  // shifted mask
-    _lh_array_tag_bits          = 2,
+    _lh_array_tag_bits          = 3,
     _lh_array_tag_shift         = BitsPerInt - _lh_array_tag_bits,
-    _lh_array_tag_obj_value     = ~0x01   // 0x80000000 >> 30
+    _lh_array_tag_type_value      = ~0x3,  // bits ~100 compare as int, ie. sign extended
+    _lh_array_tag_vt_value        = ~0x2,  // bits ~101
+    _lh_array_tag_obj_value       = ~0x1   // bits ~110
   };
 
-  static const unsigned int _lh_array_tag_type_value = 0Xffffffff; // ~0x00,  // 0xC0000000 >> 30
-
   static int layout_helper_size_in_bytes(jint lh) {
     assert(lh > (jint)_lh_neutral_value, "must be instance");
     return (int) lh & ~_lh_instance_slow_path_bit;
@@ -329,12 +329,13 @@
     return (jint)lh < (jint)_lh_neutral_value;
   }
   static bool layout_helper_is_typeArray(jint lh) {
-    // _lh_array_tag_type_value == (lh >> _lh_array_tag_shift);
-    return (juint)lh >= (juint)(_lh_array_tag_type_value << _lh_array_tag_shift);
+    return _lh_array_tag_type_value == (lh >> _lh_array_tag_shift);
   }
   static bool layout_helper_is_objArray(jint lh) {
-    // _lh_array_tag_obj_value == (lh >> _lh_array_tag_shift);
-    return (jint)lh < (jint)(_lh_array_tag_type_value << _lh_array_tag_shift);
+    return _lh_array_tag_obj_value == (lh >> _lh_array_tag_shift);
+  }
+  static bool layout_helper_is_valueArray(jint lh) {
+    return _lh_array_tag_vt_value == (lh >> _lh_array_tag_shift);
   }
   static int layout_helper_header_size(jint lh) {
     assert(lh < (jint)_lh_neutral_value, "must be array");
@@ -345,7 +346,7 @@
   static BasicType layout_helper_element_type(jint lh) {
     assert(lh < (jint)_lh_neutral_value, "must be array");
     int btvalue = (lh >> _lh_element_type_shift) & _lh_element_type_mask;
-    assert(btvalue >= T_BOOLEAN && btvalue <= T_OBJECT, "sanity");
+    assert((btvalue >= T_BOOLEAN && btvalue <= T_OBJECT) || btvalue == T_VALUETYPE, "sanity");
     return (BasicType) btvalue;
   }
 
@@ -516,7 +517,10 @@
   virtual bool is_array_klass_slow()        const { return false; }
   virtual bool is_objArray_klass_slow()     const { return false; }
   virtual bool is_typeArray_klass_slow()    const { return false; }
+  virtual bool is_valueArray_klass_slow()   const { return false; }
 #endif // ASSERT
+  // current implementation uses this method even in non debug builds
+  virtual bool is_value_slow()          const { return false; }
  public:
 
   // Fast non-virtual versions
@@ -542,6 +546,11 @@
   inline  bool is_typeArray_klass()           const { return assert_same_query(
                                                     layout_helper_is_typeArray(layout_helper()),
                                                     is_typeArray_klass_slow()); }
+  inline  bool is_value()                     const { return is_value_slow(); } //temporary hack
+  inline  bool is_valueArray_klass()          const { return assert_same_query(
+                                                    layout_helper_is_valueArray(layout_helper()),
+                                                    is_valueArray_klass_slow()); }
+
   #undef assert_same_query
 
   // Access flags
--- a/src/share/vm/oops/klassVtable.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/klassVtable.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -93,13 +93,14 @@
     vtable_length += *num_new_mirandas * vtableEntry::size();
   }
 
-  if (Universe::is_bootstrapping() && vtable_length == 0) {
+  if (Universe::is_bootstrapping() && vtable_length == 0 && classname != vmSymbols::java_lang____Value()) {
     // array classes don't have their superclass set correctly during
     // bootstrapping
     vtable_length = Universe::base_vtable_size();
   }
 
-  if (super == NULL && vtable_length != Universe::base_vtable_size()) {
+  if (super == NULL && vtable_length != Universe::base_vtable_size()
+      && !class_flags.is_value_type()) {
     if (Universe::is_bootstrapping()) {
       // Someone is attempting to override java.lang.Object incorrectly on the
       // bootclasspath.  The JVM cannot recover from this error including throwing
@@ -115,7 +116,8 @@
     }
   }
   assert(vtable_length % vtableEntry::size() == 0, "bad vtable length");
-  assert(vtable_length >= Universe::base_vtable_size(), "vtable too small");
+  assert(vtable_length >= Universe::base_vtable_size()
+         || class_flags.is_value_type(), "vtable too small");
 
   *vtable_length_ret = vtable_length;
 }
@@ -1331,6 +1333,18 @@
   virtual void doit(Klass* intf, int method_count) = 0;
 };
 
+int count_interface_methods_needing_itable_index(Array<Method*>* methods) {
+  int method_count = 0;
+  if (methods->length() > 0) {
+    for (int i = methods->length(); --i >= 0; ) {
+      if (interface_method_needs_itable_index(methods->at(i))) {
+        method_count++;
+      }
+    }
+  }
+  return method_count;
+}
+
 // Visit all interfaces with at least one itable method
 void visit_all_interfaces(Array<Klass*>* transitive_intf, InterfaceVisiterClosure *blk) {
   // Handle array argument
--- a/src/share/vm/oops/klassVtable.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/klassVtable.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -305,7 +305,10 @@
   itableMethodEntry* method_entry(int i) { assert(0 <= i && i <= _size_method_table, "index out of bounds");
                                            return &((itableMethodEntry*)method_start())[i]; }
 
-  int size_offset_table()                { return _size_offset_table; }
+  InstanceKlass* klass() const          { return _klass; }
+  int table_offset() const              { return _table_offset; }
+  int size_offset_table() const         { return _size_offset_table; }
+  int size_method_table() const         { return _size_method_table; }
 
   // Initialization
   void initialize_itable(bool checkconstraints, TRAPS);
--- a/src/share/vm/oops/method.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/method.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -2214,6 +2214,8 @@
   if (highest_comp_level() != CompLevel_none)
     st->print_cr(" - highest level:     %d", highest_comp_level());
   st->print_cr(" - vtable index:      %d",   _vtable_index);
+  if (valid_itable_index())
+    st->print_cr(" - itable index:      %d",   itable_index());
   st->print_cr(" - i2i entry:         " INTPTR_FORMAT, p2i(interpreter_entry()));
   st->print(   " - adapters:          ");
   AdapterHandlerEntry* a = ((Method*)this)->adapter();
@@ -2291,6 +2293,7 @@
   st->print("%s", internal_name());
   print_address_on(st);
   st->print(" ");
+  if (WizardMode) access_flags().print_on(st);
   name()->print_value_on(st);
   st->print(" ");
   signature()->print_value_on(st);
--- a/src/share/vm/oops/methodData.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/methodData.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -742,6 +742,7 @@
   case Bytecodes::_jsr_w:
     return JumpData::static_cell_count();
   case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokedirect:
   case Bytecodes::_invokeinterface:
     if (MethodData::profile_arguments() || MethodData::profile_return()) {
       return variable_cell_count;
@@ -805,6 +806,7 @@
       }
       break;
     case Bytecodes::_invokevirtual:
+    case Bytecodes::_invokedirect:
     case Bytecodes::_invokeinterface: {
       assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile");
       if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
@@ -832,6 +834,7 @@
   case Bytecodes::_instanceof:
   case Bytecodes::_aastore:
   case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokedirect:
   case Bytecodes::_invokeinterface:
   case Bytecodes::_if_acmpeq:
   case Bytecodes::_if_acmpne:
@@ -986,6 +989,7 @@
     tag = DataLayout::jump_data_tag;
     break;
   case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokedirect:
   case Bytecodes::_invokeinterface: {
     int virtual_call_data_cell_count = VirtualCallData::static_cell_count();
     if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
--- a/src/share/vm/oops/objArrayKlass.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/objArrayKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -32,6 +32,7 @@
 #include "gc/shared/specialized_oop_closures.hpp"
 #include "memory/iterator.inline.hpp"
 #include "memory/metadataFactory.hpp"
+#include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
 #include "oops/arrayKlass.inline.hpp"
@@ -99,31 +100,7 @@
   }
 
   // Create type name for klass.
-  Symbol* name = NULL;
-  if (!element_klass->is_instance_klass() ||
-      (name = InstanceKlass::cast(element_klass)->array_name()) == NULL) {
-
-    ResourceMark rm(THREAD);
-    char *name_str = element_klass->name()->as_C_string();
-    int len = element_klass->name()->utf8_length();
-    char *new_str = NEW_RESOURCE_ARRAY(char, len + 4);
-    int idx = 0;
-    new_str[idx++] = '[';
-    if (element_klass->is_instance_klass()) { // it could be an array or simple type
-      new_str[idx++] = 'L';
-    }
-    memcpy(&new_str[idx], name_str, len * sizeof(char));
-    idx += len;
-    if (element_klass->is_instance_klass()) {
-      new_str[idx++] = ';';
-    }
-    new_str[idx++] = '\0';
-    name = SymbolTable::new_permanent_symbol(new_str, CHECK_0);
-    if (element_klass->is_instance_klass()) {
-      InstanceKlass* ik = InstanceKlass::cast(element_klass);
-      ik->set_array_name(name);
-    }
-  }
+  Symbol* name = ArrayKlass::create_element_klass_array_name(element_klass, CHECK_NULL);
 
   // Initialize instance variables
   ObjArrayKlass* oak = ObjArrayKlass::allocate(loader_data, n, element_klass, name, CHECK_0);
@@ -156,7 +133,9 @@
   } else {
     bk = element_klass;
   }
-  assert(bk != NULL && (bk->is_instance_klass() || bk->is_typeArray_klass()), "invalid bottom klass");
+  assert(bk != NULL && (bk->is_instance_klass()
+      || bk->is_typeArray_klass()
+      || bk->is_valueArray_klass()), "invalid bottom klass");
   this->set_bottom_klass(bk);
   this->set_class_loader_data(bk->class_loader_data());
 
@@ -189,28 +168,30 @@
 
 oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) {
   int length = *sizes;
+  if (rank == 1) { // last dim may be valueArray
+    return oopFactory::new_array(element_klass(), length, CHECK_NULL);
+  }
+  guarantee(rank > 1, "Rank below 1");
   // Call to lower_dimension uses this pointer, so most be called before a
   // possible GC
   Klass* ld_klass = lower_dimension();
   // If length < 0 allocate will throw an exception.
   objArrayOop array = allocate(length, CHECK_NULL);
   objArrayHandle h_array (THREAD, array);
-  if (rank > 1) {
-    if (length != 0) {
-      for (int index = 0; index < length; index++) {
-        ArrayKlass* ak = ArrayKlass::cast(ld_klass);
-        oop sub_array = ak->multi_allocate(rank-1, &sizes[1], CHECK_NULL);
-        h_array->obj_at_put(index, sub_array);
-      }
-    } else {
-      // Since this array dimension has zero length, nothing will be
-      // allocated, however the lower dimension values must be checked
-      // for illegal values.
-      for (int i = 0; i < rank - 1; ++i) {
-        sizes += 1;
-        if (*sizes < 0) {
-          THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
-        }
+  if (length != 0) {
+    for (int index = 0; index < length; index++) {
+      ArrayKlass* ak = ArrayKlass::cast(ld_klass);
+      oop sub_array = ak->multi_allocate(rank-1, &sizes[1], CHECK_NULL);
+      h_array->obj_at_put(index, sub_array);
+    }
+  } else {
+    // Since this array dimension has zero length, nothing will be
+    // allocated, however the lower dimension values must be checked
+    // for illegal values.
+    for (int i = 0; i < rank - 1; ++i) {
+      sizes += 1;
+      if (*sizes < 0) {
+        THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
       }
     }
   }
@@ -429,7 +410,7 @@
 void ObjArrayKlass::print_on(outputStream* st) const {
 #ifndef PRODUCT
   Klass::print_on(st);
-  st->print(" - instance klass: ");
+  st->print(" - element klass: ");
   element_klass()->print_value_on(st);
   st->cr();
 #endif //PRODUCT
@@ -483,7 +464,8 @@
   guarantee(element_klass()->is_klass(), "should be klass");
   guarantee(bottom_klass()->is_klass(), "should be klass");
   Klass* bk = bottom_klass();
-  guarantee(bk->is_instance_klass() || bk->is_typeArray_klass(),  "invalid bottom klass");
+  guarantee(bk->is_instance_klass() || bk->is_typeArray_klass() || bk->is_valueArray_klass(),
+            "invalid bottom klass");
 }
 
 void ObjArrayKlass::oop_verify_on(oop obj, outputStream* st) {
--- a/src/share/vm/oops/oop.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/oop.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -133,6 +133,8 @@
 bool oopDesc::is_array_noinline()             const { return is_array();               }
 bool oopDesc::is_objArray_noinline()          const { return is_objArray();            }
 bool oopDesc::is_typeArray_noinline()         const { return is_typeArray();           }
+bool oopDesc::is_value_noinline()             const { return is_value();               }
+bool oopDesc::is_valueArray_noinline()        const { return is_valueArray();          }
 
 bool oopDesc::has_klass_gap() {
   // Only has a klass gap when compressed class pointers are used.
--- a/src/share/vm/oops/oop.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/oop.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -115,12 +115,16 @@
   inline bool is_array()               const;
   inline bool is_objArray()            const;
   inline bool is_typeArray()           const;
+  inline bool is_value()               const;
+  inline bool is_valueArray()          const;
 
   // type test operations that don't require inclusion of oop.inline.hpp.
   bool is_instance_noinline()          const;
   bool is_array_noinline()             const;
   bool is_objArray_noinline()          const;
   bool is_typeArray_noinline()         const;
+  bool is_value_noinline()             const;
+  bool is_valueArray_noinline()        const;
 
  private:
   // field addresses in oop
--- a/src/share/vm/oops/oop.inline.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/oop.inline.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -293,6 +293,8 @@
 bool oopDesc::is_array()     const { return klass()->is_array_klass();     }
 bool oopDesc::is_objArray()  const { return klass()->is_objArray_klass();  }
 bool oopDesc::is_typeArray() const { return klass()->is_typeArray_klass(); }
+bool oopDesc::is_value()     const { return klass()->is_value(); }
+bool oopDesc::is_valueArray()  const { return klass()->is_valueArray_klass(); }
 
 void*      oopDesc::field_base(int offset)          const { return (void*)&((char*)this)[offset]; }
 
--- a/src/share/vm/oops/oopsHierarchy.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/oopsHierarchy.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -47,6 +47,7 @@
 typedef class   arrayOopDesc*                    arrayOop;
 typedef class     objArrayOopDesc*            objArrayOop;
 typedef class     typeArrayOopDesc*            typeArrayOop;
+typedef class     valueArrayOopDesc*            valueArrayOop;
 
 #else
 
@@ -172,6 +173,7 @@
 DEF_OOP(array);
 DEF_OOP(objArray);
 DEF_OOP(typeArray);
+DEF_OOP(valueArray);
 
 #endif // CHECK_UNHANDLED_OOPS
 
@@ -205,8 +207,10 @@
 class     InstanceMirrorKlass;
 class     InstanceClassLoaderKlass;
 class     InstanceRefKlass;
+class     ValueKlass;
 class   ArrayKlass;
 class     ObjArrayKlass;
 class     TypeArrayKlass;
+class     ValueArrayKlass;
 
 #endif // SHARE_VM_OOPS_OOPSHIERARCHY_HPP
--- a/src/share/vm/oops/typeArrayKlass.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/typeArrayKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -45,6 +45,7 @@
 #include "utilities/macros.hpp"
 
 bool TypeArrayKlass::compute_is_subtype_of(Klass* k) {
+  ShouldNotReachHere();
   if (!k->is_typeArray_klass()) {
     return ArrayKlass::compute_is_subtype_of(k);
   }
--- a/src/share/vm/oops/typeArrayOop.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/oops/typeArrayOop.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -143,7 +143,7 @@
 
   // Returns the number of words necessary to hold an array of "len"
   // elements each of the given "byte_size".
- private:
+
   static int object_size(int lh, int length) {
     int instance_header_size = Klass::layout_helper_header_size(lh);
     int element_shift = Klass::layout_helper_log2_element_size(lh);
@@ -159,7 +159,6 @@
     return align_object_size((intptr_t)size_in_words);
   }
 
- public:
   inline int object_size();
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/oops/valueArrayKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/moduleEntry.hpp"
+#include "classfile/packageEntry.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
+#include "memory/metadataFactory.hpp"
+#include "memory/resourceArea.hpp"
+#include "memory/universe.hpp"
+#include "memory/universe.inline.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/klass.inline.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/arrayKlass.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/valueKlass.hpp"
+#include "oops/valueArrayOop.hpp"
+#include "oops/verifyOopClosure.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "utilities/macros.hpp"
+
+#include "oops/valueArrayKlass.hpp"
+
+// Allocation...
+
+ValueArrayKlass::ValueArrayKlass(Klass* element_klass, Symbol* name) : ArrayKlass(name) {
+  assert(element_klass->is_value(), "Expected Value");
+
+  set_element_klass(ValueKlass::cast(element_klass));
+  set_class_loader_data(element_klass->class_loader_data());
+  set_layout_helper(array_layout_helper(ValueKlass::cast(element_klass)));
+
+  assert((1 << Klass::layout_helper_log2_element_size(layout_helper())) >=
+      element_value_store_size(), "sanity");
+  assert(is_array_klass(), "sanity");
+  assert(is_valueArray_klass(), "sanity");
+
+  CMH("tweak name symbol refcnt ?")
+#ifndef PRODUCT
+  if (PrintValueArrayLayout) {
+    print();
+  }
+#endif
+}
+
+void ValueArrayKlass::set_element_klass(ValueKlass* k) {
+  _element_klass = k;
+  _element_value_store_size = k->raw_value_byte_size();
+}
+
+ValueArrayKlass* ValueArrayKlass::allocate_klass(Klass*  element_klass,
+                                                 Symbol* name,
+                                                 TRAPS) {
+  assert(ValueArrayFlatten, "Flatten array not allowed");
+  assert(ValueKlass::cast(element_klass)->is_atomic() || (!ValueArrayAtomicAccess), "Atomic by-default");
+
+  ClassLoaderData* loader_data = element_klass->class_loader_data();
+  int size = ArrayKlass::static_size(ValueArrayKlass::header_size());
+  ValueArrayKlass* vak = new (loader_data, size, THREAD) ValueArrayKlass(element_klass, name);
+  if (vak == NULL) {
+    return NULL;
+  }
+  loader_data->add_class(vak);
+  complete_create_array_klass(vak, vak->super(), vak->module(), CHECK_NULL);
+  return vak;
+}
+
+ValueArrayKlass* ValueArrayKlass::allocate_klass(Klass* element_klass, TRAPS) {
+  Symbol* name = ArrayKlass::create_element_klass_array_name(element_klass, CHECK_NULL);
+  return allocate_klass(element_klass, name, THREAD);
+}
+
+void ValueArrayKlass::initialize(TRAPS) {
+  element_klass()->initialize(THREAD);
+}
+
+// Oops allocation...
+oop ValueArrayKlass::allocate(int length, bool do_zero, TRAPS) {
+  if (length < 0) {
+    THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
+  }
+  if (length > max_elements()) {
+    report_java_out_of_memory("Requested array size exceeds VM limit");
+    JvmtiExport::post_array_size_exhausted();
+    THROW_OOP_0(Universe::out_of_memory_error_array_size());
+  }
+
+  size_t size = valueArrayOopDesc::object_size(layout_helper(), length);
+  if (do_zero) {
+    return CollectedHeap::array_allocate(this, (int)size, length, CHECK_NULL);
+  } else {
+    return CollectedHeap::array_allocate_nozero(this, (int)size, length, CHECK_NULL);
+  }
+}
+
+
+oop ValueArrayKlass::multi_allocate(int rank, jint* last_size, TRAPS) {
+  // For valueArrays this is only called for the last dimension
+  assert(rank == 1, "just checking");
+  int length = *last_size;
+  return allocate(length, true, THREAD);
+}
+
+jint ValueArrayKlass::array_layout_helper(ValueKlass* vk) {
+  BasicType etype = T_VALUETYPE;
+  int atag  = _lh_array_tag_vt_value;
+  int esize = upper_log2(vk->raw_value_byte_size());
+  int hsize = arrayOopDesc::base_offset_in_bytes(etype);
+
+  int lh = (atag       << _lh_array_tag_shift)
+    |      (hsize      << _lh_header_size_shift)
+    |      ((int)etype << _lh_element_type_shift)
+    |      ((esize)    << _lh_log2_element_size_shift);
+
+  assert(lh < (int)_lh_neutral_value, "must look like an array layout");
+  assert(layout_helper_is_array(lh), "correct kind");
+  assert(layout_helper_is_valueArray(lh), "correct kind");
+  assert(!layout_helper_is_typeArray(lh), "correct kind");
+  assert(!layout_helper_is_objArray(lh), "correct kind");
+  assert(layout_helper_header_size(lh) == hsize, "correct decode");
+  assert(layout_helper_element_type(lh) == etype, "correct decode");
+  assert(layout_helper_log2_element_size(lh) == esize, "correct decode");
+  assert((1 << esize) < BytesPerLong || is_size_aligned(hsize, HeapWordsPerLong), "unaligned base");
+
+  return lh;
+}
+
+int ValueArrayKlass::oop_size(oop obj) const {
+  assert(obj->is_valueArray(),"must be a value array");
+  valueArrayOop array = valueArrayOop(obj);
+  return array->object_size();
+}
+
+jint ValueArrayKlass::max_elements() const {
+  return arrayOopDesc::max_array_length(arrayOopDesc::header_size(T_VALUETYPE), element_byte_size());
+}
+
+oop ValueArrayKlass::protection_domain() const {
+  return element_klass()->protection_domain();
+}
+
+void ValueArrayKlass::copy_array(arrayOop s, int src_pos,
+                                 arrayOop d, int dst_pos, int length, TRAPS) {
+  assert(s->is_valueArray(), "must be value array");
+
+   // Check destination
+   if (!d->is_valueArray() || element_klass() != ValueArrayKlass::cast(d->klass())->element_klass()) {
+     THROW(vmSymbols::java_lang_ArrayStoreException());
+   }
+
+   // Check is all offsets and lengths are non negative
+   if (src_pos < 0 || dst_pos < 0 || length < 0) {
+     THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
+   }
+   // Check if the ranges are valid
+   if  ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length())
+      || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) ) {
+     THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
+   }
+   // Check zero copy
+   if (length == 0)
+     return;
+
+   valueArrayOop sa = valueArrayOop(s);
+   valueArrayOop da = valueArrayOop(d);
+   address src = (address) sa->value_at_addr(src_pos, layout_helper());
+   address dst = (address) da->value_at_addr(dst_pos, layout_helper());
+   if (contains_oops()) {
+     int elem_incr = 1 << log2_element_size();
+     address src_end = src + (length << log2_element_size());
+     while (src < src_end) {
+       element_klass()->value_store(src, dst, element_value_store_size(), true, false);
+       src += elem_incr;
+       dst += elem_incr;
+     }
+   } else {
+     // we are basically a type array...don't bother limiting element copy
+     // it would have to be a lot wasted space to be worth value_store() calls, need a setting here ?
+     Copy::conjoint_memory_atomic(src, dst, (size_t)length << log2_element_size());
+   }
+}
+
+
+Klass* ValueArrayKlass::array_klass_impl(bool or_null, int n, TRAPS) {
+
+  assert(dimension() <= n, "check order of chain");
+  int dim = dimension();
+  if (dim == n) return this;
+
+  if (higher_dimension() == NULL) {
+    if (or_null)  return NULL;
+
+    ResourceMark rm;
+    JavaThread *jt = (JavaThread *)THREAD;
+    {
+      MutexLocker mc(Compile_lock, THREAD);   // for vtables
+      // Ensure atomic creation of higher dimensions
+      MutexLocker mu(MultiArray_lock, THREAD);
+
+      // Check if another thread beat us
+      if (higher_dimension() == NULL) {
+
+        // Create multi-dim klass object and link them together
+        Klass* k =
+          ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this, CHECK_NULL);
+        ObjArrayKlass* ak = ObjArrayKlass::cast(k);
+        ak->set_lower_dimension(this);
+        OrderAccess::storestore();
+        set_higher_dimension(ak);
+        assert(ak->is_objArray_klass(), "incorrect initialization of ObjArrayKlass");
+      }
+    }
+  } else {
+    CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
+  }
+
+  ObjArrayKlass *ak = ObjArrayKlass::cast(higher_dimension());
+  if (or_null) {
+    return ak->array_klass_or_null(n);
+  }
+  return ak->array_klass(n, THREAD);
+}
+
+Klass* ValueArrayKlass::array_klass_impl(bool or_null, TRAPS) {
+  return array_klass_impl(or_null, dimension() +  1, THREAD);
+}
+
+ModuleEntry* ValueArrayKlass::module() const {
+  assert(element_klass() != NULL, "ObjArrayKlass returned unexpected NULL bottom_klass");
+  // The array is defined in the module of its bottom class
+  return element_klass()->module();
+}
+
+PackageEntry* ValueArrayKlass::package() const {
+  assert(element_klass() != NULL, "ObjArrayKlass returned unexpected NULL bottom_klass");
+  return element_klass()->package();
+}
+
+void ValueArrayKlass::print_on(outputStream* st) const {
+#ifndef PRODUCT
+  assert(!is_objArray_klass(), "Unimplemented");
+
+  st->print("Value Type Array: ");
+  Klass::print_on(st);
+
+  st->print(" - element klass: ");
+  element_klass()->print_value_on(st);
+  st->cr();
+
+  int elem_size = element_byte_size();
+  st->print(" - element size %i ", elem_size);
+  st->print("aligned layout size %i", 1 << layout_helper_log2_element_size(layout_helper()));
+  st->cr();
+#endif //PRODUCT
+}
+
+void ValueArrayKlass::print_value_on(outputStream* st) const {
+  assert(is_klass(), "must be klass");
+
+  element_klass()->print_value_on(st);
+  st->print("[]");
+}
+
+
+#ifndef PRODUCT
+void ValueArrayKlass::oop_print_on(oop obj, outputStream* st) {
+  ArrayKlass::oop_print_on(obj, st);
+  valueArrayOop va = valueArrayOop(obj);
+  ValueKlass* vk = element_klass();
+  int print_len = MIN2((intx) va->length(), MaxElementPrintSize);
+  for(int index = 0; index < print_len; index++) {
+    int off = (address) va->value_at_addr(index, layout_helper()) - (address) obj;
+    st->print_cr(" - Index %3d offset %3d: ", index, off);
+    oop obj = (oop) ((address)va->value_at_addr(index, layout_helper()) - vk->first_field_offset());
+    FieldPrinter print_field(st, obj);
+    vk->do_nonstatic_fields(&print_field);
+    st->cr();
+  }
+  int remaining = va->length() - print_len;
+  if (remaining > 0) {
+    st->print_cr(" - <%d more elements, increase MaxElementPrintSize to print>", remaining);
+  }
+}
+#endif //PRODUCT
+
+void ValueArrayKlass::oop_print_value_on(oop obj, outputStream* st) {
+  assert(obj->is_valueArray(), "must be valueArray");
+  st->print("a ");
+  element_klass()->print_value_on(st);
+  int len = valueArrayOop(obj)->length();
+  st->print("[%d] ", len);
+  obj->print_address_on(st);
+  if (PrintMiscellaneous && (WizardMode || Verbose)) {
+    int lh = layout_helper();
+    st->print("{");
+    for (int i = 0; i < len; i++) {
+      if (i > 4) {
+        st->print("..."); break;
+      }
+      st->print(" " INTPTR_FORMAT, (intptr_t)(void*)valueArrayOop(obj)->value_at_addr(i , lh));
+    }
+    st->print(" }");
+  }
+}
+
+// Verification
+
+void ValueArrayKlass::oop_verify_on(oop obj, outputStream* st) {
+  ArrayKlass::oop_verify_on(obj, st);
+  guarantee(obj->is_valueArray(), "must be valueArray");
+
+  if (element_klass()->contains_oops()) {
+    valueArrayOop va = valueArrayOop(obj);
+    NoHeaderExtendedOopClosure wrapClosure(&VerifyOopClosure::verify_oop);
+    va->oop_iterate(&wrapClosure);
+  }
+}
+
+void ValueArrayKlass::verify_on(outputStream* st) {
+  ArrayKlass::verify_on(st);
+  guarantee(element_klass()->is_value(), "should be value type klass");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/oops/valueArrayKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_OOPS_VALUEARRAYKLASS_HPP
+#define SHARE_VM_OOPS_VALUEARRAYKLASS_HPP
+
+#include "classfile/classLoaderData.hpp"
+#include "oops/arrayKlass.hpp"
+#include "oops/valueKlass.hpp"
+#include "utilities/macros.hpp"
+
+/**
+ * Array of values, gives a layout of typeArrayOop, but needs oops iterators
+ */
+class ValueArrayKlass : public ArrayKlass {
+  friend class VMStructs;
+ private:
+  int            _element_value_store_size;  // pow2 addressing, limit value store copy size
+  ValueKlass*    _element_klass;             // The klass of the elements of this array type
+
+  // Constructor
+  ValueArrayKlass(Klass* element_klass, Symbol* name);
+  void set_element_klass(ValueKlass* k);
+
+  static ValueArrayKlass* allocate_klass(Klass* element_klass, Symbol* name, TRAPS);
+protected:
+  // Returns the ArrayKlass for n'th dimension.
+  Klass* array_klass_impl(bool or_null, int n, TRAPS);
+
+  // Returns the array class with this class as element type.
+  Klass* array_klass_impl(bool or_null, TRAPS);
+
+ public:
+
+  ValueArrayKlass() {}
+
+  // Casting from Klass*
+  static ValueArrayKlass* cast(Klass* k) {
+    assert(k->is_valueArray_klass(), "cast to ValueArrayKlass");
+    return (ValueArrayKlass*) k;
+  }
+
+  // klass allocation
+  static ValueArrayKlass* allocate_klass(Klass* element_klass, TRAPS);
+
+  void initialize(TRAPS);
+
+  // Instance variables
+  ValueKlass* element_klass() const     { return _element_klass; }
+  ValueKlass** element_klass_addr()     { return &_element_klass; }
+
+  ModuleEntry* module() const;
+  PackageEntry* package() const;
+
+  int element_byte_size() const { return 1 << layout_helper_log2_element_size(_layout_helper); }
+  int element_value_store_size() const { return _element_value_store_size; }
+
+  bool is_valueArray_klass_slow() const { return true; }
+
+  bool contains_oops() { return element_klass()->contains_oops(); }
+  bool is_atomic() { return element_klass()->is_atomic(); }
+
+  oop protection_domain() const;
+
+  static jint array_layout_helper(ValueKlass* vklass); // layout helper for values
+
+  // sizing
+  static int header_size()  { return sizeof(ValueArrayKlass)/HeapWordSize; }
+  int size() const          { return ArrayKlass::static_size(header_size()); }
+
+  jint max_elements() const;
+
+  int oop_size(oop obj) const;
+
+  // Oop Allocation
+  oop allocate(int length, bool do_zero, TRAPS);
+  oop multi_allocate(int rank, jint* sizes, TRAPS);
+
+  // Naming
+  const char* internal_name() const { return external_name(); }
+
+  // Copying
+  void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS);
+
+  // Compiler/Interpreter offset
+  static ByteSize element_klass_offset() { return in_ByteSize(offset_of(ValueArrayKlass, _element_klass)); }
+
+  // GC specific object visitors
+  //
+  // Mark Sweep
+  int oop_ms_adjust_pointers(oop obj);
+
+#if INCLUDE_ALL_GCS
+  // Parallel Scavenge
+  void oop_ps_push_contents(  oop obj, PSPromotionManager* pm);
+  // Parallel Compact
+  void oop_pc_follow_contents(oop obj, ParCompactionManager* cm);
+  void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
+#endif
+
+  CMH("Oop iterators. Don't have embedded oops yet, so CMH...")
+
+ private:
+  template <bool nv, typename OopClosureType>
+  inline void oop_oop_iterate(oop obj, OopClosureType* closure);
+  template <bool nv, typename OopClosureType>
+  inline void oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr);
+
+  template <bool nv, typename T, class OopClosureType>
+  inline void oop_oop_iterate_elements_specialized(valueArrayOop a, OopClosureType* closure);
+
+  template <bool nv, class OopClosureType>
+  inline void oop_oop_iterate_elements_bounded(valueArrayOop a, OopClosureType* closure, MemRegion mr);
+
+  template <bool nv, typename T, class OopClosureType>
+  inline void oop_oop_iterate_elements_specialized_bounded(valueArrayOop a, OopClosureType* closure, void* low, void* high);
+
+ public:
+  template <bool nv, class OopClosureType>
+  inline void oop_oop_iterate_elements(valueArrayOop a, OopClosureType* closure);
+
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_RANGE)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_RANGE)
+
+#if INCLUDE_ALL_GCS
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_NO_BACKWARDS)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_NO_BACKWARDS)
+#endif // INCLUDE_ALL_GCS
+
+ public:
+  // Printing
+  void print_on(outputStream* st) const;
+  void print_value_on(outputStream* st) const;
+
+  void oop_print_value_on(oop obj, outputStream* st);
+#ifndef PRODUCT
+  void oop_print_on(oop obj, outputStream* st);
+#endif
+
+  // Verification
+  void verify_on(outputStream* st);
+  void oop_verify_on(oop obj, outputStream* st);
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/oops/valueArrayKlass.inline.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_OOPS_VALUEARRAYKLASS_INLINE_HPP
+#define SHARE_VM_OOPS_VALUEARRAYKLASS_INLINE_HPP
+
+#include "memory/memRegion.hpp"
+#include "memory/iterator.inline.hpp"
+#include "oops/arrayKlass.hpp"
+#include "oops/klass.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/valueArrayKlass.hpp"
+#include "oops/valueArrayOop.hpp"
+#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
+#include "utilities/macros.hpp"
+
+/*
+ * Warning incomplete: requires embedded oops, not yet enabled, so consider this a "sketch-up" of oop iterators
+ */
+
+template <bool nv, typename T, class OopClosureType>
+void ValueArrayKlass::oop_oop_iterate_elements_specialized(valueArrayOop a,
+                                                           OopClosureType* closure) {
+  assert(contains_oops(), "Nothing to iterate");
+
+  const int shift = Klass::layout_helper_log2_element_size(layout_helper());
+  const int addr_incr = 1 << shift;
+  uintptr_t elem_addr = (uintptr_t) a->base();
+  const uintptr_t stop_addr = elem_addr + ((uintptr_t)a->length() << shift);
+  const int oop_offset = element_klass()->first_field_offset();
+
+  while (elem_addr < stop_addr) {
+    element_klass()->oop_iterate_specialized<nv, T>((address)(elem_addr - oop_offset), closure);
+    elem_addr += addr_incr;
+  }
+}
+
+template <bool nv, typename T, class OopClosureType>
+void ValueArrayKlass::oop_oop_iterate_elements_specialized_bounded(valueArrayOop a,
+                                                                   OopClosureType* closure,
+                                                                   void* lo, void* hi) {
+  assert(contains_oops(), "Nothing to iterate");
+
+  const int shift = Klass::layout_helper_log2_element_size(layout_helper());
+  const int addr_incr = 1 << shift;
+  uintptr_t elem_addr = (uintptr_t)a->base();
+  uintptr_t stop_addr = elem_addr + ((uintptr_t)a->length() << shift);
+  const int oop_offset = element_klass()->first_field_offset();
+
+  if (elem_addr < (uintptr_t) lo) {
+    uintptr_t diff = ((uintptr_t) lo) - elem_addr;
+    elem_addr += (diff >> shift) << shift;
+  }
+  if (stop_addr > (uintptr_t) hi) {
+    uintptr_t diff = stop_addr - ((uintptr_t) hi);
+    stop_addr -= (diff >> shift) << shift;
+  }
+
+  const uintptr_t end = stop_addr;
+  while (elem_addr < end) {
+    element_klass()->oop_iterate_specialized_bounded<nv, T>((address)(elem_addr - oop_offset), closure, lo, hi);
+    elem_addr += addr_incr;
+  }
+}
+
+template <bool nv, class OopClosureType>
+void ValueArrayKlass::oop_oop_iterate_elements(valueArrayOop a, OopClosureType* closure) {
+  if (contains_oops()) {
+    if (UseCompressedOops) {
+      oop_oop_iterate_elements_specialized<nv, narrowOop>(a, closure);
+    } else {
+      oop_oop_iterate_elements_specialized<nv, oop>(a, closure);
+    }
+  }
+}
+
+template <bool nv, typename OopClosureType>
+void ValueArrayKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
+  assert(obj->is_valueArray(),"must be a value array");
+
+  if (Devirtualizer<nv>::do_metadata(closure)) {
+    Devirtualizer<nv>::do_klass(closure, obj->klass());
+    Devirtualizer<nv>::do_klass(closure, ValueArrayKlass::cast(obj->klass())->element_klass());
+  }
+
+  oop_oop_iterate_elements<nv>(valueArrayOop(obj), closure);
+}
+
+template <bool nv, class OopClosureType>
+void ValueArrayKlass::oop_oop_iterate_elements_bounded(valueArrayOop a, OopClosureType* closure, MemRegion mr) {
+  if (contains_oops()) {
+    if (UseCompressedOops) {
+      oop_oop_iterate_elements_specialized_bounded<nv, narrowOop>(a, closure, mr.start(), mr.end());
+    } else {
+      oop_oop_iterate_elements_specialized_bounded<nv, oop>(a, closure, mr.start(), mr.end());
+    }
+  }
+}
+
+
+template <bool nv, typename OopClosureType>
+void ValueArrayKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
+  valueArrayOop a = valueArrayOop(obj);
+  if (Devirtualizer<nv>::do_metadata(closure)) {
+    Devirtualizer<nv>::do_klass(closure, a->klass());
+    Devirtualizer<nv>::do_klass(closure, ValueArrayKlass::cast(obj->klass())->element_klass());
+  }
+  oop_oop_iterate_elements_bounded<nv>(a, closure, mr);
+}
+
+
+#define ALL_VALUE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)    \
+  OOP_OOP_ITERATE_DEFN(             ValueArrayKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_BOUNDED(     ValueArrayKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_NO_BACKWARDS(ValueArrayKlass, OopClosureType, nv_suffix)
+
+
+#endif // SHARE_VM_OOPS_VALUEARRAYKLASS_INLINE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/oops/valueArrayOop.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+
+#include "valueArrayOop.hpp"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/oops/valueArrayOop.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_OOPS_VALUEARRAYOOP_HPP
+#define SHARE_VM_OOPS_VALUEARRAYOOP_HPP
+
+#include "oops/arrayOop.hpp"
+#include "oops/klass.hpp"
+#include "oops/oop.inline.hpp"
+
+#include <limits.h>
+
+
+// A valueArrayOop is an array containing value types (may include flatten embedded oop elements).
+
+class valueArrayOopDesc : public arrayOopDesc {
+
+ public:
+  void*  base() const { return arrayOopDesc::base(T_VALUETYPE); }
+
+  void* value_at_addr(int index, int lh) const {
+    assert(is_within_bounds(index), "index out of bounds");
+
+    address addr = (address) base();
+    addr += (index << Klass::layout_helper_log2_element_size(lh));
+    return (void*) addr;
+  }
+
+  // Sizing
+  static size_t element_size(int lh, int nof_elements) {
+    return nof_elements << Klass::layout_helper_log2_element_size(lh);
+  }
+
+  static int object_size(int lh, int length) {
+    julong size_in_bytes = header_size_in_bytes() + element_size(lh, length);
+    julong size_in_words = ((size_in_bytes + (HeapWordSize-1)) >> LogHeapWordSize);
+    assert(size_in_words <= (julong)max_jint, "no overflow");
+    return align_object_size((intptr_t)size_in_words);
+  }
+
+  int object_size() {
+    return object_size(klass()->layout_helper(), length());
+  }
+
+};
+
+#endif // SHARE_VM_OOPS_VALUEARRAYOOP_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/oops/valueKlass.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "interpreter/interpreter.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/fieldStreams.hpp"
+#include "oops/method.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "oops/valueKlass.hpp"
+#include "oops/valueArrayKlass.hpp"
+#include "utilities/copy.hpp"
+
+int ValueKlass::first_field_offset() const {
+#ifdef ASSERT
+  int first_offset = INT_MAX;
+  for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
+    if (fs.offset() < first_offset) first_offset= fs.offset();
+  }
+#endif
+  int base_offset = instanceOopDesc::base_offset_in_bytes();
+  // The first field of value types is aligned on a long boundary
+  base_offset = align_size_up(base_offset, BytesPerLong);
+  assert(base_offset = first_offset, "inconsistent offsets");
+  return base_offset;
+}
+
+int ValueKlass::raw_value_byte_size() const {
+  int heapOopAlignedSize = nonstatic_field_size() << LogBytesPerHeapOop;
+  // If bigger than 64 bits or needs oop alignment, then use jlong aligned
+  // which for values should be jlong aligned, asserts in raw_field_copy otherwise
+  if (heapOopAlignedSize >= longSize || contains_oops()) {
+    return heapOopAlignedSize;
+  }
+  // Small primitives...
+  // If a few small basic type fields, return the actual size, i.e.
+  // 1 byte = 1
+  // 2 byte = 2
+  // 3 byte = 4, because pow2 needed for element stores
+  int first_offset = first_field_offset();
+  int last_offset = 0; // find the last offset, add basic type size
+  for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
+    if (fs.offset() > last_offset) {
+      int tsz = 0;
+      BasicType type = fs.field_descriptor().field_type();
+      if (is_java_primitive(type)) {
+        tsz = type2aelembytes(type);
+      } else if (type == T_VALUETYPE) {
+        // Not just primitives. Layout aligns embedded value, so use jlong aligned it is
+        return heapOopAlignedSize;
+      } else {
+        guarantee(0, "Unknown type %d", type);
+      }
+      assert(tsz > 0, "Invariant");
+      last_offset = fs.offset() + tsz;
+    }
+  }
+  assert(last_offset > first_offset, "Invariant");
+  return 1 << upper_log2(last_offset - first_offset);
+}
+
+bool ValueKlass::is_atomic() {
+  return (nonstatic_field_size() * heapOopSize) <= longSize;
+}
+
+int ValueKlass::nonstatic_oop_count() {
+  int oops = 0;
+  int map_count = nonstatic_oop_map_count();
+  OopMapBlock* block = start_of_nonstatic_oop_maps();
+  OopMapBlock* end = block + map_count;
+  while (block != end) {
+    oops += block->count();
+    block++;
+  }
+  return oops;
+}
+
+// Arrays of...
+
+bool ValueKlass::flatten_array() {
+  if (!ValueArrayFlatten) {
+    return false;
+  }
+
+  int elem_bytes = raw_value_byte_size();
+  // Too big
+  if ((ValueArrayElemMaxFlatSize >= 0) && (elem_bytes > ValueArrayElemMaxFlatSize)) {
+    return false;
+  }
+  // Too many embedded oops
+  if ((ValueArrayElemMaxFlatOops >= 0) && (nonstatic_oop_count() > ValueArrayElemMaxFlatOops)) {
+    return false;
+  }
+
+  return true;
+}
+
+
+Klass* ValueKlass::array_klass_impl(bool or_null, int n, TRAPS) {
+  if (!flatten_array()) {
+    return InstanceKlass::array_klass_impl(or_null, n, THREAD);
+  }
+
+  // Basically the same as instanceKlass, but using "ValueArrayKlass::allocate_klass"
+  if (array_klasses() == NULL) {
+    if (or_null) return NULL;
+
+    ResourceMark rm;
+    JavaThread *jt = (JavaThread *)THREAD;
+    {
+      // Atomic creation of array_klasses
+      MutexLocker mc(Compile_lock, THREAD);   // for vtables
+      MutexLocker ma(MultiArray_lock, THREAD);
+
+      // Check if update has already taken place
+      if (array_klasses() == NULL) {
+        Klass* ak;
+        if (is_atomic() || (!ValueArrayAtomicAccess)) {
+          ak = ValueArrayKlass::allocate_klass(this, CHECK_NULL);
+        } else {
+          ak = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, CHECK_NULL);
+        }
+        set_array_klasses(ak);
+      }
+    }
+  }
+  // _this will always be set at this point
+  ArrayKlass* ak = ArrayKlass::cast(array_klasses());
+  if (or_null) {
+    return ak->array_klass_or_null(n);
+  }
+  return ak->array_klass(n, THREAD);
+}
+
+Klass* ValueKlass::array_klass_impl(bool or_null, TRAPS) {
+  return array_klass_impl(or_null, 1, THREAD);
+}
+
+void ValueKlass::raw_field_copy(void* src, void* dst, size_t raw_byte_size) {
+  /*
+   * Try not to shear fields even if not an atomic store...
+   *
+   * First 3 cases handle value array store, otherwise works on the same basis
+   * as JVM_Clone, at this size data is aligned. The order of primitive types
+   * is largest to smallest, and it not possible for fields to stradle long
+   * copy boundaries.
+   *
+   * If MT without exclusive access, possible to observe partial value store,
+   * but not partial primitive and reference field values
+   */
+  switch (raw_byte_size) {
+    case 1:
+      *((jbyte*) dst) = *(jbyte*)src;
+      break;
+    case 2:
+      *((jshort*) dst) = *(jshort*)src;
+      break;
+    case 4:
+      *((jint*) dst) = *(jint*) src;
+      break;
+    default:
+      assert(raw_byte_size % sizeof(jlong) == 0, "Unaligned raw_byte_size");
+      Copy::conjoint_jlongs_atomic((jlong*)src, (jlong*)dst, raw_byte_size >> LogBytesPerLong);
+  }
+}
+
+/*
+ * Store the value of this klass contained with src into dst.
+ *
+ * This operation is appropriate for use from vastore, vaload and putfield (for values)
+ *
+ * GC barriers currently can lock with no safepoint check and allocate c-heap,
+ * so raw point is "safe" for now.
+ *
+ * Going forward, look to use machine generated (stub gen or bc) version for most used klass layouts
+ *
+ */
+void ValueKlass::value_store(void* src, void* dst, size_t raw_byte_size, bool dst_heap, bool dst_uninitialized) {
+  if (contains_oops() && dst_heap) {
+    // src/dst aren't oops, need offset to adjust oop map offset
+    const address dst_oop_addr = ((address) dst) - first_field_offset();
+
+    // Pre-barriers...
+    OopMapBlock* map = start_of_nonstatic_oop_maps();
+    OopMapBlock* const end = map + nonstatic_oop_map_count();
+    while (map != end) {
+      // Shame we can't just use the existing oop iterator...src/dst aren't oop
+      address doop_address = dst_oop_addr + map->offset();
+      if (UseCompressedOops) {
+        oopDesc::bs()->write_ref_array_pre((narrowOop*) doop_address, map->count(), dst_uninitialized);
+      } else {
+        oopDesc::bs()->write_ref_array_pre((oop*) doop_address, map->count(), dst_uninitialized);
+      }
+      map++;
+    }
+
+    raw_field_copy(src, dst, raw_byte_size);
+
+    // Post-barriers...
+    map = start_of_nonstatic_oop_maps();
+    while (map != end) {
+      address doop_address = dst_oop_addr + map->offset();
+      oopDesc::bs()->write_ref_array((HeapWord*) doop_address, map->count());
+      map++;
+    }
+  } else {   // Primitive-only case...
+    raw_field_copy(src, dst, raw_byte_size);
+  }
+}
+
+oop ValueKlass::derive_value_type_copy(Handle src, InstanceKlass* target_klass, TRAPS) {
+  assert(InstanceKlass::cast(src->klass())->derive_value_type_klass() == target_klass, "Not this DVT");
+
+  // Allocate new for safety, simply reinstalling the klass pointer is a little too risky
+  target_klass->initialize(CHECK_0);
+  instanceOop value = target_klass->allocate_instance(CHECK_0);
+  value_store(data_for_oop(src()), data_for_oop(value), true, true);
+  return value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/oops/valueKlass.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_OOPS_VALUEKLASS_HPP
+#define SHARE_VM_OOPS_VALUEKLASS_HPP
+
+#include "oops/instanceKlass.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+
+// A ValueKlass is a specialized InstanceKlass for value types.
+
+
+class ValueKlass: public InstanceKlass {
+  friend class VMStructs;
+  friend class InstanceKlass;
+
+private:
+
+  // Constructor
+  ValueKlass(const ClassFileParser& parser)
+    : InstanceKlass(parser, InstanceKlass::_misc_kind_value_type) { }
+
+  // static Klass* array_klass_impl(InstanceKlass* this_k, bool or_null, int n, TRAPS);
+ protected:
+  // Returns the array class for the n'th dimension
+  Klass* array_klass_impl(bool or_null, int n, TRAPS);
+
+  // Returns the array class with this class as element type
+  Klass* array_klass_impl(bool or_null, TRAPS);
+
+ public:
+  // Type testing
+  bool is_value_slow() const        { return true; }
+
+  // Casting from Klass*
+  static ValueKlass* cast(Klass* k) {
+    assert(k->is_value(), "cast to ValueKlass");
+    return (ValueKlass*) k;
+  }
+
+  // Use this to return the size of an instance in heap words
+  // Implementation is currently simple because all value types are allocated
+  // in Java heap like Java objects.
+  virtual int size_helper() const {
+    return layout_helper_to_size_helper(layout_helper());
+  }
+
+  // minimum number of bytes occupied by nonstatic fields, HeapWord aligned or pow2
+  int raw_value_byte_size() const;
+
+  int first_field_offset() const;
+
+  address data_for_oop(oop o) const {
+    return ((address) (void*) o) + first_field_offset();
+  }
+
+   oop oop_for_data(address data) const {
+    oop o = (oop) (data - first_field_offset());
+    assert(o->is_oop(false), "Not an oop");
+    return o;
+  }
+
+  // Query if h/w provides atomic load/store
+  bool is_atomic();
+
+  bool flatten_array();
+
+  bool contains_oops() const { return nonstatic_oop_map_count() > 0; }
+  int nonstatic_oop_count();
+
+  // Prototype general store methods...
+
+  // copy the fields, with no concern for GC barriers
+  void raw_field_copy(void* src, void* dst, size_t raw_byte_size);
+
+  void value_store(void* src, void* dst, bool dst_is_heap, bool dst_uninitialized) {
+    value_store(src, dst, nonstatic_field_size() << LogBytesPerHeapOop, dst_is_heap, dst_uninitialized);
+  }
+
+  // store the value of this klass contained with src into dst, raw data ptr
+  void value_store(void* src, void* dst, size_t raw_byte_size, bool dst_is_heap, bool dst_uninitialized);
+
+
+  oop derive_value_type_copy(Handle src, InstanceKlass* target_klass, TRAPS);
+
+  // GC support...
+
+  // oop iterate raw value type data pointer (where oop_addr may not be an oop, but backing/array-element)
+  template <bool nv, typename T, class OopClosureType>
+  inline void oop_iterate_specialized(const address oop_addr, OopClosureType* closure);
+
+  template <bool nv, typename T, class OopClosureType>
+  inline void oop_iterate_specialized_bounded(const address oop_addr, OopClosureType* closure, void* lo, void* hi);
+
+};
+
+#endif /* SHARE_VM_OOPS_VALUEKLASS_HPP */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/oops/valueKlass.inline.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_OOPS_VALUEKLASS_INLINE_HPP
+#define SHARE_VM_OOPS_VALUEKLASS_INLINE_HPP
+
+#include "memory/memRegion.hpp"
+#include "memory/iterator.inline.hpp"
+#include "oops/klass.hpp"
+#include "oops/valueArrayKlass.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
+#include "utilities/macros.hpp"
+
+template <bool nv, typename T, class OopClosureType>
+void ValueKlass::oop_iterate_specialized(const address oop_addr, OopClosureType* closure) {
+  OopMapBlock* map = start_of_nonstatic_oop_maps();
+  OopMapBlock* const end_map = map + nonstatic_oop_map_count();
+
+  for (; map < end_map; map++) {
+    T* p = (T*) (oop_addr + map->offset());
+    T* const end = p + map->count();
+    for (; p < end; ++p) {
+      Devirtualizer<nv>::do_oop(closure, p);
+    }
+  }
+}
+
+template <bool nv, typename T, class OopClosureType>
+inline void ValueKlass::oop_iterate_specialized_bounded(const address oop_addr, OopClosureType* closure, void* lo, void* hi) {
+  OopMapBlock* map = start_of_nonstatic_oop_maps();
+  OopMapBlock* const end_map = map + nonstatic_oop_map_count();
+
+  T* const l   = (T*) lo;
+  T* const h   = (T*) hi;
+
+  for (; map < end_map; map++) {
+    T* p = (T*) (oop_addr + map->offset());
+    T* end = p + map->count();
+    if (p < l) {
+      p = l;
+    }
+    if (end > h) {
+      end = h;
+    }
+    for (; p < end; ++p) {
+      Devirtualizer<nv>::do_oop(closure, p);
+    }
+  }
+}
+
+
+#endif // SHARE_VM_OOPS_VALUEKLASS_INLINE_HPP
--- a/src/share/vm/prims/jni.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/prims/jni.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -882,6 +882,7 @@
   virtual void get_float  () = 0;
   virtual void get_double () = 0;
   virtual void get_object () = 0;
+  virtual void get_valuetype() = 0;
 
   JNI_ArgumentPusher(Symbol* signature) : SignatureIterator(signature) {
     this->_return_type = T_ILLEGAL;
@@ -902,6 +903,7 @@
   inline void do_float()                    { if (!is_return_type()) get_float();  }
   inline void do_double()                   { if (!is_return_type()) get_double(); }
   inline void do_object(int begin, int end) { if (!is_return_type()) get_object(); }
+  inline void do_valuetype(int begin, int end) { if (!is_return_type()) get_valuetype();  }
   inline void do_array(int begin, int end)  { if (!is_return_type()) get_object(); } // do_array uses get_object -- there is no get_array
   inline void do_void()                     { }
 
@@ -934,6 +936,8 @@
   inline void get_double() { _arguments->push_double(va_arg(_ap, jdouble)); }
   inline void get_object() { jobject l = va_arg(_ap, jobject);
                              _arguments->push_oop(Handle((oop *)l, false)); }
+  inline void get_valuetype() { jobject l = va_arg(_ap, jobject);
+                                _arguments->push_oop(Handle((oop *)l, false)); }
 
   inline void set_ap(va_list rap) {
     va_copy(_ap, rap);
@@ -979,6 +983,9 @@
           case obj_parm:
             get_object();
             break;
+          case valuetype_parm:
+            get_valuetype();
+            break;
           case long_parm:
             get_long();
             break;
@@ -1023,6 +1030,8 @@
   inline void get_float()  { _arguments->push_float((_ap++)->f); }
   inline void get_double() { _arguments->push_double((_ap++)->d);}
   inline void get_object() { _arguments->push_oop(Handle((oop *)(_ap++)->l, false)); }
+  // value types are implemented with oops too
+  inline void get_valuetype() { _arguments->push_oop(Handle((oop *)(_ap++)->l, false)); }
 
   inline void set_ap(const jvalue *rap) { _ap = rap; }
 
@@ -1065,6 +1074,9 @@
           case obj_parm:
             get_object();
             break;
+          case valuetype_parm:
+            get_valuetype();
+            break;
           case long_parm:
             get_long();
             break;
--- a/src/share/vm/prims/jni.h	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/prims/jni.h	Wed Apr 26 13:37:50 2017 -0400
@@ -64,6 +64,7 @@
 
 #ifdef __cplusplus
 
+class _jvaluetype {};
 class _jobject {};
 class _jclass : public _jobject {};
 class _jthrowable : public _jobject {};
@@ -79,6 +80,7 @@
 class _jdoubleArray : public _jarray {};
 class _jobjectArray : public _jarray {};
 
+typedef _jvaluetype *jvaluetype;
 typedef _jobject *jobject;
 typedef _jclass *jclass;
 typedef _jthrowable *jthrowable;
@@ -127,6 +129,7 @@
     jfloat   f;
     jdouble  d;
     jobject  l;
+    jvaluetype q;
 } jvalue;
 
 struct _jfieldID;
--- a/src/share/vm/prims/jvm.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/prims/jvm.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -46,6 +46,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueArrayKlass.hpp"
 #include "prims/jvm.h"
 #include "prims/jvm_misc.hpp"
 #include "prims/jvmtiExport.hpp"
@@ -2270,6 +2271,48 @@
   return JNIHandles::make_local(env, asd);
 JVM_END
 
+// Arrays support /////////////////////////////////////////////////////////////
+
+JVM_ENTRY(jboolean, JVM_ArrayIsAccessAtomic(JNIEnv *env, jclass unused, jobject array))
+  JVMWrapper("JVM_ArrayIsAccessAtomic");
+  oop o = JNIHandles::resolve(array);
+  Klass* k = o->klass();
+  if ((o == NULL) || (!k->is_array_klass())) {
+    THROW_0(vmSymbols::java_lang_IllegalArgumentException());
+  }
+  if (k->is_valueArray_klass()) {
+    return ValueArrayKlass::cast(k)->is_atomic();
+  }
+  return true;
+JVM_END
+
+JVM_ENTRY(jobject, JVM_ArrayEnsureAccessAtomic(JNIEnv *env, jclass unused, jobject array))
+  JVMWrapper("JVM_ArrayEnsureAccessAtomic");
+  oop o = JNIHandles::resolve(array);
+  Klass* k = o->klass();
+  if ((o == NULL) || (!k->is_array_klass())) {
+    THROW_0(vmSymbols::java_lang_IllegalArgumentException());
+  }
+  if (k->is_valueArray_klass()) {
+    ValueArrayKlass* vk = ValueArrayKlass::cast(k);
+    if (!vk->is_atomic()) {
+      /**
+       * Need to decide how to implement:
+       *
+       * 1) Change to objArrayOop layout, therefore oop->klass() differs so
+       * then "<atomic>[Qfoo;" klass needs to subclass "[Qfoo;" to pass through
+       * "checkcast" & "instanceof"
+       *
+       * 2) Use extra header in the valueArrayOop to flag atomicity required and
+       * possibly per instance lock structure. Said info, could be placed in
+       * "trailer" rather than disturb the current arrayOop
+       */
+      Unimplemented();
+    }
+  }
+  return array;
+JVM_END
+
 // Verification ////////////////////////////////////////////////////////////////////////////////
 
 // Reflection for the verifier /////////////////////////////////////////////////////////////////
--- a/src/share/vm/prims/jvm.h	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/prims/jvm.h	Wed Apr 26 13:37:50 2017 -0400
@@ -663,6 +663,22 @@
 JVM_AssertionStatusDirectives(JNIEnv *env, jclass unused);
 
 /*
+  * java.util.Arrays
+  */
+
+ /*
+  * Query whether access to the given array is atomic
+  */
+ JNIEXPORT jboolean JNICALL
+ JVM_ArrayIsAccessAtomic(JNIEnv *env, jclass unused, jobject array);
+
+ /*
+  * Return an array whose loads and stores will always be atomic
+  */
+ JNIEXPORT jobject JNICALL
+ JVM_ArrayEnsureAccessAtomic(JNIEnv *env, jclass unused, jobject array);
+
+/*
  * java.util.concurrent.atomic.AtomicLong
  */
 JNIEXPORT jboolean JNICALL
@@ -972,6 +988,7 @@
 #define JVM_ACC_TRANSIENT     0x0080  /* not persistent */
 #define JVM_ACC_VARARGS       0x0080  /* method declared with variable number of args */
 #define JVM_ACC_NATIVE        0x0100  /* implemented in C */
+#define JVM_ACC_VALUE         0x0100  /* value type class */
 #define JVM_ACC_INTERFACE     0x0200  /* class is an interface */
 #define JVM_ACC_ABSTRACT      0x0400  /* no definition provided */
 #define JVM_ACC_STRICT        0x0800  /* strict floating point */
@@ -1050,6 +1067,7 @@
 #define JVM_SIGNATURE_BYTE              'B'
 #define JVM_SIGNATURE_CHAR              'C'
 #define JVM_SIGNATURE_CLASS             'L'
+#define JVM_SIGNATURE_VALUE_CLASS       'Q'
 #define JVM_SIGNATURE_ENDCLASS          ';'
 #define JVM_SIGNATURE_ENUM              'E'
 #define JVM_SIGNATURE_FLOAT             'F'
@@ -1134,7 +1152,8 @@
                                         JVM_ACC_ABSTRACT | \
                                         JVM_ACC_ANNOTATION | \
                                         JVM_ACC_ENUM | \
-                                        JVM_ACC_SYNTHETIC)
+                                        JVM_ACC_SYNTHETIC | \
+                                        JVM_ACC_VALUE)
 
 #define JVM_RECOGNIZED_FIELD_MODIFIERS (JVM_ACC_PUBLIC | \
                                         JVM_ACC_PRIVATE | \
--- a/src/share/vm/prims/whitebox.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/prims/whitebox.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -43,6 +43,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/objArrayOop.inline.hpp"
 #include "prims/wbtestmethods/parserTests.hpp"
 #include "prims/whitebox.hpp"
 #include "runtime/arguments.hpp"
@@ -1580,6 +1581,100 @@
   return ConstantPool::encode_invokedynamic_index(index);
 WB_END
 
+WB_ENTRY(jobjectArray, WB_getObjectsViaKlassOopMaps(JNIEnv* env, jobject wb, jobject thing))
+  oop aoop = JNIHandles::resolve(thing);
+  if (!aoop->is_instance()) {
+    return NULL;
+  }
+  instanceHandle ih(THREAD, (instanceOop) aoop);
+  InstanceKlass* klass = InstanceKlass::cast(aoop->klass());
+  if (klass->nonstatic_oop_map_count() == 0) {
+    return NULL;
+  }
+  const OopMapBlock* map = klass->start_of_nonstatic_oop_maps();
+  const OopMapBlock* const end = map + klass->nonstatic_oop_map_count();
+  int oop_count = 0;
+  while (map < end) {
+    oop_count += map->count();
+    map++;
+  }
+
+  objArrayOop result_array =
+      oopFactory::new_objArray(SystemDictionary::Object_klass(), oop_count, CHECK_NULL);
+  map = klass->start_of_nonstatic_oop_maps();
+  instanceOop ioop = ih();
+  int index = 0;
+  while (map < end) {
+    int offset = map->offset();
+    for (unsigned int j = 0; j < map->count(); j++) {
+      result_array->obj_at_put(index++, ioop->obj_field(offset));
+      offset += heapOopSize;
+    }
+    map++;
+  }
+  return (jobjectArray)JNIHandles::make_local(env, result_array);
+WB_END
+
+class CollectOops : public OopClosure {
+ public:
+  GrowableArray<Handle>* array;
+
+  objArrayOop create_results(TRAPS) {
+    objArrayOop result_array =
+        oopFactory::new_objArray(SystemDictionary::Object_klass(), array->length(), CHECK_NULL);
+    for (int i = 0 ; i < array->length(); i++) {
+      result_array->obj_at_put(i, array->at(i)());
+    }
+    return result_array;
+  }
+
+  jobjectArray create_jni_result(JNIEnv* env, TRAPS) {
+    return (jobjectArray)JNIHandles::make_local(env, create_results(THREAD));
+  }
+
+  void add_oop(oop o) {
+    // Value might be oop, but JLS can't see as Object, just iterate through it...
+    if (o != NULL && o->is_value()) {
+      NoHeaderExtendedOopClosure wrapClosure(this);
+      o->oop_iterate(&wrapClosure);
+    } else {
+      array->append(Handle(Thread::current(), o));
+    }
+  }
+
+  void do_oop(oop* o) { add_oop(*o); }
+  void do_oop(narrowOop* v) { add_oop(oopDesc::load_decode_heap_oop(v)); }
+};
+
+
+WB_ENTRY(jobjectArray, WB_getObjectsViaOopIterator(JNIEnv* env, jobject wb, jobject thing))
+  ResourceMark rm(THREAD);
+  GrowableArray<Handle>* array = new GrowableArray<Handle>(128);
+  CollectOops collectOops;
+  collectOops.array = array;
+
+  NoHeaderExtendedOopClosure wrapClosure(&collectOops);
+  JNIHandles::resolve(thing)->oop_iterate(&wrapClosure);
+
+  return collectOops.create_jni_result(env, THREAD);
+WB_END
+
+WB_ENTRY(jobjectArray, WB_getObjectsViaFrameOopIterator(JNIEnv* env, jobject wb, jint depth))
+  ResourceMark rm(THREAD);
+  GrowableArray<Handle>* array = new GrowableArray<Handle>(128);
+  CollectOops collectOops;
+  collectOops.array = array;
+  StackFrameStream sfs(thread);
+  while (depth > 0) { // Skip the native WB API frame
+    sfs.next();
+    frame* f = sfs.current();
+    f->oops_do(&collectOops, NULL, sfs.register_map());
+    depth--;
+  }
+  return collectOops.create_jni_result(env, THREAD);
+WB_END
+
+
 WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb, jboolean preserve_static_stubs))
   VM_ClearICs clear_ics(preserve_static_stubs == JNI_TRUE);
   VMThread::execute(&clear_ics);
--- a/src/share/vm/runtime/arguments.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/arguments.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -2511,6 +2511,16 @@
     FLAG_SET_CMDLINE(bool, PostLoopMultiversioning, false);
   }
 #endif
+
+  if (LP64_ONLY(false &&) !FLAG_IS_DEFAULT(ValueTypePassFieldsAsArgs)) {
+    FLAG_SET_CMDLINE(bool, ValueTypePassFieldsAsArgs, false);
+    warning("ValueTypePassFieldsAsArgs is not supported on this platform");
+  }
+
+  if (FLAG_IS_DEFAULT(TieredCompilation)) {
+    // C1 has no support for value types
+    TieredCompilation = false;
+  }
   return status;
 }
 
--- a/src/share/vm/runtime/fieldDescriptor.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/fieldDescriptor.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -31,6 +31,7 @@
 #include "oops/instanceKlass.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/fieldStreams.hpp"
+#include "oops/valueKlass.hpp"
 #include "runtime/fieldDescriptor.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/signature.hpp"
@@ -146,8 +147,10 @@
 }
 
 void fieldDescriptor::print_on_for(outputStream* st, oop obj) {
-  print_on(st);
   BasicType ft = field_type();
+  if (ft != T_VALUETYPE) {
+    print_on(st);
+  }
   jint as_int = 0;
   switch (ft) {
     case T_BYTE:
@@ -195,6 +198,26 @@
       NOT_LP64(as_int = obj->int_field(offset()));
       obj->obj_field(offset())->print_value_on(st);
       break;
+    case T_VALUETYPE:
+      {
+        // Resolve klass of flattened value type field
+        Thread* THREAD = Thread::current();
+        ResourceMark rm(THREAD);
+        SignatureStream ss(signature(), false);
+        Klass* k = ss.as_klass(Handle(THREAD, field_holder()->class_loader()),
+            Handle(THREAD, field_holder()->protection_domain()),
+            SignatureStream::ReturnNull, THREAD);
+        assert(k != NULL && !HAS_PENDING_EXCEPTION, "can resolve klass?");
+        ValueKlass* vk = ValueKlass::cast(k);
+        int field_offset = offset() - vk->first_field_offset();
+        obj = (oop)((address)obj + field_offset);
+        // Print flattened fields of the value type field
+        st->print_cr("Flattened value type '%s':", vk->name()->as_C_string());
+        FieldPrinter print_field(st, obj);
+        vk->do_nonstatic_fields(&print_field);
+        return; // Do not print underlying representation
+        break;
+      }
     default:
       ShouldNotReachHere();
       break;
@@ -206,6 +229,7 @@
   } else if (as_int < 0 || as_int > 9) {
     st->print(" (%x)", as_int);
   }
+  st->cr();
 }
 
 #endif /* PRODUCT */
--- a/src/share/vm/runtime/fieldType.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/fieldType.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -66,7 +66,8 @@
       // If it is an array, the type is the last character
       return (i + 1 == len);
     case 'L':
-      // If it is an object, the last character must be a ';'
+    case 'Q':
+      // If it is an object or a value type, the last character must be a ';'
       return sig->byte_at(len - 1) == ';';
   }
 
@@ -87,7 +88,7 @@
   ResourceMark rm;
   char *element = signature->as_C_string() + index;
   BasicType element_type = char2type(element[0]);
-  if (element_type == T_OBJECT) {
+  if (element_type == T_OBJECT || element_type == T_VALUETYPE) {
     int len = (int)strlen(element);
     assert(element[len-1] == ';', "last char should be a semicolon");
     element[len-1] = '\0';        // chop off semicolon
--- a/src/share/vm/runtime/fieldType.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/fieldType.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -69,6 +69,14 @@
              (signature->byte_at(sig_length - 1) == ';'));
   }
 
+  static bool is_valuetype(Symbol* signature) {
+    int sig_length = signature->utf8_length();
+    // Must start with 'Q' and end with ';'
+    return (sig_length >= 2 &&
+        (signature->byte_at(0) == 'Q') &&
+        (signature->byte_at(sig_length - 1) == ';'));
+  }
+
   // Parse field and extract array information. Works for T_ARRAY only.
   static BasicType get_array_info(Symbol* signature, FieldArrayInfo& ai, TRAPS);
 };
--- a/src/share/vm/runtime/frame.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/frame.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -795,7 +795,7 @@
 
   void set(int size, BasicType type) {
     _offset -= size;
-    if (type == T_OBJECT || type == T_ARRAY) oop_offset_do();
+    if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) oop_offset_do();
   }
 
   void oop_offset_do() {
@@ -848,7 +848,7 @@
 
   void set(int size, BasicType type) {
     assert (_offset >= 0, "illegal offset");
-    if (type == T_OBJECT || type == T_ARRAY) oop_at_offset_do(_offset);
+    if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) oop_at_offset_do(_offset);
     _offset -= size;
   }
 
@@ -999,7 +999,7 @@
   VMRegPair*      _regs;        // VMReg list of arguments
 
   void set(int size, BasicType type) {
-    if (type == T_OBJECT || type == T_ARRAY) handle_oop_offset();
+    if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) handle_oop_offset();
     _offset += size;
   }
 
--- a/src/share/vm/runtime/globals.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/globals.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -1279,6 +1279,24 @@
   notproduct(bool, PrintFieldLayout, false,                                 \
           "Print field layout for each class")                              \
                                                                             \
+  notproduct(bool, PrintValueLayout, false,                                 \
+          "Print field layout for each value type")                         \
+                                                                            \
+  notproduct(bool, PrintValueArrayLayout, false,                            \
+          "Print array layout for each value type array")                   \
+                                                                            \
+  product(bool, ValueArrayFlatten, true,                                    \
+          "Flatten value array elements, if possible")                      \
+                                                                            \
+  product(intx, ValueArrayElemMaxFlatSize, -1,                              \
+          "Max size for flattening value array elements, <0 no limit")      \
+                                                                            \
+  product(intx, ValueArrayElemMaxFlatOops, 4,                               \
+          "Max nof embedded object references in a value type to flatten, <0 no limit")  \
+                                                                            \
+  product(bool, ValueArrayAtomicAccess, false,                              \
+          "Atomic value array accesses by-default, for all value arrays")   \
+                                                                            \
   /* Need to limit the extent of the padding to reasonable size.          */\
   /* 8K is well beyond the reasonable HW cache line size, even with       */\
   /* aggressive prefetching, while still leaving the room for segregating */\
@@ -4020,6 +4038,14 @@
   experimental(bool, AlwaysAtomicAccesses, false,                           \
           "Accesses to all variables should always be atomic")              \
                                                                             \
+  /* Valhalla prototyping */                                                \
+  product(bool, ValhallaMVT1_0, true,                                       \
+          "Enable DeriveValueType annotated classes to be rewritten")       \
+                                                                            \
+  develop_pd(bool, ValueTypePassFieldsAsArgs,                               \
+             "Pass each field as an argument at calls")                     \
+                                                                            \
+                                                                            \
   product(bool, EnableTracing, false,                                       \
           "Enable event-based tracing")                                     \
                                                                             \
@@ -4059,7 +4085,13 @@
   diagnostic(bool, CompilerDirectivesPrint, false,                          \
              "Print compiler directives on installation.")                  \
   diagnostic(int,  CompilerDirectivesLimit, 50,                             \
-             "Limit on number of compiler directives.")
+             "Limit on number of compiler directives.")                     \
+                                                                            \
+  product(bool, EnableValhalla, false,                                      \
+             "Enable experimental Valhalla features")                       \
+                                                                            \
+  product(bool, EnableMVT, false,                                           \
+             "Enable experimental Minimal Value Types")                     \
 
 
 /*
--- a/src/share/vm/runtime/handles.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/handles.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -28,6 +28,7 @@
 #include "oops/oop.hpp"
 #include "oops/oopsHierarchy.hpp"
 
+class ValueKlass;
 class InstanceKlass;
 class Klass;
 
@@ -121,6 +122,7 @@
 DEF_HANDLE(array            , is_array_noinline            )
 DEF_HANDLE(objArray         , is_objArray_noinline         )
 DEF_HANDLE(typeArray        , is_typeArray_noinline        )
+DEF_HANDLE(valueArray       , is_valueArray_noinline       )
 
 //------------------------------------------------------------------------------------------------------------------------
 
--- a/src/share/vm/runtime/javaCalls.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/javaCalls.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -545,6 +545,7 @@
   void do_long()                       { check_long(T_LONG);         }
   void do_void()                       { check_return_type(T_VOID);  }
   void do_object(int begin, int end)   { check_obj(T_OBJECT);        }
+  void do_valuetype(int begin, int end){ check_obj(T_VALUETYPE);     }
   void do_array(int begin, int end)    { check_obj(T_OBJECT);        }
 };
 
--- a/src/share/vm/runtime/reflection.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/reflection.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -335,7 +335,7 @@
     if (k->is_array_klass() && ArrayKlass::cast(k)->dimension() >= MAX_DIM) {
       THROW_0(vmSymbols::java_lang_IllegalArgumentException());
     }
-    return oopFactory::new_objArray(k, length, THREAD);
+    return oopFactory::new_array(k, length, THREAD);
   }
 }
 
@@ -751,7 +751,7 @@
                                      TRAPS) {
 
 
-  if (T_OBJECT == ss->type() || T_ARRAY == ss->type()) {
+  if (T_OBJECT == ss->type() || T_ARRAY == ss->type() || T_VALUETYPE == ss->type()) {
     Symbol* name = ss->as_symbol(CHECK_NULL);
     oop loader = method->method_holder()->class_loader();
     oop protection_domain = method->method_holder()->protection_domain();
--- a/src/share/vm/runtime/sharedRuntime.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -2297,6 +2297,7 @@
 
       case T_OBJECT:
       case T_ARRAY:
+      case T_VALUETYPE:
         // In other words, we assume that any register good enough for
         // an int or long is good enough for a managed pointer.
 #ifdef _LP64
--- a/src/share/vm/runtime/signature.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/signature.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -40,7 +40,7 @@
 // Signature  = "(" {Parameter} ")" ReturnType.
 // Parameter  = FieldType.
 // ReturnType = FieldType | "V".
-// FieldType  = "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z" | "L" ClassName ";" | "[" FieldType.
+// FieldType  = "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z" | "L" ClassName ";" | "Q" ValueTypeName ";" | "[" FieldType.
 // ClassName  = string.
 
 
@@ -97,6 +97,15 @@
       if (_parameter_index < 0 ) _return_type = T_OBJECT;
       size = T_OBJECT_size;
       break;
+    case 'Q':
+      { int begin = ++_index;
+        Symbol* sig = _signature;
+        while (sig->byte_at(_index++) != ';') ;
+        do_valuetype(begin, _index);
+      }
+      if (_parameter_index < 0 ) _return_type = T_VALUETYPE;
+      size = T_VALUETYPE_size;
+      break;
     case '[':
       { int begin = ++_index;
         skip_optional_size();
@@ -105,7 +114,7 @@
           _index++;
           skip_optional_size();
         }
-        if (sig->byte_at(_index) == 'L') {
+        if (sig->byte_at(_index) == 'L' || sig->byte_at(_index) == 'Q') {
           while (sig->byte_at(_index++) != ';') ;
         } else {
           _index++;
@@ -192,6 +201,10 @@
         do_object(0, 0);
         _parameter_index += T_OBJECT_size;
         break;
+      case valuetype_parm:
+        do_valuetype(0,0);
+        _parameter_index += T_VALUETYPE_size;
+        break;
       case long_parm:
         do_long();
         _parameter_index += T_LONG_size;
@@ -242,6 +255,7 @@
           _index++;
         }
         break;
+      case 'Q':
       case 'L':
         {
           while (sig->byte_at(_index++) != ';') ;
@@ -319,6 +333,12 @@
       while (sig->byte_at(_end++) != ';');
       break;
     }
+    case 'Q': {
+      _type = T_VALUETYPE;
+      Symbol* sig = _signature;
+      while (sig->byte_at(_end++) != ';');
+      break;
+    }
     case '[': {
       _type = T_ARRAY;
       Symbol* sig = _signature;
@@ -353,7 +373,8 @@
 
 bool SignatureStream::is_object() const {
   return _type == T_OBJECT
-      || _type == T_ARRAY;
+      || _type == T_ARRAY
+      || _type == T_VALUETYPE;
 }
 
 bool SignatureStream::is_array() const {
@@ -365,7 +386,7 @@
   int begin = _begin;
   int end   = _end;
 
-  if (   _signature->byte_at(_begin) == 'L'
+  if ( ( _signature->byte_at(_begin) == 'L' || _signature->byte_at(_begin) == 'Q' )
       && _signature->byte_at(_end-1) == ';') {
     begin++;
     end--;
@@ -406,7 +427,7 @@
   int begin = _begin;
   int end   = _end;
 
-  if (   _signature->byte_at(_begin) == 'L'
+  if ( ( _signature->byte_at(_begin) == 'L' || _signature->byte_at(_begin) == 'Q' )
       && _signature->byte_at(_end-1) == ';') {
     begin++;
     end--;
@@ -487,6 +508,7 @@
     case 'B': case 'C': case 'D': case 'F': case 'I':
     case 'J': case 'S': case 'Z': case 'V':
       return index + 1;
+    case 'Q':
     case 'L':
       for (index = index + 1; index < limit; ++index) {
         char c = type[index];
--- a/src/share/vm/runtime/signature.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/runtime/signature.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -78,7 +78,8 @@
       float_parm           = 7,
       double_parm          = 8,
       obj_parm             = 9,
-      done_parm            = 10,  // marker for end of parameters
+      valuetype_parm       = 10,
+      done_parm            = 11,  // marker for end of parameters
 
     // max parameters is wordsize minus
     //    The sign bit, termination field, the result and static bit fields
@@ -115,6 +116,7 @@
   // Object types (begin indexes the first character of the entry, end indexes the first character after the entry)
   virtual void do_object(int begin, int end) = 0;
   virtual void do_array (int begin, int end) = 0;
+  virtual void do_valuetype(int begin, int end) = 0;
 
   static bool is_static(uint64_t fingerprint) {
     assert(fingerprint != (uint64_t)CONST64(-1), "invalid fingerprint");
@@ -144,6 +146,7 @@
   void do_void()                       { type_name("void"    ); }
   void do_object(int begin, int end)   { type_name("jobject" ); }
   void do_array (int begin, int end)   { type_name("jobject" ); }
+  void do_valuetype(int begin, int end){ type_name("jvaluetype"); }
 
  public:
   SignatureTypeNames(Symbol* signature) : SignatureIterator(signature) {}
@@ -172,6 +175,7 @@
   void do_void  ()                     { set(T_VOID_size   , T_VOID   ); }
   void do_object(int begin, int end)   { set(T_OBJECT_size , T_OBJECT ); }
   void do_array (int begin, int end)   { set(T_ARRAY_size  , T_ARRAY  ); }
+  void do_valuetype(int begin, int end){ set(T_VALUETYPE_size, T_VALUETYPE); }
 
  public:
   SignatureInfo(Symbol* signature) : SignatureIterator(signature) {
@@ -238,6 +242,7 @@
 
   void do_object(int begin, int end)  { _fingerprint |= (((uint64_t)obj_parm) << _shift_count); _shift_count += parameter_feature_size; }
   void do_array (int begin, int end)  { _fingerprint |= (((uint64_t)obj_parm) << _shift_count); _shift_count += parameter_feature_size; }
+  void do_valuetype(int begin, int end) { _fingerprint |= (((uint64_t)valuetype_parm) << _shift_count); _shift_count += parameter_feature_size; }
 
   void do_void()    { ShouldNotReachHere(); }
 
@@ -302,6 +307,7 @@
   void do_void  ()                     { ShouldNotReachHere();                               }
   void do_object(int begin, int end)   { pass_object(); _jni_offset++; _offset++;        }
   void do_array (int begin, int end)   { pass_object(); _jni_offset++; _offset++;        }
+  void do_valuetype(int begin, int end){ pass_valuetype();  _jni_offset++; _offset++;        }
 
  public:
   methodHandle method() const          { return _method; }
@@ -312,6 +318,7 @@
   virtual void pass_int()              = 0;
   virtual void pass_long()             = 0;
   virtual void pass_object()           = 0;
+  virtual void pass_valuetype()        = 0;
   virtual void pass_float()            = 0;
 #ifdef _LP64
   virtual void pass_double()           = 0;
--- a/src/share/vm/utilities/accessFlags.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/utilities/accessFlags.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -119,6 +119,7 @@
   bool is_interface   () const         { return (_flags & JVM_ACC_INTERFACE   ) != 0; }
   bool is_abstract    () const         { return (_flags & JVM_ACC_ABSTRACT    ) != 0; }
   bool is_strict      () const         { return (_flags & JVM_ACC_STRICT      ) != 0; }
+  bool is_value_type  () const         { return (_flags & JVM_ACC_VALUE       ) != 0; }
 
   // Attribute flags
   bool is_synthetic   () const         { return (_flags & JVM_ACC_SYNTHETIC   ) != 0; }
--- a/src/share/vm/utilities/exceptions.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/utilities/exceptions.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -232,6 +232,8 @@
 // with a TRAPS argument.
 
 #define THREAD_AND_LOCATION                      THREAD, __FILE__, __LINE__
+#define THREAD_AND_LOCATION_DECL                 TRAPS, const char* file, int line
+#define THREAD_AND_LOCATION_ARGS                 THREAD, file, line
 
 #define THROW_OOP(e)                                \
   { Exceptions::_throw_oop(THREAD_AND_LOCATION, e);                             return;  }
--- a/src/share/vm/utilities/globalDefinitions.cpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/utilities/globalDefinitions.cpp	Wed Apr 26 13:37:50 2017 -0400
@@ -94,7 +94,7 @@
       num_type_chars++;
     }
   }
-  assert(num_type_chars == 11, "must have tested the right number of mappings");
+  assert(num_type_chars == 12, "must have tested the right number of mappings");
   assert(char2type(0) == T_ILLEGAL, "correct illegality");
 
   {
@@ -112,6 +112,7 @@
       case T_DOUBLE:
       case T_LONG:
       case T_OBJECT:
+      case T_VALUETYPE:
       case T_ADDRESS:     // random raw pointer
       case T_METADATA:    // metadata pointer
       case T_NARROWOOP:   // compressed pointer
@@ -177,11 +178,12 @@
   }
   _type2aelembytes[T_OBJECT] = heapOopSize;
   _type2aelembytes[T_ARRAY]  = heapOopSize;
+  _type2aelembytes[T_VALUETYPE] = heapOopSize;
 }
 
 
 // Map BasicType to signature character
-char type2char_tab[T_CONFLICT+1]={ 0, 0, 0, 0, 'Z', 'C', 'F', 'D', 'B', 'S', 'I', 'J', 'L', '[', 'V', 0, 0, 0, 0, 0};
+char type2char_tab[T_CONFLICT+1]={ 0, 0, 0, 0, 'Z', 'C', 'F', 'D', 'B', 'S', 'I', 'J', 'L', '[', 'Q', 'V', 0, 0, 0, 0, 0};
 
 // Map BasicType to Java type name
 const char* type2name_tab[T_CONFLICT+1] = {
@@ -196,6 +198,7 @@
   "long",
   "object",
   "array",
+  "valuetype",
   "void",
   "*address*",
   "*narrowoop*",
@@ -215,7 +218,7 @@
 }
 
 // Map BasicType to size in words
-int type2size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 1, -1};
+int type2size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 0, 1, 1, 1, 1, -1};
 
 BasicType type2field[T_CONFLICT+1] = {
   (BasicType)0,            // 0,
@@ -232,12 +235,13 @@
   T_LONG,                  // T_LONG     = 11,
   T_OBJECT,                // T_OBJECT   = 12,
   T_OBJECT,                // T_ARRAY    = 13,
-  T_VOID,                  // T_VOID     = 14,
-  T_ADDRESS,               // T_ADDRESS  = 15,
-  T_NARROWOOP,             // T_NARROWOOP= 16,
-  T_METADATA,              // T_METADATA = 17,
-  T_NARROWKLASS,           // T_NARROWKLASS = 18,
-  T_CONFLICT               // T_CONFLICT = 19,
+  T_VALUETYPE,             // T_VALUETYPE = 14
+  T_VOID,                  // T_VOID     = 15,
+  T_ADDRESS,               // T_ADDRESS  = 16,
+  T_NARROWOOP,             // T_NARROWOOP= 17,
+  T_METADATA,              // T_METADATA = 18,
+  T_NARROWKLASS,           // T_NARROWKLASS = 19,
+  T_CONFLICT               // T_CONFLICT = 20,
 };
 
 
@@ -256,12 +260,13 @@
   T_LONG,    // T_LONG     = 11,
   T_OBJECT,  // T_OBJECT   = 12,
   T_OBJECT,  // T_ARRAY    = 13,
-  T_VOID,    // T_VOID     = 14,
-  T_ADDRESS, // T_ADDRESS  = 15,
-  T_NARROWOOP, // T_NARROWOOP  = 16,
-  T_METADATA,  // T_METADATA   = 17,
-  T_NARROWKLASS, // T_NARROWKLASS  = 18,
-  T_CONFLICT // T_CONFLICT = 19,
+  T_VALUETYPE, // T_VALUETYPE =14
+  T_VOID,    // T_VOID     = 15,
+  T_ADDRESS, // T_ADDRESS  = 16,
+  T_NARROWOOP, // T_NARROWOOP  = 17,
+  T_METADATA,  // T_METADATA   = 18,
+  T_NARROWKLASS, // T_NARROWKLASS  = 19,
+  T_CONFLICT // T_CONFLICT = 20,
 };
 
 
@@ -280,12 +285,13 @@
   T_LONG_aelem_bytes,        // T_LONG     = 11,
   T_OBJECT_aelem_bytes,      // T_OBJECT   = 12,
   T_ARRAY_aelem_bytes,       // T_ARRAY    = 13,
-  0,                         // T_VOID     = 14,
-  T_OBJECT_aelem_bytes,      // T_ADDRESS  = 15,
-  T_NARROWOOP_aelem_bytes,   // T_NARROWOOP= 16,
-  T_OBJECT_aelem_bytes,      // T_METADATA = 17,
-  T_NARROWKLASS_aelem_bytes, // T_NARROWKLASS= 18,
-  0                          // T_CONFLICT = 19,
+  T_VALUETYPE_aelem_bytes,   // T_VALUETYPE = 14
+  0,                         // T_VOID     = 15,
+  T_OBJECT_aelem_bytes,      // T_ADDRESS  = 16,
+  T_NARROWOOP_aelem_bytes,   // T_NARROWOOP= 17,
+  T_OBJECT_aelem_bytes,      // T_METADATA = 18,
+  T_NARROWKLASS_aelem_bytes, // T_NARROWKLASS= 19,
+  0                          // T_CONFLICT = 20,
 };
 
 #ifdef ASSERT
--- a/src/share/vm/utilities/globalDefinitions.hpp	Wed Apr 05 22:48:35 2017 +0000
+++ b/src/share/vm/utilities/globalDefinitions.hpp	Wed Apr 26 13:37:50 2017 -0400
@@ -577,6 +577,15 @@
 
 
 //----------------------------------------------------------------------------------------------------
+// Prototyping
+// "Code Missing Here" macro, un-define when integrating back from prototyping stage and break
+// compilation on purpose (i.e. "forget me not")
+#define PROTOTYPE
+#ifdef PROTOTYPE
+#define CMH(m)
+#endif
+
+//----------------------------------------------------------------------------------------------------
 // Miscellaneous
 
 // 6302670 Eliminate Hotspot __fabsf dependency
@@ -653,12 +662,13 @@
   T_LONG        = 11,
   T_OBJECT      = 12,
   T_ARRAY       = 13,
-  T_VOID        = 14,
-  T_ADDRESS     = 15,
-  T_NARROWOOP   = 16,
-  T_METADATA    = 17,
-  T_NARROWKLASS = 18,
-  T_CONFLICT    = 19, // for stack value type with conflicting contents
+  T_VALUETYPE   = 14,
+  T_VOID        = 15,
+  T_ADDRESS     = 16,
+  T_NARROWOOP   = 17,
+  T_METADATA    = 18,
+  T_NARROWKLASS = 19,
+  T_CONFLICT    = 20, // for stack value type with conflicting contents
   T_ILLEGAL     = 99
 };
 
@@ -689,6 +699,7 @@
   case 'V': return T_VOID;
   case 'L': return T_OBJECT;
   case '[': return T_ARRAY;
+  case 'Q':return T_VALUETYPE;
   }
   return T_ILLEGAL;
 }
@@ -719,7 +730,8 @@
   T_ARRAY_size       = 1,
   T_NARROWOOP_size   = 1,
   T_NARROWKLASS_size = 1,
-  T_VOID_size        = 0
+  T_VOID_size        = 0,
+  T_VALUETYPE_size   = 1
 };
 
 
@@ -742,9 +754,11 @@
 #ifdef _LP64
   T_OBJECT_aelem_bytes      = 8,
   T_ARRAY_aelem_bytes       = 8,
+  T_VALUETYPE_aelem_bytes   = 8,
 #else
   T_OBJECT_aelem_bytes      = 4,
   T_ARRAY_aelem_bytes       = 4,
+  T_VALUETYPE_aelem_bytes   = 4,
 #endif
   T_NARROWOOP_aelem_bytes   = 4,
   T_NARROWKLASS_aelem_bytes = 4,
@@ -770,6 +784,7 @@
     jint     i;
     jlong    l;
     jobject  h;
+    jvaluetype q;
   } JavaCallValue;
 
  private:
@@ -840,7 +855,8 @@
   ftos = 6,             // float tos cached
   dtos = 7,             // double tos cached
   atos = 8,             // object cached
-  vtos = 9,             // tos not cached
+  qtos = 9,             // value type cached
+  vtos = 10,             // tos not cached
   number_of_states,
   ilgl                  // illegal state: should not occur
 };
@@ -856,6 +872,7 @@
     case T_LONG   : return ltos;
     case T_FLOAT  : return ftos;
     case T_DOUBLE : return dtos;
+    case T_VALUETYPE : return qtos;
     case T_VOID   : return vtos;
     case T_ARRAY  : // fall through
     case T_OBJECT : return atos;
@@ -874,6 +891,7 @@
     case ftos : return T_FLOAT;
     case dtos : return T_DOUBLE;
     case atos : return T_OBJECT;
+    case qtos : return T_VALUETYPE;
     case vtos : return T_VOID;
   }
   return T_ILLEGAL;
@@ -1159,6 +1177,16 @@
   return log2_intptr(x);
 }
 
+// the argument doesn't need to be a power of two
+inline int upper_log2(intptr_t x) {
+  int shift = log2_intptr(x);
+  intptr_t y = 1 << shift;
+  if (y < x) {
+    shift++;
+  }
+  return shift;
+}
+
 //* the argument must be exactly a power of 2
 inline int exact_log2_long(jlong x) {
   #ifdef ASSERT
--- a/test/TEST.groups	Wed Apr 05 22:48:35 2017 +0000
+++ b/test/TEST.groups	Wed Apr 26 13:37:50 2017 -0400
@@ -31,11 +31,15 @@
   gc
 
 hotspot_runtime = \
-  runtime
+  runtime \
+  -runtime/valhalla
 
 hotspot_serviceability = \
   serviceability
 
+hotspot_valhalla = \
+  runtime/valhalla
+
 hotspot_misc = \
   / \
  -applications \