changeset 13007:b32107cabbcf mvt

Initial commit of MVT prototype
author thartmann
date Wed, 17 May 2017 09:01:40 +0200
parents 63807dc3f4a8
children cbd149ccab1b
files src/cpu/aarch64/vm/globals_aarch64.hpp src/cpu/ppc/vm/globals_ppc.hpp src/cpu/sparc/vm/globals_sparc.hpp 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/sharedRuntime_x86_32.cpp src/cpu/x86/vm/sharedRuntime_x86_64.cpp src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp src/cpu/x86/vm/templateTable_x86.cpp src/cpu/zero/vm/globals_zero.hpp src/share/vm/ci/bcEscapeAnalyzer.cpp src/share/vm/ci/ciArrayKlass.cpp src/share/vm/ci/ciArrayKlass.hpp src/share/vm/ci/ciClassList.hpp src/share/vm/ci/ciConstant.cpp 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/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/code/codeBlob.cpp src/share/vm/code/codeBlob.hpp src/share/vm/compiler/compileBroker.cpp src/share/vm/compiler/methodLiveness.cpp src/share/vm/gc/parallel/psCompactionManager.cpp src/share/vm/gc/parallel/psParallelCompact.cpp src/share/vm/gc/parallel/psPromotionManager.cpp src/share/vm/interpreter/abstractInterpreter.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.cpp 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/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/opto/addnode.cpp src/share/vm/opto/buildOopMap.cpp src/share/vm/opto/callGenerator.cpp src/share/vm/opto/callnode.cpp src/share/vm/opto/callnode.hpp src/share/vm/opto/cfgnode.cpp src/share/vm/opto/chaitin.cpp src/share/vm/opto/classes.cpp src/share/vm/opto/classes.hpp src/share/vm/opto/compile.cpp src/share/vm/opto/compile.hpp src/share/vm/opto/escape.cpp src/share/vm/opto/generateOptoStub.cpp src/share/vm/opto/graphKit.cpp src/share/vm/opto/graphKit.hpp src/share/vm/opto/lcm.cpp src/share/vm/opto/library_call.cpp src/share/vm/opto/live.cpp src/share/vm/opto/loopopts.cpp src/share/vm/opto/machnode.cpp src/share/vm/opto/macro.cpp src/share/vm/opto/macro.hpp src/share/vm/opto/macroArrayCopy.cpp src/share/vm/opto/matcher.cpp src/share/vm/opto/memnode.cpp src/share/vm/opto/node.hpp src/share/vm/opto/parse.hpp src/share/vm/opto/parse1.cpp src/share/vm/opto/parse2.cpp src/share/vm/opto/parse3.cpp src/share/vm/opto/parseHelper.cpp src/share/vm/opto/runtime.cpp src/share/vm/opto/split_if.cpp src/share/vm/opto/type.cpp src/share/vm/opto/type.hpp src/share/vm/opto/valuetypenode.cpp src/share/vm/opto/valuetypenode.hpp src/share/vm/precompiled/precompiled.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/deoptimization.cpp src/share/vm/runtime/deoptimization.hpp 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/sharedRuntime.hpp 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 test/compiler/valhalla/valuetypes/ValueCapableClass1.java test/compiler/valhalla/valuetypes/ValueCapableClass2.java test/compiler/valhalla/valuetypes/ValueTypeTestBench.java test/runtime/valhalla/valuetypes/IntValue.java test/runtime/valhalla/valuetypes/Long8Value.java test/runtime/valhalla/valuetypes/Person.java test/runtime/valhalla/valuetypes/Point.java test/runtime/valhalla/valuetypes/VDefaultTest.java test/runtime/valhalla/valuetypes/VWithFieldTest.java test/runtime/valhalla/valuetypes/ValueTypeCreation.java test/runtime/valhalla/valuetypes/ValueTypeGetField.java
diffstat 185 files changed, 9716 insertions(+), 1164 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/aarch64/vm/globals_aarch64.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/cpu/aarch64/vm/globals_aarch64.hpp	Wed May 17 09:01:40 2017 +0200
@@ -69,6 +69,8 @@
 
 define_pd_global(bool, PreserveFramePointer, false);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, false);
+
 // GC Ergo Flags
 define_pd_global(uintx, CMSYoungGenPerWorker, 64*M);  // default max size of CMS young gen, per GC worker thread
 
--- a/src/cpu/ppc/vm/globals_ppc.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/cpu/ppc/vm/globals_ppc.hpp	Wed May 17 09:01:40 2017 +0200
@@ -73,6 +73,8 @@
 
 define_pd_global(bool, PreserveFramePointer,  false);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, false);
+
 // GC Ergo Flags
 define_pd_global(size_t, CMSYoungGenPerWorker, 16*M);  // Default max size of CMS young gen, per GC worker thread.
 
--- a/src/cpu/sparc/vm/globals_sparc.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/cpu/sparc/vm/globals_sparc.hpp	Wed May 17 09:01:40 2017 +0200
@@ -78,6 +78,8 @@
 
 define_pd_global(bool, PreserveFramePointer, false);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, false);
+
 // GC Ergo Flags
 define_pd_global(size_t, CMSYoungGenPerWorker, 16*M);  // default max size of CMS young gen, per GC worker thread
 
