changeset 47254:d4fe87089809 mvt

import changes from mvt/hotspot
author dsimms
date Tue, 26 Sep 2017 16:15:08 +0200
parents 4bded5db79fd
children 3eaad6e1e845
files src/hotspot/cpu/aarch64/globals_aarch64.hpp src/hotspot/cpu/ppc/globals_ppc.hpp src/hotspot/cpu/sparc/globals_sparc.hpp src/hotspot/cpu/x86/abstractInterpreter_x86.cpp src/hotspot/cpu/x86/frame_x86.cpp src/hotspot/cpu/x86/frame_x86.hpp src/hotspot/cpu/x86/frame_x86.inline.hpp src/hotspot/cpu/x86/globals_x86.hpp src/hotspot/cpu/x86/interp_masm_x86.cpp src/hotspot/cpu/x86/interp_masm_x86.hpp src/hotspot/cpu/x86/interpreterRT_x86.hpp src/hotspot/cpu/x86/interpreterRT_x86_32.cpp src/hotspot/cpu/x86/interpreterRT_x86_64.cpp src/hotspot/cpu/x86/macroAssembler_x86.cpp src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp src/hotspot/cpu/x86/stubGenerator_x86_64.cpp src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp src/hotspot/cpu/x86/templateTable_x86.cpp src/hotspot/cpu/x86/x86_64.ad src/hotspot/cpu/zero/globals_zero.hpp src/hotspot/share/adlc/formssel.cpp src/hotspot/share/c1/c1_GraphBuilder.cpp src/hotspot/share/c1/c1_IR.hpp src/hotspot/share/c1/c1_LinearScan.cpp src/hotspot/share/ci/bcEscapeAnalyzer.cpp src/hotspot/share/ci/ciArray.hpp src/hotspot/share/ci/ciArrayKlass.cpp src/hotspot/share/ci/ciArrayKlass.hpp src/hotspot/share/ci/ciClassList.hpp src/hotspot/share/ci/ciConstant.cpp src/hotspot/share/ci/ciConstant.hpp src/hotspot/share/ci/ciEnv.cpp src/hotspot/share/ci/ciEnv.hpp src/hotspot/share/ci/ciField.cpp src/hotspot/share/ci/ciField.hpp src/hotspot/share/ci/ciInstance.cpp src/hotspot/share/ci/ciInstanceKlass.cpp src/hotspot/share/ci/ciInstanceKlass.hpp src/hotspot/share/ci/ciKlass.hpp src/hotspot/share/ci/ciMetadata.hpp src/hotspot/share/ci/ciMethodBlocks.cpp src/hotspot/share/ci/ciObjArrayKlass.cpp src/hotspot/share/ci/ciObject.hpp src/hotspot/share/ci/ciObjectFactory.cpp src/hotspot/share/ci/ciReplay.cpp src/hotspot/share/ci/ciStreams.cpp src/hotspot/share/ci/ciStreams.hpp src/hotspot/share/ci/ciSymbol.hpp src/hotspot/share/ci/ciType.cpp src/hotspot/share/ci/ciType.hpp src/hotspot/share/ci/ciTypeFlow.cpp src/hotspot/share/ci/ciTypeFlow.hpp src/hotspot/share/ci/ciValueArray.hpp src/hotspot/share/ci/ciValueArrayKlass.cpp src/hotspot/share/ci/ciValueArrayKlass.hpp src/hotspot/share/ci/ciValueKlass.cpp src/hotspot/share/ci/ciValueKlass.hpp src/hotspot/share/ci/compilerInterface.hpp src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/classfile/classFileParser.hpp src/hotspot/share/classfile/classLoader.cpp src/hotspot/share/classfile/classLoaderData.cpp src/hotspot/share/classfile/classLoaderData.hpp src/hotspot/share/classfile/javaClasses.cpp src/hotspot/share/classfile/stackMapFrame.cpp src/hotspot/share/classfile/stackMapTable.cpp src/hotspot/share/classfile/systemDictionary.cpp src/hotspot/share/classfile/systemDictionary.hpp src/hotspot/share/classfile/verificationType.cpp src/hotspot/share/classfile/verificationType.hpp src/hotspot/share/classfile/verifier.cpp src/hotspot/share/classfile/verifier.hpp src/hotspot/share/classfile/vmSymbols.cpp src/hotspot/share/classfile/vmSymbols.hpp src/hotspot/share/code/codeBlob.cpp src/hotspot/share/code/codeBlob.hpp src/hotspot/share/code/compiledMethod.cpp src/hotspot/share/code/debugInfoRec.cpp src/hotspot/share/code/debugInfoRec.hpp src/hotspot/share/code/nmethod.cpp src/hotspot/share/code/pcDesc.hpp src/hotspot/share/code/scopeDesc.cpp src/hotspot/share/code/scopeDesc.hpp src/hotspot/share/compiler/compileBroker.cpp src/hotspot/share/compiler/methodLiveness.cpp src/hotspot/share/gc/parallel/psCompactionManager.cpp src/hotspot/share/gc/parallel/psParallelCompact.cpp src/hotspot/share/gc/parallel/psPromotionManager.cpp src/hotspot/share/interpreter/abstractInterpreter.hpp src/hotspot/share/interpreter/bytecodeInterpreter.cpp src/hotspot/share/interpreter/bytecodeTracer.cpp src/hotspot/share/interpreter/bytecodes.cpp src/hotspot/share/interpreter/bytecodes.hpp src/hotspot/share/interpreter/interpreterRuntime.cpp src/hotspot/share/interpreter/interpreterRuntime.hpp src/hotspot/share/interpreter/linkResolver.cpp src/hotspot/share/interpreter/oopMapCache.cpp src/hotspot/share/interpreter/rewriter.cpp src/hotspot/share/interpreter/templateInterpreter.cpp src/hotspot/share/interpreter/templateInterpreter.hpp src/hotspot/share/interpreter/templateInterpreterGenerator.cpp src/hotspot/share/interpreter/templateInterpreterGenerator.hpp src/hotspot/share/interpreter/templateTable.cpp src/hotspot/share/interpreter/templateTable.hpp src/hotspot/share/jvmci/jvmciCodeInstaller.cpp src/hotspot/share/jvmci/jvmciCompilerToVM.cpp src/hotspot/share/jvmci/jvmciCompilerToVM.hpp src/hotspot/share/jvmci/jvmciEnv.cpp src/hotspot/share/jvmci/vmStructs_jvmci.cpp src/hotspot/share/logging/logTag.hpp src/hotspot/share/memory/allocation.hpp src/hotspot/share/memory/allocation.inline.hpp src/hotspot/share/memory/iterator.hpp src/hotspot/share/memory/iterator.inline.hpp src/hotspot/share/memory/oopFactory.cpp src/hotspot/share/memory/oopFactory.hpp src/hotspot/share/memory/universe.inline.hpp src/hotspot/share/memory/vtBuffer.cpp src/hotspot/share/memory/vtBuffer.hpp src/hotspot/share/oops/arrayKlass.cpp src/hotspot/share/oops/arrayKlass.hpp src/hotspot/share/oops/arrayOop.hpp src/hotspot/share/oops/constantPool.cpp src/hotspot/share/oops/constantPool.hpp src/hotspot/share/oops/cpCache.cpp src/hotspot/share/oops/cpCache.hpp src/hotspot/share/oops/generateOopMap.cpp src/hotspot/share/oops/generateOopMap.hpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/instanceKlass.hpp src/hotspot/share/oops/instanceKlass.inline.hpp src/hotspot/share/oops/instanceOop.hpp src/hotspot/share/oops/klass.hpp src/hotspot/share/oops/klassVtable.cpp src/hotspot/share/oops/klassVtable.hpp src/hotspot/share/oops/method.cpp src/hotspot/share/oops/method.hpp src/hotspot/share/oops/methodData.cpp src/hotspot/share/oops/objArrayKlass.cpp src/hotspot/share/oops/objArrayKlass.hpp src/hotspot/share/oops/oop.cpp src/hotspot/share/oops/oop.hpp src/hotspot/share/oops/oop.inline.hpp src/hotspot/share/oops/oopsHierarchy.hpp src/hotspot/share/oops/typeArrayKlass.cpp src/hotspot/share/oops/typeArrayOop.hpp src/hotspot/share/oops/valueArrayKlass.cpp src/hotspot/share/oops/valueArrayKlass.hpp src/hotspot/share/oops/valueArrayKlass.inline.hpp src/hotspot/share/oops/valueArrayOop.cpp src/hotspot/share/oops/valueArrayOop.hpp src/hotspot/share/oops/valueKlass.cpp src/hotspot/share/oops/valueKlass.hpp src/hotspot/share/oops/valueKlass.inline.hpp src/hotspot/share/opto/addnode.cpp src/hotspot/share/opto/buildOopMap.cpp src/hotspot/share/opto/callGenerator.cpp src/hotspot/share/opto/callGenerator.hpp src/hotspot/share/opto/callnode.cpp src/hotspot/share/opto/callnode.hpp src/hotspot/share/opto/castnode.cpp src/hotspot/share/opto/castnode.hpp src/hotspot/share/opto/cfgnode.cpp src/hotspot/share/opto/chaitin.cpp src/hotspot/share/opto/classes.cpp src/hotspot/share/opto/classes.hpp src/hotspot/share/opto/compile.cpp src/hotspot/share/opto/compile.hpp src/hotspot/share/opto/connode.cpp src/hotspot/share/opto/divnode.cpp src/hotspot/share/opto/divnode.hpp src/hotspot/share/opto/doCall.cpp src/hotspot/share/opto/escape.cpp src/hotspot/share/opto/generateOptoStub.cpp src/hotspot/share/opto/graphKit.cpp src/hotspot/share/opto/graphKit.hpp src/hotspot/share/opto/lcm.cpp src/hotspot/share/opto/library_call.cpp src/hotspot/share/opto/live.cpp src/hotspot/share/opto/loopopts.cpp src/hotspot/share/opto/machnode.cpp src/hotspot/share/opto/machnode.hpp src/hotspot/share/opto/macro.cpp src/hotspot/share/opto/macro.hpp src/hotspot/share/opto/macroArrayCopy.cpp src/hotspot/share/opto/matcher.cpp src/hotspot/share/opto/matcher.hpp src/hotspot/share/opto/memnode.cpp src/hotspot/share/opto/memnode.hpp src/hotspot/share/opto/mulnode.cpp src/hotspot/share/opto/multnode.cpp src/hotspot/share/opto/multnode.hpp src/hotspot/share/opto/node.cpp src/hotspot/share/opto/node.hpp src/hotspot/share/opto/output.cpp src/hotspot/share/opto/parse.hpp src/hotspot/share/opto/parse1.cpp src/hotspot/share/opto/parse2.cpp src/hotspot/share/opto/parse3.cpp src/hotspot/share/opto/parseHelper.cpp src/hotspot/share/opto/phaseX.cpp src/hotspot/share/opto/phaseX.hpp src/hotspot/share/opto/runtime.cpp src/hotspot/share/opto/runtime.hpp src/hotspot/share/opto/split_if.cpp src/hotspot/share/opto/type.cpp src/hotspot/share/opto/type.hpp src/hotspot/share/opto/valuetypenode.cpp src/hotspot/share/opto/valuetypenode.hpp src/hotspot/share/precompiled/precompiled.hpp src/hotspot/share/prims/jni.cpp src/hotspot/share/prims/jni.h src/hotspot/share/prims/jvm.cpp src/hotspot/share/prims/jvm.h src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp src/hotspot/share/prims/jvmtiRedefineClasses.cpp src/hotspot/share/prims/jvmtiTagMap.cpp src/hotspot/share/prims/methodComparator.cpp src/hotspot/share/prims/methodHandles.cpp src/hotspot/share/prims/whitebox.cpp src/hotspot/share/runtime/arguments.cpp src/hotspot/share/runtime/deoptimization.cpp src/hotspot/share/runtime/deoptimization.hpp src/hotspot/share/runtime/fieldDescriptor.cpp src/hotspot/share/runtime/fieldType.cpp src/hotspot/share/runtime/fieldType.hpp src/hotspot/share/runtime/frame.cpp src/hotspot/share/runtime/frame.hpp src/hotspot/share/runtime/globals.hpp src/hotspot/share/runtime/handles.cpp src/hotspot/share/runtime/handles.hpp src/hotspot/share/runtime/javaCalls.cpp src/hotspot/share/runtime/mutexLocker.cpp src/hotspot/share/runtime/reflection.cpp src/hotspot/share/runtime/safepoint.cpp src/hotspot/share/runtime/sharedRuntime.cpp src/hotspot/share/runtime/sharedRuntime.hpp src/hotspot/share/runtime/signature.cpp src/hotspot/share/runtime/signature.hpp src/hotspot/share/runtime/stubRoutines.cpp src/hotspot/share/runtime/stubRoutines.hpp src/hotspot/share/runtime/thread.cpp src/hotspot/share/runtime/thread.hpp src/hotspot/share/runtime/vframeArray.cpp src/hotspot/share/runtime/vmStructs.cpp src/hotspot/share/runtime/vm_operations.cpp src/hotspot/share/runtime/vm_operations.hpp src/hotspot/share/services/diagnosticCommand.cpp src/hotspot/share/services/diagnosticCommand.hpp src/hotspot/share/services/nmtCommon.cpp src/hotspot/share/shark/sharkCacheDecache.cpp src/hotspot/share/utilities/accessFlags.hpp src/hotspot/share/utilities/constantTag.cpp src/hotspot/share/utilities/constantTag.hpp src/hotspot/share/utilities/exceptions.hpp src/hotspot/share/utilities/globalDefinitions.cpp src/hotspot/share/utilities/globalDefinitions.hpp src/hotspot/share/utilities/growableArray.hpp src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java test/hotspot/jtreg/TEST.groups test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue1.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBoundValueTypes.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeArray.java test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnresolvedValueClass.java test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueCapableClass1.java test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueCapableClass2.java test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTestBench.java test/hotspot/jtreg/runtime/valhalla/valuetypes/DeriveValueTypeCreation.java test/hotspot/jtreg/runtime/valhalla/valuetypes/Empty.java test/hotspot/jtreg/runtime/valhalla/valuetypes/IntValue.java test/hotspot/jtreg/runtime/valhalla/valuetypes/Long8Value.java test/hotspot/jtreg/runtime/valhalla/valuetypes/MVTCombo.java test/hotspot/jtreg/runtime/valhalla/valuetypes/MVTComboDebugTier1.java test/hotspot/jtreg/runtime/valhalla/valuetypes/MVTComboTier1.java test/hotspot/jtreg/runtime/valhalla/valuetypes/Person.java test/hotspot/jtreg/runtime/valhalla/valuetypes/PersonVcc.java test/hotspot/jtreg/runtime/valhalla/valuetypes/Point.java test/hotspot/jtreg/runtime/valhalla/valuetypes/Test8186715.java test/hotspot/jtreg/runtime/valhalla/valuetypes/UninitializedValueFieldsTest.java test/hotspot/jtreg/runtime/valhalla/valuetypes/VDefaultTest.java test/hotspot/jtreg/runtime/valhalla/valuetypes/VTBufferTest.java test/hotspot/jtreg/runtime/valhalla/valuetypes/VWithFieldTest.java test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueCapableClass.java test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueOops.java test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeCreation.java test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeDensity.java test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeGenerator.java test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeGetField.java test/hotspot/jtreg/runtime/valhalla/valuetypes/VboxUnbox.java test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/ValueCapableClass.java test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/VloadTest.java test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/VunboxErrorIndex.java
diffstat 295 files changed, 20801 insertions(+), 1880 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp	Tue Sep 26 16:15:08 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/hotspot/cpu/ppc/globals_ppc.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/ppc/globals_ppc.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -73,6 +73,9 @@
 
 define_pd_global(bool, PreserveFramePointer,  false);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, false);
+define_pd_global(bool, ValueTypeReturnedAsFields, 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/hotspot/cpu/sparc/globals_sparc.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/sparc/globals_sparc.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -78,6 +78,9 @@
 
 define_pd_global(bool, PreserveFramePointer, false);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, false);
+define_pd_global(bool, ValueTypeReturnedAsFields, 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/hotspot/cpu/x86/abstractInterpreter_x86.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp	Tue Sep 26 16:15:08 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/hotspot/cpu/x86/frame_x86.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/frame_x86.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -583,6 +583,7 @@
 
   switch (type) {
     case T_OBJECT  :
+    case T_VALUETYPE:
     case T_ARRAY   : {
       oop obj;
       if (method->is_native()) {
@@ -641,6 +642,7 @@
     DESCRIBE_FP_OFFSET(interpreter_frame_mirror);
     DESCRIBE_FP_OFFSET(interpreter_frame_mdp);
     DESCRIBE_FP_OFFSET(interpreter_frame_cache);
+    DESCRIBE_FP_OFFSET(interpreter_frame_vt_alloc_ptr);
     DESCRIBE_FP_OFFSET(interpreter_frame_locals);
     DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
     DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
--- a/src/hotspot/cpu/x86/frame_x86.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/frame_x86.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -73,7 +73,8 @@
     interpreter_frame_mirror_offset                  = interpreter_frame_method_offset - 1,
     interpreter_frame_mdp_offset                     = interpreter_frame_mirror_offset - 1,
     interpreter_frame_cache_offset                   = interpreter_frame_mdp_offset - 1,
-    interpreter_frame_locals_offset                  = interpreter_frame_cache_offset - 1,
+    interpreter_frame_vt_alloc_ptr_offset            = interpreter_frame_cache_offset - 1,
+    interpreter_frame_locals_offset                  = interpreter_frame_vt_alloc_ptr_offset - 1,
     interpreter_frame_bcp_offset                     = interpreter_frame_locals_offset - 1,
     interpreter_frame_initial_sp_offset              = interpreter_frame_bcp_offset - 1,
 
--- a/src/hotspot/cpu/x86/frame_x86.inline.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -192,6 +192,10 @@
   return (oop*)addr_at(interpreter_frame_mirror_offset);
 }
 
+inline intptr_t** frame::interpreter_frame_vt_alloc_ptr_addr() const {
+  return (intptr_t**)addr_at(interpreter_frame_vt_alloc_ptr_offset);
+}
+
 // top of expression stack
 inline intptr_t* frame::interpreter_frame_tos_address() const {
   intptr_t* last_sp = interpreter_frame_last_sp();
--- a/src/hotspot/cpu/x86/globals_x86.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/globals_x86.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -101,6 +101,9 @@
 
 define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, LP64_ONLY(true) NOT_LP64(false));
+define_pd_global(bool, ValueTypeReturnedAsFields, LP64_ONLY(true) NOT_LP64(false));
+
 #define ARCH_FLAGS(develop, \
                    product, \
                    diagnostic, \
--- a/src/hotspot/cpu/x86/interp_masm_x86.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -27,10 +27,12 @@
 #include "interpreter/interpreter.hpp"
 #include "interpreter/interpreterRuntime.hpp"
 #include "logging/log.hpp"
+#include "memory/vtBuffer.hpp"
 #include "oops/arrayOop.hpp"
 #include "oops/markOop.hpp"
 #include "oops/methodData.hpp"
 #include "oops/method.hpp"
+#include "oops/valueKlass.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/basicLock.hpp"
@@ -344,6 +346,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 +368,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;
@@ -625,6 +629,8 @@
 
 void InterpreterMacroAssembler::pop(TosState state) {
   switch (state) {
+  case ptos: // Fall through
+  case qtos: // Fall through
   case atos: pop_ptr();                 break;
   case btos:
   case ztos:
@@ -643,6 +649,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:
@@ -679,6 +686,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
@@ -728,6 +736,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
@@ -927,7 +936,8 @@
         Register ret_addr,
         bool throw_monitor_exception,
         bool install_monitor_exception,
-        bool notify_jvmdi) {
+        bool notify_jvmdi,
+        bool load_values) {
   // Note: Registers rdx xmm0 may be in use for the
   // result check if synchronized method
   Label unlocked, unlock, no_unlock;
@@ -1069,6 +1079,28 @@
     notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA
   }
 
+  Label vtbuffer_slow, vtbuffer_done;
+  const Register thread1 = NOT_LP64(rcx) LP64_ONLY(r15_thread);
+  const uintptr_t chunk_mask = VTBufferChunk::chunk_mask();
+  movptr(rbx, Address(rbp, frame::interpreter_frame_vt_alloc_ptr_offset * wordSize));
+  NOT_LP64(get_thread(thread1));
+  movptr(rcx, Address(thread1, JavaThread::vt_alloc_ptr_offset()));
+  cmpptr(rbx, rcx);
+  jcc(Assembler::equal, vtbuffer_done);
+  andptr(rbx, chunk_mask);
+  andptr(rcx, chunk_mask);
+  cmpptr(rbx, rcx);
+  jcc(Assembler::notEqual, vtbuffer_slow);
+  movptr(rbx, Address(rbp, frame::interpreter_frame_vt_alloc_ptr_offset * wordSize));
+  movptr(Address(thread1, JavaThread::vt_alloc_ptr_offset()), rbx);
+  jmp(vtbuffer_done);
+  bind(vtbuffer_slow);
+  push(state);
+  call_VM(noreg, CAST_FROM_FN_PTR(address,
+                                  InterpreterRuntime::recycle_vtbuffer));
+  pop(state);
+  bind(vtbuffer_done);
+
   // remove activation
   // get sender sp
   movptr(rbx,
@@ -1094,6 +1126,27 @@
 
     bind(no_reserved_zone_enabling);
   }
+  if (load_values) {
+    // We are returning a value type, load its fields into registers
+#ifndef _LP64
+    super_call_VM_leaf(StubRoutines::load_value_type_fields_in_regs());
+#else
+    load_klass(rdi, rax);
+    movptr(rdi, Address(rdi, ValueKlass::unpack_handler_offset()));
+
+    Label skip;
+    testptr(rdi, rdi);
+    jcc(Assembler::equal, skip);
+
+    // Load fields from a buffered value with a value class specific
+    // handler
+    call(rdi);
+
+    bind(skip);
+#endif
+    // call above kills the value in rbx. Reload it.
+    movptr(rbx, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize));
+  }
   leave();                           // remove frame anchor
   pop(ret_addr);                     // get return address
   mov(rsp, rbx);                     // set sp to sender sp
--- a/src/hotspot/cpu/x86/interp_masm_x86.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -215,7 +215,8 @@
   void remove_activation(TosState state, Register ret_addr,
                          bool throw_monitor_exception = true,
                          bool install_monitor_exception = true,
-                         bool notify_jvmdi = true);
+                         bool notify_jvmdi = true,
+                         bool load_values = false);
   void get_method_counters(Register method, Register mcs, Label& skip);
 
   // Object locking
--- a/src/hotspot/cpu/x86/interpreterRT_x86.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/interpreterRT_x86.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -52,6 +52,7 @@
   void pass_double();
 #endif // AMD64
   void pass_object();
+  void pass_valuetype();
 
  public:
   // Creation
--- a/src/hotspot/cpu/x86/interpreterRT_x86_32.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/interpreterRT_x86_32.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -56,6 +56,10 @@
   box (offset(), jni_offset() + 1);
 }
 
+void InterpreterRuntime::SignatureHandlerGenerator::pass_valuetype() {
+  box (offset(), jni_offset() + 1);
+}
+
 void InterpreterRuntime::SignatureHandlerGenerator::move(int from_offset, int to_offset) {
   __ movl(temp(), Address(from(), Interpreter::local_offset_in_bytes(from_offset)));
   __ movl(Address(to(), to_offset * wordSize), temp());
@@ -123,6 +127,13 @@
     _from -= Interpreter::stackElementSize;
    }
 
+  virtual void pass_valuetype() {
+    // pass address of from
+    intptr_t from_addr = (intptr_t)(_from + Interpreter::local_offset_in_bytes(0));
+    *_to++ = (*(intptr_t*)from_addr == 0) ? NULL_WORD : from_addr;
+    _from -= Interpreter::stackElementSize;
+   }
+
  public:
   SlowSignatureHandler(const methodHandle& method, address from, intptr_t* to) :
     NativeSignatureIterator(method) {
--- a/src/hotspot/cpu/x86/interpreterRT_x86_64.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/interpreterRT_x86_64.cpp	Tue Sep 26 16:15:08 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/hotspot/cpu/x86/macroAssembler_x86.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -2617,6 +2617,10 @@
   call_VM_leaf(entry_point, 3);
 }
 
+void MacroAssembler::super_call_VM_leaf(address entry_point) {
+  MacroAssembler::call_VM_leaf_base(entry_point, 1);
+}
+
 void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0) {
   pass_arg0(this, arg_0);
   MacroAssembler::call_VM_leaf_base(entry_point, 1);
@@ -6076,7 +6080,11 @@
 }
 
 void MacroAssembler::verify_oop(Register reg, const char* s) {
-  if (!VerifyOops) return;
+  if (!VerifyOops || VerifyAdapterSharing) {
+    // Below address of the code string confuses VerifyAdapterSharing
+    // because it may differ between otherwise equivalent adapters.
+    return;
+  }
 
   // Pass register number to verify_oop_subroutine
   const char* b = NULL;
@@ -6166,7 +6174,11 @@
 
 
 void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
-  if (!VerifyOops) return;
+  if (!VerifyOops || VerifyAdapterSharing) {
+    // Below address of the code string confuses VerifyAdapterSharing
+    // because it may differ between otherwise equivalent adapters.
+    return;
+  }
 
   // Address adjust(addr.base(), addr.index(), addr.scale(), addr.disp() + BytesPerWord);
   // Pass register number to verify_oop_subroutine
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -510,6 +510,15 @@
   return align_up(stack, 2);
 }
 
+const uint SharedRuntime::java_return_convention_max_int = 1;
+const uint SharedRuntime::java_return_convention_max_float = 1;
+int SharedRuntime::java_return_convention(const BasicType *sig_bt,
+                                          VMRegPair *regs,
+                                          int total_args_passed) {
+  Unimplemented();
+  return 0;
+}
+
 // Patch the callers callsite with entry to compiled code if it exists.
 static void patch_callers_callsite(MacroAssembler *masm) {
   Label L;
@@ -571,11 +580,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
@@ -597,7 +608,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);
@@ -608,14 +619,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:
@@ -665,7 +676,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
@@ -682,7 +693,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);
       }
     }
@@ -715,10 +726,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.
@@ -807,11 +818,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;
     }
 
@@ -820,7 +831,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;
     //
@@ -861,7 +872,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);
@@ -879,7 +890,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
@@ -927,14 +938,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
@@ -971,9 +982,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);
 }
 
@@ -3131,3 +3146,8 @@
   // frame_size_words or bytes??
   return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
 }
+
+BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) {
+  Unimplemented();
+  return NULL;
+}
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -28,6 +28,7 @@
 #endif
 #include "asm/macroAssembler.hpp"
 #include "asm/macroAssembler.inline.hpp"
+#include "classfile/symbolTable.hpp"
 #include "code/debugInfoRec.hpp"
 #include "code/icBuffer.hpp"
 #include "code/vtableStubs.hpp"
@@ -484,6 +485,7 @@
     case T_OBJECT:
     case T_ARRAY:
     case T_ADDRESS:
+    case T_VALUETYPEPTR:
       if (int_args < Argument::n_int_register_parameters_j) {
         regs[i].set2(INT_ArgReg[int_args++]->as_VMReg());
       } else {
@@ -517,6 +519,88 @@
   return align_up(stk_args, 2);
 }
 
+// Same as java_calling_convention() but for multiple return
+// values. There's no way to store them on the stack so if we don't
+// have enough registers, multiple values can't be returned.
+const uint SharedRuntime::java_return_convention_max_int = Argument::n_int_register_parameters_j+1;
+const uint SharedRuntime::java_return_convention_max_float = Argument::n_float_register_parameters_j;
+int SharedRuntime::java_return_convention(const BasicType *sig_bt,
+                                          VMRegPair *regs,
+                                          int total_args_passed) {
+  // Create the mapping between argument positions and
+  // registers.
+  static const Register INT_ArgReg[java_return_convention_max_int] = {
+    rax, j_rarg5, j_rarg4, j_rarg3, j_rarg2, j_rarg1, j_rarg0
+  };
+  static const XMMRegister FP_ArgReg[java_return_convention_max_float] = {
+    j_farg0, j_farg1, j_farg2, j_farg3,
+    j_farg4, j_farg5, j_farg6, j_farg7
+  };
+
+
+  uint int_args = 0;
+  uint fp_args = 0;
+
+  for (int i = 0; i < total_args_passed; i++) {
+    switch (sig_bt[i]) {
+    case T_BOOLEAN:
+    case T_CHAR:
+    case T_BYTE:
+    case T_SHORT:
+    case T_INT:
+      if (int_args < Argument::n_int_register_parameters_j+1) {
+        regs[i].set1(INT_ArgReg[int_args]->as_VMReg());
+        int_args++;
+      } else {
+        return -1;
+      }
+      break;
+    case T_VOID:
+      // halves of T_LONG or T_DOUBLE
+      assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half");
+      regs[i].set_bad();
+      break;
+    case T_LONG:
+      assert(sig_bt[i + 1] == T_VOID, "expecting half");
+      // fall through
+    case T_OBJECT:
+    case T_ARRAY:
+    case T_ADDRESS:
+    case T_METADATA:
+    case T_VALUETYPEPTR:
+      if (int_args < Argument::n_int_register_parameters_j+1) {
+        regs[i].set2(INT_ArgReg[int_args]->as_VMReg());
+        int_args++;
+      } else {
+        return -1;
+      }
+      break;
+    case T_FLOAT:
+      if (fp_args < Argument::n_float_register_parameters_j) {
+        regs[i].set1(FP_ArgReg[fp_args]->as_VMReg());
+        fp_args++;
+      } else {
+        return -1;
+      }
+      break;
+    case T_DOUBLE:
+      assert(sig_bt[i + 1] == T_VOID, "expecting half");
+      if (fp_args < Argument::n_float_register_parameters_j) {
+        regs[i].set2(FP_ArgReg[fp_args]->as_VMReg());
+        fp_args++;
+      } else {
+        return -1;
+      }
+      break;
+    default:
+      ShouldNotReachHere();
+      break;
+    }
+  }
+
+  return int_args + fp_args;
+}
+
 // Patch the callers callsite with entry to compiled code if it exists.
 static void patch_callers_callsite(MacroAssembler *masm) {
   Label L;
@@ -559,13 +643,117 @@
   __ 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,
+                                   bool is_oop) {
+  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_XMMRegister()) {
+    Register val = rax;
+    assert_different_registers(to.base(), val);
+    if(r_1->is_stack()) {
+      int ld_off = r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace;
+      __ load_sized_value(val, Address(rsp, ld_off), size_in_bytes, /* is_signed */ false);
+    } else {
+      val = r_1->as_Register();
+    }
+    if (is_oop) {
+      __ store_heap_oop(to, val);
+    } else {
+      __ store_sized_value(to, val, 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
@@ -575,11 +763,57 @@
 
   __ bind(skip_fixup);
 
+  bool has_value_argument = false;
+  if (ValueTypePassFieldsAsArgs) {
+    // Is there a value type argument?
+    for (int i = 0; i < sig_extended.length() && !has_value_argument; i++) {
+      has_value_argument = (sig_extended.at(i)._bt == T_VALUETYPE);
+    }
+    if (has_value_argument) {
+      // 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
+      __ get_vm_result(r13, r15_thread); // Use r13 as temporary because r10 is trashed by movptr()
+      __ get_vm_result_2(rbx, r15_thread); // TODO: required to keep the callee Method live?
+      __ 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
@@ -597,97 +831,94 @@
   __ 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;
+
+  // 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).
+  bool has_oop_field = false;
+  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, false);
+      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);
+      }
+#endif /* ASSERT */
+    } else {
+      ignored++;
+      // get the buffer from the just allocated pool of buffers
+      int index = arrayOopDesc::base_offset_in_bytes(T_OBJECT) + next_vt_arg * type2aelembytes(T_VALUETYPE);
+      __ load_heap_oop(r11, Address(r10, index));
+      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 {
+          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;
+          bool is_oop = (bt == T_OBJECT || bt == T_ARRAY);
+          has_oop_field = has_oop_field || is_oop;
+          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, is_oop);
+        }
+      } while (vt != 0);
+      // pass the buffer to the interpreter
+      __ movptr(Address(rsp, st_off), r11);
     }
-
-    // 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 a value type was allocated and initialized, apply post barrier to all oop fields
+  if (has_value_argument && has_oop_field) {
+    __ push(r13); // save senderSP
+    __ push(rbx); // save callee
+    // Allocate argument register save area
+    if (frame::arg_reg_save_area_bytes != 0) {
+      __ subptr(rsp, frame::arg_reg_save_area_bytes);
     }
-    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));
-        __ 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 {
-          __ movq(Address(rsp, st_off), rax);
-        }
-      }
-    } 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());
-      }
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::apply_post_barriers), r15_thread, r10);
+    // De-allocate argument register save area
+    if (frame::arg_reg_save_area_bytes != 0) {
+      __ addptr(rsp, frame::arg_reg_save_area_bytes);
     }
+    __ pop(rbx); // restore callee
+    __ pop(r13); // restore sender SP
   }
 
   // Schedule the branch target address early.
@@ -708,10 +939,60 @@
   __ 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,
+                                   bool is_oop) {
+  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_XMMRegister()) {
+    // 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.
+    Register dst = r_1->is_stack() ? r13 : r_1->as_Register();
+    if (is_oop) {
+      __ load_heap_oop(dst, from);
+    } else {
+      __ load_sized_value(dst, from, size_in_bytes, is_signed);
+    }
+    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;
+      __ movq(Address(rsp, st_off), dst);
+    }
+  } 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
@@ -817,84 +1098,64 @@
   }
 #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), false);
+      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;
+          bool is_oop = (bt == T_OBJECT || bt == T_ARRAY);
+          gen_i2c_adapter_helper(masm, bt, prev_bt, size_in_bytes, regs[next_arg_comp - ignored], Address(r10, off), is_oop);
+        }
+      } while (vt != 0);
     }
   }
 
@@ -911,7 +1172,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);
@@ -919,14 +1180,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
@@ -963,10 +1224,50 @@
 
   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();
-  return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+  new_adapter = AdapterBlob::create(masm->code(), frame_complete, frame_size_in_words, oop_maps);
+
+  // If value types are passed as fields, save the extended signature as symbol in
+  // the AdapterHandlerEntry to be used by nmethod::preserve_callee_argument_oops().
+  Symbol* extended_signature = NULL;
+  if (ValueTypePassFieldsAsArgs) {
+    bool has_value_argument = false;
+    Thread* THREAD = Thread::current();
+    ResourceMark rm(THREAD);
+    int length = sig_extended.length();
+    char* sig_str = NEW_RESOURCE_ARRAY(char, 2*length + 3);
+    int idx = 0;
+    sig_str[idx++] = '(';
+    for (int index = 0; index < length; index++) {
+      BasicType bt = sig_extended.at(index)._bt;
+      if (bt == T_VALUETYPE) {
+        has_value_argument = true;
+      } else if (bt == T_VOID) {
+        // Ignore
+      } else {
+        if (bt == T_ARRAY) {
+          bt = T_OBJECT; // We don't know the element type, treat as Object
+        }
+        sig_str[idx++] = type2char(bt);
+        if (bt == T_OBJECT) {
+          sig_str[idx++] = ';';
+        }
+      }
+    }
+    sig_str[idx++] = ')';
+    sig_str[idx++] = '\0';
+    if (has_value_argument) {
+      // Extended signature is only required if a value type argument is passed
+      extended_signature = SymbolTable::new_permanent_symbol(sig_str, THREAD);
+    }
+  }
+
+  return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, extended_signature);
 }
 
 int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
@@ -3861,3 +4162,100 @@
   _exception_blob =  ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
 }
 #endif // COMPILER2
+
+BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) {
+  BufferBlob* buf = BufferBlob::create("value types pack/unpack", 16 * K);
+  CodeBuffer buffer(buf);
+  short buffer_locs[20];
+  buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
+                                         sizeof(buffer_locs)/sizeof(relocInfo));
+
+  MacroAssembler _masm(&buffer);
+  MacroAssembler* masm = &_masm;
+
+  const Array<SigEntry>* sig_vk = vk->extended_sig();
+  const Array<VMRegPair>* regs = vk->return_regs();
+
+  int pack_fields_off = __ offset();
+
+  int j = 1;
+  for (int i = 0; i < sig_vk->length(); i++) {
+    BasicType bt = sig_vk->at(i)._bt;
+    if (bt == T_VALUETYPE) {
+      continue;
+    }
+    if (bt == T_VOID) {
+      if (sig_vk->at(i-1)._bt == T_LONG ||
+          sig_vk->at(i-1)._bt == T_DOUBLE) {
+        j++;
+      }
+      continue;
+    }
+    int off = sig_vk->at(i)._offset;
+    VMRegPair pair = regs->at(j);
+    VMReg r_1 = pair.first();
+    VMReg r_2 = pair.second();
+    Address to(rax, off);
+    if (bt == T_FLOAT) {
+      __ movflt(to, r_1->as_XMMRegister());
+    } else if (bt == T_DOUBLE) {
+      __ movdbl(to, r_1->as_XMMRegister());
+    } else if (bt == T_OBJECT || bt == T_ARRAY) {
+      __ store_heap_oop(to, r_1->as_Register());
+    } else {
+      assert(is_java_primitive(bt), "unexpected basic type");
+      size_t size_in_bytes = type2aelembytes(bt);
+      __ store_sized_value(to, r_1->as_Register(), size_in_bytes);
+    }
+    j++;
+  }
+  assert(j == regs->length(), "missed a field?");
+
+  __ ret(0);
+
+  int unpack_fields_off = __ offset();
+
+  j = 1;
+  for (int i = 0; i < sig_vk->length(); i++) {
+    BasicType bt = sig_vk->at(i)._bt;
+    if (bt == T_VALUETYPE) {
+      continue;
+    }
+    if (bt == T_VOID) {
+      if (sig_vk->at(i-1)._bt == T_LONG ||
+          sig_vk->at(i-1)._bt == T_DOUBLE) {
+        j++;
+      }
+      continue;
+    }
+    int off = sig_vk->at(i)._offset;
+    VMRegPair pair = regs->at(j);
+    VMReg r_1 = pair.first();
+    VMReg r_2 = pair.second();
+    Address from(rax, off);
+    if (bt == T_FLOAT) {
+      __ movflt(r_1->as_XMMRegister(), from);
+    } else if (bt == T_DOUBLE) {
+      __ movdbl(r_1->as_XMMRegister(), from);
+    } else if (bt == T_OBJECT || bt == T_ARRAY) {
+      __ load_heap_oop(r_1->as_Register(), from);
+    } else {
+      assert(is_java_primitive(bt), "unexpected basic type");
+      size_t size_in_bytes = type2aelembytes(bt);
+      __ load_sized_value(r_1->as_Register(), from, size_in_bytes, bt != T_CHAR && bt != T_BOOLEAN);
+    }
+    j++;
+  }
+  assert(j == regs->length(), "missed a field?");
+
+  if (StressValueTypeReturnedAsFields) {
+    __ load_klass(rax, rax);
+    __ orptr(rax, 1);
+  }
+
+  __ ret(0);
+
+  __ flush();
+
+  return BufferedValueTypeBlob::create(&buffer, pack_fields_off, unpack_fields_off);
+}
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -995,7 +995,7 @@
     StubCodeMark mark(this, "StubRoutines", "verify_oop");
     address start = __ pc();
 
-    Label exit, error;
+    Label exit, error, in_Java_heap;
 
     __ pushf();
     __ incrementl(ExternalAddress((address) StubRoutines::verify_oop_count_addr()));
@@ -1029,7 +1029,14 @@
     __ andptr(c_rarg2, c_rarg3);
     __ movptr(c_rarg3, (intptr_t) Universe::verify_oop_bits());
     __ cmpptr(c_rarg2, c_rarg3);
-    __ jcc(Assembler::notZero, error);
+    __ jcc(Assembler::zero, in_Java_heap);
+    // Not in Java heap, but could be valid if it's a bufferable value type
+    __ load_klass(c_rarg2, rax);
+    __ movbool(c_rarg2, Address(c_rarg2, InstanceKlass::extra_flags_offset()));
+    __ andptr(c_rarg2, InstanceKlass::_extra_is_bufferable);
+    __ testbool(c_rarg2);
+    __ jcc(Assembler::zero, error);
+    __ bind(in_Java_heap);
 
     // set r12 to heapbase for load_klass()
     __ reinit_heapbase();
@@ -4975,6 +4982,146 @@
     StubRoutines::_fpu_subnormal_bias2[2]= 0x7bff;
   }
 
+  // Call here from the interpreter or compiled code to either load
+  // multiple returned values from the value type instance being
+  // returned to registers or to store returned values to a newly
+  // allocated value type instance.
+  address generate_return_value_stub(address destination, const char* name, bool has_res) {
+    // We need to save all registers the calling convention may use so
+    // the runtime calls read or update those registers. This needs to
+    // be in sync with SharedRuntime::java_return_convention().
+    enum layout {
+      pad_off = frame::arg_reg_save_area_bytes/BytesPerInt, pad_off_2,
+      rax_off, rax_off_2,
+      j_rarg5_off, j_rarg5_2,
+      j_rarg4_off, j_rarg4_2,
+      j_rarg3_off, j_rarg3_2,
+      j_rarg2_off, j_rarg2_2,
+      j_rarg1_off, j_rarg1_2,
+      j_rarg0_off, j_rarg0_2,
+      j_farg0_off, j_farg0_2,
+      j_farg1_off, j_farg1_2,
+      j_farg2_off, j_farg2_2,
+      j_farg3_off, j_farg3_2,
+      j_farg4_off, j_farg4_2,
+      j_farg5_off, j_farg5_2,
+      j_farg6_off, j_farg6_2,
+      j_farg7_off, j_farg7_2,
+      rbp_off, rbp_off_2,
+      return_off, return_off_2,
+
+      framesize
+    };
+
+    CodeBuffer buffer(name, 1000, 512);
+    MacroAssembler* masm = new MacroAssembler(&buffer);
+
+    int frame_size_in_bytes = align_up(framesize*BytesPerInt, 16);
+    assert(frame_size_in_bytes == framesize*BytesPerInt, "misaligned");
+    int frame_size_in_slots = frame_size_in_bytes / BytesPerInt;
+    int frame_size_in_words = frame_size_in_bytes / wordSize;
+
+    OopMapSet *oop_maps = new OopMapSet();
+    OopMap* map = new OopMap(frame_size_in_slots, 0);
+
+    map->set_callee_saved(VMRegImpl::stack2reg(rax_off), rax->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_rarg5_off), j_rarg5->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_rarg4_off), j_rarg4->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_rarg3_off), j_rarg3->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_rarg2_off), j_rarg2->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_rarg1_off), j_rarg1->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_rarg0_off), j_rarg0->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_farg0_off), j_farg0->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_farg1_off), j_farg1->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_farg2_off), j_farg2->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_farg3_off), j_farg3->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_farg4_off), j_farg4->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_farg5_off), j_farg5->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_farg6_off), j_farg6->as_VMReg());
+    map->set_callee_saved(VMRegImpl::stack2reg(j_farg7_off), j_farg7->as_VMReg());
+
+    int start = __ offset();
+
+    __ subptr(rsp, frame_size_in_bytes - 8 /* return address*/);
+
+    __ movptr(Address(rsp, rbp_off * BytesPerInt), rbp);
+    __ movdbl(Address(rsp, j_farg7_off * BytesPerInt), j_farg7);
+    __ movdbl(Address(rsp, j_farg6_off * BytesPerInt), j_farg6);
+    __ movdbl(Address(rsp, j_farg5_off * BytesPerInt), j_farg5);
+    __ movdbl(Address(rsp, j_farg4_off * BytesPerInt), j_farg4);
+    __ movdbl(Address(rsp, j_farg3_off * BytesPerInt), j_farg3);
+    __ movdbl(Address(rsp, j_farg2_off * BytesPerInt), j_farg2);
+    __ movdbl(Address(rsp, j_farg1_off * BytesPerInt), j_farg1);
+    __ movdbl(Address(rsp, j_farg0_off * BytesPerInt), j_farg0);
+
+    __ movptr(Address(rsp, j_rarg0_off * BytesPerInt), j_rarg0);
+    __ movptr(Address(rsp, j_rarg1_off * BytesPerInt), j_rarg1);
+    __ movptr(Address(rsp, j_rarg2_off * BytesPerInt), j_rarg2);
+    __ movptr(Address(rsp, j_rarg3_off * BytesPerInt), j_rarg3);
+    __ movptr(Address(rsp, j_rarg4_off * BytesPerInt), j_rarg4);
+    __ movptr(Address(rsp, j_rarg5_off * BytesPerInt), j_rarg5);
+    __ movptr(Address(rsp, rax_off * BytesPerInt), rax);
+
+    int frame_complete = __ offset();
+
+    __ set_last_Java_frame(noreg, noreg, NULL);
+
+    __ mov(c_rarg0, r15_thread);
+    __ mov(c_rarg1, rax);
+
+    __ call(RuntimeAddress(destination));
+
+    // Set an oopmap for the call site.
+
+    oop_maps->add_gc_map( __ offset() - start, map);
+
+    // clear last_Java_sp
+    __ reset_last_Java_frame(false);
+
+    __ movptr(rbp, Address(rsp, rbp_off * BytesPerInt));
+    __ movdbl(j_farg7, Address(rsp, j_farg7_off * BytesPerInt));
+    __ movdbl(j_farg6, Address(rsp, j_farg6_off * BytesPerInt));
+    __ movdbl(j_farg5, Address(rsp, j_farg5_off * BytesPerInt));
+    __ movdbl(j_farg4, Address(rsp, j_farg4_off * BytesPerInt));
+    __ movdbl(j_farg3, Address(rsp, j_farg3_off * BytesPerInt));
+    __ movdbl(j_farg2, Address(rsp, j_farg2_off * BytesPerInt));
+    __ movdbl(j_farg1, Address(rsp, j_farg1_off * BytesPerInt));
+    __ movdbl(j_farg0, Address(rsp, j_farg0_off * BytesPerInt));
+
+    __ movptr(j_rarg0, Address(rsp, j_rarg0_off * BytesPerInt));
+    __ movptr(j_rarg1, Address(rsp, j_rarg1_off * BytesPerInt));
+    __ movptr(j_rarg2, Address(rsp, j_rarg2_off * BytesPerInt));
+    __ movptr(j_rarg3, Address(rsp, j_rarg3_off * BytesPerInt));
+    __ movptr(j_rarg4, Address(rsp, j_rarg4_off * BytesPerInt));
+    __ movptr(j_rarg5, Address(rsp, j_rarg5_off * BytesPerInt));
+    __ movptr(rax, Address(rsp, rax_off * BytesPerInt));
+
+    __ addptr(rsp, frame_size_in_bytes-8);
+
+    // check for pending exceptions
+    Label pending;
+    __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
+    __ jcc(Assembler::notEqual, pending);
+
+    if (has_res) {
+      __ get_vm_result(rax, r15_thread);
+    }
+
+    __ ret(0);
+
+    __ bind(pending);
+
+    __ movptr(rax, Address(r15_thread, Thread::pending_exception_offset()));
+    __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+
+    // -------------
+    // make sure all code is generated
+    masm->flush();
+
+    RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, false);
+    return stub->entry_point();
+  }
+
   // Initialization
   void generate_initial() {
     // Generates all stubs and initializes the entry points
@@ -5076,6 +5223,9 @@
         StubRoutines::_dtan = generate_libmTan();
       }
     }
+
+    StubRoutines::_load_value_type_fields_in_regs = generate_return_value_stub(CAST_FROM_FN_PTR(address, SharedRuntime::load_value_type_fields_in_regs), "load_value_type_fields_in_regs", false);
+    StubRoutines::_store_value_type_fields_to_buf = generate_return_value_stub(CAST_FROM_FN_PTR(address, SharedRuntime::store_value_type_fields_to_buf), "store_value_type_fields_to_buf", true);
   }
 
   void generate_all() {
--- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -34,6 +34,7 @@
 #include "oops/methodData.hpp"
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/arguments.hpp"
@@ -55,7 +56,7 @@
 // Run with +PrintInterpreter to get the VM to print out the size.
 // Max size with JVMTI
 #ifdef AMD64
-int TemplateInterpreter::InterpreterCodeSize = JVMCI_ONLY(268) NOT_JVMCI(256) * 1024;
+int TemplateInterpreter::InterpreterCodeSize = JVMCI_ONLY(280) NOT_JVMCI(268) * 1024;
 #else
 int TemplateInterpreter::InterpreterCodeSize = 224 * 1024;
 #endif // AMD64
@@ -203,6 +204,61 @@
   // and NULL it as marker that esp is now tos until next java call
   __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD);
 
+  if (state == qtos && ValueTypeReturnedAsFields) {
+#ifndef _LP64
+    __ super_call_VM_leaf(StubRoutines::store_value_type_fields_to_buf());
+#else
+    // A value type is being returned. If fields are in registers we
+    // need to allocate a value type instance and initialize it with
+    // the value of the fields.
+    Label skip, slow_case;
+    // We only need a new buffered value if a new one is not returned
+    __ testptr(rax, 1);
+    __ jcc(Assembler::zero, skip);
+
+    // Try to allocate a new buffered value (from the heap)
+    if (UseTLAB) {
+      __ mov(rbx, rax);
+      __ andptr(rbx, -2);
+
+      __ movl(r14, Address(rbx, Klass::layout_helper_offset()));
+
+      __ movptr(r13, Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())));
+      __ lea(r14, Address(r13, r14, Address::times_1));
+      __ cmpptr(r14, Address(r15_thread, in_bytes(JavaThread::tlab_end_offset())));
+      __ jcc(Assembler::above, slow_case);
+      __ movptr(Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())), r14);
+
+      if (UseBiasedLocking) {
+        __ movptr(rax, Address(rbx, Klass::prototype_header_offset()));
+        __ movptr(Address(r13, oopDesc::mark_offset_in_bytes ()), rax);
+      } else {
+        __ movptr(Address(r13, oopDesc::mark_offset_in_bytes ()),
+                  (intptr_t)markOopDesc::prototype());
+      }
+      __ xorl(rax, rax); // use zero reg to clear memory (shorter code)
+      __ store_klass_gap(r13, rax);  // zero klass gap for compressed oops
+      __ mov(rax, rbx);
+      __ store_klass(r13, rbx);  // klass
+
+      // We have our new buffered value, initialize its fields with a
+      // value class specific handler
+      __ movptr(rbx, Address(rax, ValueKlass::pack_handler_offset()));
+      __ mov(rax, r13);
+      __ call(rbx);
+      __ jmp(skip);
+    }
+
+    __ bind(slow_case);
+    // We failed to allocate a new value, fall back to a runtime
+    // call. Some oop field may be live in some registers but we can't
+    // tell. That runtime call will take care of preserving them
+    // across a GC if there's one.
+    __ super_call_VM_leaf(StubRoutines::store_value_type_fields_to_buf());
+    __ bind(skip);
+#endif
+  }
+
   __ restore_bcp();
   __ restore_locals();
 