--- a/src/cpu/x86/vm/abstractInterpreter_x86.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/abstractInterpreter_x86.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/frame_x86.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/globals_x86.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/interp_masm_x86.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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;
@@ -626,6 +628,7 @@
 
 void InterpreterMacroAssembler::pop(TosState state) {
   switch (state) {
+  case qtos: // Fall through
   case atos: pop_ptr();                 break;
   case btos:
   case ztos:
@@ -644,6 +647,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:
@@ -680,6 +684,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
@@ -729,6 +734,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 May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/interpreterRT_x86.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/interpreterRT_x86_32.cpp	Wed May 17 09:01:40 2017 +0200
@@ -56,6 +56,14 @@
   box (offset(), jni_offset() + 1);
 }
 
+void InterpreterRuntime::SignatureHandlerGenerator::pass_valuetype() {
+  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 +131,20 @@
     _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;
+   }
+
+  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 May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/interpreterRT_x86_64.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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/sharedRuntime_x86_32.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Wed May 17 09:01:40 2017 +0200
@@ -570,11 +570,13 @@
 }
 
 static void gen_c2i_adapter(MacroAssembler *masm,
-                            int total_args_passed,
-                            int comp_args_on_stack,
-                            const BasicType *sig_bt,
+                            const GrowableArray<SigEntry>& sig_extended,
                             const VMRegPair *regs,
-                            Label& skip_fixup) {
+                            Label& skip_fixup,
+                            address start,
+                            OopMapSet*& oop_maps,
+                            int& frame_complete,
+                            int& frame_size_in_words) {
   // Before we get into the guts of the C2I adapter, see if we should be here
   // at all.  We've come from compiled code and are attempting to jump to the
   // interpreter, which means the caller made a static call to get here
@@ -596,7 +598,7 @@
   // Since all args are passed on the stack, total_args_passed * interpreter_
   // stack_element_size  is the
   // space we need.
-  int extraspace = total_args_passed * Interpreter::stackElementSize;
+  int extraspace = sig_extended.length() * Interpreter::stackElementSize;
 
   // Get return address
   __ pop(rax);
@@ -607,14 +609,14 @@
   __ subptr(rsp, extraspace);
 
   // Now write the args into the outgoing interpreter space
-  for (int i = 0; i < total_args_passed; i++) {
-    if (sig_bt[i] == T_VOID) {
-      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
+  for (int i = 0; i < sig_extended.length(); i++) {
+    if (sig_extended.at(i)._bt == T_VOID) {
+      assert(i > 0 && (sig_extended.at(i-1)._bt == T_LONG || sig_extended.at(i-1)._bt == T_DOUBLE), "missing half");
       continue;
     }
 
     // st_off points to lowest address on stack.
-    int st_off = ((total_args_passed - 1) - i) * Interpreter::stackElementSize;
+    int st_off = ((sig_extended.length() - 1) - i) * Interpreter::stackElementSize;
     int next_off = st_off - Interpreter::stackElementSize;
 
     // Say 4 args:
@@ -664,7 +666,7 @@
         NOT_LP64(ShouldNotReachHere());
         // Two VMRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG
         // T_DOUBLE and T_LONG use two slots in the interpreter
-        if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
+        if (sig_extended.at(i)._bt == T_LONG || sig_extended.at(i)._bt == T_DOUBLE) {
           // long/double in gpr
 #ifdef ASSERT
           // Overwrite the unused slot with known junk
@@ -681,7 +683,7 @@
       if (!r_2->is_valid()) {
         __ movflt(Address(rsp, st_off), r_1->as_XMMRegister());
       } else {
-        assert(sig_bt[i] == T_DOUBLE || sig_bt[i] == T_LONG, "wrong type");
+        assert(sig_extended.at(i)._bt == T_DOUBLE || sig_extended.at(i)._bt == T_LONG, "wrong type");
         move_c2i_double(masm, r_1->as_XMMRegister(), st_off);
       }
     }
@@ -714,10 +716,10 @@
 }
 
 void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
-                                    int total_args_passed,
                                     int comp_args_on_stack,
-                                    const BasicType *sig_bt,
+                                    const GrowableArray<SigEntry>& sig_extended,
                                     const VMRegPair *regs) {
+
   // Note: rsi contains the senderSP on entry. We must preserve it since
   // we may do a i2c -> c2i transition if we lose a race where compiled
   // code goes non-entrant while we get args ready.
@@ -806,11 +808,11 @@
 
   // Now generate the shuffle code.  Pick up all register args and move the
   // rest through the floating point stack top.
-  for (int i = 0; i < total_args_passed; i++) {
-    if (sig_bt[i] == T_VOID) {
+  for (int i = 0; i < sig_extended.length(); i++) {
+    if (sig_extended.at(i)._bt == T_VOID) {
       // Longs and doubles are passed in native word order, but misaligned
       // in the 32-bit build.
-      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
+      assert(i > 0 && (sig_extended.at(i-1)._bt == T_LONG || sig_extended.at(i-1)._bt == T_DOUBLE), "missing half");
       continue;
     }
 
@@ -819,7 +821,7 @@
     assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(),
             "scrambled load targets?");
     // Load in argument order going down.
-    int ld_off = (total_args_passed - i) * Interpreter::stackElementSize;
+    int ld_off = (sig_extended.length() - i) * Interpreter::stackElementSize;
     // Point to interpreter value (vs. tag)
     int next_off = ld_off - Interpreter::stackElementSize;
     //
@@ -860,7 +862,7 @@
         // are accessed as negative so LSW is at LOW address
 
         // ld_off is MSW so get LSW
-        const int offset = (NOT_LP64(true ||) sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)?
+        const int offset = (NOT_LP64(true ||) sig_extended.at(i)._bt==T_LONG||sig_extended.at(i)._bt==T_DOUBLE)?
                            next_off : ld_off;
         __ movptr(rsi, Address(saved_sp, offset));
         __ movptr(Address(rsp, st_off), rsi);
@@ -878,7 +880,7 @@
         // the interpreter allocates two slots but only uses one for thr T_LONG or T_DOUBLE case
         // So we must adjust where to pick up the data to match the interpreter.
 
-        const int offset = (NOT_LP64(true ||) sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)?
+        const int offset = (NOT_LP64(true ||) sig_extended.at(i)._bt==T_LONG||sig_extended.at(i)._bt==T_DOUBLE)?
                            next_off : ld_off;
 
         // this can be a misaligned move
@@ -926,14 +928,14 @@
 
 // ---------------------------------------------------------------
 AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
-                                                            int total_args_passed,
                                                             int comp_args_on_stack,
-                                                            const BasicType *sig_bt,
+                                                            const GrowableArray<SigEntry>& sig_extended,
                                                             const VMRegPair *regs,
-                                                            AdapterFingerPrint* fingerprint) {
+                                                            AdapterFingerPrint* fingerprint,
+                                                            AdapterBlob*& new_adapter) {
   address i2c_entry = __ pc();
 
-  gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
+  gen_i2c_adapter(masm, comp_args_on_stack, sig_extended, regs);
 
   // -------------------------------------------------------------------------
   // Generate a C2I adapter.  On entry we know rbx, holds the Method* during calls
@@ -970,9 +972,13 @@
 
   address c2i_entry = __ pc();
 
-  gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
+  OopMapSet* oop_maps = NULL;
+  int frame_complete = CodeOffsets::frame_never_safe;
+  int frame_size_in_words = 0;
+  gen_c2i_adapter(masm, sig_extended, regs, skip_fixup, i2c_entry, oop_maps, frame_complete, frame_size_in_words);
 
   __ flush();
+  new_adapter = AdapterBlob::create(masm->code(), frame_complete, frame_size_in_words, oop_maps);
   return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
 }
 
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Wed May 17 09:01:40 2017 +0200
@@ -483,6 +483,7 @@
     case T_OBJECT:
     case T_ARRAY:
     case T_ADDRESS:
+    case T_VALUETYPE: // just treat as ref for now
       if (int_args < Argument::n_int_register_parameters_j) {
         regs[i].set2(INT_ArgReg[int_args++]->as_VMReg());
       } else {
@@ -558,13 +559,107 @@
   __ bind(L);
 }
 
+// For each value type argument, sig includes the list of fields of
+// the value type. This utility function computes the number of
+// arguments for the call if value types are passed by reference (the
+// calling convention the interpreter expects).
+static int compute_total_args_passed_int(const GrowableArray<SigEntry>& sig_extended) {
+  int total_args_passed = 0;
+  if (ValueTypePassFieldsAsArgs) {
+    for (int i = 0; i < sig_extended.length(); i++) {
+      BasicType bt = sig_extended.at(i)._bt;
+      if (bt == T_VALUETYPE) {
+        // In sig_extended, a value type argument starts with:
+        // T_VALUETYPE, followed by the types of the fields of the
+        // value type and T_VOID to mark the end of the value
+        // type. Value types are flattened so, for instance, in the
+        // case of a value type with an int field and a value type
+        // field that itself has 2 fields, an int and a long:
+        // T_VALUETYPE T_INT T_VALUETYPE T_INT T_LONG T_VOID (second
+        // slot for the T_LONG) T_VOID (inner T_VALUETYPE) T_VOID
+        // (outer T_VALUETYPE)
+        total_args_passed++;
+        int vt = 1;
+        do {
+          i++;
+          BasicType bt = sig_extended.at(i)._bt;
+          BasicType prev_bt = sig_extended.at(i-1)._bt;
+          if (bt == T_VALUETYPE) {
+            vt++;
+          } else if (bt == T_VOID &&
+                     prev_bt != T_LONG &&
+                     prev_bt != T_DOUBLE) {
+            vt--;
+          }
+        } while (vt != 0);
+      } else {
+        total_args_passed++;
+      }
+    }
+  } else {
+    total_args_passed = sig_extended.length();
+  }
+  return total_args_passed;
+}
+
+
+static void gen_c2i_adapter_helper(MacroAssembler* masm,
+                                   BasicType bt,
+                                   BasicType prev_bt,
+                                   size_t size_in_bytes,
+                                   const VMRegPair& reg_pair,
+                                   const Address& to,
+                                   int extraspace) {
+  assert(bt != T_VALUETYPE || !ValueTypePassFieldsAsArgs, "no value type here");
+  if (bt == T_VOID) {
+    assert(prev_bt == T_LONG || prev_bt == T_DOUBLE, "missing half");
+    return;
+  }
+
+  // Say 4 args:
+  // i   st_off
+  // 0   32 T_LONG
+  // 1   24 T_VOID
+  // 2   16 T_OBJECT
+  // 3    8 T_BOOL
+  // -    0 return address
+  //
+  // However to make thing extra confusing. Because we can fit a long/double in
+  // a single slot on a 64 bt vm and it would be silly to break them up, the interpreter
+  // leaves one slot empty and only stores to a single slot. In this case the
+  // slot that is occupied is the T_VOID slot. See I said it was confusing.
+
+  bool wide = (size_in_bytes == wordSize);
+  VMReg r_1 = reg_pair.first();
+  VMReg r_2 = reg_pair.second();
+  assert(r_2->is_valid() == wide, "invalid size");
+  if (!r_1->is_valid()) {
+    assert(!r_2->is_valid(), "must be invalid");
+    return;
+  }
+  if (r_1->is_stack()) {
+    int ld_off = r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace;
+    __ load_sized_value(rax, Address(rsp, ld_off), size_in_bytes, /* is_signed */ false);
+    __ store_sized_value(to, rax, size_in_bytes);
+  } else if (r_1->is_Register()) {
+    __ store_sized_value(to, r_1->as_Register(), size_in_bytes);
+  } else {
+    if (wide) {
+      __ movdbl(to, r_1->as_XMMRegister());
+    } else {
+      __ movflt(to, r_1->as_XMMRegister());
+    }
+  }
+}
 
 static void gen_c2i_adapter(MacroAssembler *masm,
-                            int total_args_passed,
-                            int comp_args_on_stack,
-                            const BasicType *sig_bt,
+                            const GrowableArray<SigEntry>& sig_extended,
                             const VMRegPair *regs,
-                            Label& skip_fixup) {
+                            Label& skip_fixup,
+                            address start,
+                            OopMapSet*& oop_maps,
+                            int& frame_complete,
+                            int& frame_size_in_words) {
   // Before we get into the guts of the C2I adapter, see if we should be here
   // at all.  We've come from compiled code and are attempting to jump to the
   // interpreter, which means the caller made a static call to get here
@@ -574,11 +669,59 @@
 
   __ bind(skip_fixup);
 
+  if (ValueTypePassFieldsAsArgs) {
+    // Is there a value type arguments?
+    int i = 0;
+    for (; i < sig_extended.length() && sig_extended.at(i)._bt != T_VALUETYPE; i++);
+
+    if (i < sig_extended.length()) {
+      // There is at least a value type argument: we're coming from
+      // compiled code so we have no buffers to back the value
+      // types. Allocate the buffers here with a runtime call.
+      oop_maps = new OopMapSet();
+      OopMap* map = NULL;
+
+      map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words);
+
+      frame_complete = __ offset();
+
+      __ set_last_Java_frame(noreg, noreg, NULL);
+
+      __ mov(c_rarg0, r15_thread);
+      __ mov(c_rarg1, rbx);
+
+      __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::allocate_value_types)));
+
+      oop_maps->add_gc_map((int)(__ pc() - start), map);
+      __ reset_last_Java_frame(false);
+
+      RegisterSaver::restore_live_registers(masm);
+
+      Label no_exception;
+      __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
+      __ jcc(Assembler::equal, no_exception);
+
+      __ movptr(Address(r15_thread, JavaThread::vm_result_offset()), (int)NULL_WORD);
+      __ movptr(rax, Address(r15_thread, Thread::pending_exception_offset()));
+      __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+
+      __ bind(no_exception);
+
+      // We get an array of objects from the runtime call
+      int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(T_OBJECT);
+      __ get_vm_result(r13, r15_thread);
+      __ get_vm_result_2(rbx, r15_thread); // TODO: required to keep the callee Method live?
+      __ addptr(r13, offset_in_bytes);
+      __ mov(r10, r13);
+    }
+  }
+
+
   // Since all args are passed on the stack, total_args_passed *
   // Interpreter::stackElementSize is the space we need. Plus 1 because
   // we also account for the return address location since
   // we store it first rather than hold it in rax across all the shuffling
-
+  int total_args_passed = compute_total_args_passed_int(sig_extended);
   int extraspace = (total_args_passed * Interpreter::stackElementSize) + wordSize;
 
   // stack is aligned, keep it that way
@@ -596,96 +739,72 @@
   __ movptr(Address(rsp, 0), rax);
 
   // Now write the args into the outgoing interpreter space
-  for (int i = 0; i < total_args_passed; i++) {
-    if (sig_bt[i] == T_VOID) {
-      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
-      continue;
-    }
-
-    // offset to start parameters
-    int st_off   = (total_args_passed - i) * Interpreter::stackElementSize;
-    int next_off = st_off - Interpreter::stackElementSize;
-
-    // Say 4 args:
-    // i   st_off
-    // 0   32 T_LONG
-    // 1   24 T_VOID
-    // 2   16 T_OBJECT
-    // 3    8 T_BOOL
-    // -    0 return address
-    //
-    // However to make thing extra confusing. Because we can fit a long/double in
-    // a single slot on a 64 bt vm and it would be silly to break them up, the interpreter
-    // leaves one slot empty and only stores to a single slot. In this case the
-    // slot that is occupied is the T_VOID slot. See I said it was confusing.
-
-    VMReg r_1 = regs[i].first();
-    VMReg r_2 = regs[i].second();
-    if (!r_1->is_valid()) {
-      assert(!r_2->is_valid(), "");
-      continue;
-    }
-    if (r_1->is_stack()) {
-      // memory to memory use rax
-      int ld_off = r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace;
-      if (!r_2->is_valid()) {
-        // sign extend??
-        __ movl(rax, Address(rsp, ld_off));
+
+  // next_arg_comp is the next argument from the compiler point of
+  // view (value type fields are passed in registers/on the stack). In
+  // sig_extended, a value type argument starts with: T_VALUETYPE,
+  // followed by the types of the fields of the value type and T_VOID
+  // to mark the end of the value type. ignored counts the number of
+  // T_VALUETYPE/T_VOID. next_vt_arg is the next value type argument:
+  // used to get the buffer for that argument from the pool of buffers
+  // we allocated above and want to pass to the
+  // interpreter. next_arg_int is the next argument from the
+  // interpreter point of view (value types are passed by reference).
+  for (int next_arg_comp = 0, ignored = 0, next_vt_arg = 0, next_arg_int = 0;
+       next_arg_comp < sig_extended.length(); next_arg_comp++) {
+    assert(ignored <= next_arg_comp, "shouldn't skip over more slot than there are arguments");
+    assert(next_arg_int < total_args_passed, "more arguments for the interpreter than expected?");
+    BasicType bt = sig_extended.at(next_arg_comp)._bt;
+    int st_off = (total_args_passed - next_arg_int) * Interpreter::stackElementSize;
+    if (!ValueTypePassFieldsAsArgs || bt != T_VALUETYPE) {
+      int next_off = st_off - Interpreter::stackElementSize;
+      const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : st_off;
+      const VMRegPair reg_pair = regs[next_arg_comp-ignored];
+      size_t size_in_bytes = reg_pair.second()->is_valid() ? 8 : 4;
+      gen_c2i_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL,
+                             size_in_bytes, reg_pair, Address(rsp, offset), extraspace);
+      next_arg_int++;
+#ifdef ASSERT
+      if (bt == T_LONG || bt == T_DOUBLE) {
+        // Overwrite the unused slot with known junk
+        __ mov64(rax, CONST64(0xdeadffffdeadaaaa));
         __ movptr(Address(rsp, st_off), rax);
-
-      } else {
-
-        __ movq(rax, Address(rsp, ld_off));
-
-        // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG
-        // T_DOUBLE and T_LONG use two slots in the interpreter
-        if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
-          // ld_off == LSW, ld_off+wordSize == MSW
-          // st_off == MSW, next_off == LSW
-          __ movq(Address(rsp, next_off), rax);
-#ifdef ASSERT
-          // Overwrite the unused slot with known junk
-          __ mov64(rax, CONST64(0xdeadffffdeadaaaa));
-          __ movptr(Address(rsp, st_off), rax);
+      }
 #endif /* ASSERT */
+    } else {
+      ignored++;
+      // get the buffer from the just allocated pool of buffers
+      __ load_heap_oop(r11, Address(r10, next_vt_arg * type2aelembytes(T_VALUETYPE)));
+      next_vt_arg++; next_arg_int++;
+      int vt = 1;
+      // write fields we get from compiled code in registers/stack
+      // slots to the buffer: we know we are done with that value type
+      // argument when we hit the T_VOID that acts as an end of value
+      // type delimiter for this value type. Value types are flattened
+      // so we might encounter embedded value types. Each entry in
+      // sig_extended contains a field offset in the buffer.
+      do {
+        next_arg_comp++;
+        BasicType bt = sig_extended.at(next_arg_comp)._bt;
+        BasicType prev_bt = sig_extended.at(next_arg_comp-1)._bt;
+        if (bt == T_VALUETYPE) {
+          vt++;
+          ignored++;
+        } else if (bt == T_VOID &&
+                   prev_bt != T_LONG &&
+                   prev_bt != T_DOUBLE) {
+          vt--;
+          ignored++;
         } else {
-          __ movq(Address(rsp, st_off), rax);
+          int off = sig_extended.at(next_arg_comp)._offset;
+          assert(off > 0, "offset in object should be positive");
+          size_t size_in_bytes = is_java_primitive(bt) ? type2aelembytes(bt) : wordSize;
+          gen_c2i_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL,
+                                 size_in_bytes, regs[next_arg_comp-ignored], Address(r11, off), extraspace);
         }
-      }
-    } else if (r_1->is_Register()) {
-      Register r = r_1->as_Register();
-      if (!r_2->is_valid()) {
-        // must be only an int (or less ) so move only 32bits to slot
-        // why not sign extend??
-        __ movl(Address(rsp, st_off), r);
-      } else {
-        // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG
-        // T_DOUBLE and T_LONG use two slots in the interpreter
-        if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
-          // long/double in gpr
-#ifdef ASSERT
-          // Overwrite the unused slot with known junk
-          __ mov64(rax, CONST64(0xdeadffffdeadaaab));
-          __ movptr(Address(rsp, st_off), rax);
-#endif /* ASSERT */
-          __ movq(Address(rsp, next_off), r);
-        } else {
-          __ movptr(Address(rsp, st_off), r);
-        }
-      }
-    } else {
-      assert(r_1->is_XMMRegister(), "");
-      if (!r_2->is_valid()) {
-        // only a float use just part of the slot
-        __ movflt(Address(rsp, st_off), r_1->as_XMMRegister());
-      } else {
-#ifdef ASSERT
-        // Overwrite the unused slot with known junk
-        __ mov64(rax, CONST64(0xdeadffffdeadaaac));
-        __ movptr(Address(rsp, st_off), rax);
-#endif /* ASSERT */
-        __ movdbl(Address(rsp, next_off), r_1->as_XMMRegister());
-      }
+      } while (vt != 0);
+      // pass the buffer to the interpreter
+      __ movptr(Address(rsp, st_off), r11);
     }
   }
 
@@ -707,10 +826,56 @@
   __ bind(L_fail);
 }
 