@@ -341,6 +397,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));
@@ -678,6 +735,10 @@
   __ movptr(rdx, Address(rdx, ConstMethod::constants_offset()));
   __ movptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes()));
   __ push(rdx); // set constant pool cache
+  const Register thread1 = NOT_LP64(rdx) LP64_ONLY(r15_thread);
+  NOT_LP64(__ get_thread(thread1));
+  __ movptr(rdx, Address(thread1, JavaThread::vt_alloc_ptr_offset()));
+  __ push(rdx); // value type allocation pointer when activation is created
   __ push(rlocals); // set locals pointer
   if (native_call) {
     __ push(0); // no bcp
@@ -1796,10 +1857,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/hotspot/cpu/x86/templateTable_x86.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp	Tue Sep 26 16:15:08 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:
@@ -445,6 +448,19 @@
 
   // resolved class - need to call vm to get java mirror of the class
   __ cmpl(rdx, JVM_CONSTANT_Class);
+  __ jcc(Assembler::equal, call_ldc);
+
+  // unresolved value type - get the resolved class
+  __ cmpl(rdx, JVM_CONSTANT_UnresolvedValue);
+  __ jccb(Assembler::equal, call_ldc);
+
+  // unresolved value type in error state - call into runtime to throw the error
+  // from the first resolution attempt
+  __ cmpl(rdx, JVM_CONSTANT_UnresolvedValueInError);
+  __ jccb(Assembler::equal, call_ldc);
+
+  // resolved value type - need to call vm to get java mirror
+  __ cmpl(rdx, JVM_CONSTANT_Value);
   __ jcc(Assembler::notEqual, notClass);
 
   __ bind(call_ldc);
@@ -636,6 +652,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 +696,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 +779,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 +968,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 +1020,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 +1127,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);
@@ -2047,6 +2117,36 @@
 }
 
 void TemplateTable::branch(bool is_jsr, bool is_wide) {
+  if (ValueTypesThreadLocalRecycling) {
+    Label no_vt_recycling, no_fixing_required;
+    const Register thread1 = NOT_LP64(rbx) LP64_ONLY(r15_thread);
+    NOT_LP64(__ get_thread(thread1));
+    __ movptr(rbx, Address(thread1, in_bytes(JavaThread::vt_alloc_ptr_offset())));
+    __ testptr(rbx, rbx);
+    __ jcc(Assembler::zero, no_vt_recycling);
+    __ movptr(rcx, Address(rbp, frame::interpreter_frame_vt_alloc_ptr_offset * wordSize));
+    __ testptr(rcx, rcx);
+    __ jcc(Assembler::notZero, no_fixing_required);
+    // vt_alloc_ptr in JavaThread is non-null but frame vt_alloc_ptr is null
+    // which means frame vt_alloc_ptr needs to be initialized
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::fix_frame_vt_alloc_ptr));
+    __ movptr(rcx, Address(rbp, frame::interpreter_frame_vt_alloc_ptr_offset * wordSize));
+    __ bind(no_fixing_required);
+    __ testptr(rcx, rbx);
+    __ jcc(Assembler::equal, no_vt_recycling);
+    __ andptr(rcx, VTBufferChunk::chunk_mask());
+    __ movl(rcx, Address(rcx, VTBufferChunk::index_offset()));
+    __ andptr(rbx, VTBufferChunk::chunk_mask());
+    __ movl(rbx, Address(rbx, VTBufferChunk::index_offset()));
+    __ subl(rbx, rcx);
+    __ get_method(rcx);
+    __ movl(rcx, Address(rcx, Method::max_vt_buffer_offset()));
+    __ cmpl(rbx, rcx);
+    __ jcc(Assembler::lessEqual, no_vt_recycling);
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::recycle_buffered_values));
+    __ bind(no_vt_recycling);
+  }
+
   __ get_method(rcx); // rcx holds method
   __ profile_taken_branch(rax, rbx); // rax holds updated MDP, rbx
                                      // holds bumped taken count
@@ -2563,13 +2663,31 @@
     __ bind(skip_register_finalizer);
   }
 
+  if (state == qtos) {
+    const Register thread1 = NOT_LP64(rcx) LP64_ONLY(r15_thread);
+    __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::return_value), rax);
+    NOT_LP64(__ get_thread(thread1));
+    __ get_vm_result(rax, thread1);
+  }
   // Narrow result if state is itos but result type is smaller.
   // Need to narrow in the return bytecode rather than in generate_return_entry
   // since compiled code callers expect the result to already be narrowed.
   if (state == itos) {
     __ narrow(rax);
   }
-  __ remove_activation(state, rbcp);
+
+#ifdef ASSERT
+  if (EnableMVT || EnableValhalla) {
+    if (state == atos) {
+      const Register thread1 = NOT_LP64(rcx) LP64_ONLY(r15_thread);
+      __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::check_areturn), rax);
+      NOT_LP64(__ get_thread(thread1));
+      __ get_vm_result(rax, thread1);
+    }
+  }
+#endif // ASSERT
+
+  __ remove_activation(state, rbcp, true, true, true, state == qtos && ValueTypeReturnedAsFields);
 
   __ jmp(rbcp);
 }
@@ -2756,17 +2874,18 @@
   const Register off   = rbx;
   const Register flags = rax;
   const Register bc    = LP64_ONLY(c_rarg3) NOT_LP64(rcx); // uses same reg as obj, so don't mix them
+  const Register flags2 = rdx;
 
   resolve_cache_and_index(byte_no, cache, index, sizeof(u2));
   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;
+
+  __ movl(flags2, flags);
 
   __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
   // Make sure we don't need to mask edx after the above shift
@@ -2776,6 +2895,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
@@ -2785,6 +2905,37 @@
   __ jmp(Done);
 
   __ bind(notByte);
+
+  __ cmpl(flags, qtos);
+  __ jcc(Assembler::notEqual, notValueType);
+  // qtos
+  if (is_static) {
+    Label initialized;
+    // Issue below if the static field has not been initialized yet
+    __ load_heap_oop(rax, field);
+    __ testptr(rax, rax);
+    __ jcc(Assembler::notZero, initialized);
+    __ andl(flags2, ConstantPoolCacheEntry::field_index_mask);
+    __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::initialize_static_value_field),
+         obj, flags2);
+    __ verify_oop(rax);
+    __ bind(initialized);
+    __ push(qtos);
+  } else {
+    pop_and_check_object(obj);
+    __ andl(flags2, ConstantPoolCacheEntry::field_index_mask);
+    call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::qgetfield),
+        obj, flags2);
+    __ 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);
 
@@ -2918,6 +3069,21 @@
   getfield_or_static(byte_no, 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.
@@ -3014,6 +3180,7 @@
   const Register off   = rbx;
   const Register flags = rax;
   const Register bc    = LP64_ONLY(c_rarg3) NOT_LP64(rcx);
+  const Register flags2 = rdx;
 
   resolve_cache_and_index(byte_no, cache, index, sizeof(u2));
   jvmti_post_field_mod(cache, index, is_static);
@@ -3024,16 +3191,15 @@
   //                                              Assembler::StoreStore));
 
   Label notVolatile, Done;
-  __ movl(rdx, flags);
-  __ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
-  __ andl(rdx, 0x1);
+
+  __ movl(flags2, flags);
 
   // field addresses
   const Address field(obj, off, Address::times_1, 0*wordSize);
   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);
 
@@ -3085,6 +3251,29 @@
   }
 
   __ 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
+      pop_and_check_object(rbx);
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::qputfield),
+          rbx, rax, flags2);
+      __ jmp(notVolatile); // value types are never volatile
+    } else {
+      // Store into the static field
+      // Value types in static fields are currently handled with indirection
+      // but a copy to the Java heap might be required if the value is currently
+      // stored in a thread local buffer
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::qputstatic), rax, off, obj);
+    }
+    __ jmp(Done);
+  }
+
+  __ bind(notValueType);
   __ cmpl(flags, itos);
   __ jcc(Assembler::notEqual, notInt);
 
@@ -3216,8 +3405,11 @@
 
   __ bind(Done);
 
+  __ shrl(flags2, ConstantPoolCacheEntry::is_volatile_shift);
+  __ andl(flags2, 0x1);
+
   // Check for volatile store
-  __ testl(rdx, rdx);
+  __ testl(flags2, flags2);
   __ jcc(Assembler::zero, notVolatile);
   volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad |
                                                Assembler::StoreStore));
@@ -3254,6 +3446,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
@@ -3279,6 +3472,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
@@ -3329,6 +3523,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;
@@ -3418,6 +3615,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);
@@ -4003,6 +4203,20 @@
   __ bind(done);
 }
 
+void TemplateTable::vdefault() {
+  transition(vtos, qtos);
+
+  Register rarg1 = LP64_ONLY(c_rarg1) NOT_LP64(rcx);
+  Register rarg2 = LP64_ONLY(c_rarg2) NOT_LP64(rdx);
+
+  __ get_unsigned_2_byte_index_at_bcp(rarg2, 1);
+  __ get_constant_pool(rarg1);
+
+  call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::vdefault),
+      rarg1, rarg2);
+  __ verify_oop(rax);
+}
+
 void TemplateTable::newarray() {
   transition(itos, atos);
   Register rarg1 = LP64_ONLY(c_rarg1) NOT_LP64(rdx);
@@ -4157,6 +4371,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/hotspot/cpu/x86/x86_64.ad	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/x86/x86_64.ad	Tue Sep 26 16:15:08 2017 +0200
@@ -12148,8 +12148,24 @@
 %}
 
 // Call runtime without safepoint
+// entry point is null, target holds the address to call
+instruct CallLeafNoFPInDirect(rRegP target)
+%{
+  predicate(n->as_Call()->entry_point() == NULL);
+  match(CallLeafNoFP target);
+
+  ins_cost(300);
+  format %{ "call_leaf_nofp,runtime indirect " %}
+  ins_encode %{
+     __ call($target$$Register);
+  %}
+
+  ins_pipe(pipe_slow);
+%}
+
 instruct CallLeafNoFPDirect(method meth)
 %{
+  predicate(n->as_Call()->entry_point() != NULL);
   match(CallLeafNoFP);
   effect(USE meth);
 
--- a/src/hotspot/cpu/zero/globals_zero.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/cpu/zero/globals_zero.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -78,6 +78,9 @@
 
 define_pd_global(bool, PreserveFramePointer, false);
 
+define_pd_global(bool, ValueTypePassFieldsAsArgs, false);
+define_pd_global(bool, ValueTypeReturnedAsFields, false);
+
 // No performance work done here yet.
 define_pd_global(bool, CompactStrings, false);
 
--- a/src/hotspot/share/adlc/formssel.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/adlc/formssel.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -890,7 +890,8 @@
       strcmp(_matrule->_opType,"TailCall"  )==0 ||
       strcmp(_matrule->_opType,"TailJump"  )==0 ||
       strcmp(_matrule->_opType,"SafePoint" )==0 ||
-      strcmp(_matrule->_opType,"Halt"      )==0 )
+      strcmp(_matrule->_opType,"Halt"      )==0 ||
+      strcmp(_matrule->_opType,"CallLeafNoFP")==0)
     return AdlcVMDeps::Parms;   // Skip the machine-state edges
 
   if( _matrule->_rChild &&
--- a/src/hotspot/share/c1/c1_GraphBuilder.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -2131,7 +2131,8 @@
   bool will_link;
   ciKlass* klass = stream()->get_klass(will_link);
   assert(klass->is_instance_klass(), "must be an instance klass");
-  NewInstance* new_instance = new NewInstance(klass->as_instance_klass(), state_before, stream()->is_unresolved_klass());
+  NewInstance* new_instance = new NewInstance(klass->as_instance_klass(), state_before,
+                                              stream()->is_unresolved_klass() || stream()->is_unresolved_value_type());
   _memory->new_instance(new_instance);
   apush(append_split(new_instance));
 }
--- a/src/hotspot/share/c1/c1_IR.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/c1/c1_IR.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -244,7 +244,7 @@
     bool reexecute = topmost ? should_reexecute() : false;
     bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis.
     bool rethrow_exception = false;
-    recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(), reexecute, rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals);
+    recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(), reexecute, rethrow_exception, is_method_handle_invoke, return_oop, false, locvals, expvals, monvals);
   }
 };
 
--- a/src/hotspot/share/c1/c1_LinearScan.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/c1/c1_LinearScan.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -61,9 +61,9 @@
 
 // Map BasicType to spill size in 32-bit words, matching VMReg's notion of words
 #ifdef _LP64
-static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 0, 2,  1, 2, 1, -1};
+static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 0, 2,  1, 2, 1, 2, -1};
 #else
-static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, -1, 1, 1, -1};
+static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, -1, 1, 1, 1, -1};
 #endif
 
 
--- a/src/hotspot/share/ci/bcEscapeAnalyzer.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/bcEscapeAnalyzer.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -431,6 +431,7 @@
         break;
       }
       case Bytecodes::_aload:
+      case Bytecodes::_vload:
         state.apush(state._vars[s.get_index()]);
         break;
       case Bytecodes::_iload:
@@ -484,6 +485,7 @@
         set_method_escape(state.apop());
         state.lpush();
         break;
+      case Bytecodes::_vaload:
       case Bytecodes::_aaload:
         { state.spop();
           ArgumentMap array = state.apop();
@@ -517,6 +519,7 @@
         state.lpop();
         break;
       case Bytecodes::_astore:
+      case Bytecodes::_vstore:
         state._vars[s.get_index()] = state.apop();
         break;
       case Bytecodes::_astore_0:
@@ -562,6 +565,17 @@
         set_modified(arr, OFFSET_ANY, type2size[T_OBJECT]*HeapWordSize);
         break;
       }
+      case Bytecodes::_vastore:
+      {
+        set_global_escape(state.apop());
+        state.spop();
+        ArgumentMap arr = state.apop();
+        // If the array is flattened, a larger part of it is modified than
+        // the size of a reference. However, if OFFSET_ANY is given as
+        // parameter to set_modified(), size is not taken into account.
+        set_modified(arr, OFFSET_ANY, type2size[T_VALUETYPE]*HeapWordSize);
+        break;
+      }
       case Bytecodes::_pop:
         state.raw_pop();
         break;
@@ -850,6 +864,7 @@
         fall_through = false;
         break;
       case Bytecodes::_areturn:
+      case Bytecodes::_vreturn:
         set_returned(state.apop());
         fall_through = false;
         break;
@@ -943,8 +958,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();
+        }
+        set_method_escape(state.apop());
+        state.apush(allocated_obj);
+        break;
+      }
       case Bytecodes::_newarray:
       case Bytecodes::_anewarray:
         state.spop();
@@ -1012,6 +1043,11 @@
       }
       case Bytecodes::_breakpoint:
         break;
+      case Bytecodes::_vbox:
+      case Bytecodes::_vunbox:
+        set_method_escape(state.apop());
+        state.apush(allocated_obj);
+        break;
       default:
         ShouldNotReachHere();
         break;
--- a/src/hotspot/share/ci/ciArray.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciArray.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -31,6 +31,7 @@
 #include "oops/arrayOop.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/typeArrayOop.hpp"
+#include "oops/valueArrayOop.hpp"
 
 // ciArray
 //
@@ -44,6 +45,7 @@
   ciArray(    arrayHandle h_a) : ciObject(h_a), _length(h_a()->length()) {}
   ciArray( objArrayHandle h_a) : ciObject(h_a), _length(h_a()->length()) {}
   ciArray(typeArrayHandle h_a) : ciObject(h_a), _length(h_a()->length()) {}
+  ciArray(valueArrayHandle h_a): ciObject(h_a), _length(h_a()->length()) {}
 
   ciArray(ciKlass* klass, int len) : ciObject(klass), _length(len) {}
 
--- a/src/hotspot/share/ci/ciArrayKlass.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciArrayKlass.cpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciArrayKlass.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciArrayKlass.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciClassList.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciClassList.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciConstant.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciConstant.cpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciConstant.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciConstant.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciEnv.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciEnv.cpp	Tue Sep 26 16:15:08 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"
@@ -394,7 +395,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.
@@ -449,7 +450,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,
@@ -464,14 +465,18 @@
                              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);
+      }
     }
   }
 
   if (found_klass == NULL && !cpool.is_null() && cpool->has_preresolution()) {
     // Look inside the constant pool for pre-resolved class entries.
     for (int i = cpool->length() - 1; i >= 1; i--) {
-      if (cpool->tag_at(i).is_klass()) {
+      if (cpool->tag_at(i).is_klass() || cpool->tag_at(i).is_value_type()) {
         Klass* kls = cpool->resolved_klass_at(i);
         if (kls->name() == sym) {
           found_klass = kls;
@@ -490,6 +495,22 @@
 
   // Not yet loaded into the VM, or not governed by loader constraints.
   // Make a CI representative for it.
+  int i = 0;
+  while (sym->byte_at(i) == '[') {
+    i++;
+  }
+  if (i > 0 && sym->byte_at(i) == 'Q') {
+    assert(EnableValhalla || EnableMVT, "only for value types");
+    // An unloaded array class of value types is an ObjArrayKlass, an
+    // unloaded value type class is an InstanceKlass. For consistency,
+    // make the signature of the unloaded array of value type use L
+    // rather than Q.
+    char *new_name = CURRENT_THREAD_ENV->name_buffer(sym->utf8_length()+1);
+    strncpy(new_name, (char*)sym->base(), sym->utf8_length());
+    new_name[i] = 'L';
+    new_name[sym->utf8_length()] = '\0';
+    return get_unloaded_klass(accessing_klass, ciSymbol::make(new_name));
+  }
   return get_unloaded_klass(accessing_klass, name);
 }
 
@@ -625,7 +646,8 @@
       assert (constant->is_instance(), "must be an instance, or not? ");
       return ciConstant(T_OBJECT, constant);
     }
-  } else if (tag.is_klass() || tag.is_unresolved_klass()) {
+  } else if (tag.is_klass() || tag.is_unresolved_klass() ||
+             tag.is_value_type() || tag.is_unresolved_value_type()) {
     // 4881222: allow ldc to take a class type
     ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor);
     if (HAS_PENDING_EXCEPTION) {
--- a/src/hotspot/share/ci/ciEnv.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciEnv.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciField.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciField.cpp	Tue Sep 26 16:15:08 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,8 +367,8 @@
                         Bytecodes::Code bc) {
   VM_ENTRY_MARK;
   assert(bc == Bytecodes::_getstatic || bc == Bytecodes::_putstatic ||
-         bc == Bytecodes::_getfield  || bc == Bytecodes::_putfield,
-         "unexpected bytecode");
+         bc == Bytecodes::_getfield  || bc == Bytecodes::_putfield  ||
+         bc == Bytecodes::_vwithfield, "unexpected bytecode");
 
   if (_offset == -1) {
     // at creation we couldn't link to our holder so we need to
--- a/src/hotspot/share/ci/ciField.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciField.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciInstance.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciInstance.cpp	Tue Sep 26 16:15:08 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);
@@ -99,7 +100,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/hotspot/share/ci/ciInstanceKlass.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciInstanceKlass.cpp	Tue Sep 26 16:15:08 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;
+  _vcc_klass = 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;
+  _vcc_klass = 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,20 @@
   return NULL;
 }
 
+ciInstanceKlass* ciInstanceKlass::vcc_klass() {
+  InstanceKlass* ik = get_instanceKlass();
+  if (ik->has_vcc_klass()) {
+    if (_vcc_klass == NULL) {
+      VM_ENTRY_MARK;
+      InstanceKlass* k = InstanceKlass::cast(ik->get_vcc_klass());
+      _vcc_klass = CURRENT_THREAD_ENV->get_instance_klass(k);
+    }
+    return _vcc_klass;
+  } 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 +682,116 @@
 // 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();
-      _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();
-        }
+      InstanceKlass* holder = fd->field_holder();
+      oop mirror = holder->java_mirror();
+      _out->print("staticfield %s %s ", _holder, fd->name()->as_quoted_ascii());
+      BasicType bt = fd->field_type();
+      if (bt != T_OBJECT && bt != T_ARRAY) {
+        _out->print("%s ", fd->signature()->as_quoted_ascii());
+      }
+      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) {
+  BasicType bt = fd->field_type();
+  switch (bt) {
+    case T_BYTE:    _out->print("%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:
+    case T_OBJECT: {
+      oop value =  mirror->obj_field_acquire(fd->offset());
+      if (value == NULL) {
+        _out->print("null");
+      } else {
+        _out->print("%s", value->klass()->signature_name());
+        if (value->is_array()) {
+          _out->print(" %d", ((arrayOop)value)->length());
+        } else {
+          assert(value->is_instance() && bt == T_OBJECT, "what else?");
+          if (value->is_a(SystemDictionary::String_klass())) {
+            _out->print(" \"");
+            _out->print_raw(java_lang_String::as_quoted_ascii(value));
+            _out->print("\"");
+          }          
+        }
+      }
+      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/hotspot/share/ci/ciInstanceKlass.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciInstanceKlass.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -65,8 +65,13 @@
 
   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*       _vcc_klass; // points 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 +190,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 +201,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 +226,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 +247,7 @@
 
   bool is_leaf_type();
   ciInstanceKlass* implementor();
+  ciInstanceKlass* vcc_klass();
 
   // Is the defining class loader of this class the default loader?
   bool uses_default_loader() const;
--- a/src/hotspot/share/ci/ciKlass.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciKlass.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -44,6 +44,7 @@
   friend class ciMethod;
   friend class ciMethodData;
   friend class ciObjArrayKlass;
+  friend class ciValueArrayKlass;
   friend class ciReceiverTypeData;
 
 private:
--- a/src/hotspot/share/ci/ciMetadata.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciMetadata.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciMethodBlocks.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciMethodBlocks.cpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciObjArrayKlass.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciObjArrayKlass.cpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciObject.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciObject.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -127,6 +127,7 @@
   virtual bool is_array()                   { return false; }
   virtual bool is_obj_array()               { return false; }
   virtual bool is_type_array()              { return false; }
+  virtual bool is_value_array()             { return false; }
 
   // Is this a type or value which has no associated class?
   // It is true of primitive types and null objects.
--- a/src/hotspot/share/ci/ciObjectFactory.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciObjectFactory.cpp	Tue Sep 26 16:15:08 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,8 @@
 #include "ci/ciTypeArray.hpp"
 #include "ci/ciTypeArrayKlass.hpp"
 #include "ci/ciUtilities.hpp"
+#include "ci/ciValueArray.hpp"
+#include "ci/ciValueArrayKlass.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
@@ -150,7 +153,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]);
     }
@@ -346,6 +350,9 @@
   } else if (o->is_typeArray()) {
     typeArrayHandle h_ta(THREAD, (typeArrayOop)o);
     return new (arena()) ciTypeArray(h_ta);
+  } else if (o->is_valueArray()) {
+    valueArrayHandle h_ta(THREAD, (valueArrayOop)o);
+    return new (arena()) ciValueArray(h_ta);
   }
 
   // The oop is of some type not supported by the compiler interface.
@@ -378,8 +385,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 +537,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/hotspot/share/ci/ciReplay.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciReplay.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -33,6 +33,7 @@
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
 #include "prims/jvm.h"
 #include "utilities/copy.hpp"
 #include "utilities/macros.hpp"
@@ -704,14 +705,25 @@
           }
           break;
         }
+
+        case JVM_CONSTANT_UnresolvedValue: {
+          if (tag == JVM_CONSTANT_Value) {
+            tty->print_cr("Resolving value type %s at %d", cp->klass_name_at(i)->as_utf8(), i);
+            Klass* k = cp->klass_at(i, CHECK);
+          }
+          break;
+        }
+
         case JVM_CONSTANT_Long:
         case JVM_CONSTANT_Double:
           parsed_two_word = i + 1;
 
         case JVM_CONSTANT_ClassIndex:
+        case JVM_CONSTANT_ValueIndex:
         case JVM_CONSTANT_StringIndex:
         case JVM_CONSTANT_String:
         case JVM_CONSTANT_UnresolvedClassInError:
+        case JVM_CONSTANT_UnresolvedValueInError:
         case JVM_CONSTANT_Fieldref:
         case JVM_CONSTANT_Methodref:
         case JVM_CONSTANT_InterfaceMethodref:
@@ -738,6 +750,16 @@
           }
           break;
 
+        case JVM_CONSTANT_Value:
+          if (tag == JVM_CONSTANT_Value) {
+          } else if (tag == JVM_CONSTANT_UnresolvedValue) {
+            tty->print_cr("Warning: entry was unresolved in the replay data");
+          } else {
+            report_error("Unexpected tag");
+            return;
+          }
+          break;
+
         case 0:
           if (parsed_two_word == i) continue;
 
@@ -749,6 +771,149 @@
     }
   }
 
+  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:
+      case T_OBJECT: {
+        Thread* THREAD = Thread::current();
+        bool res = _replay->process_staticfield_reference(string_value, _vt, fd, THREAD);
+        assert(res, "should succeed for arrays & objects");
+        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;
+      }
+      default: {
+        fatal("Unhandled type: %s", type2name(bt));
+      }
+      }
+    }
+  };
+
+  bool process_staticfield_reference(const char* field_signature, oop java_mirror, fieldDescriptor* fd, TRAPS) {
+    if (field_signature[0] == '[') {
+      int length = parse_int("array length");
+      oop value = NULL;
+
+      if (field_signature[1] == '[') {
+        // multi dimensional array
+        Klass* k = resolve_klass(field_signature, CHECK_(true));
+        ArrayKlass* kelem = (ArrayKlass *)k;
+        int rank = 0;
+        while (field_signature[rank] == '[') {
+          rank++;
+        }
+        int* dims = NEW_RESOURCE_ARRAY(int, rank);
+        dims[0] = length;
+        for (int i = 1; i < rank; i++) {
+          dims[i] = 1; // These aren't relevant to the compiler
+        }
+        value = kelem->multi_allocate(rank, dims, CHECK_(true));
+      } else {
+        if (strcmp(field_signature, "[B") == 0) {
+          value = oopFactory::new_byteArray(length, CHECK_(true));
+        } else if (strcmp(field_signature, "[Z") == 0) {
+          value = oopFactory::new_boolArray(length, CHECK_(true));
+        } else if (strcmp(field_signature, "[C") == 0) {
+          value = oopFactory::new_charArray(length, CHECK_(true));
+        } else if (strcmp(field_signature, "[S") == 0) {
+          value = oopFactory::new_shortArray(length, CHECK_(true));
+        } else if (strcmp(field_signature, "[F") == 0) {
+          value = oopFactory::new_singleArray(length, CHECK_(true));
+        } else if (strcmp(field_signature, "[D") == 0) {
+          value = oopFactory::new_doubleArray(length, CHECK_(true));
+        } else if (strcmp(field_signature, "[I") == 0) {
+          value = oopFactory::new_intArray(length, CHECK_(true));
+        } else if (strcmp(field_signature, "[J") == 0) {
+          value = oopFactory::new_longArray(length, CHECK_(true));
+        } else if (field_signature[0] == '[' && field_signature[1] == 'L') {
+          Klass* kelem = resolve_klass(field_signature + 1, CHECK_(true));
+          value = oopFactory::new_objArray(kelem, length, CHECK_(true));
+        } else {
+          report_error("unhandled array staticfield");
+        }
+      }
+      java_mirror->obj_field_put(fd->offset(), value);
+      return true;
+    } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) {
+      const char* string_value = parse_escaped_string();
+      Handle value = java_lang_String::create_from_str(string_value, CHECK_(true));
+      java_mirror->obj_field_put(fd->offset(), value());
+      return true;
+    } else if (field_signature[0] == 'L') {
+      Klass* k = resolve_klass(field_signature, CHECK_(true));
+      oop value = InstanceKlass::cast(k)->allocate_instance(CHECK_(true));
+      java_mirror->obj_field_put(fd->offset(), value);
+      return true;
+    }
+    return false;
+  }
+
   // 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
@@ -776,89 +941,56 @@
     }
 
     oop java_mirror = k->java_mirror();
-    if (field_signature[0] == '[') {
-      int length = parse_int("array length");
-      oop value = NULL;
-
-      if (field_signature[1] == '[') {
-        // multi dimensional array
-        ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK);
-        if (kelem == NULL) {
-          return;
-        }
-        int rank = 0;
-        while (field_signature[rank] == '[') {
-          rank++;
-        }
-        int* dims = NEW_RESOURCE_ARRAY(int, rank);
-        dims[0] = length;
-        for (int i = 1; i < rank; i++) {
-          dims[i] = 1; // These aren't relevant to the compiler
-        }
-        value = kelem->multi_allocate(rank, dims, CHECK);
-      } else {
-        if (strcmp(field_signature, "[B") == 0) {
-          value = oopFactory::new_byteArray(length, CHECK);
-        } else if (strcmp(field_signature, "[Z") == 0) {
-          value = oopFactory::new_boolArray(length, CHECK);
-        } else if (strcmp(field_signature, "[C") == 0) {
-          value = oopFactory::new_charArray(length, CHECK);
-        } else if (strcmp(field_signature, "[S") == 0) {
-          value = oopFactory::new_shortArray(length, CHECK);
-        } else if (strcmp(field_signature, "[F") == 0) {
-          value = oopFactory::new_singleArray(length, CHECK);
-        } else if (strcmp(field_signature, "[D") == 0) {
-          value = oopFactory::new_doubleArray(length, CHECK);
-        } else if (strcmp(field_signature, "[I") == 0) {
-          value = oopFactory::new_intArray(length, CHECK);
-        } else if (strcmp(field_signature, "[J") == 0) {
-          value = oopFactory::new_longArray(length, CHECK);
-        } else if (field_signature[0] == '[' && field_signature[1] == 'L') {
-          Klass* kelem = resolve_klass(field_signature + 1, CHECK);
-          value = oopFactory::new_objArray(kelem, length, CHECK);
-        } else {
-          report_error("unhandled array staticfield");
-        }
+    if (strcmp(field_signature, "I") == 0) {
+      const char* string_value = parse_escaped_string();
+      int value = atoi(string_value);
+      java_mirror->int_field_put(fd.offset(), value);
+    } else if (strcmp(field_signature, "B") == 0) {
+      const char* string_value = parse_escaped_string();
+      int value = atoi(string_value);
+      java_mirror->byte_field_put(fd.offset(), value);
+    } else if (strcmp(field_signature, "C") == 0) {
+      const char* string_value = parse_escaped_string();
+      int value = atoi(string_value);
+      java_mirror->char_field_put(fd.offset(), value);
+    } else if (strcmp(field_signature, "S") == 0) {
+      const char* string_value = parse_escaped_string();
+      int value = atoi(string_value);
+      java_mirror->short_field_put(fd.offset(), value);
+    } else if (strcmp(field_signature, "Z") == 0) {
+      const char* string_value = parse_escaped_string();
+      int value = atoi(string_value);
+      java_mirror->bool_field_put(fd.offset(), value);
+    } else if (strcmp(field_signature, "J") == 0) {
+      const char* string_value = parse_escaped_string();
+      jlong value;
+      if (sscanf(string_value, JLONG_FORMAT, &value) != 1) {
+        fprintf(stderr, "Error parsing long: %s\n", string_value);
+        return;
+      }
+      java_mirror->long_field_put(fd.offset(), value);
+    } else if (strcmp(field_signature, "F") == 0) {
+      const char* string_value = parse_escaped_string();
+      float value = atof(string_value);
+      java_mirror->float_field_put(fd.offset(), value);
+    } else if (strcmp(field_signature, "D") == 0) {
+      const char* string_value = parse_escaped_string();
+      double value = atof(string_value);
+      java_mirror->double_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);
+      if (HAS_PENDING_EXCEPTION) {
+        return;
       }
       java_mirror->obj_field_put(fd.offset(), value);
     } else {
-      const char* string_value = parse_escaped_string();
-      if (strcmp(field_signature, "I") == 0) {
-        int value = atoi(string_value);
-        java_mirror->int_field_put(fd.offset(), value);
-      } else if (strcmp(field_signature, "B") == 0) {
-        int value = atoi(string_value);
-        java_mirror->byte_field_put(fd.offset(), value);
-      } else if (strcmp(field_signature, "C") == 0) {
-        int value = atoi(string_value);
-        java_mirror->char_field_put(fd.offset(), value);
-      } else if (strcmp(field_signature, "S") == 0) {
-        int value = atoi(string_value);
-        java_mirror->short_field_put(fd.offset(), value);
-      } else if (strcmp(field_signature, "Z") == 0) {
-        int value = atoi(string_value);
-        java_mirror->bool_field_put(fd.offset(), value);
-      } else if (strcmp(field_signature, "J") == 0) {
-        jlong value;
-        if (sscanf(string_value, JLONG_FORMAT, &value) != 1) {
-          fprintf(stderr, "Error parsing long: %s\n", string_value);
-          return;
-        }
-        java_mirror->long_field_put(fd.offset(), value);
-      } else if (strcmp(field_signature, "F") == 0) {
-        float value = atof(string_value);
-        java_mirror->float_field_put(fd.offset(), value);
-      } else if (strcmp(field_signature, "D") == 0) {
-        double value = atof(string_value);
-        java_mirror->double_field_put(fd.offset(), value);
-      } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) {
-        Handle value = java_lang_String::create_from_str(string_value, CHECK);
-        java_mirror->obj_field_put(fd.offset(), value());
-      } else if (field_signature[0] == 'L') {
-        Klass* k = resolve_klass(string_value, CHECK);
-        oop value = InstanceKlass::cast(k)->allocate_instance(CHECK);
-        java_mirror->obj_field_put(fd.offset(), value);
-      } else {
+      bool res = process_staticfield_reference(field_signature, java_mirror, &fd, CHECK);
+      if (!res)  {
         report_error("unhandled staticfield");
       }
     }
--- a/src/hotspot/share/ci/ciStreams.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciStreams.cpp	Tue Sep 26 16:15:08 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());
@@ -266,7 +269,8 @@
   assert(cur_bc() == Bytecodes::_getfield ||
          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/hotspot/share/ci/ciStreams.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciStreams.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -249,6 +249,12 @@
     return tag.is_unresolved_klass();
   }
 
+  // True if the klass-using bytecode points to an unresolved value type
+  bool is_unresolved_value_type() const {
+    constantTag tag = get_constant_pool_tag(get_klass_index());
+    return tag.is_unresolved_value_type();
+  }
+
   // If this bytecode is one of get_field, get_static, put_field,
   // or put_static, get the referenced field.
   ciField* get_field(bool& will_link);
--- a/src/hotspot/share/ci/ciSymbol.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciSymbol.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciType.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciType.cpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciType.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciType.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciTypeFlow.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciTypeFlow.cpp	Tue Sep 26 16:15:08 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,42 @@
 }
 
 // ------------------------------------------------------------------
+// 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_value_type()) {
+    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");
+  if (!will_link) {
+    trap(str, klass, str->get_field_holder_index());
+  } else {
+    ciType* type = pop_value();
+    ciType* field_type = field->type();
+    assert(field_type->is_loaded(), "field type must be loaded");
+    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 +854,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_instance_klass(), "must be an instance class");
+  pop_object();
+  push_object(klass->as_instance_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 +932,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 +948,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 +963,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 +994,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;
@@ -1435,6 +1497,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 +1527,16 @@
       push(value2);
       break;
     }