+static void gen_i2c_adapter_helper(MacroAssembler* masm,
+                                   BasicType bt,
+                                   BasicType prev_bt,
+                                   size_t size_in_bytes,
+                                   const VMRegPair& reg_pair,
+                                   const Address& from) {
+  assert(bt != T_VALUETYPE || !ValueTypePassFieldsAsArgs, "no value type here");
+  if (bt == T_VOID) {
+    // Longs and doubles are passed in native word order, but misaligned
+    // in the 32-bit build.
+    assert(prev_bt == T_LONG || prev_bt == T_DOUBLE, "missing half");
+    return;
+  }
+  assert(!reg_pair.second()->is_valid() || reg_pair.first()->next() == reg_pair.second(),
+         "scrambled load targets?");
+
+  bool wide = (size_in_bytes == wordSize);
+  VMReg r_1 = reg_pair.first();
+  VMReg r_2 = reg_pair.second();
+  assert(r_2->is_valid() == wide, "invalid size");
+  if (!r_1->is_valid()) {
+    assert(!r_2->is_valid(), "must be invalid");
+    return;
+  }
+
+  bool is_signed = (bt != T_CHAR) && (bt != T_BOOLEAN);
+  if (r_1->is_stack()) {
+    // Convert stack slot to an SP offset (+ wordSize to account for return address)
+    int st_off = reg_pair.first()->reg2stack() * VMRegImpl::stack_slot_size + wordSize;
+    // We can use r13 as a temp here because compiled code doesn't need r13 as an input
+    // and if we end up going thru a c2i because of a miss a reasonable value of r13
+    // will be generated.
+    __ load_sized_value(r13, from, size_in_bytes, is_signed);
+    __ movq(Address(rsp, st_off), r13);
+  } else if (r_1->is_Register()) {
+    Register r = r_1->as_Register();
+    assert(r != rax, "must be different");
+    __ load_sized_value(r, from, size_in_bytes, is_signed);
+  } else {
+    if (wide) {
+      __ movdbl(r_1->as_XMMRegister(), from);
+    } else {
+      __ movflt(r_1->as_XMMRegister(), from);
+    }
+  }
+}
+
 void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
-                                    int total_args_passed,
                                     int comp_args_on_stack,
-                                    const BasicType *sig_bt,
+                                    const GrowableArray<SigEntry>& sig_extended,
                                     const VMRegPair *regs) {
 
   // Note: r13 contains the senderSP on entry. We must preserve it since
@@ -816,84 +981,63 @@
   }
 #endif // INCLUDE_JVMCI
 
+  int total_args_passed = compute_total_args_passed_int(sig_extended);
   // Now generate the shuffle code.  Pick up all register args and move the
   // rest through the floating point stack top.
-  for (int i = 0; i < total_args_passed; i++) {
-    if (sig_bt[i] == T_VOID) {
-      // Longs and doubles are passed in native word order, but misaligned
-      // in the 32-bit build.
-      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
-      continue;
-    }
-
-    // Pick up 0, 1 or 2 words from SP+offset.
-
-    assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(),
-            "scrambled load targets?");
-    // Load in argument order going down.
-    int ld_off = (total_args_passed - i)*Interpreter::stackElementSize;
-    // Point to interpreter value (vs. tag)
-    int next_off = ld_off - Interpreter::stackElementSize;
-    //
-    //
-    //
-    VMReg r_1 = regs[i].first();
-    VMReg r_2 = regs[i].second();
-    if (!r_1->is_valid()) {
-      assert(!r_2->is_valid(), "");
-      continue;
-    }
-    if (r_1->is_stack()) {
-      // Convert stack slot to an SP offset (+ wordSize to account for return address )
-      int st_off = regs[i].first()->reg2stack()*VMRegImpl::stack_slot_size + wordSize;
-
-      // We can use r13 as a temp here because compiled code doesn't need r13 as an input
-      // and if we end up going thru a c2i because of a miss a reasonable value of r13
-      // will be generated.
-      if (!r_2->is_valid()) {
-        // sign extend???
-        __ movl(r13, Address(saved_sp, ld_off));
-        __ movptr(Address(rsp, st_off), r13);
-      } else {
-        //
-        // We are using two optoregs. This can be either T_OBJECT, T_ADDRESS, T_LONG, or T_DOUBLE
-        // the interpreter allocates two slots but only uses one for thr T_LONG or T_DOUBLE case
-        // So we must adjust where to pick up the data to match the interpreter.
-        //
-        // Interpreter local[n] == MSW, local[n+1] == LSW however locals
-        // are accessed as negative so LSW is at LOW address
-
-        // ld_off is MSW so get LSW
-        const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)?
-                           next_off : ld_off;
-        __ movq(r13, Address(saved_sp, offset));
-        // st_off is LSW (i.e. reg.first())
-        __ movq(Address(rsp, st_off), r13);
-      }
-    } else if (r_1->is_Register()) {  // Register argument
-      Register r = r_1->as_Register();
-      assert(r != rax, "must be different");
-      if (r_2->is_valid()) {
-        //
-        // We are using two VMRegs. This can be either T_OBJECT, T_ADDRESS, T_LONG, or T_DOUBLE
-        // the interpreter allocates two slots but only uses one for thr T_LONG or T_DOUBLE case
-        // So we must adjust where to pick up the data to match the interpreter.
-
-        const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)?
-                           next_off : ld_off;
-
-        // this can be a misaligned move
-        __ movq(r, Address(saved_sp, offset));
-      } else {
-        // sign extend and use a full word?
-        __ movl(r, Address(saved_sp, ld_off));
-      }
+
+  // next_arg_comp is the next argument from the compiler point of
+  // view (value type fields are passed in registers/on the stack). In
+  // sig_extended, a value type argument starts with: T_VALUETYPE,
+  // followed by the types of the fields of the value type and T_VOID
+  // to mark the end of the value type. ignored counts the number of
+  // T_VALUETYPE/T_VOID. next_arg_int is the next argument from the
+  // interpreter point of view (value types are passed by reference).
+  for (int next_arg_comp = 0, ignored = 0, next_arg_int = 0; next_arg_comp < sig_extended.length(); next_arg_comp++) {
+    assert(ignored <= next_arg_comp, "shouldn't skip over more slot than there are arguments");
+    assert(next_arg_int < total_args_passed, "more arguments from the interpreter than expected?");
+    BasicType bt = sig_extended.at(next_arg_comp)._bt;
+    int ld_off = (total_args_passed - next_arg_int)*Interpreter::stackElementSize;
+    if (!ValueTypePassFieldsAsArgs || bt != T_VALUETYPE) {
+      // Load in argument order going down.
+      // Point to interpreter value (vs. tag)
+      int next_off = ld_off - Interpreter::stackElementSize;
+      int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : ld_off;
+      const VMRegPair reg_pair = regs[next_arg_comp-ignored];
+      size_t size_in_bytes = reg_pair.second()->is_valid() ? 8 : 4;
+      gen_i2c_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL,
+                             size_in_bytes, reg_pair, Address(saved_sp, offset));
+      next_arg_int++;
     } else {
-      if (!r_2->is_valid()) {
-        __ movflt(r_1->as_XMMRegister(), Address(saved_sp, ld_off));
-      } else {
-        __ movdbl(r_1->as_XMMRegister(), Address(saved_sp, next_off));
-      }
+      next_arg_int++;
+      ignored++;
+      // get the buffer for that value type
+      __ movptr(r10, Address(saved_sp, ld_off));
+      int vt = 1;
+      // load fields to registers/stack slots from the buffer: we know
+      // we are done with that value type argument when we hit the
+      // T_VOID that acts as an end of value type delimiter for this
+      // value type. Value types are flattened so we might encounter
+      // embedded value types. Each entry in sig_extended contains a
+      // field offset in the buffer.
+      do {
+        next_arg_comp++;
+        BasicType bt = sig_extended.at(next_arg_comp)._bt;
+        BasicType prev_bt = sig_extended.at(next_arg_comp-1)._bt;
+        if (bt == T_VALUETYPE) {
+          vt++;
+          ignored++;
+        } else if (bt == T_VOID &&
+                   prev_bt != T_LONG &&
+                   prev_bt != T_DOUBLE) {
+          vt--;
+          ignored++;
+        } else {
+          int off = sig_extended.at(next_arg_comp)._offset;
+          assert(off > 0, "offset in object should be positive");
+          size_t size_in_bytes = is_java_primitive(bt) ? type2aelembytes(bt) : wordSize;
+          gen_i2c_adapter_helper(masm, bt, prev_bt, size_in_bytes, regs[next_arg_comp - ignored], Address(r10, off));
+        }
+      } while (vt != 0);
     }
   }
 
@@ -910,7 +1054,7 @@
   __ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx);
 
   // put Method* where a c2i would expect should we end up there
-  // only needed becaus eof c2 resolve stubs return Method* as a result in
+  // only needed because of c2 resolve stubs return Method* as a result in
   // rax
   __ mov(rax, rbx);
   __ jmp(r11);
@@ -918,14 +1062,14 @@
 
 // ---------------------------------------------------------------
 AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
-                                                            int total_args_passed,
                                                             int comp_args_on_stack,
-                                                            const BasicType *sig_bt,
+                                                            const GrowableArray<SigEntry>& sig_extended,
                                                             const VMRegPair *regs,
-                                                            AdapterFingerPrint* fingerprint) {
+                                                            AdapterFingerPrint* fingerprint,
+                                                            AdapterBlob*& new_adapter) {
   address i2c_entry = __ pc();
 
-  gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
+  gen_i2c_adapter(masm, comp_args_on_stack, sig_extended, regs);
 
   // -------------------------------------------------------------------------
   // Generate a C2I adapter.  On entry we know rbx holds the Method* during calls
@@ -962,9 +1106,13 @@
 
   address c2i_entry = __ pc();
 
-  gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
+  OopMapSet* oop_maps = NULL;
+  int frame_complete = CodeOffsets::frame_never_safe;
+  int frame_size_in_words = 0;
+  gen_c2i_adapter(masm, sig_extended, regs, skip_fixup, i2c_entry, oop_maps, frame_complete, frame_size_in_words);
 
   __ flush();
+  new_adapter = AdapterBlob::create(masm->code(), frame_complete, frame_size_in_words, oop_maps);
   return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
 }
 
--- a/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/cpu/x86/vm/templateTable_x86.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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);
@@ -4001,6 +4137,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);
@@ -4155,6 +4305,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/cpu/zero/vm/globals_zero.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/cpu/zero/vm/globals_zero.hpp	Wed May 17 09:01:40 2017 +0200
@@ -78,6 +78,8 @@
 
 define_pd_global(bool, PreserveFramePointer, false);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, false);
+
 // No performance work done here yet.
 define_pd_global(bool, CompactStrings, false);
 
--- a/src/share/vm/ci/bcEscapeAnalyzer.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp	Wed May 17 09:01:40 2017 +0200
@@ -427,6 +427,7 @@
         break;
       }
       case Bytecodes::_aload:
+      case Bytecodes::_vload:
         state.apush(state._vars[s.get_index()]);
         break;
       case Bytecodes::_iload:
@@ -480,6 +481,7 @@
         set_method_escape(state.apop());
         state.lpush();
         break;
+      case Bytecodes::_vaload:
       case Bytecodes::_aaload:
         { state.spop();
           ArgumentMap array = state.apop();
@@ -513,6 +515,7 @@
         state.lpop();
         break;
       case Bytecodes::_astore:
+      case Bytecodes::_vstore:
         state._vars[s.get_index()] = state.apop();
         break;
       case Bytecodes::_astore_0:
@@ -550,6 +553,7 @@
         set_modified(arr, OFFSET_ANY, type2size[T_LONG]*HeapWordSize);
         break;
       }
+      case Bytecodes::_vastore:
       case Bytecodes::_aastore:
       {
         set_global_escape(state.apop());
@@ -846,11 +850,13 @@
         fall_through = false;
         break;
       case Bytecodes::_areturn:
+      case Bytecodes::_vreturn:
         set_returned(state.apop());
         fall_through = false;
         break;
       case Bytecodes::_getstatic:
       case Bytecodes::_getfield:
+      case Bytecodes::_vgetfield:
         { bool ignored_will_link;
           ciField* field = s.get_field(ignored_will_link);
           BasicType field_type = field->type()->basic_type();
@@ -939,8 +945,24 @@
         }
         break;
       case Bytecodes::_new:
+      case Bytecodes::_vdefault:
         state.apush(allocated_obj);
         break;
+      case Bytecodes::_vwithfield: {
+        bool will_link;
+        ciField* field = s.get_field(will_link);
+        BasicType field_type = field->type()->basic_type();
+        if (field_type == T_OBJECT || field_type == T_ARRAY) {
+          set_global_escape(state.apop());
+        } else if (type2size[field_type] == 1) {
+          state.spop();
+        } else {
+          state.lpop();
+        }
+        state.apop();
+        state.apush(allocated_obj);
+        break;
+      }
       case Bytecodes::_newarray:
       case Bytecodes::_anewarray:
         state.spop();
--- a/src/share/vm/ci/ciArrayKlass.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciArrayKlass.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciArrayKlass.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciClassList.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciConstant.cpp	Wed May 17 09:01:40 2017 +0200
@@ -56,6 +56,7 @@
   case T_DOUBLE:
     tty->print("%lf", _value._double);
     break;
+  case T_VALUETYPE:
   case T_OBJECT:
   case T_ARRAY:
     _value._object->print();
--- a/src/share/vm/ci/ciConstant.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciConstant.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciEnv.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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);
+      }
     }
   }
 
--- a/src/share/vm/ci/ciEnv.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciEnv.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciField.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciField.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciInstance.cpp	Wed May 17 09:01:40 2017 +0200
@@ -69,6 +69,7 @@
     case T_FLOAT:   return ciConstant(obj->float_field(offset));
     case T_DOUBLE:  return ciConstant(obj->double_field(offset));
     case T_LONG:    return ciConstant(obj->long_field(offset));