+  case Bytecodes::_vunbox:
+     {
+       do_vunbox(str);
+       break;
+     }
+     case Bytecodes::_vbox:
+     {
+       do_vbox(str);
+       break;
+     }
   case Bytecodes::_wide:
   default:
     {
@@ -1745,9 +1820,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 +2264,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/hotspot/share/ci/ciTypeFlow.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/ciTypeFlow.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciValueArray.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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_CI_CIVALUEARRAY_HPP
+#define SHARE_VM_CI_CIVALUEARRAY_HPP
+
+#include "ci/ciArray.hpp"
+#include "ci/ciClassList.hpp"
+#include "oops/valueArrayOop.hpp"
+
+// ciValueArray
+//
+// This class represents a valueArrayOop in the HotSpot virtual
+// machine.
+class ciValueArray : public ciArray {
+  CI_PACKAGE_ACCESS
+
+protected:
+  ciValueArray(valueArrayHandle h_o) : ciArray(h_o) {}
+
+  ciValueArray(ciValueKlass* klass, int len) : ciArray(klass, len) {}
+
+  valueArrayOop get_valueArrayOop() {
+    return (valueArrayOop)get_oop();
+  }
+
+  const char* type_string() { return "ciValuejArray"; }
+
+public:
+  // What kind of ciObject is this?
+  bool is_value_array() { return true; }
+};
+
+#endif // SHARE_VM_CI_CIVALUEARRAY_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/ci/ciValueArrayKlass.cpp	Tue Sep 26 16:15:08 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++] = 'Q';
+    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/hotspot/share/ci/ciValueArrayKlass.hpp	Tue Sep 26 16:15:08 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/hotspot/share/ci/ciValueKlass.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -0,0 +1,154 @@
+/*
+ * 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();
+  _field_index_map = new (arena) GrowableArray<int>(arena, nof_declared_nonstatic_fields(), 0, 0);
+  if (!has_nonstatic_fields()) {
+    return 0;
+  }
+
+  // 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");
+
+  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 (_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();
+  )
+}
+
+bool ciValueKlass::contains_oops() const {
+  GUARDED_VM_ENTRY(
+    ValueKlass* vklass = ValueKlass::cast(get_Klass());
+    return vklass->contains_oops();
+  )
+}
+
+// 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/hotspot/share/ci/ciValueKlass.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -0,0 +1,86 @@
+/*
+ * 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/ciEnv.hpp"
+#include "ci/ciFlags.hpp"
+#include "ci/ciInstanceKlass.hpp"
+#include "ci/ciSymbol.hpp"
+#include "oops/valueKlass.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();
+
+  ValueKlass* get_valueKlass() const {
+    return ValueKlass::cast(get_Klass());
+  }
+
+public:
+  bool      is_valuetype() const { return true; }
+  bool      flatten_array() const;
+  bool      contains_oops() 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();
+
+  // Can a value type instance of this type be returned as multiple
+  // returned values?
+  bool can_be_returned_as_fields() const {
+    return this != ciEnv::current()->___Value_klass() && get_valueKlass()->return_regs() != NULL;
+  }
+};
+
+#endif // SHARE_VM_CI_CIVALUEKLASS_HPP
--- a/src/hotspot/share/ci/compilerInterface.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/ci/compilerInterface.hpp	Tue Sep 26 16:15:08 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/hotspot/share/classfile/classFileParser.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -54,6 +54,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"
@@ -87,7 +88,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
@@ -146,12 +147,18 @@
     // so we don't need bounds-check for reading tag.
     const u1 tag = cfs->get_u1_fast();
     switch (tag) {
-      case JVM_CONSTANT_Class : {
+      case JVM_CONSTANT_Class: {
         cfs->guarantee_more(3, CHECK);  // name_index, tag/access_flags
         const u2 name_index = cfs->get_u2_fast();
         cp->klass_index_at_put(index, name_index);
         break;
       }
+      case JVM_CONSTANT_Value: {  // may be present in a retransform situation
+        cfs->guarantee_more(3, CHECK);  // name_index, tag/access_flags
+        const u2 name_index = cfs->get_u2_fast();
+        cp->value_type_index_at_put(index, name_index);
+        break;
+      }
       case JVM_CONSTANT_Fieldref: {
         cfs->guarantee_more(5, CHECK);  // class_index, name_and_type_index, tag/access_flags
         const u2 class_index = cfs->get_u2_fast();
@@ -401,8 +408,9 @@
   for (index = 1; index < length; index++) {          // Index 0 is unused
     const jbyte tag = cp->tag_at(index).value();
     switch (tag) {
-      case JVM_CONSTANT_Class: {
-        ShouldNotReachHere();     // Only JVM_CONSTANT_ClassIndex should be present
+      case JVM_CONSTANT_Class:
+      case JVM_CONSTANT_Value: {
+        ShouldNotReachHere();     // Only JVM_CONSTANT_[Class|Value]Index should be present
         break;
       }
       case JVM_CONSTANT_Fieldref:
@@ -413,7 +421,10 @@
         if (!_need_verify) break;
         const int klass_ref_index = cp->klass_ref_index_at(index);
         const int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
-        check_property(valid_klass_reference_at(klass_ref_index),
+        check_property(valid_klass_reference_at(klass_ref_index) ||
+                       (valid_value_type_reference_at(klass_ref_index) &&
+                        ((EnableMVT && (tag == JVM_CONSTANT_Fieldref)) ||
+                         EnableValhalla)),
                        "Invalid constant pool index %u in class file %s",
                        klass_ref_index, CHECK);
         check_property(valid_cp_range(name_and_type_ref_index, length) &&
@@ -463,7 +474,42 @@
         check_property(valid_symbol_at(class_index),
           "Invalid constant pool index %u in class file %s",
           class_index, CHECK);
-        cp->unresolved_klass_at_put(index, class_index, num_klasses++);
+
+        Symbol* const name = cp->symbol_at(class_index);
+        const unsigned int name_len = name->utf8_length();
+
+        // check explicitly for ;Qjava/lang/__Value;
+        if (name_len == 20 &&
+            name->equals(";Qjava/lang/__Value;")) {
+            cp->symbol_at_put(class_index, vmSymbols::java_lang____Value());
+            cp->unresolved_value_type_at_put(index, class_index, num_klasses++);
+        } else if (EnableValhalla || EnableMVT) {
+          const char* derive_vt_classname_postfix = "$Value;";
+          // check for a value type
+          // check for name > 3 to rule out ";Q;" where no name is present
+          if (name_len != 0 &&
+              name_len > 3 &&
+              name->starts_with(";Q") &&
+              ((EnableValhalla && (name->byte_at(name_len-1) == ';')) ||
+               (EnableMVT && ClassLoader::string_ends_with(name->as_utf8(), derive_vt_classname_postfix)))) {
+            Symbol* const strippedsym = SymbolTable::new_symbol(name, 2, name_len-1, CHECK);
+            assert(strippedsym != NULL, "failure to create value type stripped name");
+            cp->symbol_at_put(class_index, strippedsym);
+            cp->unresolved_value_type_at_put(index, class_index, num_klasses++);
+          } else {
+            cp->unresolved_klass_at_put(index, class_index, num_klasses++);
+          }
+        } else {
+          cp->unresolved_klass_at_put(index, class_index, num_klasses++);
+        }
+        break;
+      }
+      case JVM_CONSTANT_ValueIndex: {
+        const int class_index = cp->value_type_index_at(index);
+        check_property(valid_symbol_at(class_index),
+          "Invalid constant pool index %u in class file %s",
+          class_index, CHECK);
+        cp->unresolved_value_type_at_put(index, class_index, num_klasses++);
         break;
       }
       case JVM_CONSTANT_StringIndex: {
@@ -595,7 +641,8 @@
   for (index = 1; index < length; index++) {
     const jbyte tag = cp->tag_at(index).value();
     switch (tag) {
-      case JVM_CONSTANT_UnresolvedClass: {
+      case JVM_CONSTANT_UnresolvedClass:
+      case JVM_CONSTANT_UnresolvedValue: {
         const Symbol* const class_name = cp->klass_name_at(index);
         // check the name, even if _cp_patches will overwrite it
         verify_legal_class_name(class_name, CHECK);
@@ -999,6 +1046,7 @@
     _jdk_internal_vm_annotation_Contended,
     _field_Stable,
     _jdk_internal_vm_annotation_ReservedStackAccess,
+    _jdk_incubator_mvt_ValueCapableClass,
     _annotation_LIMIT
   };
   const Location _location;
@@ -1034,6 +1082,8 @@
 
   void set_stable(bool stable) { set_annotation(_field_Stable); }
   bool is_stable() const { return has_annotation(_field_Stable); }
+
+  bool is_value_capable_class() const { return has_annotation(_jdk_incubator_mvt_ValueCapableClass); }
 };
 
 // This class also doubles as a holder for metadata cleanup.
@@ -1386,11 +1436,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
 };
@@ -1410,12 +1462,14 @@
   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_VALUETYPEPTR= 20,
+  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 21,
   BAD_ALLOCATION_TYPE, // 0
   BAD_ALLOCATION_TYPE, // 1
   BAD_ALLOCATION_TYPE, // 2
@@ -1430,12 +1484,14 @@
   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_VALUETYPEPTR= 20,
+  BAD_ALLOCATION_TYPE, // T_CONFLICT    = 21,
 };
 
 static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) {
@@ -1544,6 +1600,9 @@
       signature_index, CHECK);
     const Symbol* const sig = cp->symbol_at(signature_index);
     verify_legal_field_signature(name, sig, CHECK);
+    if (sig->starts_with("Q")) {
+      _has_value_fields = true;
+    }
 
     u2 constantvalue_index = 0;
     bool is_synthetic = false;
@@ -2075,6 +2134,12 @@
       if (RestrictReservedStack && !privileged) break; // honor privileges
       return _jdk_internal_vm_annotation_ReservedStackAccess;
     }
+    case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_incubator_mvt_ValueCapableClass_signature) : {
+      if (_location != _in_class) {
+        break;
+      }
+      return _jdk_incubator_mvt_ValueCapableClass;
+    }
     default: {
       break;
     }
@@ -2117,6 +2182,9 @@
 void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
   assert(ik != NULL, "invariant");
   ik->set_is_contended(is_contended());
+  if (is_value_capable_class()) {
+    ik->set_has_vcc_annotation();
+  }
 }
 
 #define MAX_ARGS_SIZE 255
@@ -3085,7 +3153,8 @@
     // Inner class index
     const u2 inner_class_info_index = cfs->get_u2_fast();
     check_property(
-      valid_klass_reference_at(inner_class_info_index),
+      (valid_klass_reference_at(inner_class_info_index) ||
+       ((EnableValhalla || EnableMVT) && valid_value_type_reference_at(inner_class_info_index))),
       "inner_class_info_index %u has bad constant type in class file %s",
       inner_class_info_index, CHECK_0);
     // Outer class index
@@ -3105,14 +3174,20 @@
       guarantee_property(inner_class_info_index != outer_class_info_index,
                          "Class is both outer and inner class in class file %s", CHECK_0);
     }
-    // Access flags
-    jint flags;
+
+    jint recognized_modifiers = RECOGNIZED_INNER_CLASS_MODIFIERS;
     // JVM_ACC_MODULE is defined in JDK-9 and later.
     if (_major_version >= JAVA_9_VERSION) {
-      flags = cfs->get_u2_fast() & (RECOGNIZED_INNER_CLASS_MODIFIERS | JVM_ACC_MODULE);
-    } else {
-      flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS;
+      recognized_modifiers |= JVM_ACC_MODULE;
     }
+    // JVM_ACC_VALUE is defined for class file version 53.1 and later
+    if (supports_value_types()) {
+      recognized_modifiers |= JVM_ACC_VALUE;
+    }
+
+    // Access flags
+    jint flags = cfs->get_u2_fast() & recognized_modifiers;
+
     if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
       // Set abstract bit for old class files for backward compatibility
       flags |= JVM_ACC_ABSTRACT;
@@ -3569,19 +3644,21 @@
   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);
   } else {
-    check_property(valid_klass_reference_at(super_class_index),
+    check_property((valid_klass_reference_at(super_class_index) ||
+                    ((EnableValhalla || EnableMVT) && valid_value_type_reference_at(super_class_index))),
                    "Invalid superclass index %u in class file %s",
                    super_class_index,
                    CHECK_NULL);
     // The class name should be legal because it is checked when parsing constant pool.
     // However, make sure it is not an array type.
     bool is_array = false;
-    if (cp->tag_at(super_class_index).is_klass()) {
+    if (cp->tag_at(super_class_index).is_klass() || cp->tag_at(super_class_index).is_value_type()) {
       super_klass = InstanceKlass::cast(cp->resolved_klass_at(super_class_index));
       if (need_verify)
         is_array = super_klass->is_array_klass();
@@ -3596,39 +3673,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,
@@ -3669,16 +3713,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,
@@ -3691,6 +3877,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.
   //
@@ -3711,8 +3903,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)) ) {
@@ -3729,6 +3922,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_value_capable_class()) {
+    int old = nonstatic_fields_start;
+    nonstatic_fields_start = align_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();
@@ -3738,6 +3941,14 @@
     next_nonstatic_field_offset += ContendedPaddingWidth;
   }
 
+  // Temporary value types restrictions
+  if (is_value_type() || is_value_capable_class()) {
+    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
@@ -3748,16 +3959,60 @@
   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;
+
+  if (is_value_type() && (!has_nonstatic_fields)) {
+    // There are a number of fixes required throughout the type system and JIT
+    if (class_name() != vmSymbols::java_lang____Value()) {
+      throwValueTypeLimitation(THREAD_AND_LOCATION, "Value Types do not support zero instance size yet");
+    }
+  }
 
   // Prepare list of oops for oop map generation.
   //
@@ -3767,15 +4022,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
 
@@ -3824,13 +4081,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 +
@@ -3913,6 +4165,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_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).
@@ -3929,6 +4191,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;
@@ -3949,6 +4213,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_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;
@@ -3958,26 +4245,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 ) {
@@ -4086,30 +4354,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_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:
@@ -4144,12 +4399,24 @@
   // This helps to alleviate memory contention effects for subclass fields
   // and/or adjacent object.
   if (is_contended_class) {
+    assert(!is_value_type() && !is_value_capable_class(), "@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_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_value_capable_class()) {
+    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_up(notaligned_nonstatic_fields_end, nonstatic_field_sz_align);
   int instance_end              = align_up(notaligned_nonstatic_fields_end, wordSize);
   int static_fields_end         = align_up(next_static_byte_offset, wordSize);
 
@@ -4161,8 +4428,9 @@
   int instance_size             = align_object_size(instance_end / wordSize);
 
   assert(instance_size == align_object_size(align_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
@@ -4173,12 +4441,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,
@@ -4186,62 +4453,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");
 
@@ -4315,6 +4539,11 @@
   }
 }
 
+bool ClassFileParser::supports_value_types() const {
+  // Value types are only supported by class file version 53.1 and later
+  return _major_version > JAVA_9_VERSION || (_major_version == JAVA_9_VERSION && _minor_version >= 1);
+}
+
 // Attach super classes and interface classes to class loader data
 static void record_defined_class_dependencies(const InstanceKlass* defined_klass,
                                               TRAPS) {
@@ -4339,6 +4568,18 @@
         defining_loader_data->record_dependency(local_interfaces->at(i), CHECK);
       }
     }
+
+    for (FieldStream st((InstanceKlass*)defined_klass, false, false); !st.eos(); st.next()) {
+      Symbol* signature = st.signature();
+      if (signature->starts_with("Q")) {
+        Klass* klass = SystemDictionary::resolve_or_fail(signature,
+                                                         Handle(THREAD, defined_klass->class_loader()),
+                                                         Handle(THREAD, defined_klass->protection_domain()), true, CHECK);
+        assert(klass != NULL, "Sanity check");
+        assert(klass->access_flags().is_value_type(), "Value type expected");
+        defining_loader_data->record_dependency(klass, CHECK);
+      }
+    }
   }
 }
 
@@ -4593,7 +4834,9 @@
 
 void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const {
   const bool is_module = (flags & JVM_ACC_MODULE) != 0;
+  const bool is_value_type = (flags & JVM_ACC_VALUE) != 0;
   assert(_major_version >= JAVA_9_VERSION || !is_module, "JVM_ACC_MODULE should not be set");
+  assert(supports_value_types() || !is_value_type, "JVM_ACC_VALUE should not be set");
   if (is_module) {
     ResourceMark rm(THREAD);
     Exceptions::fthrow(
@@ -4639,7 +4882,7 @@
           (is_protected && is_private));
 }
 
-static bool is_supported_version(u2 major, u2 minor){
+static bool is_supported_version(u2 major, u2 minor) {
   const u2 max_version = JAVA_MAX_SUPPORTED_VERSION;
   return (major >= JAVA_MIN_SUPPORTED_VERSION) &&
          (major <= max_version) &&
@@ -4929,7 +5172,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);
@@ -5179,7 +5423,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 {
@@ -5313,7 +5557,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");
@@ -5327,7 +5571,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*
@@ -5413,10 +5657,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);
@@ -5460,6 +5704,18 @@
                                              CHECK);
   }
 
+  if (is_value_type()) {
+    ValueKlass* vk = ValueKlass::cast(ik);
+    vk->set_if_bufferable();
+    vk->initialize_calling_convention();
+  }
+
+  // Valhalla shady value type conversion
+  if (_parsed_annotations->is_value_capable_class()) {
+    ik->create_value_capable_class(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()) {
@@ -5472,6 +5728,18 @@
   // Update the loader_data graph.
   record_defined_class_dependencies(ik, CHECK);
 
+  for (FieldStream st((InstanceKlass*)ik, false, false); !st.eos(); st.next()) {
+    Symbol* signature = st.signature();
+    if (signature->starts_with("Q")) {
+      Klass* klass = SystemDictionary::resolve_or_fail(signature,
+                                                       Handle(THREAD, ik->class_loader()),
+                                                       Handle(THREAD, ik->protection_domain()), true, CHECK);
+      assert(klass != NULL, "Sanity check");
+      assert(klass->access_flags().is_value_type(), "Value type expected");
+      ik->set_value_field_klass(st.index(), klass);
+    }
+  }
+
   ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
 
   if (!is_internal()) {
@@ -5640,7 +5908,8 @@
   _has_finalizer(false),
   _has_empty_finalizer(false),
   _has_vanilla_constructor(false),
-  _max_bootstrap_specifier_index(-1) {
+  _max_bootstrap_specifier_index(-1),
+  _has_value_fields(false) {
 
   _class_name = name != NULL ? name : vmSymbols::unknown_class_name();
 
@@ -5837,14 +6106,18 @@
   // ACCESS FLAGS
   stream->guarantee_more(8, CHECK);  // flags, this_class, super_class, infs_len
 
-  // Access flags
-  jint flags;
+  jint recognized_modifiers = JVM_RECOGNIZED_CLASS_MODIFIERS;
   // JVM_ACC_MODULE is defined in JDK-9 and later.
   if (_major_version >= JAVA_9_VERSION) {
-    flags = stream->get_u2_fast() & (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_MODULE);
-  } else {
-    flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
-  }
+    recognized_modifiers |= JVM_ACC_MODULE;
+  }
+  // JVM_ACC_VALUE is defined for class file version 53.1 and later
+  if (supports_value_types()) {
+    recognized_modifiers |= JVM_ACC_VALUE;
+  }
+
+  // Access flags
+  jint flags = stream->get_u2_fast() & recognized_modifiers;
 
   if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
     // Set abstract bit for old class files for backward compatibility
@@ -5865,8 +6138,9 @@
   // This class and superclass
   _this_class_index = stream->get_u2_fast();
   check_property(
-    valid_cp_range(_this_class_index, cp_size) &&
-      cp->tag_at(_this_class_index).is_unresolved_klass(),
+    (valid_cp_range(_this_class_index, cp_size) &&
+     (cp->tag_at(_this_class_index).is_unresolved_klass() ||
+      cp->tag_at(_this_class_index).is_unresolved_value_type())),
     "Invalid this class index %u in constant pool in class file %s",
     _this_class_index, CHECK);
 
@@ -6063,8 +6337,27 @@
       );
       return;
     }
+
+    // For a java/lang/__Value super class, the class inheriting, must be a value class
+    if ((EnableValhalla || EnableMVT) &&
+        _super_klass->name() == vmSymbols::java_lang____Value()) {
+      guarantee_property((_access_flags.get_flags() & JVM_ACC_VALUE) != 0,
+                         "Only a value class can inherit from java/lang/__Value",
+                         CHECK);
+    }
+
+    // For a value class, only java/lang/__Value is an acceptable super class
+    if ((EnableValhalla || EnableMVT) &&
+        _access_flags.get_flags() & JVM_ACC_VALUE) {
+      guarantee_property(_super_klass->name() == vmSymbols::java_lang____Value(),
+                         "Value class can only inherit java/lang/__Value",
+                         CHECK);
+    }
+
     // 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");
     }
   }
@@ -6140,6 +6433,11 @@
 
   return _stream->clone();
 }
+
+bool ClassFileParser::is_value_capable_class() const {
+  return _parsed_annotations->is_value_capable_class();
+}
+
 // ----------------------------------------------------------------------------
 // debugging
 
--- a/src/hotspot/share/classfile/classFileParser.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/classFileParser.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -55,6 +55,7 @@
  class FieldAllocationCount;
  class FieldAnnotationCollector;
  class FieldLayoutInfo;
+ class OopMapBlocksBuilder;
 
  public:
   // The ClassFileParser has an associated "publicity" level
@@ -158,6 +159,7 @@
   bool _has_nonstatic_concrete_methods;
   bool _declares_nonstatic_concrete_methods;
   bool _has_final_method;
+  bool _has_value_fields;
 
   // precomputed flags
   bool _has_finalizer;
@@ -393,6 +395,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,
@@ -456,6 +463,11 @@
              _cp->tag_at(index).is_klass_or_reference();
   }
 
+  bool valid_value_type_reference_at(int index) const {
+    return _cp->is_within_bounds(index) &&
+             _cp->tag_at(index).is_value_type_or_reference();
+  }
+
   // Checks that the cpool index is in range and is a utf8
   bool valid_symbol_at(int cpool_index) const {
     return _cp->is_within_bounds(cpool_index) &&
@@ -495,6 +507,9 @@
                      FieldLayoutInfo* info,
                      TRAPS);
 
+  // Check if the class file supports value types
+  bool supports_value_types() const;
+
  public:
   ClassFileParser(ClassFileStream* stream,
                   Symbol* name,
@@ -525,6 +540,11 @@
 
   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_value_capable_class() const;
+  bool has_value_fields() const { return _has_value_fields; }
+
+  u2 java_fields_count() const { return _java_fields_count; }
 
   const InstanceKlass* host_klass() const { return _host_klass; }
   const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
--- a/src/hotspot/share/classfile/classLoader.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/classLoader.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -212,7 +212,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;
       }
@@ -1998,6 +1998,11 @@
     return false;
   }
 
+  // Don't compile methods in __Value if value types are disabled
+  if (!EnableMVT && !EnableValhalla && m->method_holder()->name() == vmSymbols::java_lang____Value()) {
+    return false;
+  }
+
   return CompilationPolicy::can_be_compiled(m, comp_level);
 }
 
--- a/src/hotspot/share/classfile/classLoaderData.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/classLoaderData.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -65,6 +65,7 @@
 #include "memory/resourceArea.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/jniHandles.hpp"
@@ -300,6 +301,16 @@
   }
 }
 
+void ClassLoaderData::value_classes_do(void f(ValueKlass*)) {
+  // Lock-free access requires load_ptr_acquire
+  for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
+    if (k->is_value()) {
+      f(ValueKlass::cast(k));
+    }
+    assert(k != k->next_link(), "no loops!");
+  }
+}
+
 void ClassLoaderData::modules_do(void f(ModuleEntry*)) {
   assert_locked_or_safepoint(Module_lock);
   if (_unnamed_module != NULL) {
@@ -559,6 +570,7 @@
 void ClassLoaderData::unload() {
   _unloading = true;
 
+  value_classes_do(ValueKlass::cleanup);
   // Tell serviceability tools these classes are unloading
   classes_do(InstanceKlass::notify_unload_class);
 
@@ -827,7 +839,11 @@
       } else if (m->is_constantPool()) {
         MetadataFactory::free_metadata(this, (ConstantPool*)m);
       } else if (m->is_klass()) {
-        MetadataFactory::free_metadata(this, (InstanceKlass*)m);
+        if (!((Klass*)m)->is_value()) {
+          MetadataFactory::free_metadata(this, (InstanceKlass*)m);
+        } else {
+          MetadataFactory::free_metadata(this, (ValueKlass*)m);
+        }
       } else {
         ShouldNotReachHere();
       }
--- a/src/hotspot/share/classfile/classLoaderData.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/classLoaderData.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -281,6 +281,7 @@
   void classes_do(void f(Klass*));
   void loaded_classes_do(KlassClosure* klass_closure);
   void classes_do(void f(InstanceKlass*));
+  void value_classes_do(void f(ValueKlass*));
   void methods_do(void f(Method*));
   void modules_do(void f(ModuleEntry*));
   void packages_do(void f(PackageEntry*));
--- a/src/hotspot/share/classfile/javaClasses.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -45,6 +45,7 @@
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayOop.hpp"
+#include "oops/valueArrayKlass.hpp"
 #include "prims/resolvedMethodTable.hpp"
 #include "runtime/fieldDescriptor.hpp"
 #include "runtime/handles.inline.hpp"
@@ -853,7 +854,11 @@
 
     // It might also have a component mirror.  This mirror must already exist.
     if (k->is_array_klass()) {
-      if (k->is_typeArray_klass()) {
+      if (k->is_valueArray_klass()) {
+        Klass* element_klass = (Klass*) ValueArrayKlass::cast(k)->element_klass();
+        comp_mirror = Handle(THREAD, element_klass->java_mirror());
+      }
+      else if (k->is_typeArray_klass()) {
         BasicType type = TypeArrayKlass::cast(k)->element_type();
         comp_mirror = Handle(THREAD, Universe::java_mirror(type));
       } else {
@@ -1028,18 +1033,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/hotspot/share/classfile/stackMapFrame.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/stackMapFrame.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -101,6 +101,7 @@
   switch (ss.type()) {
     case T_OBJECT:
     case T_ARRAY:
+    case T_VALUETYPE:
     {
       Symbol* sig = ss.as_symbol(CHECK_(VerificationType::bogus_type()));
       // Create another symbol to save as signature stream unreferences
@@ -109,6 +110,9 @@
         verifier()->create_temporary_symbol(sig, 0, sig->utf8_length(),
                                  CHECK_(VerificationType::bogus_type()));
       assert(sig_copy == sig, "symbols don't match");
+      if (ss.type() == T_VALUETYPE) {
+        return VerificationType::valuetype_type(sig_copy);
+      }
       return VerificationType::reference_type(sig_copy);
     }
     case T_INT:     return VerificationType::integer_type();
--- a/src/hotspot/share/classfile/stackMapTable.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/stackMapTable.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -169,10 +169,16 @@
     int nconstants = _cp->length();
     if ((class_index <= 0 || class_index >= nconstants) ||
         (!_cp->tag_at(class_index).is_klass() &&
-         !_cp->tag_at(class_index).is_unresolved_klass())) {
+         !_cp->tag_at(class_index).is_unresolved_klass() &&
+         !_cp->tag_at(class_index).is_value_type() &&
+         !_cp->tag_at(class_index).is_unresolved_value_type())) {
       _stream->stackmap_format_error("bad class index", THREAD);
       return VerificationType::bogus_type();
     }
+    if (_cp->tag_at(class_index).is_value_type() ||
+        _cp->tag_at(class_index).is_unresolved_value_type()) {
+      return VerificationType::valuetype_type(_cp->klass_name_at(class_index));
+    }
     return VerificationType::reference_type(_cp->klass_name_at(class_index));
   }
   if (tag == ITEM_UninitializedThis) {
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -61,6 +61,7 @@
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayKlass.hpp"
+#include "oops/valueKlass.hpp"
 #include "prims/jvm.h"
 #include "prims/jvmtiEnvBase.hpp"
 #include "prims/resolvedMethodTable.hpp"
@@ -74,6 +75,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/diagnosticCommand.hpp"
@@ -241,9 +243,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);
@@ -268,7 +270,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,
@@ -284,6 +286,34 @@
   return k;
 }
 
+// Temporary Minimal Value Type support code. Attempt to load VCC for DVT descriptor
+Klass* SystemDictionary::resolve_dvt_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
+  assert(EnableMVT && FieldType::is_dvt_postfix(class_name), "Invariant");
+
+  ResourceMark rm(THREAD);
+  // Given a "Q-type" descriptor and EnableMVT, original exception is not so interesting
+  CLEAR_PENDING_EXCEPTION;
+
+  TempNewSymbol vcc_name = SymbolTable::new_symbol(FieldType::dvt_unmangle_vcc(class_name), CHECK_NULL);
+  Klass* vcc = do_resolve_instance_class_or_null(vcc_name, class_loader, protection_domain, CHECK_NULL);
+  if (vcc == NULL) {
+    return NULL;
+  }
+  Klass* dvt = do_resolve_instance_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
+  if ((dvt !=NULL) && dvt->is_value() && (ValueKlass::cast(dvt)->get_vcc_klass() == vcc)) {
+    return dvt;
+  }
+  if (vcc->is_instance_klass() && (!InstanceKlass::cast(vcc)->has_vcc_annotation())) {
+    static const char not_vcc_msg[] =
+        "Failed to resolve %s, found possible ValueCapableClass name mangle match is not ValueCapableClass annotated: %s";
+    size_t buflen = strlen(not_vcc_msg) + class_name->utf8_length() + vcc_name->utf8_length();
+    char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
+    jio_snprintf(buf, buflen, not_vcc_msg, class_name->as_C_string(), vcc_name->as_C_string());
+    THROW_MSG_NULL(vmSymbols::java_lang_NoClassDefFoundError(), buf);
+  }
+  return NULL;
+}
+
 
 // Must be called for any super-class or super-interface resolution
 // during class definition to allow class circularity checking
@@ -639,16 +669,27 @@
 #endif // INCLUDE_TRACE
 }
 
+Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
+                                                        Handle class_loader,
+                                                        Handle protection_domain,
+                                                        TRAPS) {
+  Klass* k = do_resolve_instance_class_or_null(name, class_loader, protection_domain, THREAD);
+  if (EnableMVT && (k == NULL) && FieldType::is_dvt_postfix(name)) {
+    k = resolve_dvt_or_null(name, class_loader, protection_domain, THREAD);
+  }
+  return k;
+}
+
 // Be careful when modifying this code: once you have run
 // placeholders()->find_and_add(PlaceholderTable::LOAD_INSTANCE),
 // you need to find_and_remove it before returning.
 // So be careful to not exit with a CHECK_ macro betweeen these calls.
-Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
+Klass* SystemDictionary::do_resolve_instance_class_or_null(Symbol* name,
                                                         Handle class_loader,
                                                         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");
 
   EventClassLoad class_load_start_event;
 
@@ -974,7 +1015,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);
@@ -2074,6 +2115,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) {
@@ -2329,7 +2384,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/hotspot/share/classfile/systemDictionary.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -188,6 +188,9 @@
   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(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. */                                                          \
@@ -209,6 +212,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. */                                                                       \
@@ -250,8 +255,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)
   };
 
 
@@ -419,6 +426,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; })
 
@@ -615,7 +624,9 @@
 
   // Basic loading operations
   static Klass* resolve_instance_class_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS);
+  static Klass* do_resolve_instance_class_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS);
   static Klass* resolve_array_class_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS);
+  static Klass* resolve_dvt_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS);
   static InstanceKlass* handle_parallel_super_load(Symbol* class_name, Symbol* supername, Handle class_loader, Handle protection_domain, Handle lockObject, TRAPS);
   // Wait on SystemDictionary_lock; unlocks lockObject before
   // waiting; relocks lockObject with correct recursion count
--- a/src/hotspot/share/classfile/verificationType.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/verificationType.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -135,6 +135,11 @@
         name(), 2, name()->utf8_length() - 1,
         CHECK_(VerificationType::bogus_type()));
       return VerificationType::reference_type(component);
+    case 'Q':
+      component = context->create_temporary_symbol(
+        name(), 2, name()->utf8_length() - 1,
+        CHECK_(VerificationType::bogus_type()));
+      return VerificationType::valuetype_type(component);
     default:
       // Met an invalid type signature, e.g. [X
       return VerificationType::bogus_type();
@@ -159,6 +164,7 @@
     case Double_2nd:       st->print("double_2nd"); break;
     case Null:             st->print("null"); break;
     case ReferenceQuery:   st->print("reference type"); break;
+    case ValueTypeQuery:   st->print("value type"); break;
     case Category1Query:   st->print("category1 type"); break;
     case Category2Query:   st->print("category2 type"); break;
     case Category2_2ndQuery: st->print("category2_2nd type"); break;
--- a/src/hotspot/share/classfile/verificationType.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/verificationType.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -70,21 +70,23 @@
 
     // Enum for the _data field
     enum {
-      // Bottom two bits determine if the type is a reference, primitive,
-      // uninitialized or a query-type.
-      TypeMask           = 0x00000003,
+      // Bottom three bits determine if the type is a reference, value type,
+      // primitive, uninitialized or a query-type.
+      TypeMask           = 0x00000007,
 
       // Topmost types encoding
-      Reference          = 0x0,        // _sym contains the name
+      Reference          = 0x0,        // _sym contains the name of an object 
       Primitive          = 0x1,        // see below for primitive list
       Uninitialized      = 0x2,        // 0x00ffff00 contains bci
       TypeQuery          = 0x3,        // Meta-types used for category testing
+      ValueType          = 0x4,        // _sym contains the name of a value type
 
       // Utility flags
       ReferenceFlag      = 0x00,       // For reference query types
       Category1Flag      = 0x01,       // One-word values
       Category2Flag      = 0x02,       // First word of a two-word value
       Category2_2ndFlag  = 0x04,       // Second word of a two-word value
+      ValueTypeFlag      = 0x08,       // For value type query types
 
       // special reference values
       Null               = 0x00000000, // A reference with a 0 sym is null
@@ -116,7 +118,8 @@
       ReferenceQuery     = (ReferenceFlag     << 1 * BitsPerByte) | TypeQuery,
       Category1Query     = (Category1Flag     << 1 * BitsPerByte) | TypeQuery,
       Category2Query     = (Category2Flag     << 1 * BitsPerByte) | TypeQuery,
-      Category2_2ndQuery = (Category2_2ndFlag << 1 * BitsPerByte) | TypeQuery
+      Category2_2ndQuery = (Category2_2ndFlag << 1 * BitsPerByte) | TypeQuery,
+      ValueTypeQuery     = (ValueTypeFlag     << 1 * BitsPerByte) | TypeQuery
     };
 
   VerificationType(uintptr_t raw_data) {
@@ -149,6 +152,8 @@
   // any reference is assignable to reference_check.
   static VerificationType reference_check()
     { return VerificationType(ReferenceQuery); }
+  static VerificationType valuetype_check()
+    { return VerificationType(ValueTypeQuery); }
   static VerificationType category1_check()
     { return VerificationType(Category1Query); }
   static VerificationType category2_check()
@@ -158,17 +163,28 @@
 
   // For reference types, store the actual Symbol
   static VerificationType reference_type(Symbol* sh) {
-      assert(((uintptr_t)sh & 0x3) == 0, "Symbols must be aligned");
+      assert(((uintptr_t)sh & TypeMask) == 0, "Symbols must be aligned");
       // If the above assert fails in the future because oop* isn't aligned,
       // then this type encoding system will have to change to have a tag value
       // to descriminate between oops and primitives.
       return VerificationType((uintptr_t)sh);
-  }
+  }  
   static VerificationType uninitialized_type(u2 bci)
     { return VerificationType(bci << 1 * BitsPerByte | Uninitialized); }
   static VerificationType uninitialized_this_type()
     { return uninitialized_type(BciForThis); }
 
+  // For value types, store the actual Symbol* and set the 3rd bit.
+  // Provides a way for a value type to be distinguished from a reference type.
+  static VerificationType valuetype_type(Symbol* sh) {
+      assert(((uintptr_t)sh & TypeMask) == 0, "Symbols must be aligned");
+      assert((uintptr_t)sh != 0, "Null is not a valid value type");
+      // If the above assert fails in the future because oop* isn't aligned,
+      // then this type encoding system will have to change to have a tag value
+      // to descriminate between oops and primitives.
+      return VerificationType((uintptr_t)sh | ValueType);
+  }
+
   // Create based on u1 read from classfile
   static VerificationType from_tag(u1 tag);
 
@@ -184,11 +200,12 @@
   bool is_double() const    { return (_u._data == Double); }
   bool is_long2() const     { return (_u._data == Long_2nd); }
   bool is_double2() const   { return (_u._data == Double_2nd); }
-  bool is_reference() const { return ((_u._data & TypeMask) == Reference); }
+  bool is_reference() const { return (((_u._data & TypeMask) == Reference) && !is_valuetype_check()); }
+  bool is_valuetype() const { return ((_u._data & TypeMask) == ValueType); }
   bool is_category1() const {
     // This should return true for all one-word types, which are category1
-    // primitives, and references (including uninitialized refs).  Though
-    // the 'query' types should technically return 'false' here, if we
+    // primitives, references (including uninitialized refs) and value types.
+    // Though the 'query' types should technically return 'false' here, if we
     // allow this to return true, we can perform the test using only
     // 2 operations rather than 8 (3 masks, 3 compares and 2 logical 'ands').
     // Since noone should call this on a query type anyway, this is ok.
@@ -202,6 +219,7 @@
     return ((_u._data & Category2_2nd) == Category2_2nd);
   }
   bool is_reference_check() const { return _u._data == ReferenceQuery; }
+  bool is_valuetype_check() const { return _u._data == ValueTypeQuery; }
   bool is_category1_check() const { return _u._data == Category1Query; }
   bool is_category2_check() const { return _u._data == Category2Query; }
   bool is_category2_2nd_check() const { return _u._data == Category2_2ndQuery; }
@@ -219,6 +237,7 @@
   bool is_float_array() const { return is_x_array('F'); }
   bool is_double_array() const { return is_x_array('D'); }
   bool is_object_array() const { return is_x_array('L'); }
+  bool is_value_array() const { return is_x_array('Q'); }
   bool is_array_array() const { return is_x_array('['); }
   bool is_reference_array() const
     { return is_object_array() || is_array_array(); }