+    case T_VALUETYPE:  // fall through
     case T_OBJECT:  // fall through
     case T_ARRAY: {
       oop o = obj->obj_field(offset);
@@ -98,7 +99,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciInstanceKlass.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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,8 +62,10 @@
   _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;
+  _derive_value_type = NULL;
   _implementor = NULL; // we will fill these lazily
 
   Thread *thread = Thread::current();
@@ -101,8 +105,10 @@
   _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;
+  _derive_value_type = NULL;
   _is_anonymous = false;
   _loader = loader;
   _protection_domain = protection_domain;
@@ -398,6 +404,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 +457,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 +475,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 +489,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 +521,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 +537,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;
@@ -605,6 +660,21 @@
   return NULL;
 }
 
+ciInstanceKlass* ciInstanceKlass::derive_value_type() {
+  InstanceKlass* ik = get_instanceKlass();
+  if (ik->is_derive_value_type()) {
+    if (_derive_value_type == NULL) {
+      VM_ENTRY_MARK;
+      InstanceKlass* k = ik->derive_value_type_klass();
+      _derive_value_type = CURRENT_THREAD_ENV->get_instance_klass(k);
+      assert(_derive_value_type != NULL, "must have derive value type");
+    }
+    return _derive_value_type;
+  } else {
+    return NULL;
+  }
+}
+
 // Utility class for printing of the contents of the static fields for
 // use by compilation replay.  It only prints out the information that
 // could be consumed by the compiler, so for primitive types it prints
@@ -613,77 +683,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciInstanceKlass.hpp	Wed May 17 09:01:40 2017 +0200
@@ -65,8 +65,15 @@
 
   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.
 
+  ciInstanceKlass*       _derive_value_type; // This field points:
+                                             //   - to the derived value type class corresponding to the current value-capable class;
+                                             //   - to the value-capable class corresponding to the current derived value type class.
+
   // The possible values of the _implementor fall into following three cases:
   //   NULL: no implementor.
   //   A ciInstanceKlass that's not itself: one implementor.
@@ -185,6 +192,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 +203,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 +228,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
@@ -233,6 +249,7 @@
 
   bool is_leaf_type();
   ciInstanceKlass* implementor();
+  ciInstanceKlass* derive_value_type();
 
   // Is the defining class loader of this class the default loader?
   bool uses_default_loader() const;
--- a/src/share/vm/ci/ciKlass.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciKlass.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciMetadata.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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/ciMethodBlocks.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciMethodBlocks.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciObjArrayKlass.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciObjectFactory.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciReplay.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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,22 @@
         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 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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciStreams.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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();
 }
 
--- a/src/share/vm/ci/ciSymbol.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciSymbol.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciType.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciType.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciTypeFlow.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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;
 
@@ -1435,6 +1494,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 +1524,16 @@
       push(value2);
       break;
     }