@@ -244,14 +263,14 @@
   }
 
   Symbol* name() const {
-    assert(is_reference() && !is_null(), "Must be a non-null reference");
-    return _u._sym;
+    assert(!is_null() && (is_reference() || is_valuetype()), "Must be a non-null reference or a value type");
+    return (is_reference() ? _u._sym : ((Symbol*)(_u._data & ~(uintptr_t)ValueType)));
   }
 
   bool equals(const VerificationType& t) const {
     return (_u._data == t._u._data ||
-      (is_reference() && t.is_reference() && !is_null() && !t.is_null() &&
-       name() == t.name()));
+            (((is_reference() && t.is_reference()) || (is_valuetype() && t.is_valuetype())) &&
+             !is_null() && !t.is_null() && name() == t.name()));
   }
 
   bool operator ==(const VerificationType& t) const {
@@ -280,6 +299,8 @@
           return from.is_category2_2nd();
         case ReferenceQuery:
           return from.is_reference() || from.is_uninitialized();
+        case ValueTypeQuery:
+          return from.is_valuetype();
         case Boolean:
         case Byte:
         case Char:
@@ -291,6 +312,8 @@
             return is_reference_assignable_from(from, context,
                                                 from_field_is_protected,
                                                 THREAD);
+          } else if (is_valuetype() && from.is_valuetype()) {
+            return is_valuetype_assignable_from(from, context, THREAD);
           } else {
             return false;
           }
@@ -335,6 +358,14 @@
     const VerificationType&, ClassVerifier*, bool from_field_is_protected,
     TRAPS) const;
 
+  bool is_valuetype_assignable_from(const VerificationType& from, ClassVerifier* context, TRAPS) const {
+    // 1. Check names - two value types are assignable if they have the same name
+    // 2. Check java/lang/__Value - from may be trying to be assigned to a __Value parameter
+    assert(is_valuetype() && from.is_valuetype(), "Is value type assignable called with a non-value type");
+    return (name() == from.name() ||
+            name() == vmSymbols::java_lang____Value());
+  }
+
  public:
   static bool resolve_and_check_assignability(InstanceKlass* klass, Symbol* name,
                                               Symbol* from_name, bool from_field_is_protected,
--- a/src/hotspot/share/classfile/verifier.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/verifier.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -239,8 +239,9 @@
   return (should_verify_for(klass->class_loader(), should_verify_class) &&
     // return if the class is a bootstrapping class
     // or defineClass specified not to verify by default (flags override passed arg)
-    // We need to skip the following four for bootstraping
+    // We need to skip the following few for bootstrapping
     name != vmSymbols::java_lang_Object() &&
+    name != vmSymbols::java_lang____Value() &&
     name != vmSymbols::java_lang_Class() &&
     name != vmSymbols::java_lang_String() &&
     name != vmSymbols::java_lang_Throwable() &&
@@ -251,6 +252,11 @@
     // Shared classes shouldn't have stackmaps either.
     !klass->is_shared() &&
 
+    // A MVT derived value type contains no code atrribute - no private static
+    // methods, no instance methods, no <clinit>, no <init>.  So while format
+    // checking is performed on it, verification is not.
+    (!((EnableMVT || EnableValhalla) && klass->access_flags().is_value_type())) &&
+
     // As of the fix for 4486457 we disable verification for all of the
     // dynamically-generated bytecodes associated with the 1.4
     // reflection implementation, not just those associated with
@@ -584,12 +590,22 @@
   return VerificationType::reference_type(vmSymbols::java_lang_Object());
 }
 
+VerificationType ClassVerifier::__value_type() const {
+  return VerificationType::valuetype_type(vmSymbols::java_lang____Value());
+}
+
 TypeOrigin ClassVerifier::ref_ctx(const char* sig, TRAPS) {
   VerificationType vt = VerificationType::reference_type(
       create_temporary_symbol(sig, (int)strlen(sig), THREAD));
   return TypeOrigin::implicit(vt);
 }
 
+TypeOrigin ClassVerifier::valuetype_ctx(const char* sig, TRAPS) {
+  VerificationType vt = VerificationType::valuetype_type(
+      create_temporary_symbol(sig, (int)strlen(sig), THREAD));
+  return TypeOrigin::implicit(vt);
+}
+
 void ClassVerifier::verify_class(TRAPS) {
   log_info(verification)("Verifying class %s with new format", _klass->external_name());
 
@@ -634,6 +650,12 @@
     return;
   }
 
+  // Verify value type bytecodes if enabled and class file version supports them.
+  // Commented check out for now until class file version 54.1 is generated.
+  bool vbytecodes_allowed = (EnableMVT || EnableValhalla);
+                             //_klass->major_version() >= Verifier::VALUETYPE_MAJOR_VERSION &&
+                             //_klass->minor_version() >= Verifier::VALUETYPE_MINOR_VERSION);
+
   // Initial stack map frame: offset is 0, stack is initially empty.
   StackMapFrame current_frame(max_locals, max_stack, this);
   // Set initial locals
@@ -841,6 +863,15 @@
           index = opcode - Bytecodes::_dload_0;
           verify_dload(index, &current_frame, CHECK_VERIFY(this));
           no_control_flow = false; break;
+        case Bytecodes::_vload :
+          if (!vbytecodes_allowed) {
+            class_format_error(
+              "vload not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          verify_vload(bcs.get_index(), &current_frame, CHECK_VERIFY(this));
+          no_control_flow = false; break;
         case Bytecodes::_aload :
           verify_aload(bcs.get_index(), &current_frame, CHECK_VERIFY(this));
           no_control_flow = false; break;
@@ -973,6 +1004,37 @@
           }
           no_control_flow = false; break;
         }
+        case Bytecodes::_vaload : {
+          if (!vbytecodes_allowed) {
+            class_format_error(
+              "vaload not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          type = current_frame.pop_stack(
+            VerificationType::integer_type(), CHECK_VERIFY(this));
+          atype = current_frame.pop_stack(
+            VerificationType::reference_check(), CHECK_VERIFY(this));
+          // The null check is strictly not be necessary, left in for future proofing.
+          // Will be reconsidered if type indexes are removed.
+          if (atype.is_null() || !atype.is_value_array()) {
+            verify_error(ErrorContext::bad_type(bci,
+                current_frame.stack_top_ctx(),
+                TypeOrigin::implicit(VerificationType::reference_check())),
+                bad_type_msg, "vaload");
+            return;
+          }
+          VerificationType component = atype.get_component(this, CHECK_VERIFY(this));
+          if (!component.is_valuetype()) {
+            verify_error(ErrorContext::bad_type(bci,
+                current_frame.stack_top_ctx(),
+                TypeOrigin::implicit(VerificationType::valuetype_check())),
+                bad_type_msg, "vaload");
+            return;  
+          } 
+          current_frame.push_stack(component, CHECK_VERIFY(this));
+          no_control_flow = false; break;
+        }
         case Bytecodes::_istore :
           verify_istore(bcs.get_index(), &current_frame, CHECK_VERIFY(this));
           no_control_flow = false; break;
@@ -1013,6 +1075,15 @@
           index = opcode - Bytecodes::_dstore_0;
           verify_dstore(index, &current_frame, CHECK_VERIFY(this));
           no_control_flow = false; break;
+        case Bytecodes::_vstore :
+          if (!vbytecodes_allowed) {
+            class_format_error(
+              "vstore not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          verify_vstore(bcs.get_index(), &current_frame, CHECK_VERIFY(this));
+          no_control_flow = false; break;
         case Bytecodes::_astore :
           verify_astore(bcs.get_index(), &current_frame, CHECK_VERIFY(this));
           no_control_flow = false; break;
@@ -1139,6 +1210,28 @@
           }
           // 4938384: relaxed constraint in JVMS 3nd edition.
           no_control_flow = false; break;
+        case Bytecodes::_vastore :
+          if (!vbytecodes_allowed) {
+            class_format_error(
+              "vastore not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          type = current_frame.pop_stack(__value_type(), CHECK_VERIFY(this));
+          type2 = current_frame.pop_stack(
+            VerificationType::integer_type(), CHECK_VERIFY(this));
+          atype = current_frame.pop_stack(
+            VerificationType::reference_check(), CHECK_VERIFY(this));
+          // The null check is strictly not be necessary, left in for future proofing.
+          // Will be reconsidered if type indexes are removed.
+          if (atype.is_null() || !atype.is_value_array()) {
+            verify_error(ErrorContext::bad_type(bci,
+                current_frame.stack_top_ctx(),
+                TypeOrigin::implicit(VerificationType::reference_check())),
+                bad_type_msg, "vastore");
+            return;
+          }
+          no_control_flow = false; break;
         case Bytecodes::_pop :
           current_frame.pop_stack(
             VerificationType::category1_check(), CHECK_VERIFY(this));
@@ -1590,6 +1683,18 @@
           verify_return_value(return_type, type, bci,
                               &current_frame, CHECK_VERIFY(this));
           no_control_flow = true; break;
+        case Bytecodes::_vreturn :
+          if (!vbytecodes_allowed) {
+            class_format_error(
+              "vreturn not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          type = current_frame.pop_stack(
+            VerificationType::valuetype_check(), CHECK_VERIFY(this));
+          verify_return_value(return_type, type, bci,
+                              &current_frame, CHECK_VERIFY(this));
+          no_control_flow = true; break;
         case Bytecodes::_return :
           if (return_type != VerificationType::bogus_type()) {
             verify_error(ErrorContext::bad_code(bci),
@@ -1618,6 +1723,15 @@
           verify_field_instructions(
             &bcs, &current_frame, cp, false, CHECK_VERIFY(this));
           no_control_flow = false; break;
+        case Bytecodes::_vwithfield :
+          if (!vbytecodes_allowed) {
+            class_format_error(
+              "vwithfield not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          verify_vwithfield(&bcs, &current_frame, cp, CHECK_VERIFY(this));
+          no_control_flow = false; break;
         case Bytecodes::_invokevirtual :
         case Bytecodes::_invokespecial :
         case Bytecodes::_invokestatic :
@@ -1636,7 +1750,7 @@
           index = bcs.get_index_u2();
           verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
           VerificationType new_class_type =
-            cp_index_to_type(index, cp, CHECK_VERIFY(this));
+            cp_index_to_reference_type(index, cp, CHECK_VERIFY(this));
           if (!new_class_type.is_object()) {
             verify_error(ErrorContext::bad_type(bci,
                 TypeOrigin::cp(index, new_class_type)),
@@ -1647,6 +1761,27 @@
           current_frame.push_stack(type, CHECK_VERIFY(this));
           no_control_flow = false; break;
         }
+        case Bytecodes::_vdefault :
+        {
+          if (!vbytecodes_allowed) {
+            class_format_error(
+              "vdefault not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          index = bcs.get_index_u2();
+          verify_cp_value_type(bci, index, cp, CHECK_VERIFY(this));
+          VerificationType new_value_type =
+            cp_index_to_valuetype(index, cp, CHECK_VERIFY(this));
+          if (!new_value_type.is_valuetype()) {
+            verify_error(ErrorContext::bad_type(bci,
+                TypeOrigin::cp(index, new_value_type)),
+                "Illegal vdefault instruction");
+            return;
+          }
+          current_frame.push_stack(new_value_type, CHECK_VERIFY(this));
+          no_control_flow = false; break;
+        }
         case Bytecodes::_newarray :
           type = get_newarray_type(bcs.get_index(), bci, CHECK_VERIFY(this));
           current_frame.pop_stack(
@@ -1673,7 +1808,7 @@
           index = bcs.get_index_u2();
           verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
           current_frame.pop_stack(object_type(), CHECK_VERIFY(this));
-          VerificationType klass_type = cp_index_to_type(
+          VerificationType klass_type = cp_index_to_reference_type(
             index, cp, CHECK_VERIFY(this));
           current_frame.push_stack(klass_type, CHECK_VERIFY(this));
           no_control_flow = false; break;
@@ -1686,6 +1821,36 @@
             VerificationType::integer_type(), CHECK_VERIFY(this));
           no_control_flow = false; break;
         }
+        case Bytecodes::_vbox : {
+          if (!EnableMVT || !vbytecodes_allowed) {
+            class_format_error(
+              "vbox not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          index = bcs.get_index_u2();
+          verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
+          current_frame.pop_stack(VerificationType::valuetype_check(), CHECK_VERIFY(this));
+          VerificationType klass_type = cp_index_to_reference_type(
+            index, cp, CHECK_VERIFY(this));
+          current_frame.push_stack(klass_type, CHECK_VERIFY(this));
+          no_control_flow = false; break;
+        }
+        case Bytecodes::_vunbox : {
+          if (!EnableMVT || !vbytecodes_allowed) {
+            class_format_error(
+              "vunbox not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          index = bcs.get_index_u2();
+          verify_cp_value_type(bci, index, cp, CHECK_VERIFY(this));
+          current_frame.pop_stack(object_type(), CHECK_VERIFY(this));
+          VerificationType value_type = cp_index_to_valuetype(
+            index, cp, CHECK_VERIFY(this));
+          current_frame.push_stack(value_type, CHECK_VERIFY(this));
+          no_control_flow = false; break;
+        }
         case Bytecodes::_monitorenter :
         case Bytecodes::_monitorexit :
           current_frame.pop_stack(
@@ -1695,9 +1860,9 @@
         {
           index = bcs.get_index_u2();
           u2 dim = *(bcs.bcp()+3);
-          verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
+          verify_cp_class_or_value_type(bci, index, cp, CHECK_VERIFY(this));
           VerificationType new_array_type =
-            cp_index_to_type(index, cp, CHECK_VERIFY(this));
+            cp_index_to_reference_type(index, cp, CHECK_VERIFY(this));
           if (!new_array_type.is_array()) {
             verify_error(ErrorContext::bad_type(bci,
                 TypeOrigin::cp(index, new_array_type)),
@@ -1804,7 +1969,7 @@
     }
     int catch_type_index = exhandlers.catch_type_index(i);
     if (catch_type_index != 0) {
-      VerificationType catch_type = cp_index_to_type(
+      VerificationType catch_type = cp_index_to_reference_type(
         catch_type_index, cp, CHECK_VERIFY(this));
       VerificationType throwable =
         VerificationType::reference_type(vmSymbols::java_lang_Throwable());
@@ -1907,7 +2072,7 @@
       if (catch_type_index != 0) {
         if (was_recursively_verified()) return;
         // We know that this index refers to a subclass of Throwable
-        VerificationType catch_type = cp_index_to_type(
+        VerificationType catch_type = cp_index_to_reference_type(
           catch_type_index, cp, CHECK_VERIFY(this));
         new_frame->push_stack(catch_type, CHECK_VERIFY(this));
       } else {
@@ -1949,6 +2114,11 @@
 
   verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
   unsigned int tag = cp->tag_at(index).value();
+
+  if (tag == JVM_CONSTANT_Value) {
+    tag = SAFE_JVM_CONSTANT_Value; //avoid overflow
+  }
+
   if ((types & (1 << tag)) == 0) {
     verify_error(ErrorContext::bad_cp_index(bci, index),
       "Illegal type at constant pool entry %d in class %s",
@@ -1969,6 +2139,32 @@
   }
 }
 
+void ClassVerifier::verify_cp_value_type(
+    u2 bci, int index, const constantPoolHandle& cp, TRAPS) {
+  verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
+  constantTag tag = cp->tag_at(index);
+  if (!tag.is_value_type() && !tag.is_unresolved_value_type()) {
+    verify_error(ErrorContext::bad_cp_index(bci, index),
+        "Illegal type at constant pool entry %d in class %s",
+        index, cp->pool_holder()->external_name());
+    return;
+  }
+}
+
+// Used for MVT value type overloaded bytecodes (anewarray, getfield, multianewarray)
+void ClassVerifier::verify_cp_class_or_value_type(
+    u2 bci, int index, const constantPoolHandle& cp, TRAPS) {
+  verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
+  constantTag tag = cp->tag_at(index);
+  if (!tag.is_klass() && !tag.is_unresolved_klass() &&
+      !tag.is_value_type() && !tag.is_unresolved_value_type()) {
+    verify_error(ErrorContext::bad_cp_index(bci, index),
+        "Illegal type at constant pool entry %d in class %s",
+        index, cp->pool_holder()->external_name());
+    return;
+  }
+}
+
 void ClassVerifier::verify_error(ErrorContext ctx, const char* msg, ...) {
   stringStream ss;
 
@@ -2056,12 +2252,17 @@
   constantTag tag = cp->tag_at(index);
   unsigned int types;
   if (opcode == Bytecodes::_ldc || opcode == Bytecodes::_ldc_w) {
-    if (!tag.is_unresolved_klass()) {
+    if (!tag.is_unresolved_klass() && !tag.is_unresolved_value_type()) {
       types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float)
-            | (1 << JVM_CONSTANT_String)  | (1 << JVM_CONSTANT_Class)
+            | (1 << JVM_CONSTANT_String) | (1 << JVM_CONSTANT_Class)
+            | (1 << SAFE_JVM_CONSTANT_Value)
             | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType);
       // Note:  The class file parser already verified the legality of
       // MethodHandle and MethodType constants.
+      // Note: SAFE_JVM_CONSTANT_Value is used instead of JVM_CONSTANT_Value
+      //       since JVM_CONSTANT_Value is an internally defined CP tag that is
+      //       defined with a large value.  When shifting left JVM_CONSTANT_Value
+      //       would overrun the width of types.
       verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
     }
   } else {
@@ -2075,7 +2276,8 @@
     current_frame->push_stack(
       VerificationType::reference_type(
         vmSymbols::java_lang_String()), CHECK_VERIFY(this));
-  } else if (tag.is_klass() || tag.is_unresolved_klass()) {
+  } else if (tag.is_klass() || tag.is_unresolved_klass() ||
+             tag.is_value_type() || tag.is_unresolved_value_type()) {
     current_frame->push_stack(
       VerificationType::reference_type(
         vmSymbols::java_lang_Class()), CHECK_VERIFY(this));
@@ -2211,17 +2413,34 @@
     return;
   }
 
-  // Get referenced class type
-  VerificationType ref_class_type = cp_ref_index_to_type(
-    index, cp, CHECK_VERIFY(this));
-  if (!ref_class_type.is_object() &&
-    (!allow_arrays || !ref_class_type.is_array())) {
-    verify_error(ErrorContext::bad_type(bcs->bci(),
-        TypeOrigin::cp(index, ref_class_type)),
-        "Expecting reference to class in class %s at constant pool index %d",
-        _klass->external_name(), index);
-    return;
+  // Get referenced class or value type
+  constantTag field_class_tag = cp->tag_at(cp->klass_ref_index_at(index));
+  VerificationType ref_class_type;
+  
+  // getfield is overloaded to allow for either a reference or value type
+  if (bcs->raw_code() == Bytecodes::_getfield &&
+      (EnableMVT || EnableValhalla) &&
+      (field_class_tag.is_value_type() || field_class_tag.is_unresolved_value_type())) {
+    ref_class_type = cp_value_index_to_type(index, cp, CHECK_VERIFY(this));
+    if (!ref_class_type.is_valuetype()) {
+      verify_error(ErrorContext::bad_type(bcs->bci(),
+          TypeOrigin::cp(index, ref_class_type)),
+          "Expecting reference to value type in class %s at constant pool index %d",
+          _klass->external_name(), index);
+      return;
+    }
+  } else {
+    ref_class_type = cp_ref_index_to_type(index, cp, CHECK_VERIFY(this));
+    if (!ref_class_type.is_object() &&
+        (!allow_arrays || !ref_class_type.is_array())) {
+      verify_error(ErrorContext::bad_type(bcs->bci(),
+          TypeOrigin::cp(index, ref_class_type)),
+          "Expecting reference to class in class %s at constant pool index %d",
+          _klass->external_name(), index);
+      return;
+    }
   }
+
   VerificationType target_class_type = ref_class_type;
 
   assert(sizeof(VerificationType) == sizeof(uintptr_t),
@@ -2318,6 +2537,74 @@
   }
 }
 
+void ClassVerifier::verify_vwithfield(RawBytecodeStream* bcs,
+                                      StackMapFrame* current_frame,
+                                      const constantPoolHandle& cp,
+                                      TRAPS) {
+  u2 index = bcs->get_index_u2();
+  verify_cp_type(bcs->bci(), index, cp,
+      1 << JVM_CONSTANT_Fieldref, CHECK_VERIFY(this));
+
+  // Get field name and signature
+  Symbol* field_name = cp->name_ref_at(index);
+  Symbol* field_sig = cp->signature_ref_at(index);
+
+  if (!SignatureVerifier::is_valid_type_signature(field_sig)) {
+    class_format_error(
+      "Invalid signature for field in value type %s referenced "
+      "from constant pool index %d", _klass->external_name(), index);
+    return;
+  }
+
+  // Check referenced value type
+  VerificationType ref_value_type = cp_value_index_to_type(
+    index, cp, CHECK_VERIFY(this));
+  if (!ref_value_type.is_valuetype()) {
+    verify_error(ErrorContext::bad_type(bcs->bci(),
+        TypeOrigin::cp(index, ref_value_type)),
+        "Expecting reference to value type in class %s at constant pool index %d",
+        _klass->external_name(), index);
+    return;
+  }
+  VerificationType target_value_type = ref_value_type;
+
+  assert(sizeof(VerificationType) == sizeof(uintptr_t),
+        "buffer type must match VerificationType size");
+  uintptr_t field_type_buffer[2];
+  VerificationType* field_type = (VerificationType*)field_type_buffer;
+  // If we make a VerificationType[2] array directly, the compiler calls
+  // to the c-runtime library to do the allocation instead of just
+  // stack allocating it.  Plus it would run constructors.  This shows up
+  // in performance profiles.
+
+  SignatureStream sig_stream(field_sig, false);
+  int n = change_sig_to_verificationType(
+    &sig_stream, field_type, CHECK_VERIFY(this));
+  u2 bci = bcs->bci();
+
+  // The type of value2 must be compatible with the descriptor of the referenced field.
+  // n could be 2 if it is a double or long.
+  for (int i = n - 1; i >= 0; i--) {
+   current_frame->pop_stack(field_type[i], CHECK_VERIFY(this));
+  }
+
+  // The type of value1 must be the direct value class type appearing in the field reference.
+  VerificationType stack_object_type = current_frame->pop_stack(CHECK_VERIFY(this));
+
+  bool is_assignable = target_value_type.is_assignable_from(
+                         stack_object_type, this, false, CHECK_VERIFY(this));
+  if (!is_assignable) {
+    verify_error(ErrorContext::bad_type(bci,
+                 current_frame->stack_top_ctx(),
+                 TypeOrigin::cp(index, target_value_type)),
+                 "Bad type on operand stack in vwithfield");
+    return;
+  }
+
+  // The derived value class instance from another, modifying a field
+  current_frame->push_stack(stack_object_type, CHECK_VERIFY(this));
+}
+
 // Look at the method's handlers.  If the bci is in the handler's try block
 // then check if the handler_pc is already on the stack.  If not, push it
 // unless the handler has already been scanned.
@@ -2587,7 +2874,7 @@
     verify_cp_class_type(bci, new_class_index, cp, CHECK_VERIFY(this));
 
     // The method must be an <init> method of the indicated class
-    VerificationType new_class_type = cp_index_to_type(
+    VerificationType new_class_type = cp_index_to_reference_type(
       new_class_index, cp, CHECK_VERIFY(this));
     if (!new_class_type.equals(ref_class_type)) {
       verify_error(ErrorContext::bad_type(bci,
@@ -2695,7 +2982,7 @@
     return;
   }
 
-  // Get referenced class type
+  // Get referenced class or value type
   VerificationType ref_class_type;
   if (opcode == Bytecodes::_invokedynamic) {
     if (_klass->major_version() < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
@@ -2705,7 +2992,14 @@
       return;
     }
   } else {
-    ref_class_type = cp_ref_index_to_type(index, cp, CHECK_VERIFY(this));
+    constantTag method_class_tag = cp->tag_at(cp->klass_ref_index_at(index));
+    if (EnableValhalla &&
+        opcode == Bytecodes::_invokevirtual &&
+        (method_class_tag.is_value_type() || method_class_tag.is_unresolved_value_type())) {
+      ref_class_type = cp_value_index_to_type(index, cp, CHECK_VERIFY(this));
+    } else {
+      ref_class_type = cp_ref_index_to_type(index, cp, CHECK_VERIFY(this));
+    }
   }
 
   // For a small signature length, we just allocate 128 bytes instead
@@ -2930,13 +3224,18 @@
 void ClassVerifier::verify_anewarray(
     u2 bci, u2 index, const constantPoolHandle& cp,
     StackMapFrame* current_frame, TRAPS) {
-  verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
+  verify_cp_class_or_value_type(bci, index, cp, CHECK_VERIFY(this));
   current_frame->pop_stack(
     VerificationType::integer_type(), CHECK_VERIFY(this));
 
   if (was_recursively_verified()) return;
-  VerificationType component_type =
-    cp_index_to_type(index, cp, CHECK_VERIFY(this));
+  constantTag class_tag = cp->tag_at(index);
+  VerificationType component_type;
+  if (class_tag.is_value_type() || class_tag.is_unresolved_value_type()) {
+    component_type = cp_index_to_valuetype(index, cp, CHECK_VERIFY(this));
+  } else {
+    component_type = cp_index_to_reference_type(index, cp, CHECK_VERIFY(this));
+  }
   int length;
   char* arr_sig_str;
   if (component_type.is_array()) {     // it's an array
@@ -2955,11 +3254,11 @@
     strncpy(&arr_sig_str[1], component_name, length - 1);
   } else {         // it's an object or interface
     const char* component_name = component_type.name()->as_utf8();
-    // add one dimension to component with 'L' prepended and ';' postpended.
+    // add one dimension to component with 'L' or 'Q' (value type) prepended and ';' appended.
     length = (int)strlen(component_name) + 3;
     arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length);
     arr_sig_str[0] = '[';
-    arr_sig_str[1] = 'L';
+    arr_sig_str[1] = component_type.is_reference() ? 'L' : 'Q';
     strncpy(&arr_sig_str[2], component_name, length - 2);
     arr_sig_str[length - 1] = ';';
   }
@@ -3007,6 +3306,12 @@
   current_frame->push_stack(type, CHECK_VERIFY(this));
 }
 
+void ClassVerifier::verify_vload(u2 index, StackMapFrame* current_frame, TRAPS) {
+  VerificationType type = current_frame->get_local(
+    index, VerificationType::valuetype_check(), CHECK_VERIFY(this));
+  current_frame->push_stack(type, CHECK_VERIFY(this));
+}
+
 void ClassVerifier::verify_istore(u2 index, StackMapFrame* current_frame, TRAPS) {
   current_frame->pop_stack(
     VerificationType::integer_type(), CHECK_VERIFY(this));
@@ -3044,6 +3349,12 @@
   current_frame->set_local(index, type, CHECK_VERIFY(this));
 }
 
+void ClassVerifier::verify_vstore(u2 index, StackMapFrame* current_frame, TRAPS) {
+  VerificationType type = current_frame->pop_stack(
+    VerificationType::valuetype_check(), CHECK_VERIFY(this));
+  current_frame->set_local(index, type, CHECK_VERIFY(this));
+}
+
 void ClassVerifier::verify_iinc(u2 index, StackMapFrame* current_frame, TRAPS) {
   VerificationType type = current_frame->get_local(
     index, VerificationType::integer_type(), CHECK_VERIFY(this));
--- a/src/hotspot/share/classfile/verifier.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/verifier.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -33,6 +33,10 @@
 #include "utilities/exceptions.hpp"
 #include "utilities/growableArray.hpp"
 
+// For bit tests involving JVM_CONSTANT_Value during verification,
+// define a "safe" number to avoid integer overflow of types
+#define SAFE_JVM_CONSTANT_Value JVM_CONSTANT_ExternalMax
+
 // The verifier class
 class Verifier : AllStatic {
  public:
@@ -40,7 +44,9 @@
     STRICTER_ACCESS_CTRL_CHECK_VERSION  = 49,
     STACKMAP_ATTRIBUTE_MAJOR_VERSION    = 50,
     INVOKEDYNAMIC_MAJOR_VERSION         = 51,
-    NO_RELAX_ACCESS_CTRL_CHECK_VERSION  = 52
+    NO_RELAX_ACCESS_CTRL_CHECK_VERSION  = 52,
+    VALUETYPE_MAJOR_VERSION             = 53,
+    VALUETYPE_MINOR_VERSION             =  1
   };
   typedef enum { ThrowException, NoException } Mode;
 
@@ -271,7 +277,12 @@
 
   VerificationType cp_ref_index_to_type(
       int index, const constantPoolHandle& cp, TRAPS) {
-    return cp_index_to_type(cp->klass_ref_index_at(index), cp, THREAD);
+    return cp_index_to_reference_type(cp->klass_ref_index_at(index), cp, THREAD);
+  }
+
+  VerificationType cp_value_index_to_type(
+      int index, const constantPoolHandle& cp, TRAPS) {
+    return cp_index_to_valuetype(cp->klass_ref_index_at(index), cp, THREAD);
   }
 
   bool is_protected_access(
@@ -282,6 +293,8 @@
   void verify_cp_type(u2 bci, int index, const constantPoolHandle& cp,
       unsigned int types, TRAPS);
   void verify_cp_class_type(u2 bci, int index, const constantPoolHandle& cp, TRAPS);
+  void verify_cp_value_type(u2 bci, int index, const constantPoolHandle& cp, TRAPS);
+  void verify_cp_class_or_value_type(u2 bci, int index, const constantPoolHandle& cp, TRAPS);
 
   u2 verify_stackmap_table(
     u2 stackmap_index, u2 bci, StackMapFrame* current_frame,
@@ -303,6 +316,10 @@
     RawBytecodeStream* bcs, StackMapFrame* current_frame,
     const constantPoolHandle& cp, bool allow_arrays, TRAPS);
 
+  void verify_vwithfield(
+    RawBytecodeStream* bcs, StackMapFrame* current_frame,
+    const constantPoolHandle& cp, TRAPS);
+
   void verify_invoke_init(
     RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type,
     StackMapFrame* current_frame, u4 code_length, bool in_try_block,
@@ -337,16 +354,19 @@
   void verify_fload (u2 index, StackMapFrame* current_frame, TRAPS);
   void verify_dload (u2 index, StackMapFrame* current_frame, TRAPS);
   void verify_aload (u2 index, StackMapFrame* current_frame, TRAPS);
+  void verify_vload (u2 index, StackMapFrame* current_frame, TRAPS);
   void verify_istore(u2 index, StackMapFrame* current_frame, TRAPS);
   void verify_lstore(u2 index, StackMapFrame* current_frame, TRAPS);
   void verify_fstore(u2 index, StackMapFrame* current_frame, TRAPS);
   void verify_dstore(u2 index, StackMapFrame* current_frame, TRAPS);
   void verify_astore(u2 index, StackMapFrame* current_frame, TRAPS);
+  void verify_vstore(u2 index, StackMapFrame* current_frame, TRAPS);
   void verify_iinc  (u2 index, StackMapFrame* current_frame, TRAPS);
 
   bool name_in_supers(Symbol* ref_name, InstanceKlass* current);
 
   VerificationType object_type() const;
+  VerificationType __value_type() const;
 
   InstanceKlass*      _klass;  // the class being verified
   methodHandle        _method; // current method being verified
@@ -407,10 +427,14 @@
   int change_sig_to_verificationType(
     SignatureStream* sig_type, VerificationType* inference_type, TRAPS);
 
-  VerificationType cp_index_to_type(int index, const constantPoolHandle& cp, TRAPS) {
+  VerificationType cp_index_to_reference_type(int index, const constantPoolHandle& cp, TRAPS) {
     return VerificationType::reference_type(cp->klass_name_at(index));
   }
 
+  VerificationType cp_index_to_valuetype(int index, const constantPoolHandle& cp, TRAPS) {
+    return VerificationType::valuetype_type(cp->klass_name_at(index));
+  }
+
   // Keep a list of temporary symbols created during verification because
   // their reference counts need to be decremented when the verifier object
   // goes out of scope.  Since these symbols escape the scope in which they're
@@ -427,6 +451,7 @@
   }
 
   TypeOrigin ref_ctx(const char* str, TRAPS);
+  TypeOrigin valuetype_ctx(const char* str, TRAPS);
 
 };
 
@@ -436,13 +461,14 @@
   switch (bt) {
     case T_OBJECT:
     case T_ARRAY:
+    case T_VALUETYPE:
       {
         Symbol* name = sig_type->as_symbol(CHECK_0);
         // Create another symbol to save as signature stream unreferences this symbol.
         Symbol* name_copy = create_temporary_symbol(name);
         assert(name_copy == name, "symbols don't match");
-        *inference_type =
-          VerificationType::reference_type(name_copy);
+        *inference_type = ((bt == T_VALUETYPE) ? VerificationType::valuetype_type(name_copy) :
+                                                 VerificationType::reference_type(name_copy));
         return 1;
       }
     case T_LONG:
--- a/src/hotspot/share/classfile/vmSymbols.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/vmSymbols.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -207,7 +207,11 @@
       return (BasicType)i;
     }
   }
-  return T_OBJECT;
+  if (s->byte_at(0) =='Q') {
+    return T_VALUETYPE;
+  } else {
+    return T_OBJECT;
+  }
 }
 
 
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Tue Sep 26 16:15:08 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") \
@@ -317,6 +318,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(jdk_incubator_mvt_ValueCapableClass,           "jdk/incubator/mvt/ValueCapableClass")    \
+  template(jdk_incubator_mvt_ValueCapableClass_signature, "Ljdk/incubator/mvt/ValueCapableClass;")  \
+  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/hotspot/share/code/codeBlob.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/codeBlob.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -270,23 +270,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();
@@ -320,6 +324,30 @@
 }
 
 //----------------------------------------------------------------------------------------------------
+// Implementation of BufferedValueTypeBlob
+BufferedValueTypeBlob::BufferedValueTypeBlob(int size, CodeBuffer* cb, int pack_fields_off, int unpack_fields_off) :
+  BufferBlob("buffered value type", size, cb),
+  _pack_fields_off(pack_fields_off),
+  _unpack_fields_off(unpack_fields_off) {
+  CodeCache::commit(this);
+}
+
+BufferedValueTypeBlob* BufferedValueTypeBlob::create(CodeBuffer* cb, int pack_fields_off, int unpack_fields_off) {
+  ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock
+
+  BufferedValueTypeBlob* blob = NULL;
+  unsigned int size = CodeBlob::allocation_size(cb, sizeof(BufferedValueTypeBlob));
+  {
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    blob = new (size) BufferedValueTypeBlob(size, cb, pack_fields_off, unpack_fields_off);
+  }
+  // Track memory usage statistic after releasing CodeCache_lock
+  MemoryService::track_code_cache_memory_usage();
+
+  return blob;
+}
+
+//----------------------------------------------------------------------------------------------------
 // Implementation of RuntimeStub
 
 RuntimeStub::RuntimeStub(
--- a/src/hotspot/share/code/codeBlob.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/codeBlob.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -121,6 +121,7 @@
   virtual bool is_method_handles_adapter_blob() const { return false; }
   virtual bool is_aot() const                         { return false; }
   virtual bool is_compiled() const                    { return false; }
+  virtual bool is_buffered_value_type_blob() const    { return false; }
 
   inline bool is_compiled_by_c1() const    { return _type == compiler_c1; };
   inline bool is_compiled_by_c2() const    { return _type == compiler_c2; };
@@ -361,12 +362,14 @@
   friend class VMStructs;
   friend class AdapterBlob;
   friend class MethodHandlesAdapterBlob;
+  friend class BufferedValueTypeBlob;
   friend class WhiteBox;
 
  private:
   // 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();
 
@@ -395,14 +398,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; }
 };
 
 
@@ -421,6 +429,26 @@
   virtual bool is_method_handles_adapter_blob() const { return true; }
 };
 
+//----------------------------------------------------------------------------------------------------
+// BufferedValueTypeBlob : used for pack/unpack handlers
+
+class BufferedValueTypeBlob: public BufferBlob {
+private:
+  const int _pack_fields_off;
+  const int _unpack_fields_off;
+
+  BufferedValueTypeBlob(int size, CodeBuffer* cb, int pack_fields_off, int unpack_fields_off);
+
+public:
+  // Creation
+  static BufferedValueTypeBlob* create(CodeBuffer* cb, int pack_fields_off, int unpack_fields_off);
+
+  address pack_fields() const { return code_begin() + _pack_fields_off; }
+  address unpack_fields() const { return code_begin() + _unpack_fields_off; }
+
+  // Typing
+  virtual bool is_buffered_value_type_blob() const { return true; }
+};
 
 //----------------------------------------------------------------------------------------------------
 // RuntimeStub: describes stubs used by compiled code to call a (static) C++ runtime routine
--- a/src/hotspot/share/code/compiledMethod.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/compiledMethod.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -31,6 +31,7 @@
 #include "interpreter/bytecode.hpp"
 #include "memory/resourceArea.hpp"
 #include "runtime/mutexLocker.hpp"
+#include "runtime/sharedRuntime.hpp"
 
 CompiledMethod::CompiledMethod(Method* method, const char* name, CompilerType type, const CodeBlobLayout& layout, int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments)
   : CodeBlob(name, type, layout, frame_complete_offset, frame_size, oop_maps, caller_must_gc_arguments),
@@ -206,7 +207,7 @@
   guarantee(pd != NULL, "scope must be present");
   return new ScopeDesc(this, pd->scope_decode_offset(),
                        pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(),
-                       pd->return_oop());
+                       pd->return_oop(), pd->return_vt());
 }
 
 ScopeDesc* CompiledMethod::scope_desc_near(address pc) {
@@ -214,7 +215,7 @@
   guarantee(pd != NULL, "scope must be present");
   return new ScopeDesc(this, pd->scope_decode_offset(),
                        pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(),
-                       pd->return_oop());
+                       pd->return_oop(), pd->return_vt());
 }
 
 void CompiledMethod::cleanup_inline_caches(bool clean_all/*=false*/) {
@@ -312,6 +313,29 @@
       signature = callee->signature();
     }
 
+    // If value types are passed as fields, use the extended signature
+    // which contains the types of all (oop) fields of the value type.
+    if (ValueTypePassFieldsAsArgs && callee != NULL) {
+      // Get the extended signature from the callee's adapter through the attached method
+      Symbol* sig_ext = callee->adapter()->get_sig_extended();
+#ifdef ASSERT
+      // Check if receiver or one of the arguments is a value type
+      bool has_value_receiver = has_receiver && callee->method_holder()->is_value();
+      bool has_value_argument = has_value_receiver;
+      for (SignatureStream ss(signature); !has_value_argument && !ss.at_return_type(); ss.next()) {
+        if (ss.type() == T_VALUETYPE) {
+          has_value_argument = true;
+          break;
+        }
+      }
+      assert(has_value_argument == (sig_ext != NULL), "Signature is inconsistent");
+#endif
+      if (sig_ext != NULL) {
+        signature = sig_ext;
+        has_receiver = false; // The extended signature contains the receiver type
+      }
+    }
+
     fr.oops_compiled_arguments_do(signature, has_receiver, has_appendix, reg_map, f);
   }
 #endif // !SHARK
--- a/src/hotspot/share/code/debugInfoRec.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/debugInfoRec.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -287,6 +287,7 @@
                                               bool        rethrow_exception,
                                               bool        is_method_handle_invoke,
                                               bool        return_oop,
+                                              bool        return_vt,
                                               DebugToken* locals,
                                               DebugToken* expressions,
                                               DebugToken* monitors) {
@@ -303,6 +304,7 @@
   last_pd->set_rethrow_exception(rethrow_exception);
   last_pd->set_is_method_handle_invoke(is_method_handle_invoke);
   last_pd->set_return_oop(return_oop);
+  last_pd->set_return_vt(return_vt);
 
   // serialize sender stream offest
   stream()->write_int(sender_stream_offset);
--- a/src/hotspot/share/code/debugInfoRec.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/debugInfoRec.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -105,6 +105,7 @@
                       bool        rethrow_exception = false,
                       bool        is_method_handle_invoke = false,
                       bool        return_oop = false,
+                      bool        return_vt  = false,
                       DebugToken* locals      = NULL,
                       DebugToken* expressions = NULL,
                       DebugToken* monitors    = NULL);
--- a/src/hotspot/share/code/nmethod.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/nmethod.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -2164,7 +2164,7 @@
   assert(pd != NULL, "PcDesc must exist");
   for (ScopeDesc* sd = new ScopeDesc(this, pd->scope_decode_offset(),
                                      pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(),
-                                     pd->return_oop());
+                                     pd->return_oop(), pd->return_vt());
        !sd->is_top(); sd = sd->sender()) {
     sd->verify();
   }
@@ -2510,7 +2510,7 @@
   if (p != NULL && p->real_pc(this) <= end) {
     return new ScopeDesc(this, p->scope_decode_offset(),
                          p->obj_decode_offset(), p->should_reexecute(), p->rethrow_exception(),
-                         p->return_oop());
+                         p->return_oop(), p->return_vt());
   }
   return NULL;
 }
@@ -2536,32 +2536,35 @@
     }
     if (m.not_null() && !is_osr_method()) {
       ResourceMark rm;
-      int sizeargs = m->size_of_parameters();
-      BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, sizeargs);
-      VMRegPair* regs   = NEW_RESOURCE_ARRAY(VMRegPair, sizeargs);
-      {
-        int sig_index = 0;
-        if (!m->is_static())
-          sig_bt[sig_index++] = T_OBJECT; // 'this'
-        for (SignatureStream ss(m->signature()); !ss.at_return_type(); ss.next()) {
-          BasicType t = ss.type();
-          sig_bt[sig_index++] = t;
-          if (type2size[t] == 2) {
-            sig_bt[sig_index++] = T_VOID;
-          } else {
-            assert(type2size[t] == 1, "size is 1 or 2");
-          }
+      int sizeargs = 0;
+      BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, 256);
+      VMRegPair* regs   = NEW_RESOURCE_ARRAY(VMRegPair, 256);
+      Symbol* sig = m->signature();
+      bool has_value_arg = false;
+      if (ValueTypePassFieldsAsArgs && m->adapter()->get_sig_extended() != NULL) {
+        // Use extended signature if value type arguments are passed as fields
+        sig = m->adapter()->get_sig_extended();
+        has_value_arg = true;
+      } else if (!m->is_static()) {
+        sig_bt[sizeargs++] = T_OBJECT; // 'this'
+      }
+      for (SignatureStream ss(sig); !ss.at_return_type(); ss.next()) {
+        BasicType t = ss.type();
+        sig_bt[sizeargs++] = t;
+        if (type2size[t] == 2) {
+          sig_bt[sizeargs++] = T_VOID;
+        } else {
+          assert(type2size[t] == 1, "size is 1 or 2");
         }
-        assert(sig_index == sizeargs, "");
       }
       const char* spname = "sp"; // make arch-specific?
       intptr_t out_preserve = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs, false);
       int stack_slot_offset = this->frame_size() * wordSize;
       int tab1 = 14, tab2 = 24;
       int sig_index = 0;
-      int arg_index = (m->is_static() ? 0 : -1);
+      int arg_index = ((m->is_static() || has_value_arg) ? 0 : -1);
       bool did_old_sp = false;
-      for (SignatureStream ss(m->signature()); !ss.at_return_type(); ) {
+      for (SignatureStream ss(sig); !ss.at_return_type(); ) {
         bool at_this = (arg_index == -1);
         bool at_old_sp = false;
         BasicType t = (at_this ? T_OBJECT : ss.type());
@@ -2688,7 +2691,7 @@
           break;
         }
       }
-      st->print(" {reexecute=%d rethrow=%d return_oop=%d}", sd->should_reexecute(), sd->rethrow_exception(), sd->return_oop());
+      st->print(" {reexecute=%d rethrow=%d return_oop=%d return_vt=%d}", sd->should_reexecute(), sd->rethrow_exception(), sd->return_oop(), sd->return_vt());
     }
 
     // Print all scopes
--- a/src/hotspot/share/code/pcDesc.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/pcDesc.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -43,7 +43,8 @@
     PCDESC_reexecute               = 1 << 0,
     PCDESC_is_method_handle_invoke = 1 << 1,
     PCDESC_return_oop              = 1 << 2,
-    PCDESC_rethrow_exception       = 1 << 3
+    PCDESC_rethrow_exception       = 1 << 3,
+    PCDESC_return_vt               = 1 << 4
   };
 
   int _flags;
@@ -90,6 +91,9 @@
   bool     return_oop()                    const { return (_flags & PCDESC_return_oop) != 0;     }
   void set_return_oop(bool z)                    { set_flag(PCDESC_return_oop, z); }
 
+  bool     return_vt()                     const { return (_flags & PCDESC_return_vt) != 0;     }
+  void set_return_vt(bool z)                     { set_flag(PCDESC_return_vt, z); }
+
   // Returns the real pc
   address real_pc(const CompiledMethod* code) const;
 
--- a/src/hotspot/share/code/scopeDesc.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/scopeDesc.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -30,23 +30,25 @@
 #include "oops/oop.inline.hpp"
 #include "runtime/handles.inline.hpp"
 
-ScopeDesc::ScopeDesc(const CompiledMethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) {
+ScopeDesc::ScopeDesc(const CompiledMethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop, bool return_vt) {
   _code          = code;
   _decode_offset = decode_offset;
   _objects       = decode_object_values(obj_decode_offset);
   _reexecute     = reexecute;
   _rethrow_exception = rethrow_exception;
   _return_oop    = return_oop;
+  _return_vt     = return_vt;
   decode_body();
 }
 
-ScopeDesc::ScopeDesc(const CompiledMethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) {
+ScopeDesc::ScopeDesc(const CompiledMethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop, bool return_vt) {
   _code          = code;
   _decode_offset = decode_offset;
   _objects       = decode_object_values(DebugInformationRecorder::serialized_null);
   _reexecute     = reexecute;
   _rethrow_exception = rethrow_exception;
   _return_oop    = return_oop;
+  _return_vt     = return_vt;
   decode_body();
 }
 
@@ -58,6 +60,7 @@
   _reexecute     = false; //reexecute only applies to the first scope
   _rethrow_exception = false;
   _return_oop    = false;
+  _return_vt     = false;
   decode_body();
 }
 
--- a/src/hotspot/share/code/scopeDesc.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/code/scopeDesc.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -60,12 +60,12 @@
 class ScopeDesc : public ResourceObj {
  public:
   // Constructor
-  ScopeDesc(const CompiledMethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop);
+  ScopeDesc(const CompiledMethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop, bool return_vt);
 
   // Calls above, giving default value of "serialized_null" to the
   // "obj_decode_offset" argument.  (We don't use a default argument to
   // avoid a .hpp-.hpp dependency.)
-  ScopeDesc(const CompiledMethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop);
+  ScopeDesc(const CompiledMethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop, bool return_vt);
 
   // JVM state
   Method* method()      const { return _method; }
@@ -73,6 +73,7 @@
   bool should_reexecute() const { return _reexecute; }
   bool rethrow_exception() const { return _rethrow_exception; }
   bool return_oop()       const { return _return_oop; }
+  bool return_vt()        const { return _return_vt; }
 
   GrowableArray<ScopeValue*>*   locals();
   GrowableArray<ScopeValue*>*   expressions();
@@ -98,6 +99,7 @@
   bool          _reexecute;
   bool          _rethrow_exception;
   bool          _return_oop;
+  bool          _return_vt;
 
   // Decoding offsets
   int _decode_offset;
--- a/src/hotspot/share/compiler/compileBroker.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/compiler/compileBroker.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -1060,6 +1060,18 @@
   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()) {
+    ResourceMark rm;
+    for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
+      if (ss.type() == T_VALUETYPE) {
+        return NULL;
+      }
+    }
+  }
+
   // lock, make sure that the compilation
   // isn't prohibited in a straightforward way.
   AbstractCompiler* comp = CompileBroker::compiler(comp_level);
--- a/src/hotspot/share/compiler/methodLiveness.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/compiler/methodLiveness.cpp	Tue Sep 26 16:15:08 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:
@@ -779,12 +784,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 +834,7 @@
     case Bytecodes::_iinc:
     case Bytecodes::_fload:
     case Bytecodes::_aload:
+    case Bytecodes::_vload:
     case Bytecodes::_ret:
       load_one(instruction->get_index());
       break;
@@ -882,6 +891,7 @@
     case Bytecodes::_istore:
     case Bytecodes::_fstore:
     case Bytecodes::_astore:
+    case Bytecodes::_vstore:
       store_one(instruction->get_index());
       break;
 
--- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp	Tue Sep 26 16:15:08 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/hotspot/share/gc/parallel/psParallelCompact.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -59,6 +59,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/safepoint.hpp"
 #include "runtime/vmThread.hpp"
@@ -3116,6 +3117,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/hotspot/share/gc/parallel/psPromotionManager.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -42,6 +42,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;
@@ -483,6 +484,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/hotspot/share/interpreter/abstractInterpreter.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/abstractInterpreter.hpp	Tue Sep 26 16:15:08 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/hotspot/share/interpreter/bytecodeInterpreter.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -2360,12 +2360,15 @@
             }
 
           case JVM_CONSTANT_Class:
+          case JVM_CONSTANT_Value:
             VERIFY_OOP(constants->resolved_klass_at(index)->java_mirror());
             SET_STACK_OBJECT(constants->resolved_klass_at(index)->java_mirror(), 0);
             break;
 
           case JVM_CONSTANT_UnresolvedClass:
           case JVM_CONSTANT_UnresolvedClassInError:
+          case JVM_CONSTANT_UnresolvedValue:
+          case JVM_CONSTANT_UnresolvedValueInError:
             CALL_VM(InterpreterRuntime::ldc(THREAD, wide), handle_exception);
             SET_STACK_OBJECT(THREAD->vm_result(), 0);
             THREAD->set_vm_result(NULL);
--- a/src/hotspot/share/interpreter/bytecodeTracer.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -331,10 +331,12 @@
   } else if (tag.is_string()) {
     const char* string = constants->string_at_noresolve(i);
     st->print_cr(" %s", string);
-  } else if (tag.is_klass()) {
+  } else if (tag.is_klass() || tag.is_value_type()) {
     st->print_cr(" %s", constants->resolved_klass_at(i)->external_name());
   } else if (tag.is_unresolved_klass()) {
     st->print_cr(" <unresolved klass at %d>", i);
+  } else if (tag.is_unresolved_value_type()) {
+    st->print_cr(" <unresolved value type at %d>", i);
   } else if (tag.is_method_type()) {
     int i2 = constants->method_type_index_at(i);
     st->print(" <MethodType> %d", i2);
@@ -432,11 +434,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;
 
@@ -545,6 +549,7 @@
     case Bytecodes::_getstatic:
     case Bytecodes::_putfield:
     case Bytecodes::_getfield:
+    case Bytecodes::_vwithfield:
       print_field_or_method(get_index_u2_cpcache(), st);
       break;
 
@@ -569,6 +574,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/hotspot/share/interpreter/bytecodes.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/bytecodes.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -484,11 +484,21 @@
   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(_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       );
@@ -498,6 +508,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/hotspot/share/interpreter/bytecodes.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/bytecodes.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -243,10 +243,22 @@
     _jsr_w                = 201, // 0xc9
     _breakpoint           = 202, // 0xca
 
+    // value-type bytecodes
+    _vload                = 203, // 0xcb
+    _vstore               = 204, // 0xcc
+    _vaload               = 205, // 0xcd
+    _vastore              = 206, // 0xce
+    _vreturn              = 207, // 0xcf
+    _vdefault             = 208, // 0xd0
+    _vwithfield           = 209, // 0xd1
+    _vbox                 = 210, // 0xd2
+    _vunbox               = 211, // 0xd3
+
     number_of_java_codes,
 
     // JVM bytecodes
     _fast_agetfield       = number_of_java_codes,
+    _fast_qgetfield       ,
     _fast_bgetfield       ,
     _fast_cgetfield       ,
     _fast_dgetfield       ,
@@ -256,6 +268,7 @@
     _fast_sgetfield       ,
 
     _fast_aputfield       ,
+    _fast_qputfield       ,
     _fast_bputfield       ,
     _fast_zputfield       ,
     _fast_cputfield       ,
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -38,6 +38,7 @@
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
+#include "memory/vtBuffer.hpp"
 #include "oops/constantPool.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/methodData.hpp"
@@ -45,6 +46,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"
@@ -64,6 +68,7 @@
 #include "runtime/threadCritical.hpp"
 #include "utilities/align.hpp"
 #include "utilities/events.hpp"
+#include "utilities/globalDefinitions.hpp"
 #ifdef COMPILER2
 #include "opto/runtime.hpp"
 #endif
@@ -109,7 +114,9 @@
   int index = wide ? get_index_u2(thread, Bytecodes::_ldc_w) : get_index_u1(thread, Bytecodes::_ldc);
   constantTag tag = pool->tag_at(index);
 
-  assert (tag.is_unresolved_klass() || tag.is_klass(), "wrong ldc call");
+  assert ((tag.is_unresolved_klass() || tag.is_klass() ||
+           tag.is_unresolved_value_type() || tag.is_value_type()),
+          "wrong ldc call");
   Klass* klass = pool->klass_at(index, CHECK);
     oop java_class = klass->java_mirror();
     thread->set_vm_result(java_class);
@@ -166,6 +173,235 @@
   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 long*)addr));
+    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
+  bool in_heap;
+  instanceOop value = vklass->allocate_buffered_or_heap_instance(&in_heap, CHECK);
+  Handle value_h = Handle(THREAD, value);
+
+  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();
+  int field_index = cp_entry->field_index();
+  int field_offset = cp_entry->f2_as_offset();
+  Symbol* field_signature = vklass->field_signature(field_index);
+  ResourceMark rm(THREAD);
+  const char* signature = (const char *) field_signature->as_utf8();
+  BasicType field_type = char2type(signature[0]);
+
+  // Getting old value
+  frame f = last_frame(thread);
+  jint tos_idx = f.interpreter_frame_expression_stack_size() - 1;
+  int vt_offset = type2size[field_type];
+  oop old_value = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx - vt_offset);
+  assert(old_value != NULL && oopDesc::is_oop(old_value) && old_value->is_value(),"Verifying receiver");
+  Handle old_value_h(THREAD, old_value);
+
+  // Creating new value by copying the one passed in argument
+  bool in_heap;
+  instanceOop new_value = vklass->allocate_buffered_or_heap_instance(&in_heap,
+      CHECK_((type2size[field_type]) * AbstractInterpreter::stackElementSize));
+  Handle new_value_h = Handle(THREAD, new_value);
+  int first_offset = vklass->first_field_offset();
+  vklass->value_store(vklass->data_for_oop(old_value_h()),
+      vklass->data_for_oop(new_value_h()), in_heap, false);
+
+  // Updating the field specified in arguments
+  if (field_type == T_OBJECT || field_type == T_ARRAY) {
+    oop aoop = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx);
+    assert(aoop == NULL || (oopDesc::is_oop(aoop) && (!aoop->is_value())),"argument must be a reference type");
+    new_value_h()->obj_field_put(field_offset, aoop);
+  } else if (field_type == T_VALUETYPE) {
+    Klass* field_k = vklass->get_value_field_klass(field_index);
+    ValueKlass* field_vk = ValueKlass::cast(field_k);
+    oop vt_oop = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx);
+    assert(vt_oop != NULL && oopDesc::is_oop(vt_oop) && vt_oop->is_value(),"argument must be a value type");
+    assert(field_vk == vt_oop->klass(), "Must match");
+    field_vk->value_store(field_vk->data_for_oop(vt_oop),
+        ((char*)(oopDesc*)new_value_h()) + field_offset, true, false);
+  } else {
+    intptr_t* addr = f.interpreter_frame_expression_stack_at(tos_idx);
+    copy_primitive_argument(addr, new_value_h, field_offset, field_type);
+  }
+
+  // returning result
+  thread->set_vm_result(new_value_h());
+  return (type2size[field_type] + type2size[T_VALUETYPE]) * AbstractInterpreter::stackElementSize;
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::vbox(JavaThread* thread, ConstantPool* pool, int index, oopDesc* value))
+  assert(EnableMVT, "vbox is supported only when the MVT programming model is enabled");
+  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->get_vcc_klass() != target_klass) {
+    THROW_MSG(vmSymbols::java_lang_ClassCastException(), "vbox target is not derive value type box");
+  }
+  oop box = vtklass->box(Handle(THREAD, value),
+                         InstanceKlass::cast(target_klass),
+                         CHECK);
+  thread->set_vm_result(box);
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::vunbox(JavaThread* thread, ConstantPool* pool, int index, oopDesc* obj))
+assert(EnableMVT, "vunbox is supported only when the MVT programming model is enabled");
+  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");
+  }
+    if (klass != InstanceKlass::cast(target_klass)->get_vcc_klass()) {
+    THROW_MSG(vmSymbols::java_lang_ClassCastException(), "vunbox target is not derive value type");
+  }
+  oop value = ValueKlass::cast(target_klass)->unbox(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 index))
+  Handle value_h(THREAD, value);
+  InstanceKlass* klass = InstanceKlass::cast(value->klass());
+
+  Klass* field_k = klass->get_value_field_klass(index);
+  ValueKlass* field_vklass = ValueKlass::cast(field_k);
+  field_vklass->initialize(THREAD);
+
+  // allocate instance
+  bool in_heap;
+  instanceOop res = field_vklass->allocate_buffered_or_heap_instance(&in_heap, CHECK);
+  instanceHandle res_h(THREAD, res);
+  // copy value
+  field_vklass->value_store(((char*)(oopDesc*)value_h()) + klass->field_offset(index),
+                            field_vklass->data_for_oop(res), in_heap, false);
+  thread->set_vm_result(res_h());
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::initialize_static_value_field(JavaThread* thread, oopDesc* mirror, int index))
+  instanceHandle mirror_h(THREAD, (instanceOop)mirror);
+  InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror));
+  int offset = klass->field_offset(index);
+  assert(mirror->obj_field(offset) == NULL,"Field must not be initialized twice");
+
+  Klass* field_k = klass->get_value_field_klass(index);
+  ValueKlass* field_vklass = ValueKlass::cast(field_k);
+  // allocate instance, because it is going to be assigned to a static field
+  // it must not be a buffered value
+  instanceOop res = field_vklass->allocate_instance(CHECK);
+  instanceHandle res_h(THREAD, res);
+  mirror_h()->obj_field_put(offset, res_h());
+  thread->set_vm_result(res_h());
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::qputfield(JavaThread* thread, oopDesc* obj, oopDesc* value, int flags))
+  Handle value_h(THREAD, value);
+  Handle obj_h(THREAD, obj);
+  assert(!obj_h()->klass()->is_value(), "obj must be an object");
+  assert(value_h()->klass()->is_value(), "value must be an value type");
+  int index = flags & ConstantPoolCacheEntry::field_index_mask;
+
+  InstanceKlass* klass = InstanceKlass::cast(obj->klass());
+  Klass* field_k = klass->get_value_field_klass(index);
+  ValueKlass* field_vklass = ValueKlass::cast(value->klass());
+  assert(field_k == field_vklass, "Field descriptor and argument must match");
+  // copy value
+  field_vklass->value_store(field_vklass->data_for_oop(value_h()),
+                            ((char*)(oopDesc*)obj_h()) + klass->field_offset(index), true, false);
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::qputstatic(JavaThread* thread, oopDesc* value, int offset, oopDesc* mirror))
+  instanceHandle value_h(THREAD, (instanceOop)value);
+  assert(value_h()->is_value(), "qputstatic only deals with value arguments");
+  if (Universe::heap()->is_in_reserved(value_h())) {
+      mirror->obj_field_put(offset, value_h());
+  } else {
+    // The argument is a buffered value, a copy must be created in the Java heap
+    // because a static field cannot point to a thread-local buffered value
+    ValueKlass* field_vklass = ValueKlass::cast(value_h()->klass());
+    Handle mirror_h(THREAD, mirror);
+    // allocate heap instance
+    instanceOop res = field_vklass->allocate_instance(CHECK);
+    assert(Universe::heap()->is_in_reserved(res), "Must be in the Java heap");
+    instanceHandle res_h(THREAD, res);
+    // copy value
+    field_vklass->value_store(field_vklass->data_for_oop(value_h()),
+                              field_vklass->data_for_oop(res), true, false);
+    // writing static field
+    mirror_h->obj_field_put(offset, res_h());
+    assert(mirror_h->obj_field(offset) != NULL,"Sanity check");
+  }
+IRT_END
 
 IRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* thread, BasicType type, jint size))
   oop obj = oopFactory::new_typeArray(type, size, CHECK);