+  case Bytecodes::_vunbox:
+     {
+       do_vunbox(str);
+       break;
+     }
+     case Bytecodes::_vbox:
+     {
+       do_vbox(str);
+       break;
+     }
   case Bytecodes::_wide:
   default:
     {
@@ -1745,9 +1817,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 +2261,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/ciTypeFlow.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -0,0 +1,148 @@
+/*
+ * 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");
+
+  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);
+  ValueKlass* vklass = ValueKlass::cast(get_Klass());
+  for (JavaFieldStream fs(vklass); !fs.done(); fs.next()) {
+    if (fs.access_flags().is_static()) {
+      continue;
+    }
+    _field_index_map->append(fs.field_descriptor().index());
+  }
+  return _field_index_map->length();
+}
+
+// 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 May 17 09:01:40 2017 +0200
@@ -0,0 +1,73 @@
+/*
+ * 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).
+  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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/ci/compilerInterface.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/classfile/classFileParser.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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"
@@ -84,7 +85,7 @@
 #define JAVA_CLASSFILE_MAGIC              0xCAFEBABE
 #define JAVA_MIN_SUPPORTED_VERSION        45
 #define JAVA_MAX_SUPPORTED_VERSION        53
-#define JAVA_MAX_SUPPORTED_MINOR_VERSION  0
+#define JAVA_MAX_SUPPORTED_MINOR_VERSION  1
 
 // Used for two backward compatibility reasons:
 // - to check for new additions to the class file format in JDK1.5
@@ -996,6 +997,7 @@
     _jdk_internal_vm_annotation_Contended,
     _field_Stable,
     _jdk_internal_vm_annotation_ReservedStackAccess,
+    _jvm_internal_value_DeriveValueType,
     _annotation_LIMIT
   };
   const Location _location;
@@ -1031,6 +1033,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.
@@ -1383,11 +1387,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
 };
@@ -1407,12 +1413,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
@@ -1427,12 +1434,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) {
@@ -2078,6 +2086,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;
     }
@@ -3573,7 +3587,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);
@@ -3600,39 +3615,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,
@@ -3673,16 +3655,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,
@@ -3695,6 +3819,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.
   //
@@ -3715,8 +3845,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)) ) {
@@ -3733,6 +3864,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();
@@ -3742,6 +3883,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
@@ -3752,16 +3901,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.
   //
@@ -3771,15 +3957,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
 
@@ -3828,13 +4016,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 +
@@ -3917,6 +4100,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).
@@ -3933,6 +4126,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;
@@ -3953,6 +4148,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;
@@ -3962,26 +4180,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 ) {
@@ -4090,30 +4289,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:
@@ -4148,12 +4334,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);
 
@@ -4165,8 +4363,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
@@ -4177,12 +4376,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,
@@ -4190,62 +4388,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");
 
@@ -4933,7 +5088,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);
@@ -5183,7 +5339,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 {
@@ -5317,7 +5473,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");
@@ -5331,7 +5487,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*
@@ -5417,10 +5573,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);
@@ -5464,6 +5620,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()) {
@@ -6070,7 +6232,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");
     }
   }
@@ -6146,6 +6310,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/classfile/classFileParser.hpp	Wed May 17 09:01:40 2017 +0200
@@ -55,6 +55,7 @@
  class FieldAllocationCount;
  class FieldAnnotationCollector;
  class FieldLayoutInfo;
+ class OopMapBlocksBuilder;
 
  public:
   // The ClassFileParser has an associated "publicity" level
@@ -390,6 +391,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,
@@ -522,6 +528,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/classfile/classLoader.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/classfile/javaClasses.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/classfile/systemDictionary.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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);
@@ -2055,6 +2056,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) {
@@ -2306,7 +2321,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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)
   };
 
 
@@ -417,6 +425,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/classfile/vmSymbols.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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/code/codeBlob.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/code/codeBlob.cpp	Wed May 17 09:01:40 2017 +0200
@@ -276,23 +276,27 @@
   MemoryService::track_code_cache_memory_usage();
 }
 
+BufferBlob::BufferBlob(const char* name, int size, CodeBuffer* cb, int frame_complete, int frame_size, OopMapSet* oop_maps)
+  : RuntimeBlob(name, cb, sizeof(BufferBlob), size, frame_complete, frame_size, oop_maps)
+{}
+
 
 //----------------------------------------------------------------------------------------------------
 // Implementation of AdapterBlob
 
-AdapterBlob::AdapterBlob(int size, CodeBuffer* cb) :
-  BufferBlob("I2C/C2I adapters", size, cb) {
+AdapterBlob::AdapterBlob(int size, CodeBuffer* cb, int frame_complete, int frame_size, OopMapSet* oop_maps) :
+  BufferBlob("I2C/C2I adapters", size, cb, frame_complete, frame_size, oop_maps) {
   CodeCache::commit(this);
 }
 
-AdapterBlob* AdapterBlob::create(CodeBuffer* cb) {
+AdapterBlob* AdapterBlob::create(CodeBuffer* cb, int frame_complete, int frame_size, OopMapSet* oop_maps) {
   ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock
 
   AdapterBlob* blob = NULL;
   unsigned int size = CodeBlob::allocation_size(cb, sizeof(AdapterBlob));
   {
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
-    blob = new (size) AdapterBlob(size, cb);
+    blob = new (size) AdapterBlob(size, cb, frame_complete, frame_size, oop_maps);
   }
   // Track memory usage statistic after releasing CodeCache_lock
   MemoryService::track_code_cache_memory_usage();
--- a/src/share/vm/code/codeBlob.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/code/codeBlob.hpp	Wed May 17 09:01:40 2017 +0200
@@ -366,6 +366,7 @@
   // Creation support
   BufferBlob(const char* name, int size);
   BufferBlob(const char* name, int size, CodeBuffer* cb);
+  BufferBlob(const char* name, int size, CodeBuffer* cb, int frame_complete, int frame_size, OopMapSet* oop_maps);
 
   void* operator new(size_t s, unsigned size) throw();
 
@@ -394,14 +395,19 @@
 
 class AdapterBlob: public BufferBlob {
 private:
-  AdapterBlob(int size, CodeBuffer* cb);
+  AdapterBlob(int size, CodeBuffer* cb, int frame_complete, int frame_size, OopMapSet* oop_maps);
 
 public:
   // Creation
-  static AdapterBlob* create(CodeBuffer* cb);
+  static AdapterBlob* create(CodeBuffer* cb,
+                             int frame_complete,
+                             int frame_size,
+                             OopMapSet* oop_maps);
 
   // Typing
   virtual bool is_adapter_blob() const { return true; }
+
+  bool caller_must_gc_arguments(JavaThread* thread) const { return true; }
 };
 
 
--- a/src/share/vm/compiler/compileBroker.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/compiler/compileBroker.cpp	Wed May 17 09:01:40 2017 +0200
@@ -1050,6 +1050,13 @@
   assert(WhiteBoxAPI || TieredCompilation || comp_level == CompLevel_highest_tier, "only CompLevel_highest_tier must be used in non-tiered");
   // return quickly if possible
 
+  // Lambda forms with an Object in their signature can be passed a
+  // value type. If compiled as root of a compilation, C2 has no way
+  // to know a value type is passed.
+  if (ValueTypePassFieldsAsArgs && method->is_compiled_lambda_form()) {
+    return NULL;
+  }
+
   // lock, make sure that the compilation
   // isn't prohibited in a straightforward way.
   AbstractCompiler* comp = CompileBroker::compiler(comp_level);
--- a/src/share/vm/compiler/methodLiveness.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/compiler/methodLiveness.cpp	Wed May 17 09:01:40 2017 +0200
@@ -347,6 +347,7 @@
       case Bytecodes::_freturn:
       case Bytecodes::_dreturn:
       case Bytecodes::_areturn:
+      case Bytecodes::_vreturn:
       case Bytecodes::_return:
         // These opcodes are  not the normal predecessors of any other opcodes.
         break;
@@ -642,6 +643,8 @@
     case Bytecodes::_goto_w:
     case Bytecodes::_aconst_null:
     case Bytecodes::_new:
+    case Bytecodes::_vdefault:
+    case Bytecodes::_vwithfield:
     case Bytecodes::_iconst_m1:
     case Bytecodes::_iconst_0:
     case Bytecodes::_iconst_1:
@@ -668,6 +671,7 @@
     case Bytecodes::_saload:
     case Bytecodes::_laload:
     case Bytecodes::_daload:
+    case Bytecodes::_vaload:
     case Bytecodes::_aaload:
     case Bytecodes::_iastore:
     case Bytecodes::_fastore:
@@ -676,6 +680,7 @@
     case Bytecodes::_sastore:
     case Bytecodes::_lastore:
     case Bytecodes::_dastore:
+    case Bytecodes::_vastore:
     case Bytecodes::_aastore:
     case Bytecodes::_pop:
     case Bytecodes::_pop2:
@@ -766,6 +771,7 @@
     case Bytecodes::_getstatic:
     case Bytecodes::_putstatic:
     case Bytecodes::_getfield:
+    case Bytecodes::_vgetfield:
     case Bytecodes::_putfield:
     case Bytecodes::_invokevirtual:
     case Bytecodes::_invokespecial:
@@ -779,12 +785,15 @@
     case Bytecodes::_instanceof:
     case Bytecodes::_athrow:
     case Bytecodes::_areturn:
+    case Bytecodes::_vreturn:
     case Bytecodes::_monitorenter:
     case Bytecodes::_monitorexit:
     case Bytecodes::_ifnull:
     case Bytecodes::_ifnonnull:
     case Bytecodes::_multianewarray:
     case Bytecodes::_lookupswitch:
+    case Bytecodes::_vbox:
+    case Bytecodes::_vunbox:
       // These bytecodes have no effect on the method's locals.
       break;
 
@@ -826,6 +835,7 @@
     case Bytecodes::_iinc:
     case Bytecodes::_fload:
     case Bytecodes::_aload:
+    case Bytecodes::_vload:
     case Bytecodes::_ret:
       load_one(instruction->get_index());
       break;
@@ -882,6 +892,7 @@
     case Bytecodes::_istore:
     case Bytecodes::_fstore:
     case Bytecodes::_astore:
+    case Bytecodes::_vstore:
       store_one(instruction->get_index());
       break;
 
--- a/src/share/vm/gc/parallel/psCompactionManager.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/gc/parallel/psCompactionManager.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/gc/parallel/psParallelCompact.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/gc/parallel/psPromotionManager.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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/interpreter/abstractInterpreter.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/abstractInterpreter.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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/bytecodeTracer.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/bytecodeTracer.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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,6 +546,8 @@
     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;
 
@@ -568,6 +572,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/bytecodes.cpp	Wed May 17 09:01:40 2017 +0200
@@ -481,11 +481,22 @@
   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(_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 +506,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/bytecodes.hpp	Wed May 17 09:01:40 2017 +0200
@@ -243,10 +243,23 @@
     _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
+    _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 +269,7 @@
     _fast_sgetfield       ,
 
     _fast_aputfield       ,
+    _fast_qputfield       ,
     _fast_bputfield       ,
     _fast_zputfield       ,
     _fast_cputfield       ,
--- a/src/share/vm/interpreter/interpreterRuntime.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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,212 @@
   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();
+  ResourceMark rm(THREAD);
+  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 +384,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 +436,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 +811,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 +857,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);
     }
   }
 
@@ -871,6 +1130,8 @@
   case Bytecodes::_putstatic:
   case Bytecodes::_getfield:
   case Bytecodes::_putfield:
+  case Bytecodes::_vgetfield:
+  case Bytecodes::_vwithfield:
     resolve_get_put(thread, bytecode);
     break;
   case Bytecodes::_invokevirtual:
--- a/src/share/vm/interpreter/interpreterRuntime.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/interpreterRuntime.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/linkResolver.cpp	Wed May 17 09:01:40 2017 +0200
@@ -901,11 +901,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();
--- a/src/share/vm/interpreter/oopMapCache.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/oopMapCache.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/rewriter.cpp	Wed May 17 09:01:40 2017 +0200
@@ -446,6 +446,8 @@
         // 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::_invokestatic   :
         case Bytecodes::_invokeinterface:
--- a/src/share/vm/interpreter/templateInterpreter.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/templateInterpreter.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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);
 }
 
--- a/src/share/vm/interpreter/templateInterpreter.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/templateInterpreter.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/templateInterpreterGenerator.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/templateTable.cpp	Wed May 17 09:01:40 2017 +0200
@@ -460,6 +460,17 @@
   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::_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 +478,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 +501,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/interpreter/templateTable.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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();
@@ -285,7 +291,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 +301,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.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/jvmci/jvmciCompilerToVM.cpp	Wed May 17 09:01:40 2017 +0200
@@ -1423,7 +1423,7 @@
             // native wrapper do not have a scope
             if (scope != NULL && scope->objects() != NULL) {
               bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), scope->objects(), THREAD);
-              Deoptimization::reassign_fields(fst.current(), fst.register_map(), scope->objects(), realloc_failures, false);
+              Deoptimization::reassign_fields(fst.current(), fst.register_map(), scope->objects(), realloc_failures, false, THREAD);
 
               GrowableArray<ScopeValue*>* local_values = scope->locals();
               typeArrayOop array_oop = oopFactory::new_boolArray(local_values->length(), thread);
@@ -1604,7 +1604,7 @@
   }
 
   bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), objects, THREAD);
-  Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false);
+  Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false, THREAD);
 
   for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) {
     compiledVFrame* cvf = virtualFrames->at(frame_index);
--- a/src/share/vm/jvmci/jvmciCompilerToVM.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/jvmci/jvmciCompilerToVM.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/memory/iterator.inline.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/memory/oopFactory.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/memory/oopFactory.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/memory/universe.inline.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/arrayKlass.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/arrayKlass.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/arrayOop.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/cpCache.cpp	Wed May 17 09:01:40 2017 +0200
@@ -230,11 +230,12 @@
       // 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, "");
     }
     // set up for invokevirtual, even if linking for invokeinterface also:
-    set_bytecode_2(Bytecodes::_invokevirtual);
+    set_bytecode_2(invoke_code);
   } else {
     ShouldNotReachHere();
   }
--- a/src/share/vm/oops/cpCache.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/cpCache.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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
@@ -306,6 +307,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
@@ -313,6 +315,7 @@
       case Bytecodes::_invokeinterface : return 1;
       case Bytecodes::_putstatic       :    // fall through
       case Bytecodes::_putfield        :    // fall through
+      case Bytecodes::_vwithfield      :    // fall through
       case Bytecodes::_invokevirtual   : return 2;
       default                          : break;
     }
@@ -345,6 +348,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; }
@@ -357,6 +361,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/generateOopMap.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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);
@@ -134,8 +135,9 @@
     _idx    = 0;
     _effect = effect;
 
-    if (!is_static)
-      effect[_idx++] = CellTypeState::ref;
+    if (!is_static) {
+      effect[_idx++] = CellTypeState::refOrValueType;
+    }
 
     iterate_parameters();
 
@@ -174,6 +176,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 +290,8 @@
 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::refOrValueType = CellTypeState::make_any(valuetype_conflict | ref_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 +300,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 +316,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 +355,11 @@
   } else {
     os->print(" ");
   }
+  if (can_be_valuetype()) {
+    os->print("q");
+  } else {
+    os->print(" ");
+  }
   if (can_be_uninit()) {
     os->print("u|");
   } else {
@@ -576,6 +594,7 @@
     case Bytecodes::_freturn:
     case Bytecodes::_dreturn:
     case Bytecodes::_areturn:
+    case Bytecodes::_vreturn:
     case Bytecodes::_return:
     case Bytecodes::_ret:
       break;
@@ -687,13 +706,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 +837,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);
@@ -1361,6 +1382,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 +1416,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 +1451,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 +1460,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 +1493,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 +1603,19 @@
     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::_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::_invokespecial:     do_method(false, itr->get_index_u2_cpcache(), itr->bci()); break;
+    case Bytecodes::_invokestatic:      do_method(true , itr->get_index_u2_cpcache(), itr->bci()); break;
+    case Bytecodes::_invokedynamic:     do_method(true , itr->get_index_u4(),         itr->bci()); break;
     case Bytecodes::_newarray:
     case Bytecodes::_anewarray:         pp_new_ref(vCTS, itr->bci()); break;
     case Bytecodes::_checkcast:         do_checkcast(); break;
@@ -1603,10 +1635,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;
 
@@ -1622,6 +1662,9 @@
 
 void GenerateOopMap::check_type(CellTypeState expected, CellTypeState actual) {
   if (!expected.equal_kind(actual)) {
+    // dirty hack for invokevirtual
+    if (expected.equal_kind(CellTypeState::refOrValueType) &&
+        (actual.equal_kind(CellTypeState::ref) || actual.equal_kind(CellTypeState::valuetype))) return;
     verify_error("wrong type on stack (found: %c expected: %c)", actual.to_char(), expected.to_char());
   }
 }
@@ -1640,7 +1683,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 +1752,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 +1772,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 +1943,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 +1963,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 +1988,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 idx, int bci) {
  // Dig up signature for field in constant pool
   ConstantPool* cp  = _method->constants();
   Symbol* signature   = cp->signature_ref_at(idx);
@@ -1973,6 +2037,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 +2073,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/generateOopMap.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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,8 @@
   static CellTypeState uninit;
   static CellTypeState ref;
   static CellTypeState value;
+  static CellTypeState valuetype;
+  static CellTypeState refOrValueType;
   static CellTypeState refUninit;
   static CellTypeState varUninit;
   static CellTypeState top;
@@ -397,12 +421,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 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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/instanceKlass.cpp	Wed May 17 09:01:40 2017 +0200
@@ -57,6 +57,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) {
@@ -565,6 +598,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;
@@ -635,6 +723,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;
@@ -697,6 +792,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);
@@ -2218,7 +2318,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; ) {
@@ -2805,20 +2905,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 {
@@ -2828,6 +2963,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();
@@ -2854,26 +2990,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:  ");
@@ -2919,7 +3043,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);
@@ -3712,3 +3836,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 (!EnableMVT) {
+    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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/instanceKlass.hpp	Wed May 17 09:01:40 2017 +0200
@@ -100,12 +100,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;
@@ -192,11 +208,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;
 
@@ -204,23 +220,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;
@@ -286,6 +303,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
@@ -537,7 +556,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;
@@ -769,6 +788,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
 
@@ -1062,6 +1082,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());
   }
@@ -1111,7 +1133,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());
   }
 
@@ -1298,12 +1320,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,
@@ -1340,6 +1364,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/instanceKlass.inline.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/instanceOop.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/klass.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/klassVtable.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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;
 }
@@ -1321,6 +1323,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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/klassVtable.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/method.cpp	Wed May 17 09:01:40 2017 +0200
@@ -2213,6 +2213,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();
@@ -2290,6 +2292,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/objArrayKlass.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/objArrayKlass.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/oop.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/oop.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/oop.inline.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/oopsHierarchy.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/typeArrayKlass.cpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 07:14:52 2017 +0200
+++ b/src/share/vm/oops/typeArrayOop.hpp	Wed May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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 May 17 09:01:40 2017 +0200
@@ -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/opto/addnode.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/addnode.cpp	Wed May 17 09:01:40 2017 +0200
@@ -655,6 +655,12 @@
   if (tx->is_con()) {   // Left input is an add of a constant?
     txoffset = tx->get_con();
   }
+  if (tp->isa_aryptr()) {
+    // In the case of a flattened value type array, each field has its
+    // own slice so we need to extract the field being accessed from
+    // the address computation
+    return tp->is_aryptr()->with_field_offset_and_offset(txoffset);
+  }
   return tp->add_offset(txoffset);
 }
 
@@ -675,6 +681,12 @@
   if (p2->is_con()) {   // Left input is an add of a constant?
     p2offset = p2->get_con();
   }
+  if (p1->isa_aryptr()) {
+    // In the case of a flattened value type array, each field has its
+    // own slice so we need to extract the field being accessed from
+    // the address computation
+    return p1->is_aryptr()->with_field_offset_and_offset(p2offset);
+  }
   return p1->add_offset(p2offset);
 }
 
--- a/src/share/vm/opto/buildOopMap.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/buildOopMap.cpp	Wed May 17 09:01:40 2017 +0200
@@ -256,12 +256,12 @@
         regalloc->C->record_method_not_compilable("illegal oopMap register name");
         continue;
       }
-      if( t->is_ptr()->_offset == 0 ) { // Not derived?
+      if (t->is_ptr()->offset() == 0) { // Not derived?
         if( mcall ) {
           // Outgoing argument GC mask responsibility belongs to the callee,
           // not the caller.  Inspect the inputs to the call, to see if
           // this live-range is one of them.
-          uint cnt = mcall->tf()->domain()->cnt();
+          uint cnt = mcall->tf()->domain_cc()->cnt();
           uint j;
           for( j = TypeFunc::Parms; j < cnt; j++)
             if( mcall->in(j) == def )
@@ -331,7 +331,7 @@
           // Outgoing argument GC mask responsibility belongs to the callee,
           // not the caller.  Inspect the inputs to the call, to see if
           // this live-range is one of them.
-        uint cnt = mcall->tf()->domain()->cnt();
+        uint cnt = mcall->tf()->domain_cc()->cnt();
         uint j;
         for( j = TypeFunc::Parms; j < cnt; j++)
           if( mcall->in(j) == def )
--- a/src/share/vm/opto/callGenerator.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/callGenerator.cpp	Wed May 17 09:01:40 2017 +0200
@@ -39,6 +39,7 @@
 #include "opto/rootnode.hpp"
 #include "opto/runtime.hpp"
 #include "opto/subnode.hpp"
+#include "opto/valuetypenode.hpp"
 #include "runtime/sharedRuntime.hpp"
 
 // Utility function.
@@ -133,6 +134,7 @@
 JVMState* DirectCallGenerator::generate(JVMState* jvms) {
   GraphKit kit(jvms);
   kit.C->print_inlining_update(this);
+  PhaseGVN& gvn = kit.gvn();
   bool is_static = method()->is_static();
   address target = is_static ? SharedRuntime::get_resolve_static_call_stub()
                              : SharedRuntime::get_resolve_opt_virtual_call_stub();
@@ -151,9 +153,11 @@
   }
   _call_node = call;  // Save the call node in case we need it later
   if (!is_static) {
-    // Make an explicit receiver null_check as part of this call.
-    // Since we share a map with the caller, his JVMS gets adjusted.
-    kit.null_check_receiver_before_call(method());
+    if (!kit.argument(0)->is_ValueType()) {
+      // Make an explicit receiver null_check as part of this call.
+      // Since we share a map with the caller, his JVMS gets adjusted.
+      kit.null_check_receiver_before_call(method());
+    }
     if (kit.stopped()) {
       // And dump it back to the caller, decorated with any exceptions:
       return kit.transfer_exceptions_into_jvms();
@@ -168,7 +172,14 @@
   kit.set_arguments_for_java_call(call);
   kit.set_edges_for_java_call(call, false, _separate_io_proj);
   Node* ret = kit.set_results_for_java_call(call, _separate_io_proj);
-  kit.push_node(method()->return_type()->basic_type(), ret);
+  // Check if return value is a value type pointer
+  if (gvn.type(ret)->isa_valuetypeptr()) {
+    // Create ValueTypeNode from the oop and replace the return value
+    Node* vt = ValueTypeNode::make(gvn, kit.merged_memory(), ret);
+    kit.push_node(T_VALUETYPE, vt);
+  } else {
+    kit.push_node(method()->return_type()->basic_type(), ret);
+  }
   return kit.transfer_exceptions_into_jvms();
 }
 
@@ -191,7 +202,7 @@
 JVMState* VirtualCallGenerator::generate(JVMState* jvms) {
   GraphKit kit(jvms);
   Node* receiver = kit.argument(0);
-
+  PhaseGVN& gvn = kit.gvn();
   kit.C->print_inlining_update(this);
 
   if (kit.C->log() != NULL) {
@@ -251,7 +262,14 @@
   kit.set_arguments_for_java_call(call);
   kit.set_edges_for_java_call(call);
   Node* ret = kit.set_results_for_java_call(call);
-  kit.push_node(method()->return_type()->basic_type(), ret);
+  // Check if return value is a value type pointer
+  if (gvn.type(ret)->isa_valuetypeptr()) {
+    // Create ValueTypeNode from the oop and replace the return value
+    Node* vt = ValueTypeNode::make(gvn, kit.merged_memory(), ret);
+    kit.push_node(T_VALUETYPE, vt);
+  } else {
+    kit.push_node(method()->return_type()->basic_type(), ret);
+  }
 
   // Represent the effect of an implicit receiver null_check
   // as part of this call.  Since we share a map with the caller,
@@ -349,7 +367,7 @@
     return;
   }
 
-  const TypeTuple *r = call->tf()->domain();
+  const TypeTuple *r = call->tf()->domain_cc();
   for (int i1 = 0; i1 < method()->arg_size(); i1++) {
     if (call->in(TypeFunc::Parms + i1)->is_top() && r->field_at(TypeFunc::Parms + i1) != Type::HALF) {
       assert(Compile::current()->inlining_incrementally(), "shouldn't happen during parsing");
@@ -377,26 +395,48 @@
     map->init_req(i1, call->in(i1));
   }
 
+  PhaseGVN& gvn = *C->initial_gvn();
   // Make sure the state is a MergeMem for parsing.
   if (!map->in(TypeFunc::Memory)->is_MergeMem()) {
     Node* mem = MergeMemNode::make(map->in(TypeFunc::Memory));
-    C->initial_gvn()->set_type_bottom(mem);
+    gvn.set_type_bottom(mem);
     map->set_req(TypeFunc::Memory, mem);
   }
 
-  uint nargs = method()->arg_size();
   // blow away old call arguments
   Node* top = C->top();
-  for (uint i1 = 0; i1 < nargs; i1++) {
-    map->set_req(TypeFunc::Parms + i1, top);
+  for (uint i1 = TypeFunc::Parms; i1 < call->_tf->domain_cc()->cnt(); i1++) {
+    map->set_req(i1, top);
   }
   jvms->set_map(map);
 
   // Make enough space in the expression stack to transfer
   // the incoming arguments and return value.
   map->ensure_stack(jvms, jvms->method()->max_stack());
+  const TypeTuple *domain_sig = call->_tf->domain_sig();
+  uint nargs = method()->arg_size();
+  assert(domain_sig->cnt() - TypeFunc::Parms == nargs, "inconsistent signature");
+
+  uint j = TypeFunc::Parms;
   for (uint i1 = 0; i1 < nargs; i1++) {
-    map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1));
+    const Type* t = domain_sig->field_at(TypeFunc::Parms + i1);
+    if (!ValueTypePassFieldsAsArgs) {
+      Node* arg = call->in(TypeFunc::Parms + i1);
+      if (t->isa_valuetypeptr()) {
+        arg = ValueTypeNode::make(gvn, map->memory(), arg);
+      }
+      map->set_argument(jvms, i1, arg);
+    } else {
+      if (t->isa_valuetypeptr() && t->is_valuetypeptr()->klass() != C->env()->___Value_klass()) {
+        ciValueKlass* vk = t->is_valuetypeptr()->value_type()->value_klass();
+        Node* vt = C->create_vt_node(call, vk, vk, 0, j);
+        map->set_argument(jvms, i1, gvn.transform(vt));
+        j += vk->value_arg_slots();
+      } else {
+        map->set_argument(jvms, i1, call->in(j));
+        j++;
+      }
+    }
   }
 
   C->print_inlining_assert_ready();
@@ -439,6 +479,10 @@
   C->env()->notice_inlined_method(_inline_cg->method());
   C->set_inlining_progress(true);
 
+  if (result->is_ValueType()) {
+    result = result->as_ValueType()->store_to_memory(&kit);
+  }
+
   kit.replace_call(call, result, true);
 }
 
--- a/src/share/vm/opto/callnode.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/callnode.cpp	Wed May 17 09:01:40 2017 +0200
@@ -39,6 +39,7 @@
 #include "opto/regmask.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/runtime.hpp"
+#include "opto/valuetypenode.hpp"
 
 // Portions of code courtesy of Clifford Click
 
@@ -744,7 +745,7 @@
 bool CallNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) {
   assert((t_oop != NULL), "sanity");
   if (is_call_to_arraycopystub() && strcmp(_name, "unsafe_arraycopy") != 0) {
-    const TypeTuple* args = _tf->domain();
+    const TypeTuple* args = _tf->domain_sig();
     Node* dest = NULL;
     // Stubs that can be called once an ArrayCopyNode is expanded have
     // different signatures. Look for the second pointer argument,
@@ -792,7 +793,7 @@
           return true;
         }
       }
-      const TypeTuple* d = tf()->domain();
+      const TypeTuple* d = tf()->domain_cc();
       for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
         const TypeInstPtr* inst_t = d->field_at(i)->isa_instptr();
         if ((inst_t != NULL) && (!inst_t->klass_is_exact() ||
@@ -808,7 +809,7 @@
 
 // Does this call have a direct reference to n other than debug information?
 bool CallNode::has_non_debug_use(Node *n) {
-  const TypeTuple * d = tf()->domain();
+  const TypeTuple * d = tf()->domain_cc();
   for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
     Node *arg = in(i);
     if (arg == n) {
@@ -818,6 +819,16 @@
   return false;
 }
 
+bool CallNode::has_debug_use(Node *n) {
+  for (uint i = jvms()->debug_start(); i < jvms()->debug_end(); i++) {
+    Node *arg = in(i);
+    if (arg == n) {
+      return true;
+    }
+  }
+  return false;
+}
+
 // Returns the unique CheckCastPP of a call
 // or 'this' if there are several CheckCastPP or unexpected uses
 // or returns NULL if there is no one.
@@ -1129,7 +1140,31 @@
 //------------------------------Ideal------------------------------------------
 // Skip over any collapsed Regions
 Node *SafePointNode::Ideal(PhaseGVN *phase, bool can_reshape) {
-  return remove_dead_region(phase, can_reshape) ? this : NULL;
+  if (remove_dead_region(phase, can_reshape)) {
+    return this;
+  }
+  if (jvms() != NULL) {
+    bool progress = false;
+    // A ValueTypeNode that was already heap allocated in the debug
+    // info?  Reference the object directly. Helps removal of useless
+    // value type allocations with incremental inlining.
+    for (uint i = jvms()->debug_start(); i < jvms()->debug_end(); i++) {
+      Node *arg = in(i);
+      if (arg->is_ValueType()) {
+        ValueTypeNode* vt = arg->as_ValueType();
+        Node* in_oop = vt->get_oop();
+        const Type* oop_type = phase->type(in_oop);
+        if (!TypePtr::NULL_PTR->higher_equal(oop_type)) {
+          set_req(i, in_oop);
+          progress = true;
+        }
+      }
+    }
+    if (progress) {
+      return this;
+    }
+  }
+  return NULL;
 }
 
 //------------------------------Identity---------------------------------------
@@ -1368,7 +1403,10 @@
 
 //=============================================================================
 Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
-  if (remove_dead_region(phase, can_reshape))  return this;
+  Node* res = SafePointNode::Ideal(phase, can_reshape);
+  if (res != NULL) {
+    return res;
+  }
   // Don't bother trying to transform a dead node
   if (in(0) && in(0)->is_top())  return NULL;
 
--- a/src/share/vm/opto/callnode.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/callnode.hpp	Wed May 17 09:01:40 2017 +0200
@@ -572,7 +572,7 @@
   const char *_name;           // Printable name, if _method is NULL
 
   CallNode(const TypeFunc* tf, address addr, const TypePtr* adr_type)
-    : SafePointNode(tf->domain()->cnt(), NULL, adr_type),
+    : SafePointNode(tf->domain_cc()->cnt(), NULL, adr_type),
       _tf(tf),
       _entry_point(addr),
       _cnt(COUNT_UNKNOWN),
@@ -618,6 +618,7 @@
   virtual bool        may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase);
   // Does this node have a use of n other than in debug information?
   bool                has_non_debug_use(Node *n);
+  bool                has_debug_use(Node *n);
   // Returns the unique CheckCastPP of a call
   // or result projection is there are several CheckCastPP
   // or returns NULL if there is no one.
@@ -1068,7 +1069,7 @@
 
     const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0,fields);
 
-    return TypeFunc::make(domain,range);
+    return TypeFunc::make(domain, range);
   }
 
   virtual int Opcode() const;
--- a/src/share/vm/opto/cfgnode.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/cfgnode.cpp	Wed May 17 09:01:40 2017 +0200
@@ -41,6 +41,7 @@
 #include "opto/regmask.hpp"
 #include "opto/runtime.hpp"
 #include "opto/subnode.hpp"
+#include "opto/valuetypenode.hpp"
 
 // Portions of code courtesy of Clifford Click
 
@@ -1630,6 +1631,20 @@
   if( phase->type_or_null(r) == Type::TOP ) // Dead code?
     return NULL;                // No change
 
+  // If all inputs are value types, push the value type node down through the
+  // phi because value type nodes should be merged through their input values.
+  bool all_vt = true;
+  for (uint i = 1; i < req() && all_vt; ++i) {
+    all_vt = in(i) && in(i)->is_ValueType();
+  }
+  if (req() > 2 && all_vt) {
+    ValueTypeNode* vt = in(1)->as_ValueType()->clone_with_phis(phase, in(0));
+    for (uint i = 2; i < req(); ++i) {
+      vt->merge_with(phase, in(i)->as_ValueType(), i, i == (req()-1));
+    }
+    return vt;
+  }
+
   Node *top = phase->C->top();
   bool new_phi = (outcnt() == 0); // transforming new Phi
   // No change for igvn if new phi is not hooked
--- a/src/share/vm/opto/chaitin.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/chaitin.cpp	Wed May 17 09:01:40 2017 +0200
@@ -1728,10 +1728,10 @@
   // can't happen at run-time but the optimizer cannot deduce it so
   // we have to handle it gracefully.
   assert(!derived->bottom_type()->isa_narrowoop() ||
-          derived->bottom_type()->make_ptr()->is_ptr()->_offset == 0, "sanity");
+         derived->bottom_type()->make_ptr()->is_ptr()->offset() == 0, "sanity");
   const TypePtr *tj = derived->bottom_type()->isa_ptr();
   // If its an OOP with a non-zero offset, then it is derived.
-  if( tj == NULL || tj->_offset == 0 ) {
+  if (tj == NULL || tj->offset() == 0) {
     derived_base_map[derived->_idx] = derived;
     return derived;
   }
@@ -1897,9 +1897,9 @@
           Node *derived = lrgs(neighbor)._def;
           const TypePtr *tj = derived->bottom_type()->isa_ptr();
           assert(!derived->bottom_type()->isa_narrowoop() ||
-                  derived->bottom_type()->make_ptr()->is_ptr()->_offset == 0, "sanity");
+                 derived->bottom_type()->make_ptr()->is_ptr()->offset() == 0, "sanity");
           // If its an OOP with a non-zero offset, then it is derived.
-          if( tj && tj->_offset != 0 && tj->isa_oop_ptr() ) {
+          if (tj && tj->offset() != 0 && tj->isa_oop_ptr()) {
             Node *base = find_base_for_derived(derived_base_map, derived, maxlrg);
             assert(base->_idx < _lrg_map.size(), "");
             // Add reaching DEFs of derived pointer and base pointer as a
@@ -2191,7 +2191,7 @@
 
 void PhaseChaitin::dump_frame() const {
   const char *fp = OptoReg::regname(OptoReg::c_frame_pointer);
-  const TypeTuple *domain = C->tf()->domain();
+  const TypeTuple *domain = C->tf()->domain_cc();
   const int        argcnt = domain->cnt() - TypeFunc::Parms;
 
   // Incoming arguments in registers dump
--- a/src/share/vm/opto/classes.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/classes.cpp	Wed May 17 09:01:40 2017 +0200
@@ -46,6 +46,7 @@
 #include "opto/opaquenode.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/subnode.hpp"
+#include "opto/valuetypenode.hpp"
 #include "opto/vectornode.hpp"
 
 // ----------------------------------------------------------------------------
--- a/src/share/vm/opto/classes.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/classes.hpp	Wed May 17 09:01:40 2017 +0200
@@ -283,6 +283,7 @@
 macro(URShiftL)
 macro(XorI)
 macro(XorL)
+macro(ValueType)
 macro(Vector)
 macro(AddVB)
 macro(AddVS)
--- a/src/share/vm/opto/compile.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/compile.cpp	Wed May 17 09:01:40 2017 +0200
@@ -65,6 +65,7 @@
 #include "opto/runtime.hpp"
 #include "opto/stringopts.hpp"
 #include "opto/type.hpp"
+#include "opto/valuetypenode.hpp"
 #include "opto/vectornode.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/sharedRuntime.hpp"
@@ -758,7 +759,7 @@
     } else {
       // Normal case.
       init_tf(TypeFunc::make(method()));
-      StartNode* s = new StartNode(root(), tf()->domain());
+      StartNode* s = new StartNode(root(), tf()->domain_cc());
       initial_gvn()->set_type_bottom(s);
       init_start(s);
       if (method()->intrinsic_id() == vmIntrinsics::_Reference_get && UseG1GC) {
@@ -1417,16 +1418,18 @@
     if ( offset != Type::OffsetBot &&
          offset > arrayOopDesc::length_offset_in_bytes() ) {
       offset = Type::OffsetBot; // Flatten constant access into array body only
-      tj = ta = TypeAryPtr::make(ptr, ta->ary(), ta->klass(), true, offset, ta->instance_id());
+      tj = ta = TypeAryPtr::make(ptr, ta->ary(), ta->klass(), true, Type::Offset(offset), ta->_field_offset, ta->instance_id());
     }
   } else if( ta && _AliasLevel >= 2 ) {
     // For arrays indexed by constant indices, we flatten the alias
     // space to include all of the array body.  Only the header, klass
     // and array length can be accessed un-aliased.
+    // For flattened value type array, each field has its own slice so
+    // we must include the field offset.
     if( offset != Type::OffsetBot ) {
       if( ta->const_oop() ) { // MethodData* or Method*
         offset = Type::OffsetBot;   // Flatten constant access into array body
-        tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),ta->ary(),ta->klass(),false,offset);
+        tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),ta->ary(),ta->klass(),false,Type::Offset(offset), ta->_field_offset);
       } else if( offset == arrayOopDesc::length_offset_in_bytes() ) {
         // range is OK as-is.
         tj = ta = TypeAryPtr::RANGE;
@@ -1440,35 +1443,35 @@
         ptr = TypePtr::BotPTR;
       } else {                  // Random constant offset into array body
         offset = Type::OffsetBot;   // Flatten constant access into array body
-        tj = ta = TypeAryPtr::make(ptr,ta->ary(),ta->klass(),false,offset);
+        tj = ta = TypeAryPtr::make(ptr,ta->ary(),ta->klass(),false,Type::Offset(offset), ta->_field_offset);
       }
     }
     // Arrays of fixed size alias with arrays of unknown size.
     if (ta->size() != TypeInt::POS) {
       const TypeAry *tary = TypeAry::make(ta->elem(), TypeInt::POS);
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,ta->klass(),false,offset);
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,ta->klass(),false,Type::Offset(offset), ta->_field_offset);
     }
     // Arrays of known objects become arrays of unknown objects.
     if (ta->elem()->isa_narrowoop() && ta->elem() != TypeNarrowOop::BOTTOM) {
       const TypeAry *tary = TypeAry::make(TypeNarrowOop::BOTTOM, ta->size());
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset);
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,Type::Offset(offset), ta->_field_offset);
     }
     if (ta->elem()->isa_oopptr() && ta->elem() != TypeInstPtr::BOTTOM) {
       const TypeAry *tary = TypeAry::make(TypeInstPtr::BOTTOM, ta->size());
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset);
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,Type::Offset(offset), ta->_field_offset);
     }
     // Arrays of bytes and of booleans both use 'bastore' and 'baload' so
     // cannot be distinguished by bytecode alone.
     if (ta->elem() == TypeInt::BOOL) {
       const TypeAry *tary = TypeAry::make(TypeInt::BYTE, ta->size());
       ciKlass* aklass = ciTypeArrayKlass::make(T_BYTE);
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,aklass,false,offset);
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,aklass,false,Type::Offset(offset), ta->_field_offset);
     }
     // During the 2nd round of IterGVN, NotNull castings are removed.
     // Make sure the Bottom and NotNull variants alias the same.
     // Also, make sure exact and non-exact variants alias the same.
     if (ptr == TypePtr::NotNull || ta->klass_is_exact() || ta->speculative() != NULL) {
-      tj = ta = TypeAryPtr::make(TypePtr::BotPTR,ta->ary(),ta->klass(),false,offset);
+      tj = ta = TypeAryPtr::make(TypePtr::BotPTR,ta->ary(),ta->klass(),false,Type::Offset(offset), ta->_field_offset);
     }
   }
 
@@ -1482,7 +1485,7 @@
         // No constant oop pointers (such as Strings); they alias with
         // unknown strings.
         assert(!is_known_inst, "not scalarizable allocation");
-        tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
+        tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,Type::Offset(offset));
       }
     } else if( is_known_inst ) {
       tj = to; // Keep NotNull and klass_is_exact for instance type
@@ -1490,17 +1493,17 @@
       // During the 2nd round of IterGVN, NotNull castings are removed.
       // Make sure the Bottom and NotNull variants alias the same.
       // Also, make sure exact and non-exact variants alias the same.
-      tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
+      tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,Type::Offset(offset));
     }
     if (to->speculative() != NULL) {
-      tj = to = TypeInstPtr::make(to->ptr(),to->klass(),to->klass_is_exact(),to->const_oop(),to->offset(), to->instance_id());
+      tj = to = TypeInstPtr::make(to->ptr(),to->klass(),to->klass_is_exact(),to->const_oop(),Type::Offset(to->offset()), to->instance_id());
     }
     // Canonicalize the holder of this field
     if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) {
       // First handle header references such as a LoadKlassNode, even if the
       // object's klass is unloaded at compile time (4965979).
       if (!is_known_inst) { // Do it only for non-instance types
-        tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, offset);
+        tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, Type::Offset(offset));
       }
     } else if (offset < 0 || offset >= k->size_helper() * wordSize) {
       // Static fields are in the space above the normal instance
@@ -1514,9 +1517,9 @@
       ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset);
       if (!k->equals(canonical_holder) || tj->offset() != offset) {
         if( is_known_inst ) {
-          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, NULL, offset, to->instance_id());
+          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, NULL, Type::Offset(offset), to->instance_id());
         } else {
-          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset);
+          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, Type::Offset(offset));
         }
       }
     }
@@ -1533,7 +1536,7 @@
 
       tj = tk = TypeKlassPtr::make(TypePtr::NotNull,
                                    TypeKlassPtr::OBJECT->klass(),
-                                   offset);
+                                   Type::Offset(offset));
     }
 
     ciKlass* klass = tk->klass();
@@ -1541,7 +1544,7 @@
       ciKlass* k = TypeAryPtr::OOPS->klass();
       if( !k || !k->is_loaded() )                  // Only fails for some -Xcomp runs
         k = TypeInstPtr::BOTTOM->klass();
-      tj = tk = TypeKlassPtr::make( TypePtr::NotNull, k, offset );
+      tj = tk = TypeKlassPtr::make(TypePtr::NotNull, k, Type::Offset(offset));
     }
 
     // Check for precise loads from the primary supertype array and force them
@@ -1557,7 +1560,7 @@
          offset < (int)(primary_supers_offset + Klass::primary_super_limit() * wordSize)) ||
         offset == (int)in_bytes(Klass::secondary_super_cache_offset())) {
       offset = in_bytes(Klass::secondary_super_cache_offset());
-      tj = tk = TypeKlassPtr::make( TypePtr::NotNull, tk->klass(), offset );
+      tj = tk = TypeKlassPtr::make(TypePtr::NotNull, tk->klass(), Type::Offset(offset));
     }
   }
 
@@ -1777,8 +1780,9 @@
 
     // Check for final fields.
     const TypeInstPtr* tinst = flat->isa_instptr();
+    const TypeValueTypePtr* vtptr = flat->isa_valuetypeptr();
+    ciField* field = NULL;
     if (tinst && tinst->offset() >= instanceOopDesc::base_offset_in_bytes()) {
-      ciField* field;
       if (tinst->const_oop() != NULL &&
           tinst->klass() == ciEnv::current()->Class_klass() &&
           tinst->offset() >= (tinst->klass()->as_instance_klass()->size_helper() * wordSize)) {
@@ -1789,14 +1793,18 @@
         ciInstanceKlass *k = tinst->klass()->as_instance_klass();
         field = k->get_field_by_offset(tinst->offset(), false);
       }
-      assert(field == NULL ||
-             original_field == NULL ||
-             (field->holder() == original_field->holder() &&
-              field->offset() == original_field->offset() &&
-              field->is_static() == original_field->is_static()), "wrong field?");
-      // Set field() and is_rewritable() attributes.
-      if (field != NULL)  alias_type(idx)->set_field(field);
+    } else if (vtptr) {
+      // Value type field
+      ciValueKlass* vk = vtptr->klass()->as_value_klass();
+      field = vk->get_field_by_offset(vtptr->offset(), false);
     }
+    assert(field == NULL ||
+           original_field == NULL ||
+           (field->holder() == original_field->holder() &&
+            field->offset() == original_field->offset() &&
+            field->is_static() == original_field->is_static()), "wrong field?");
+    // Set field() and is_rewritable() attributes.
+    if (field != NULL)  alias_type(idx)->set_field(field);
   }
 
   // Fill the cache for next time.
@@ -2345,10 +2353,25 @@
  print_method(PHASE_OPTIMIZE_FINISHED, 2);
 }
 
+// Fixme remove
+static void check_for_value_node(Node &n, void* C) {
+  if (n.is_ValueType()) {
+#ifdef ASSERT
+    ((Compile*)C)->method()->print_short_name();
+    tty->print_cr("");
+    n.dump(-1);
+    assert(false, "Unable to match ValueTypeNode");
+#endif
+    ((Compile*)C)->record_failure("Unable to match ValueTypeNode");
+  }
+}
 
 //------------------------------Code_Gen---------------------------------------
 // Given a graph, generate code for it
 void Compile::Code_Gen() {
+  // FIXME remove
+  root()->walk(Node::nop, check_for_value_node, this);
+
   if (failing()) {
     return;
   }
@@ -3326,6 +3349,14 @@
     }
     break;
   }
+  case Op_ValueType: {
+    ValueTypeNode* vt = n->as_ValueType();
+    vt->make_scalar_in_safepoints(this);
+    if (vt->outcnt() == 0) {
+      vt->disconnect_inputs(NULL, this);
+    }
+    break;
+  }
   default:
     assert( !n->is_Call(), "" );
     assert( !n->is_Mem(), "" );
--- a/src/share/vm/opto/compile.hpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/compile.hpp	Wed May 17 09:01:40 2017 +0200
@@ -1335,6 +1335,8 @@
   CloneMap&     clone_map();
   void          set_clone_map(Dict* d);
 
+  // Create value type node from arguments at method entry
+  Node* create_vt_node(Node* n, ciValueKlass* vk, ciValueKlass* base_vk, int base_offset, int base_input);
 };
 
 #endif // SHARE_VM_OPTO_COMPILE_HPP
--- a/src/share/vm/opto/escape.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/escape.cpp	Wed May 17 09:01:40 2017 +0200
@@ -884,7 +884,7 @@
         ptnode_adr(call_idx)->set_scalar_replaceable(false);
       } else {
         // Determine whether any arguments are returned.
-        const TypeTuple* d = call->tf()->domain();
+        const TypeTuple* d = call->tf()->domain_sig();
         bool ret_arg = false;
         for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
           if (d->field_at(i)->isa_ptr() != NULL &&
@@ -931,7 +931,7 @@
     case Op_CallLeaf: {
       // Stub calls, objects do not escape but they are not scale replaceable.
       // Adjust escape state for outgoing arguments.
-      const TypeTuple * d = call->tf()->domain();
+      const TypeTuple * d = call->tf()->domain_sig();
       bool src_has_oops = false;
       for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
         const Type* at = d->field_at(i);
@@ -1059,11 +1059,16 @@
       // fall-through if not a Java method or no analyzer information
       if (call_analyzer != NULL) {
         PointsToNode* call_ptn = ptnode_adr(call->_idx);
-        const TypeTuple* d = call->tf()->domain();
+        const TypeTuple* d = call->tf()->domain_sig();
+        int extra = 0;
         for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
           const Type* at = d->field_at(i);
+          if (at->isa_valuetypeptr()) {
+            extra += at->is_valuetypeptr()->value_type()->value_klass()->field_count() - 1;
+            continue;
+          }
           int k = i - TypeFunc::Parms;
-          Node* arg = call->in(i);
+          Node* arg = call->in(i + extra);
           PointsToNode* arg_ptn = ptnode_adr(arg->_idx);
           if (at->isa_ptr() != NULL &&
               call_analyzer->is_arg_returned(k)) {
@@ -1103,7 +1108,7 @@
       // Fall-through here if not a Java method or no analyzer information
       // or some other type of call, assume the worst case: all arguments
       // globally escape.
-      const TypeTuple* d = call->tf()->domain();
+      const TypeTuple* d = call->tf()->domain_sig();
       for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
         const Type* at = d->field_at(i);
         if (at->isa_oopptr() != NULL) {
@@ -2061,8 +2066,8 @@
       }
     }
   } else if (offset != oopDesc::klass_offset_in_bytes()) {
-    if (adr_type->isa_instptr()) {
-      ciField* field = _compile->alias_type(adr_type->isa_instptr())->field();
+    if (adr_type->isa_instptr() || adr_type->isa_valuetypeptr()) {
+      ciField* field = _compile->alias_type(adr_type->is_ptr())->field();
       if (field != NULL) {
         bt = field->layout_type();
       } else {
@@ -2378,7 +2383,7 @@
     assert(offs != Type::OffsetBot, "offset must be a constant");
     t = base_t->add_offset(offs)->is_oopptr();
   }
-  int inst_id =  base_t->instance_id();
+  int inst_id = base_t->instance_id();
   assert(!t->is_known_instance() || t->instance_id() == inst_id,
                              "old type must be non-instance or match new type");
 
@@ -2402,7 +2407,13 @@
       !base_t->klass()->is_subtype_of(t->klass())) {
      return false; // bail out
   }
-  const TypeOopPtr *tinst = base_t->add_offset(t->offset())->is_oopptr();
+  const TypePtr* tinst = base_t->add_offset(t->offset());
+  if (tinst->isa_aryptr() && t->isa_aryptr()) {
+    // In the case of a flattened value type array, each field has its
+    // own slice so we need to keep track of the field being accessed.
+    tinst = tinst->is_aryptr()->with_field_offset(t->is_aryptr()->field_offset());
+  }
+
   // Do NOT remove the next line: ensure a new alias index is allocated
   // for the instance type. Note: C++ will not remove it since the call
   // has side effect.
@@ -2989,7 +3000,7 @@
       n->raise_bottom_type(tinst);
       igvn->hash_insert(n);
       record_for_optimizer(n);
-      if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr())) {
+      if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr() || t->isa_valuetypeptr())) {
 
         // First, put on the worklist all Field edges from Connection Graph
         // which is more accurate than putting immediate users from Ideal Graph.
@@ -3146,7 +3157,8 @@
               op == Op_CastP2X || op == Op_StoreCM ||
               op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives ||
               op == Op_StrCompressedCopy || op == Op_StrInflatedCopy ||
-              op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar)) {
+              op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar ||
+              op == Op_ValueType)) {
           n->dump();
           use->dump();
           assert(false, "EA: missing allocation reference path");
@@ -3285,7 +3297,7 @@
 
   //  Phase 3:  Process MergeMem nodes from mergemem_worklist.
   //            Walk each memory slice moving the first node encountered of each
-  //            instance type to the the input corresponding to its alias index.
+  //            instance type to the input corresponding to its alias index.
   uint length = _mergemem_worklist.length();
   for( uint next = 0; next < length; ++next ) {
     MergeMemNode* nmm = _mergemem_worklist.at(next);
@@ -3357,8 +3369,8 @@
   //            the Memory input of memnodes
   // First update the inputs of any non-instance Phi's from
   // which we split out an instance Phi.  Note we don't have
-  // to recursively process Phi's encounted on the input memory
-  // chains as is done in split_memory_phi() since they  will
+  // to recursively process Phi's encountered on the input memory
+  // chains as is done in split_memory_phi() since they will
   // also be processed here.
   for (int j = 0; j < orig_phis.length(); j++) {
     PhiNode *phi = orig_phis.at(j);
--- a/src/share/vm/opto/generateOptoStub.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/generateOptoStub.cpp	Wed May 17 09:01:40 2017 +0200
@@ -47,7 +47,7 @@
                         bool return_pc) {
   ResourceMark rm;
 
-  const TypeTuple *jdomain = C->tf()->domain();
+  const TypeTuple *jdomain = C->tf()->domain_sig();
   const TypeTuple *jrange  = C->tf()->range();
 
   // The procedure start
--- a/src/share/vm/opto/graphKit.cpp	Wed May 17 07:14:52 2017 +0200
+++ b/src/share/vm/opto/graphKit.cpp	Wed May 17 09:01:40 2017 +0200
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "compiler/compileLog.hpp"
+#include "ci/ciValueKlass.hpp"
 #include "gc/g1/g1SATBCardTableModRefBS.hpp"
 #include "gc/g1/heapRegion.hpp"
 #include "gc/shared/barrierSet.hpp"
@@ -42,6 +43,7 @@
 #include "opto/parse.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/runtime.hpp"
+#include "opto/valuetypenode.hpp"
 #include "runtime/deoptimization.hpp"
 #include "runtime/sharedRuntime.hpp"
 
@@ -1031,6 +1033,7 @@
   case Bytecodes::_getstatic:
   case Bytecodes::_putstatic:
   case Bytecodes::_getfield:
+  case Bytecodes::_vgetfield:
   case Bytecodes::_putfield:
     {
       bool ignored_will_link;
@@ -1074,11 +1077,21 @@
     }
     break;
 
+  case Bytecodes::_vwithfield: {
+    bool ignored_will_link;
+    ciField* field = method()->get_field_at_bci(bci(), ignored_will_link);
+    int      size  = field->type()->size();
+    inputs = size+1;
+    depth = rsize - inputs;
+    break;
+  }
+
   case Bytecodes::_ireturn:
   case Bytecodes::_lreturn:
   case Bytecodes::_freturn:
   case Bytecodes::_dreturn:
   case Bytecodes::_areturn:
+  case Bytecodes::_vreturn:
     assert(rsize == -depth, "");
     inputs = rsize;
     break;
@@ -1476,7 +1489,11 @@
     ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency, unaligned, mismatched);
   }
   ld = _gvn.transform(ld);
-  if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) {
+
+  if (bt == T_VALUETYPE) {
+    // Load value type from oop
+    ld = ValueTypeNode::make(gvn(), map()->memory(), ld);
+  } else if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) {
     // Improve graph before escape analysis and boxing elimination.
     record_for_igvn(ld);
   }
@@ -1611,11 +1628,16 @@
   set_control(ctl);
   if (stopped()) return top(); // Dead path ?
 
-  assert(bt == T_OBJECT, "sanity");
+  assert(bt == T_OBJECT || bt == T_VALUETYPE, "sanity");
   assert(val != NULL, "not dead path");
   uint adr_idx = C->get_alias_index(adr_type);
   assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
 
+  if (bt == T_VALUETYPE) {
+    // Allocate value type and store oop
+    val = val->as_ValueType()->store_to_memory(this);
+  }
+
   pre_barrier(true /* do_load */,
               control(), obj, adr, adr_idx, val, val_type,
               NULL /* pre_val */,
@@ -1661,6 +1683,11 @@
 Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt,
                                       const TypeInt* sizetype, Node* ctrl) {
   uint shift  = exact_log2(type2aelembytes(elembt));
+  ciKlass* arytype_klass = _gvn.type(ary)->is_aryptr()->klass();
+  if (arytype_klass->is_value_array_klass()) {
+    ciValueArrayKlass* vak = arytype_klass->as_value_array_klass();
+    shift = vak->log2_element_size();
+  }
   uint header = arrayOopDesc::base_offset_in_bytes(elembt);
 
   // short-circuit a common case (saves lots of confusing waste motion)
@@ -1681,6 +1708,7 @@
 Node* GraphKit::load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype) {
   const Type* elemtype = arytype->elem();
   BasicType elembt = elemtype->array_element_basic_type();
+  assert(elembt != T_VALUETYPE, "value types are not supported by this method");
   Node* adr = array_element_address(ary, idx, elembt, arytype->size());
   if (elembt == T_NARROWOOP) {
     elembt = T_OBJECT; // To satisfy switch in LoadNode::make()
@@ -1693,10 +1721,33 @@
 // Arguments (pre-popped from the stack) are taken from the JVMS.
 void GraphKit::set_arguments_for_java_call(CallJavaNode* call) {
   // Add the call arguments:
-  uint nargs = call->method()->arg_size();
-  for (uint i = 0; i < nargs; i++) {
-    Node* arg = argument(i);
-    call->init_req(i + TypeFunc::Parms, arg);
+  const TypeTuple* domain = call->tf()->domain_sig();
+  uint nargs = domain->cnt();
+  for (uint i = TypeFunc::Parms, idx = TypeFunc::Parms; i < nargs; i++) {
+    Node* arg = argument(i-TypeFunc::Parms);
+    if (ValueTypePassFieldsAsArgs) {
+      if (arg->is_ValueType()) {
+        ValueTypeNode* vt = arg->as_ValueType();
+        if (domain->field_at(i)->is_valuetypeptr()->klass() != C->env()->___Value_klass()) {
+          // We don't pass value type arguments by reference but instead
+          // pass each field of the value type
+          idx += vt->set_arguments_for_java_call(call, idx, *this);
+        } else {
+          arg = arg->as_ValueType()->store_to_memory(this);
+          call->init_req(idx, arg);
+          idx++;
+        }
+      } else {
+        call->init_req(idx, arg);
+        idx++;
+      }
+    } else {
+      if (arg->is_ValueType()) {
+        // Pass value type argument via oop to callee
+        arg = arg->as_ValueType()->store_to_memory(this);
+      }
+      call->init_req(i, arg);
+    }
   }
 }
 
@@ -2086,9 +2137,9 @@
 void GraphKit::round_double_arguments(ciMethod* dest_method) {
   // (Note:  TypeFunc::make has a cache that makes this fast.)
   const TypeFunc* tf    = TypeFunc::make(dest_method);
-  int             nargs = tf->domain()->cnt() - TypeFunc::Parms;
+  int             nargs = tf->domain_sig()->cnt() - TypeFunc::Parms;
   for (int j = 0; j < nargs; j++) {
-    const Type *targ = tf->domain()->field_at(j + TypeFunc::Parms);
+    const Type *targ = tf->domain_sig()->field_at(j + TypeFunc::Parms);
     if( targ->basic_type() == T_DOUBLE ) {
       // If any parameters are doubles, they must be rounded before
       // the call, dstore_rounding does gvn.transform
@@ -2140,7 +2191,7 @@
   if (speculative != current_type->speculative()) {
     // Build a type with a speculative type (what we think we know
     // about the type but will need a guard when we use it)
-    const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::OffsetBot, TypeOopPtr::InstanceBot, speculative);
+    const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::Offset::bottom, TypeOopPtr::InstanceBot, speculative);
     // We're changing the type, we need a new CheckCast node to carry
     // the new type. The new type depends on the control: what
     // profiling tells us is only valid from here as far as we can
@@ -2189,10 +2240,10 @@
     return;
   }
   const TypeFunc* tf    = TypeFunc::make(dest_method);
-  int             nargs = tf->domain()->cnt() - TypeFunc::Parms;
+  int             nargs = tf->domain_sig()->cnt() - TypeFunc::Parms;
   int skip = Bytecodes::has_receiver(bc) ? 1 : 0;
   for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) {
-    const Type *targ = tf->domain()->field_at(j + TypeFunc::Parms);
+    const Type *targ = tf->domain_sig()->field_at(j + TypeFunc::Parms);
     if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) {
       bool maybe_null = true;
       ciKlass* better_type = NULL;
@@ -3342,7 +3393,7 @@
       const TypePtr* telemref = oop_type->add_offset(Type::OffsetBot);
       int            elemidx  = C->get_alias_index(telemref);
       hook_memory_on_init(*this, elemidx, minit_in, minit_out);
-    } else if (oop_type->isa_instptr()) {
+    } else if (oop_type->isa_instptr() || oop_type->isa_valuetypeptr()) {
       ciInstanceKlass* ik = oop_type->klass()->as_instance_klass();
       for (int i = 0, len = ik->nof_nonstatic_fields(); i < len; i++) {
         ciField* field = ik->nonstatic_field_at(i);
@@ -3451,7 +3502,7 @@
   // Now generate allocation code
 
   // The entire memory state is needed for slow path of the allocation
-  // since GC and deoptimization can happened.
+  // since GC and deoptimization can happen.
   Node *mem = reset_memory();
   set_all_memory(mem); // Create new memory state
 
@@ -3464,7 +3515,7 @@
 }
 
 //-------------------------------new_array-------------------------------------
-// helper for both newarray and anewarray
+// helper for newarray, anewarray and vnewarray
 // The 'length' parameter is (obviously) the length of the array.
 // See comments on new_instance for the meaning of the other arguments.
 Node* GraphKit::new_array(Node* klass_node,     // array klass (maybe variable)
@@ -3523,9 +3574,10 @@
     int       hsize  = Klass::layout_helper_header_size(layout_con);
     int       eshift = Klass::layout_helper_log2_element_size(layout_con);
     BasicType etype  = Klass::layout_helper_element_type(layout_con);
+    bool is_value_array = Klass::layout_helper_is_valueArray(layout_con);
     if ((round_mask & ~right_n_bits(eshift)) == 0)
       round_mask = 0;  // strength-reduce it if it goes away completely
-    assert((hsize & right_n_bits(eshift)) == 0, "hsize is pre-rounded");
+    assert(is_value_array || (hsize & right_n_bits(eshift)) == 0, "hsize is pre-rounded");
     assert(header_size_min <= hsize, "generic minimum is smallest");
     header_size_min = hsize;
     header_size = intcon(hsize + round_mask);
@@ -3609,7 +3661,7 @@
   // Now generate allocation code
 
   // The entire memory state is needed for slow path of the allocation
-  // since GC and deoptimization can happened.
+  // since GC and deoptimization can happen.
   Node *mem = reset_memory();
   set_all_memory(mem); // Create new memory state
 
@@ -3649,9 +3701,94 @@
     }
   }
 
+  const TypeAryPtr* ary_ptr = ary_type->isa_aryptr();
+  ciKlass* elem_klass = ary_ptr != NULL ? ary_ptr->klass()->as_array_klass()->element_klass() : NULL;
+  if (elem_klass != NULL && elem_klass->is_valuetype()) {
+    ciValueKlass* vk = elem_klass->as_value_klass();
+    if (!vk->flatten_array()) {
+      // Non-flattened value type arrays need to be initialized with default value type oops
+      initialize_value_type_array(javaoop, length, elem_klass->as_value_klass(), nargs);
+      InitializeNode* init = alloc->initialization();
+      init->set_complete_with_arraycopy();
+    }
+  }
+
   return javaoop;
 }
 
+void GraphKit::initialize_value_type_array(Node* array, Node* length, ciValueKlass* vk, int nargs) {
+  // Check for zero length
+  Node* null_ctl = top();
+  null_check_common(length, T_INT, false, &null_ctl, false);
+  if (stopped()) {