@@ -175,10 +411,68 @@
 
 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 {
+    ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
+    ValueKlass* vklass = vaklass->element_klass();
+    arrayHandle ah(THREAD, array);
+    bool in_heap;
+    instanceOop value_holder = vklass->allocate_buffered_or_heap_instance(&in_heap, CHECK);
+    void* src = ((valueArrayOop)ah())->value_at_addr(index, vaklass->layout_helper());
+    vklass->value_store(src, vklass->data_for_oop(value_holder),
+                          vaklass->element_byte_size(), in_heap, false);
+    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 (ArrayKlass::cast(klass)->element_klass() != ((oop)val)->klass()) {
+    THROW(vmSymbols::java_lang_ArrayStoreException());
+  }
+  if (klass->is_objArray_klass()) {
+    if(!Universe::heap()->is_in_reserved(val)) {
+      // A Java heap allocated copy must be made because an array cannot
+      // reference a thread-local buffered value
+      Handle val_h(THREAD, (oop)val);
+      ObjArrayKlass* aklass = ObjArrayKlass::cast(klass);
+      Klass* eklass = aklass->element_klass();
+      assert(eklass->is_value(), "Sanity check");
+      assert(eklass == ((oop)val)->klass(), "Sanity check");
+      ValueKlass* vklass = ValueKlass::cast(eklass);
+      // allocate heap instance
+      instanceOop res = vklass->allocate_instance(CHECK);
+      Handle res_h(THREAD, res);
+      // copy value
+      vklass->value_store(((char*)(oopDesc*)val_h()) + vklass->first_field_offset(),
+                            ((char*)(oopDesc*)res_h()) + vklass->first_field_offset(),true, false);
+      val = res_h();
+    }
+    ((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_byte_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
@@ -189,6 +483,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;
@@ -206,6 +504,58 @@
   thread->set_vm_result(obj);
 IRT_END
 
+IRT_ENTRY(void, InterpreterRuntime::recycle_vtbuffer(JavaThread* thread))
+  VTBuffer::recycle_vtbuffer(thread, last_frame(thread));
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::recycle_buffered_values(JavaThread* thread))
+  frame f = thread->last_frame();
+  assert(f.is_interpreted_frame(), "recycling can only be triggered from interpreted frames");
+  VTBuffer::recycle_vt_in_frame(thread, &f);
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::fix_frame_vt_alloc_ptr(JavaThread* thread))
+  frame f = thread->last_frame();
+  VTBuffer::fix_frame_vt_alloc_ptr(f, VTBufferChunk::chunk(thread->vt_alloc_ptr()));
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::return_value(JavaThread* thread, oopDesc* obj))
+  if (Universe::heap()->is_in_reserved(obj)) {
+    thread->set_vm_result(obj);
+    return;
+  }
+  assert(obj->klass()->is_value(), "Sanity check");
+  ValueKlass* vk = ValueKlass::cast(obj->klass());
+  RegisterMap reg_map(thread, false);
+  frame current_frame = last_frame(thread);
+  frame caller_frame = current_frame.sender(&reg_map);
+  if (!caller_frame.is_interpreted_frame()) {
+    // caller is not an interpreted frame, creating a new value in Java heap
+    Handle obj_h(THREAD, obj);
+    instanceOop res = vk->allocate_instance(CHECK);
+    Handle res_h(THREAD, res);
+    // copy value
+    vk->value_store(vk->data_for_oop(obj_h()),
+                    vk->data_for_oop(res_h()), true, false);
+    thread->set_vm_result(res_h());
+    return;
+  } else {
+    oop dest = VTBuffer::relocate_return_value(thread, current_frame, obj);
+    thread->set_vm_result(dest);
+  }
+IRT_END
+
+IRT_ENTRY(void, InterpreterRuntime::check_areturn(JavaThread* thread, oopDesc* obj))
+  if (obj != NULL) {
+    Klass* k = obj->klass();
+    if (k->is_value()) {
+      ResourceMark rm(thread);
+      tty->print_cr("areturn used on a value from %s", k->name()->as_C_string());
+    }
+    assert(!k->is_value(), "areturn should never be used on values");
+  }
+  thread->set_vm_result(obj);
+IRT_END
 
 IRT_ENTRY(void, InterpreterRuntime::register_finalizer(JavaThread* thread, oopDesc* obj))
   assert(oopDesc::is_oop(obj), "must be a valid oop");
@@ -559,8 +909,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::_vwithfield;
 
   {
     JvmtiHideSingleStepping jhss(thread);
@@ -604,9 +955,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 = 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);
     }
   }
 
@@ -728,7 +1085,8 @@
     Symbol* signature = call.signature();
     receiver = Handle(thread,
                   thread->last_frame().interpreter_callee_receiver(signature));
-    assert(Universe::heap()->is_in_reserved_or_null(receiver()),
+    assert(Universe::heap()->is_in_reserved_or_null(receiver())
+           || VTBuffer::is_in_vt_buffer(receiver()),
            "sanity check");
     assert(receiver.is_null() ||
            !Universe::heap()->is_in_reserved(receiver->klass()),
@@ -871,6 +1229,7 @@
   case Bytecodes::_putstatic:
   case Bytecodes::_getfield:
   case Bytecodes::_putfield:
+  case Bytecodes::_vwithfield:
     resolve_get_put(thread, bytecode);
     break;
   case Bytecodes::_invokevirtual:
--- a/src/hotspot/share/interpreter/interpreterRuntime.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp	Tue Sep 26 16:15:08 2017 +0200
@@ -87,6 +87,28 @@
   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 index);
+  static void    qputfield     (JavaThread* thread, oopDesc* obj, oopDesc* value, int flags);
+  static void    qputstatic    (JavaThread* thread, oopDesc* value, int offset, oopDesc* mirror);
+  static void    initialize_static_value_field(JavaThread*, oopDesc* mirror, int offset);
+
+  // Value Buffers support
+  static void    recycle_vtbuffer(JavaThread* thread);
+  static void    recycle_buffered_values(JavaThread* thread);
+  static void    return_value(JavaThread* thread, oopDesc* obj);
+  static void    check_areturn(JavaThread* thread, oopDesc* obj);
+  static void    fix_frame_vt_alloc_ptr(JavaThread* thread);
+
+  // 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/hotspot/share/interpreter/linkResolver.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/linkResolver.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -918,11 +918,13 @@
                                  TRAPS) {
   assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic ||
          byte == Bytecodes::_getfield  || byte == Bytecodes::_putfield  ||
+         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();
@@ -966,6 +968,22 @@
     stringStream ss;
 
     if (sel_klass != current_klass) {
+      // For Minimal Value Types check if the current class is an anonymous
+      // class whose host class is the Derived Value Type class (selected class)
+      // or the Value Capable Class (VCC)
+      if (byte == Bytecodes::_vwithfield) {
+        assert(sel_klass->is_value(), "Expected Value Type");
+        if (current_klass->is_instance_klass() && InstanceKlass::cast(current_klass)->is_anonymous()) {
+          Klass* host_klass = InstanceKlass::cast(current_klass)->host_klass(); // Is host VCC of DVT ?
+
+          if (sel_klass == host_klass  || // Is DVT
+              (host_klass->is_instance_klass() && // Is VCC
+               InstanceKlass::cast(sel_klass)->get_vcc_klass() == host_klass)) {
+            return;
+          }
+        }
+      }
+
       ss.print("Update to %s final field %s.%s attempted from a different class (%s) than the field's declaring class",
                 is_static ? "static" : "non-static", resolved_klass->external_name(), fd.name()->as_C_string(),
                 current_klass->external_name());
--- a/src/hotspot/share/interpreter/oopMapCache.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/oopMapCache.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -246,6 +246,7 @@
   void pass_float()                              { /* ignore */ }
   void pass_double()                             { /* ignore */ }
   void pass_object()                             { set_one(offset()); }
+  void pass_valuetype()                          { set_one(offset()); }
 
   MaskFillerForNative(const methodHandle& method, uintptr_t* mask, int size) : NativeSignatureIterator(method) {
     _mask   = mask;
@@ -274,7 +275,7 @@
   st.print("Locals (%d): ", max_locals);
   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");
     st.print("%d", v1 ? 1 : 0);
   }
@@ -283,7 +284,7 @@
   st.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");
     st.print("%d", v1 ? 1 : 0);
   }
@@ -365,14 +366,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/hotspot/share/interpreter/rewriter.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/rewriter.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -164,7 +164,7 @@
 void Rewriter::rewrite_member_reference(address bcp, int offset, bool reverse) {
   address p = bcp + offset;
   if (!reverse) {
-    int  cp_index    = Bytes::get_Java_u2(p);
+    int cp_index    = Bytes::get_Java_u2(p);
     int  cache_index = cp_entry_to_cp_cache(cp_index);
     Bytes::put_native_u2(p, cache_index);
     if (!_method_handle_invokers.is_empty())
@@ -200,7 +200,6 @@
   }
 }
 
-
 // Adjust the invocation bytecode for a signature-polymorphic method (MethodHandle.invoke, etc.)
 void Rewriter::maybe_rewrite_invokehandle(address opc, int cp_index, int cache_index, bool reverse) {
   if (!reverse) {
@@ -455,6 +454,7 @@
       // fall through
       case Bytecodes::_getstatic      : // fall through
       case Bytecodes::_getfield       : // 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/hotspot/share/interpreter/templateInterpreter.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/templateInterpreter.cpp	Tue Sep 26 16:15:08 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/hotspot/share/interpreter/templateInterpreter.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/templateInterpreter.hpp	Tue Sep 26 16:15:08 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
@@ -155,7 +155,7 @@
 
   // Code generation
 #ifndef PRODUCT
-  static address    trace_code    (TosState state)              { return _trace_code.entry(state); }
+  static address    trace_code    (TosState state)              { return _trace_code.entry(state == ptos ? atos : state); }
 #endif // !PRODUCT
   static address*   dispatch_table(TosState state)              { return _active_table.table_for(state); }
   static address*   dispatch_table()                            { return _active_table.table_for(); }
--- a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp	Tue Sep 26 16:15:08 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,9 @@
     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;
+    case ptos: vep = __ pc(); __ pop(ptos); aep = __ pc(); qep = __ pc(); generate_and_dispatch(t); break;
     default  : ShouldNotReachHere();                                                 break;
   }
 }
--- a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp	Tue Sep 26 16:15:08 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/hotspot/share/interpreter/templateTable.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/templateTable.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -160,7 +160,9 @@
 // Implementation of TemplateTable: Debugging
 
 void TemplateTable::transition(TosState tos_in, TosState tos_out) {
-  assert(_desc->tos_in()  == tos_in , "inconsistent tos_in  information");
+  assert(_desc->tos_in()  == tos_in
+         || (_desc->tos_in() == ptos && (tos_in == atos || tos_in == qtos)),
+         "inconsistent tos_in  information");
   assert(_desc->tos_out() == tos_out, "inconsistent tos_out information");
 }
 
@@ -460,6 +462,16 @@
   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::_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,26 +479,30 @@
   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_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        );
-  def(Bytecodes::_fast_fgetfield      , ubcp|____|____|____, atos, ftos, fast_accessfield    ,  ftos        );
-  def(Bytecodes::_fast_igetfield      , ubcp|____|____|____, atos, itos, fast_accessfield    ,  itos        );
-  def(Bytecodes::_fast_lgetfield      , ubcp|____|____|____, atos, ltos, fast_accessfield    ,  ltos        );
-  def(Bytecodes::_fast_sgetfield      , ubcp|____|____|____, atos, itos, fast_accessfield    ,  itos        );
+  def(Bytecodes::_fast_agetfield      , ubcp|____|____|____, ptos, atos, fast_accessfield    ,  atos        );
+  def(Bytecodes::_fast_qgetfield      , ubcp|____|____|____, ptos, qtos, fast_accessfield    ,  qtos        );
+  def(Bytecodes::_fast_bgetfield      , ubcp|____|____|____, ptos, itos, fast_accessfield    ,  itos        );
+  def(Bytecodes::_fast_cgetfield      , ubcp|____|____|____, ptos, itos, fast_accessfield    ,  itos        );
+  def(Bytecodes::_fast_dgetfield      , ubcp|____|____|____, ptos, dtos, fast_accessfield    ,  dtos        );
+  def(Bytecodes::_fast_fgetfield      , ubcp|____|____|____, ptos, ftos, fast_accessfield    ,  ftos        );
+  def(Bytecodes::_fast_igetfield      , ubcp|____|____|____, ptos, itos, fast_accessfield    ,  itos        );
+  def(Bytecodes::_fast_lgetfield      , ubcp|____|____|____, ptos, ltos, fast_accessfield    ,  ltos        );
+  def(Bytecodes::_fast_sgetfield      , ubcp|____|____|____, ptos, 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        );
@@ -523,6 +539,7 @@
   def(Bytecodes::_nofast_aload_0      , ____|____|clvm|____, vtos, atos, nofast_aload_0      ,  _           );
   def(Bytecodes::_nofast_iload        , ubcp|____|clvm|____, vtos, itos, nofast_iload        ,  _           );
 
+
   def(Bytecodes::_shouldnotreachhere   , ____|____|____|____, vtos, vtos, shouldnotreachhere ,  _           );
   // platform specific bytecodes
   pd_initialize();
--- a/src/hotspot/share/interpreter/templateTable.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/interpreter/templateTable.hpp	Tue Sep 26 16:15:08 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();
@@ -295,14 +301,19 @@
   static void getstatic(int byte_no);
   static void putstatic(int byte_no);
   static void pop_and_check_object(Register obj);
+  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/hotspot/share/jvmci/jvmciCodeInstaller.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -1096,7 +1096,7 @@
     throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE;
   }
 
-  _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, return_oop,
+  _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, return_oop, false,
                                   locals_token, expressions_token, monitors_token);
 }
 
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -1421,7 +1421,7 @@
             // native wrappers do not have a scope
             if (scope != NULL && scope->objects() != NULL) {
               bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), scope->objects(), CHECK_NULL);
-              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(), CHECK_NULL);
@@ -1602,7 +1602,7 @@
   }
 
   bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), objects, CHECK);
-  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/hotspot/share/jvmci/jvmciCompilerToVM.hpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp	Tue Sep 26 16:15:08 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/hotspot/share/jvmci/jvmciEnv.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/jvmci/jvmciEnv.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -150,7 +150,7 @@
   if (found_klass == NULL && !cpool.is_null() && cpool->has_preresolution()) {
     // Look inside the constant pool for pre-resolved class entries.
     for (int i = cpool->length() - 1; i >= 1; i--) {
-      if (cpool->tag_at(i).is_klass()) {
+      if (cpool->tag_at(i).is_klass() || cpool->tag_at(i).is_value_type()) {
         Klass*  kls = cpool->resolved_klass_at(i);
         if (kls->name() == sym) {
           return kls;
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Tue Sep 26 16:13:34 2017 +0200
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Tue Sep 26 16:15:08 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -393,6 +393,7 @@
   declare_constant(JVM_CONSTANT_Long)                                     \
   declare_constant(JVM_CONSTANT_Double)                                   \
   declare_constant(JVM_CONSTANT_Class)                                    \
+  declare_constant(JVM_CONSTANT_Value)                                    \
   declare_constant(JVM_CONSTANT_String)                                   \
   declare_constant(JVM_CONSTANT_Fieldref)                                 \
   declare_constant(JVM_CONSTANT_Methodref)                                \
@@ -406,9 +407,12 @@