--- old/make/autoconf/hotspot.m4	2019-09-26 16:21:58.761393665 +0200
+++ new/make/autoconf/hotspot.m4	2019-09-26 16:21:58.545389958 +0200
@@ -355,7 +355,7 @@
   # Only enable ZGC on supported platforms
   # Temp diasable for Valhalla, working in Access API
   AC_MSG_CHECKING([if zgc can be built])
-  if $VALHALLA_TEMP && ((test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xx86_64") || \
+  if ((test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xx86_64") || \
      (test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xaarch64")); then
     AC_MSG_RESULT([yes])
   else
--- old/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	2019-09-26 16:21:59.433405194 +0200
+++ new/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	2019-09-26 16:21:59.173400733 +0200
@@ -37,6 +37,7 @@
 #include "gc/shared/cardTableBarrierSet.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "nativeInst_x86.hpp"
+#include "oops/oop.inline.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "runtime/frame.inline.hpp"
 #include "runtime/safepointMechanism.hpp"
--- old/src/hotspot/share/asm/macroAssembler_common.cpp	2019-09-26 16:22:00.133417204 +0200
+++ new/src/hotspot/share/asm/macroAssembler_common.cpp	2019-09-26 16:21:59.869412675 +0200
@@ -27,7 +27,7 @@
 #include "asm/assembler.hpp"
 #include "asm/assembler.inline.hpp"
 #include "asm/macroAssembler.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "runtime/signature_cc.hpp"
 #include "runtime/sharedRuntime.hpp"
 #ifdef COMPILER2
--- old/src/hotspot/share/c1/c1_Runtime1.cpp	2019-09-26 16:22:00.801428665 +0200
+++ new/src/hotspot/share/c1/c1_Runtime1.cpp	2019-09-26 16:22:00.549424341 +0200
@@ -447,22 +447,9 @@
 
 JRT_ENTRY(void, Runtime1::load_flattened_array(JavaThread* thread, valueArrayOopDesc* array, int index))
   NOT_PRODUCT(_load_flattened_array_slowcase_cnt++;)
-  Klass* klass = array->klass();
-  assert(klass->is_valueArray_klass(), "expected value array oop");
   assert(array->length() > 0 && index < array->length(), "already checked");
-
-  ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
-  ValueKlass* vklass = vaklass->element_klass();
-
-  // We have a non-empty flattened array, so the element type must have been initialized.
-  assert(vklass->is_initialized(), "must be");
-  Handle holder(THREAD, vklass->klass_holder()); // keep the vklass alive
-  valueArrayHandle ha(THREAD, array);
-  oop obj = vklass->allocate_instance(CHECK);
-
-  void* src = ha()->value_at_addr(index, vaklass->layout_helper());
-  vklass->value_store(src, vklass->data_for_oop(obj),
-                      vaklass->element_byte_size(), true, false);
+  valueArrayHandle vah(thread, array);
+  oop obj = valueArrayOopDesc::value_copy_from_index(vah, index, CHECK);
   thread->set_vm_result(obj);
 JRT_END
 
@@ -472,15 +459,7 @@
   if (value == NULL) {
     SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_NullPointerException());
   } else {
-    Klass* klass = array->klass();
-    assert(klass->is_valueArray_klass(), "expected value array");
-    assert(ArrayKlass::cast(klass)->element_klass() == value->klass(), "Store type incorrect");
-
-    ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
-    ValueKlass* vklass = vaklass->element_klass();
-    const int lh = vaklass->layout_helper();
-    vklass->value_store(vklass->data_for_oop(value), array->value_at_addr(index, lh),
-                        vaklass->element_byte_size(), true, false);
+    array->value_copy_to_index(value, index);
   }
 JRT_END
 
--- old/src/hotspot/share/ci/ciInstanceKlass.cpp	2019-09-26 16:22:01.445439714 +0200
+++ new/src/hotspot/share/ci/ciInstanceKlass.cpp	2019-09-26 16:22:01.225435939 +0200
@@ -34,7 +34,7 @@
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/fieldStreams.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/jniHandles.inline.hpp"
--- old/src/hotspot/share/ci/ciReplay.cpp	2019-09-26 16:22:02.069450420 +0200
+++ new/src/hotspot/share/ci/ciReplay.cpp	2019-09-26 16:22:01.853446713 +0200
@@ -37,7 +37,7 @@
 #include "oops/constantPool.hpp"
 #include "oops/method.inline.hpp"
 #include "oops/oop.inline.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "utilities/copy.hpp"
--- old/src/hotspot/share/ci/ciValueKlass.cpp	2019-09-26 16:22:02.629460027 +0200
+++ new/src/hotspot/share/ci/ciValueKlass.cpp	2019-09-26 16:22:02.421456459 +0200
@@ -26,7 +26,7 @@
 #include "ci/ciField.hpp"
 #include "ci/ciUtilities.inline.hpp"
 #include "ci/ciValueKlass.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 
 int ciValueKlass::compute_nonstatic_fields() {
   int result = ciInstanceKlass::compute_nonstatic_fields();
--- old/src/hotspot/share/classfile/classFileParser.cpp	2019-09-26 16:22:03.241470528 +0200
+++ new/src/hotspot/share/classfile/classFileParser.cpp	2019-09-26 16:22:02.985466135 +0200
@@ -58,7 +58,7 @@
 #include "oops/method.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/arguments.hpp"
--- old/src/hotspot/share/classfile/classLoaderData.cpp	2019-09-26 16:22:03.965482949 +0200
+++ new/src/hotspot/share/classfile/classLoaderData.cpp	2019-09-26 16:22:03.701478420 +0200
@@ -63,7 +63,7 @@
 #include "oops/access.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/oopHandle.inline.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "oops/weakHandle.inline.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/handles.inline.hpp"
--- old/src/hotspot/share/classfile/fieldLayoutBuilder.cpp	2019-09-26 16:22:04.597493792 +0200
+++ new/src/hotspot/share/classfile/fieldLayoutBuilder.cpp	2019-09-26 16:22:04.381490086 +0200
@@ -29,7 +29,7 @@
 #include "memory/resourceArea.hpp"
 #include "oops/array.hpp"
 #include "oops/instanceMirrorKlass.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 
 RawBlock::RawBlock(Kind kind, int size) {
--- old/src/hotspot/share/classfile/javaClasses.cpp	2019-09-26 16:22:05.253505047 +0200
+++ new/src/hotspot/share/classfile/javaClasses.cpp	2019-09-26 16:22:04.993500586 +0200
@@ -52,6 +52,7 @@
 #include "oops/symbol.hpp"
 #include "oops/typeArrayOop.inline.hpp"
 #include "oops/valueArrayKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/resolvedMethodTable.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
--- old/src/hotspot/share/gc/shared/barrierSet.hpp	2019-09-26 16:22:06.109519733 +0200
+++ new/src/hotspot/share/gc/shared/barrierSet.hpp	2019-09-26 16:22:05.853515341 +0200
@@ -315,6 +315,10 @@
       Raw::clone(src, dst, size);
     }
 
+    static void value_copy_in_heap(void* src, void* dst, ValueKlass* md) {
+      Raw::value_copy(src, dst, md);
+    }
+
     static oop resolve(oop obj) {
       return Raw::resolve(obj);
     }
--- old/src/hotspot/share/gc/shared/modRefBarrierSet.hpp	2019-09-26 16:22:06.813531811 +0200
+++ new/src/hotspot/share/gc/shared/modRefBarrierSet.hpp	2019-09-26 16:22:06.597528105 +0200
@@ -104,6 +104,8 @@
     static oop oop_atomic_cmpxchg_in_heap_at(oop new_value, oop base, ptrdiff_t offset, oop compare_value) {
       return oop_atomic_cmpxchg_in_heap(new_value, AccessInternal::oop_field_addr<decorators>(base, offset), compare_value);
     }
+
+    static void value_copy_in_heap(void* src, void* dst, ValueKlass* md);
   };
 };
 
--- old/src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp	2019-09-26 16:22:07.421542242 +0200
+++ new/src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp	2019-09-26 16:22:07.165537850 +0200
@@ -31,6 +31,7 @@
 #include "oops/klass.inline.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/oop.hpp"
+#include "oops/valueKlass.hpp"
 
 // count is number of array elements being written
 void ModRefBarrierSet::write_ref_array(HeapWord* start, size_t count) {
@@ -152,4 +153,36 @@
   bs->write_region(MemRegion((HeapWord*)(void*)dst, size));
 }
 
+template <DecoratorSet decorators, typename BarrierSetT>
+inline void ModRefBarrierSet::AccessBarrier<decorators, BarrierSetT>::
+value_copy_in_heap(void* src, void* dst, ValueKlass* md) {
+  if (HasDecorator<decorators, IS_DEST_UNINITIALIZED>::value || (!md->contains_oops())) {
+    Raw::value_copy(src, dst, md);
+  } else {
+    BarrierSetT* bs = barrier_set_cast<BarrierSetT>(BarrierSet::barrier_set());
+    // src/dst aren't oops, need offset to adjust oop map offset
+    const address dst_oop_addr_offset = ((address) dst) - md->first_field_offset();
+    typedef typename ValueOopType<decorators>::type OopType;
+
+    // Pre-barriers...
+    OopMapBlock* map = md->start_of_nonstatic_oop_maps();
+    OopMapBlock* const end = map + md->nonstatic_oop_map_count();
+    while (map != end) {
+      address doop_address = dst_oop_addr_offset + map->offset();
+      bs->write_ref_array_pre((OopType*) doop_address, map->count(), false);
+      map++;
+    }
+
+    Raw::value_copy(src, dst, md);
+
+    // Post-barriers...
+    map = md->start_of_nonstatic_oop_maps();
+    while (map != end) {
+      address doop_address = dst_oop_addr_offset + map->offset();
+      bs->write_ref_array((HeapWord*) doop_address, map->count());
+      map++;
+    }
+  }
+}
+
 #endif // SHARE_GC_SHARED_MODREFBARRIERSET_INLINE_HPP
--- old/src/hotspot/share/gc/z/zBarrier.hpp	2019-09-26 16:22:08.077553497 +0200
+++ new/src/hotspot/share/gc/z/zBarrier.hpp	2019-09-26 16:22:07.809548899 +0200
@@ -26,6 +26,7 @@
 
 #include "memory/allocation.hpp"
 #include "oops/oop.hpp"
+#include "oops/valueKlass.hpp"
 
 typedef bool (*ZBarrierFastPath)(uintptr_t);
 typedef uintptr_t (*ZBarrierSlowPath)(uintptr_t);
--- old/src/hotspot/share/gc/z/zBarrierSet.hpp	2019-09-26 16:22:08.717564477 +0200
+++ new/src/hotspot/share/gc/z/zBarrierSet.hpp	2019-09-26 16:22:08.461560085 +0200
@@ -84,6 +84,8 @@
 
     static void clone_in_heap(oop src, oop dst, size_t size);
 
+    static void value_copy_in_heap(void* src, void* dst, ValueKlass* md);
+
     //
     // Not in heap
     //
--- old/src/hotspot/share/gc/z/zBarrierSet.inline.hpp	2019-09-26 16:22:09.281574153 +0200
+++ new/src/hotspot/share/gc/z/zBarrierSet.inline.hpp	2019-09-26 16:22:09.069570516 +0200
@@ -214,6 +214,23 @@
   Raw::clone_in_heap(src, dst, size);
 }
 
+template <DecoratorSet decorators, typename BarrierSetT>
+inline void ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::value_copy_in_heap(void* src, void* dst, ValueKlass* md) {
+  if (md->contains_oops()) {
+    // src/dst aren't oops, need offset to adjust oop map offset
+    const address src_oop_addr_offset = ((address) src) - md->first_field_offset();
+
+    OopMapBlock* map = md->start_of_nonstatic_oop_maps();
+    OopMapBlock* const end = map + md->nonstatic_oop_map_count();
+    while (map != end) {
+      address soop_address = src_oop_addr_offset + map->offset();
+      ZBarrier::load_barrier_on_oop_array((oop*) soop_address, map->count());
+      map++;
+    }
+  }
+  Raw::value_copy_in_heap(src, dst, md);
+}
+
 //
 // Not in heap
 //
--- old/src/hotspot/share/interpreter/interpreterRuntime.cpp	2019-09-26 16:22:09.933585339 +0200
+++ new/src/hotspot/share/interpreter/interpreterRuntime.cpp	2019-09-26 16:22:09.709581497 +0200
@@ -48,10 +48,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 "oops/valueArrayOop.inline.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/nativeLookup.hpp"
 #include "runtime/atomic.hpp"
@@ -337,9 +336,7 @@
   instanceOop new_value = vklass->allocate_instance(
       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()), true, false);
+  vklass->value_copy_oop_to_new_oop(old_value_h(), new_value_h());
 
   // Updating the field specified in arguments
   if (field_type == T_ARRAY || field_type == T_OBJECT) {
@@ -357,8 +354,7 @@
       Klass* field_k = vklass->get_value_field_klass(field_index);
       ValueKlass* field_vk = ValueKlass::cast(field_k);
       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, false, false);
+      field_vk->value_copy_oop_to_new_payload(vt_oop, ((char*)(oopDesc*)new_value_h()) + field_offset);
     } else { // not flattened
       oop voop = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx);
       if (voop == NULL && cp_entry->is_flattenable()) {
@@ -445,7 +441,7 @@
 
   ValueKlass* vklass = ValueKlass::cast(value->klass());
   if (!vklass->is_empty_value()) {
-    vklass->value_store(vklass->data_for_oop(value), ((char*)(oopDesc*)rcv) + offset, true, true);
+    vklass->value_copy_oop_to_payload(value, ((char*)(oopDesc*)rcv) + offset);
   }
 JRT_END
 
@@ -466,11 +462,8 @@
   if (field_vklass->is_empty_value()) {
     res = (instanceOop)field_vklass->default_value();
   } else {
-    // allocate instance
     res = field_vklass->allocate_instance(CHECK);
-    // copy value
-    field_vklass->value_store(((char*)(oopDesc*)obj_h()) + klass->field_offset(index),
-        field_vklass->data_for_oop(res), true, true);
+    field_vklass->value_copy_payload_to_new_oop(((char*)(oopDesc*)obj_h()) + klass->field_offset(index), res);
   }
   assert(res != NULL, "Must be set in one of two paths above");
   thread->set_vm_result(res);
@@ -496,39 +489,14 @@
 JRT_END
 
 JRT_ENTRY(void, InterpreterRuntime::value_array_load(JavaThread* thread, arrayOopDesc* array, int index))
-  Klass* klass = array->klass();
-  assert(klass->is_valueArray_klass(), "expected value array oop");
-
-  ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
-  ValueKlass* vklass = vaklass->element_klass();
-  arrayHandle ah(THREAD, array);
-  instanceOop value_holder = NULL;
-  if (vklass->is_empty_value()) {
-    value_holder = (instanceOop)vklass->default_value();
-  } else {
-    value_holder = vklass->allocate_instance(CHECK);
-    void* src = ((valueArrayOop)ah())->value_at_addr(index, vaklass->layout_helper());
-    vklass->value_store(src, vklass->data_for_oop(value_holder),
-        vaklass->element_byte_size(), true, false);
-  }
-  assert(value_holder != NULL, "Must be set in one of two paths above");
+  valueArrayHandle vah(thread, (valueArrayOop)array);
+  oop value_holder = valueArrayOopDesc::value_copy_from_index(vah, index, CHECK);
   thread->set_vm_result(value_holder);
 JRT_END
 
 JRT_ENTRY(void, InterpreterRuntime::value_array_store(JavaThread* thread, void* val, arrayOopDesc* array, int index))
   assert(val != NULL, "can't store null into flat array");
-  Klass* klass = array->klass();
-  assert(klass->is_valueArray_klass(), "expected value array");
-  assert(ArrayKlass::cast(klass)->element_klass() == ((oop)val)->klass(), "Store type incorrect");
-
-  valueArrayOop varray = (valueArrayOop)array;
-  ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
-  ValueKlass* vklass = vaklass->element_klass();
-  if (!vklass->is_empty_value()) {
-    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);
-  }
+  ((valueArrayOop)array)->value_copy_to_index((oop)val, index);
 JRT_END
 
 JRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* thread, jint* first_size_address))
--- old/src/hotspot/share/memory/heapInspection.cpp	2019-09-26 16:22:10.537595701 +0200
+++ new/src/hotspot/share/memory/heapInspection.cpp	2019-09-26 16:22:10.325592064 +0200
@@ -33,7 +33,7 @@
 #include "memory/universe.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/reflectionAccessorImplKlassHelper.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "runtime/os.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "utilities/globalDefinitions.hpp"
--- old/src/hotspot/share/oops/access.hpp	2019-09-26 16:22:11.313609015 +0200
+++ new/src/hotspot/share/oops/access.hpp	2019-09-26 16:22:11.049604485 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -57,6 +57,7 @@
 // * atomic_xchg_at: Atomically swap a new value at an internal pointer address if previous value matched the compared value.
 // * arraycopy: Copy data from one heap array to another heap array. The ArrayAccess class has convenience functions for this.
 // * clone: Clone the contents of an object to a newly allocated object.
+// * value_copy: Copy the contents of a value type from one heap address to another
 // * resolve: Resolve a stable to-space invariant oop that is guaranteed not to relocate its payload until a subsequent thread transition.
 //
 // == IMPLEMENTATION ==
@@ -123,6 +124,12 @@
     verify_decorators<expected_mo_decorators | heap_oop_decorators>();
   }
 
+  template <DecoratorSet expected_mo_decorators>
+  static void verify_heap_value_decorators() {
+    const DecoratorSet heap_value_decorators = IN_HEAP | IS_DEST_UNINITIALIZED;
+    verify_decorators<expected_mo_decorators | heap_value_decorators>();
+  }
+
   static const DecoratorSet load_mo_decorators = MO_UNORDERED | MO_VOLATILE | MO_RELAXED | MO_ACQUIRE | MO_SEQ_CST;
   static const DecoratorSet store_mo_decorators = MO_UNORDERED | MO_VOLATILE | MO_RELAXED | MO_RELEASE | MO_SEQ_CST;
   static const DecoratorSet atomic_xchg_mo_decorators = MO_SEQ_CST;
@@ -213,6 +220,14 @@
     AccessInternal::clone<decorators>(src, dst, size);
   }
 
+  // Value type inline heap access (flattened)...
+
+  // Copy value type data from src to dst
+  static inline void value_copy(void* src, void* dst, ValueKlass* md) {
+    verify_heap_value_decorators<IN_HEAP>();
+    AccessInternal::value_copy<decorators>(src, dst, md);
+  }
+
   // Primitive accesses
   template <typename P>
   static inline P load(P* addr) {
--- old/src/hotspot/share/oops/access.inline.hpp	2019-09-26 16:22:12.177623838 +0200
+++ new/src/hotspot/share/oops/access.inline.hpp	2019-09-26 16:22:11.961620132 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -199,6 +199,13 @@
   };
 
   template <class GCBarrierType, DecoratorSet decorators>
+  struct PostRuntimeDispatch<GCBarrierType, BARRIER_VALUE_COPY, decorators>: public AllStatic {
+    static void access_barrier(void* src, void* dst, ValueKlass* md) {
+      GCBarrierType::value_copy_in_heap(src, dst, md);
+    }
+  };
+
+  template <class GCBarrierType, DecoratorSet decorators>
   struct PostRuntimeDispatch<GCBarrierType, BARRIER_RESOLVE, decorators>: public AllStatic {
     static oop access_barrier(oop obj) {
       return GCBarrierType::resolve(obj);
@@ -354,6 +361,13 @@
   }
 
   template <DecoratorSet decorators, typename T>
+  void RuntimeDispatch<decorators, T, BARRIER_VALUE_COPY>::value_copy_init(void* src, void* dst, ValueKlass* md) {
+    func_t function = BarrierResolver<decorators, func_t, BARRIER_VALUE_COPY>::resolve_barrier();
+    _value_copy_func = function;
+    function(src, dst, md);
+  }
+
+  template <DecoratorSet decorators, typename T>
   oop RuntimeDispatch<decorators, T, BARRIER_RESOLVE>::resolve_init(oop obj) {
     func_t function = BarrierResolver<decorators, func_t, BARRIER_RESOLVE>::resolve_barrier();
     _resolve_func = function;
--- old/src/hotspot/share/oops/accessBackend.cpp	2019-09-26 16:22:12.909636397 +0200
+++ new/src/hotspot/share/oops/accessBackend.cpp	2019-09-26 16:22:12.693632691 +0200
@@ -26,6 +26,7 @@
 #include "accessBackend.inline.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/valueKlass.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/vm_version.hpp"
 #include "utilities/copy.hpp"
--- old/src/hotspot/share/oops/accessBackend.hpp	2019-09-26 16:22:13.641648955 +0200
+++ new/src/hotspot/share/oops/accessBackend.hpp	2019-09-26 16:22:13.433645387 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -52,6 +52,14 @@
   typedef typename Conditional<needs_oop_compress, narrowOop, oop>::type type;
 };
 
+// This meta-function returns either oop or narrowOop depending on whether
+// a back-end needs to consider compressed oops types or not.
+template <DecoratorSet decorators>
+struct ValueOopType: AllStatic {
+  static const bool needs_oop_compress = HasDecorator<decorators, INTERNAL_RT_USE_COMPRESSED_OOPS>::value;
+  typedef typename Conditional<needs_oop_compress, narrowOop, oop>::type type;
+};
+
 namespace AccessInternal {
   enum BarrierType {
     BARRIER_STORE,
@@ -64,6 +72,7 @@
     BARRIER_ATOMIC_XCHG_AT,
     BARRIER_ARRAYCOPY,
     BARRIER_CLONE,
+    BARRIER_VALUE_COPY,
     BARRIER_RESOLVE
   };
 
@@ -114,6 +123,7 @@
                                      arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
                                      size_t length);
     typedef void (*clone_func_t)(oop src, oop dst, size_t size);
+    typedef void (*value_copy_func_t)(void* src, void* dst, ValueKlass* md);
     typedef oop (*resolve_func_t)(oop obj);
   };
 
@@ -141,6 +151,7 @@
   ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_XCHG_AT, atomic_xchg_at_func_t);
   ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ARRAYCOPY, arraycopy_func_t);
   ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_CLONE, clone_func_t);
+  ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_VALUE_COPY, value_copy_func_t);
   ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_RESOLVE, resolve_func_t);
 #undef ACCESS_GENERATE_ACCESS_FUNCTION
 
@@ -406,6 +417,8 @@
 
   static void clone(oop src, oop dst, size_t size);
 
+  static void value_copy(void* src, void* dst, ValueKlass* md);
+
   static oop resolve(oop obj) { return obj; }
 };
 
@@ -589,6 +602,18 @@
   };
 
   template <DecoratorSet decorators, typename T>
+  struct RuntimeDispatch<decorators, T, BARRIER_VALUE_COPY>: AllStatic {
+    typedef typename AccessFunction<decorators, T, BARRIER_VALUE_COPY>::type func_t;
+    static func_t _value_copy_func;
+
+    static void value_copy_init(void* src, void* dst, ValueKlass* md);
+
+    static inline void value_copy(void* src, void* dst, ValueKlass* md) {
+      _value_copy_func(src, dst, md);
+    }
+  };
+
+  template <DecoratorSet decorators, typename T>
   struct RuntimeDispatch<decorators, T, BARRIER_RESOLVE>: AllStatic {
     typedef typename AccessFunction<decorators, T, BARRIER_RESOLVE>::type func_t;
     static func_t _resolve_func;
@@ -642,6 +667,10 @@
   RuntimeDispatch<decorators, T, BARRIER_CLONE>::_clone_func = &clone_init;
 
   template <DecoratorSet decorators, typename T>
+  typename AccessFunction<decorators, T, BARRIER_VALUE_COPY>::type
+  RuntimeDispatch<decorators, T, BARRIER_VALUE_COPY>::_value_copy_func = &value_copy_init;
+
+  template <DecoratorSet decorators, typename T>
   typename AccessFunction<decorators, T, BARRIER_RESOLVE>::type
   RuntimeDispatch<decorators, T, BARRIER_RESOLVE>::_resolve_func = &resolve_init;
 
@@ -963,6 +992,23 @@
 
     template <DecoratorSet decorators>
     inline static typename EnableIf<
+      HasDecorator<decorators, AS_RAW>::value>::type
+    value_copy(void* src, void* dst, ValueKlass* md) {
+      typedef RawAccessBarrier<decorators & RAW_DECORATOR_MASK> Raw;
+      Raw::value_copy(src, dst, md);
+    }
+
+    template <DecoratorSet decorators>
+    inline static typename EnableIf<
+      !HasDecorator<decorators, AS_RAW>::value>::type
+      value_copy(void* src, void* dst, ValueKlass* md) {
+      const DecoratorSet expanded_decorators = decorators;
+      RuntimeDispatch<expanded_decorators, void*, BARRIER_VALUE_COPY>::value_copy(src, dst, md);
+    }
+
+
+    template <DecoratorSet decorators>
+    inline static typename EnableIf<
       HasDecorator<decorators, INTERNAL_BT_TO_SPACE_INVARIANT>::value, oop>::type
     resolve(oop obj) {
       typedef RawAccessBarrier<decorators & RAW_DECORATOR_MASK> Raw;
@@ -1268,6 +1314,12 @@
   }
 
   template <DecoratorSet decorators>
+  inline void value_copy(void* src, void* dst, ValueKlass* md) {
+    const DecoratorSet expanded_decorators = DecoratorFixup<decorators>::value;
+    PreRuntimeDispatch::value_copy<expanded_decorators>(src, dst, md);
+  }
+
+  template <DecoratorSet decorators>
   inline oop resolve(oop obj) {
     const DecoratorSet expanded_decorators = DecoratorFixup<decorators>::value;
     return PreRuntimeDispatch::resolve<expanded_decorators>(obj);
--- old/src/hotspot/share/oops/accessBackend.inline.hpp	2019-09-26 16:22:14.389661788 +0200
+++ new/src/hotspot/share/oops/accessBackend.inline.hpp	2019-09-26 16:22:14.137657465 +0200
@@ -29,6 +29,7 @@
 #include "oops/accessBackend.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "oops/oopsHierarchy.hpp"
+#include "oops/valueKlass.hpp"
 
 template <DecoratorSet decorators>
 template <DecoratorSet idecorators, typename T>
@@ -362,4 +363,9 @@
   dst->init_mark_raw();
 }
 
+template <DecoratorSet decorators>
+inline void RawAccessBarrier<decorators>::value_copy(void* src, void* dst, ValueKlass* md) {
+  assert(is_aligned(src, md->get_alignment()) && is_aligned(dst, md->get_alignment()), "Unalign value_copy");
+  AccessInternal::arraycopy_conjoint_atomic(src, dst, static_cast<size_t>(md->get_exact_size_in_bytes()));
+}
 #endif // SHARE_OOPS_ACCESSBACKEND_INLINE_HPP
--- old/src/hotspot/share/oops/method.cpp	2019-09-26 16:22:14.977671876 +0200
+++ new/src/hotspot/share/oops/method.cpp	2019-09-26 16:22:14.753668033 +0200
@@ -50,7 +50,7 @@
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/methodHandles.hpp"
 #include "prims/nativeLookup.hpp"
--- old/src/hotspot/share/oops/valueArrayKlass.cpp	2019-09-26 16:22:15.657683542 +0200
+++ new/src/hotspot/share/oops/valueArrayKlass.cpp	2019-09-26 16:22:15.385678876 +0200
@@ -248,12 +248,12 @@
            do {
              src -= elem_incr;
              dst -= elem_incr;
-             s_elem_vklass->value_store(src, dst, element_byte_size(), true, false);
+             HeapAccess<>::value_copy(src, dst, s_elem_vklass);
            } while (src > src_end);
          } else {
            address src_end = src + (length << log2_element_size());
            while (src < src_end) {
-             s_elem_vklass->value_store(src, dst, element_byte_size(), true, false);
+             HeapAccess<>::value_copy(src, dst, s_elem_vklass);
              src += elem_incr;
              dst += elem_incr;
            }
@@ -271,9 +271,7 @@
        valueArrayHandle sh(THREAD, sa);
        int dst_end = dst_pos + length;
        while (dst_pos < dst_end) {
-         oop o = s_elem_vklass->allocate_instance(CHECK);
-         s_elem_vklass->value_store(sh->value_at_addr(src_pos, layout_helper()),
-                                             s_elem_vklass->data_for_oop(o), true, true);
+         oop o = valueArrayOopDesc::value_copy_from_index(sh, src_pos, CHECK);
          dh->obj_at_put(dst_pos, o);
          dst_pos++;
          src_pos++;
@@ -298,7 +296,7 @@
        if (se->klass() != d_elem_klass) {
          THROW(vmSymbols::java_lang_ArrayStoreException());
        }
-       d_elem_vklass->value_store(d_elem_vklass->data_for_oop(se), dst, true, false);
+       d_elem_vklass->value_copy_oop_to_payload(se, dst);
        dst += delem_incr;
        src_pos++;
      }
--- old/src/hotspot/share/oops/valueArrayOop.hpp	2019-09-26 16:22:16.349695414 +0200
+++ new/src/hotspot/share/oops/valueArrayOop.hpp	2019-09-26 16:22:16.093691022 +0200
@@ -36,6 +36,12 @@
  public:
   void*  base() const;
   void* value_at_addr(int index, jint lh) const;
+
+  // Return a buffered element from index
+  static oop value_copy_from_index(valueArrayHandle vah, int index, TRAPS);
+  void value_copy_from_index(int index, oop dst) const;
+  void value_copy_to_index(oop src, int index) const;
+
   // Sizing
   static size_t element_size(int lh, int nof_elements) {
     return nof_elements << Klass::layout_helper_log2_element_size(lh);
--- old/src/hotspot/share/oops/valueArrayOop.inline.hpp	2019-09-26 16:22:16.989706394 +0200
+++ new/src/hotspot/share/oops/valueArrayOop.inline.hpp	2019-09-26 16:22:16.729701933 +0200
@@ -28,6 +28,7 @@
 #include "oops/access.inline.hpp"
 #include "oops/arrayOop.inline.hpp"
 #include "oops/valueArrayOop.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/globals.hpp"
 
@@ -45,6 +46,39 @@
   return object_size(klass()->layout_helper(), length());
 }
 
+inline oop valueArrayOopDesc::value_copy_from_index(valueArrayHandle vah, int index, TRAPS) {
+  ValueArrayKlass* vaklass = ValueArrayKlass::cast(vah->klass());
+  ValueKlass* vklass = vaklass->element_klass();
+  if (vklass->is_empty_value()) {
+    return vklass->default_value();
+  } else {
+    oop buf = vklass->allocate_instance(CHECK_NULL);
+    vklass->value_copy_payload_to_new_oop(vah->value_at_addr(index, vaklass->layout_helper()) ,buf);
+    return buf;
+  }
+}
+
+inline void valueArrayOopDesc::value_copy_from_index(int index, oop dst) const {
+  ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass());
+  ValueKlass* vklass = vaklass->element_klass();
+  if (vklass->is_empty_value()) {
+    return; // Assumes dst was a new and clean buffer (OptoRuntime::load_unknown_value())
+  } else {
+    void* src = value_at_addr(index, vaklass->layout_helper());
+    return vklass->value_copy_payload_to_new_oop(src ,dst);
+  }
+}
+
+inline void valueArrayOopDesc::value_copy_to_index(oop src, int index) const {
+  ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass());
+  ValueKlass* vklass = vaklass->element_klass();
+  if (vklass->is_empty_value()) {
+    return;
+  }
+  void* dst = value_at_addr(index, vaklass->layout_helper());
+  vklass->value_copy_oop_to_payload(src, dst);
+}
+
 
 
 #endif // SHARE_VM_OOPS_VALUEARRAYOOP_INLINE_HPP
--- old/src/hotspot/share/oops/valueKlass.cpp	2019-09-26 16:22:17.601716894 +0200
+++ new/src/hotspot/share/oops/valueKlass.cpp	2019-09-26 16:22:17.377713050 +0200
@@ -36,7 +36,7 @@
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/objArrayKlass.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "oops/valueArrayKlass.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/handles.inline.hpp"
@@ -46,6 +46,29 @@
 #include "runtime/thread.inline.hpp"
 #include "utilities/copy.hpp"
 
+  // Constructor
+ValueKlass::ValueKlass(const ClassFileParser& parser)
+    : InstanceKlass(parser, InstanceKlass::_misc_kind_value_type, InstanceKlass::ID) {
+  _adr_valueklass_fixed_block = valueklass_static_block();
+  // Addresses used for value type calling convention
+  *((Array<SigEntry>**)adr_extended_sig()) = NULL;
+  *((Array<VMRegPair>**)adr_return_regs()) = NULL;
+  *((address*)adr_pack_handler()) = NULL;
+  *((address*)adr_unpack_handler()) = NULL;
+  assert(pack_handler() == NULL, "pack handler not null");
+  *((int*)adr_default_value_offset()) = 0;
+  *((Klass**)adr_value_array_klass()) = NULL;
+  set_prototype_header(markWord::always_locked_prototype());
+}
+
+oop ValueKlass::default_value() {
+  oop val = java_mirror()->obj_field_acquire(default_value_offset());
+  assert(oopDesc::is_oop(val), "Sanity check");
+  assert(val->is_value(), "Sanity check");
+  assert(val->klass() == this, "sanity check");
+  return val;
+}
+
 int ValueKlass::first_field_offset_old() {
 #ifdef ASSERT
   int first_offset = INT_MAX;
@@ -191,124 +214,6 @@
     ArrayKlass::cast(get_value_array_klass())->array_klasses_do(f);
 }
 
-void ValueKlass::raw_field_copy(void* src, void* dst, size_t raw_byte_size) {
-  if (!UseNewLayout) {
-    /*
-     * Try not to shear fields even if not an atomic store...
-     *
-     * First 3 cases handle value array store, otherwise works on the same basis
-     * as JVM_Clone, at this size data is aligned. The order of primitive types
-     * is largest to smallest, and it not possible for fields to stradle long
-     * copy boundaries.
-     *
-     * If MT without exclusive access, possible to observe partial value store,
-     * but not partial primitive and reference field values
-     */
-    switch (raw_byte_size) {
-    case 1:
-      *((jbyte*) dst) = *(jbyte*)src;
-      break;
-    case 2:
-      *((jshort*) dst) = *(jshort*)src;
-      break;
-    case 4:
-      *((jint*) dst) = *(jint*) src;
-      break;
-    default:
-      assert(raw_byte_size % sizeof(jlong) == 0, "Unaligned raw_byte_size");
-      Copy::conjoint_jlongs_atomic((jlong*)src, (jlong*)dst, raw_byte_size >> LogBytesPerLong);
-    }
-  } else {
-    int size = this->get_exact_size_in_bytes();
-    int length;
-    switch (this->get_alignment()) {
-    case BytesPerLong:
-      length = size >> LogBytesPerLong;
-      if (length > 0) {
-        Copy::conjoint_jlongs_atomic((jlong*)src, (jlong*)dst, length);
-        size -= length << LogBytesPerLong;
-        src = (jlong*)src + length;
-        dst = (jlong*)dst + length;
-      }
-      // Fallthrough
-    case BytesPerInt:
-      length = size >> LogBytesPerInt;
-      if (length > 0) {
-        Copy::conjoint_jints_atomic((jint*)src, (jint*)dst, length);
-        size -= length << LogBytesPerInt;
-        src = (jint*)src + length;
-        dst = (jint*)dst + length;
-      }
-      // Fallthrough
-    case BytesPerShort:
-      length = size >> LogBytesPerShort;
-      if (length > 0) {
-        Copy::conjoint_jshorts_atomic((jshort*)src, (jshort*)dst, length);
-        size -= length << LogBytesPerShort;
-        src = (jshort*)src + length;
-        dst = (jshort*)dst +length;
-      }
-      // Fallthrough
-    case 1:
-      if (size > 0) Copy::conjoint_jbytes_atomic((jbyte*)src, (jbyte*)dst, size);
-      break;
-    default:
-      fatal("Unsupported alignment");
-    }
-  }
-}
-
-/*
- * Store the value of this klass contained with src into dst.
- *
- * This operation is appropriate for use from vastore, vaload and putfield (for values)
- *
- * GC barriers currently can lock with no safepoint check and allocate c-heap,
- * so raw point is "safe" for now.
- *
- * Going forward, look to use machine generated (stub gen or bc) version for most used klass layouts
- *
- */
-void ValueKlass::value_store(void* src, void* dst, size_t raw_byte_size, bool dst_heap, bool dst_uninitialized) {
-  if (contains_oops()) {
-    if (dst_heap) {
-      // src/dst aren't oops, need offset to adjust oop map offset
-      const address dst_oop_addr = ((address) dst) - first_field_offset();
-
-      ModRefBarrierSet* bs = barrier_set_cast<ModRefBarrierSet>(BarrierSet::barrier_set());
-
-      // Pre-barriers...
-      OopMapBlock* map = start_of_nonstatic_oop_maps();
-      OopMapBlock* const end = map + nonstatic_oop_map_count();
-      while (map != end) {
-        // Shame we can't just use the existing oop iterator...src/dst aren't oop
-        address doop_address = dst_oop_addr + map->offset();
-        // TEMP HACK: barrier code need to migrate to => access API (need own versions of value type ops)
-        if (UseCompressedOops) {
-          bs->write_ref_array_pre((narrowOop*) doop_address, map->count(), dst_uninitialized);
-        } else {
-          bs->write_ref_array_pre((oop*) doop_address, map->count(), dst_uninitialized);
-        }
-        map++;
-      }
-
-      raw_field_copy(src, dst, raw_byte_size);
-
-      // Post-barriers...
-      map = start_of_nonstatic_oop_maps();
-      while (map != end) {
-        address doop_address = dst_oop_addr + map->offset();
-        bs->write_ref_array((HeapWord*) doop_address, map->count());
-        map++;
-      }
-    } else { // Buffered value case
-      raw_field_copy(src, dst, raw_byte_size);
-    }
-  } else {   // Primitive-only case...
-    raw_field_copy(src, dst, raw_byte_size);
-  }
-}
-
 // Value type arguments are not passed by reference, instead each
 // field of the value type is passed as an argument. This helper
 // function collects the fields of the value types (including embedded
--- old/src/hotspot/share/oops/valueKlass.hpp	2019-09-26 16:22:18.281728559 +0200
+++ new/src/hotspot/share/oops/valueKlass.hpp	2019-09-26 16:22:18.021724099 +0200
@@ -28,7 +28,7 @@
 #include "classfile/javaClasses.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/method.hpp"
-#include "oops/oop.inline.hpp"
+//#include "oops/oop.inline.hpp"
 
 // A ValueKlass is a specialized InstanceKlass for value types.
 
@@ -40,19 +40,7 @@
  private:
 
   // Constructor
-  ValueKlass(const ClassFileParser& parser)
-    : InstanceKlass(parser, InstanceKlass::_misc_kind_value_type, InstanceKlass::ID) {
-    _adr_valueklass_fixed_block = valueklass_static_block();
-    // Addresses used for value type calling convention
-    *((Array<SigEntry>**)adr_extended_sig()) = NULL;
-    *((Array<VMRegPair>**)adr_return_regs()) = NULL;
-    *((address*)adr_pack_handler()) = NULL;
-    *((address*)adr_unpack_handler()) = NULL;
-    assert(pack_handler() == NULL, "pack handler not null");
-    *((int*)adr_default_value_offset()) = 0;
-    *((Klass**)adr_value_array_klass()) = NULL;
-    set_prototype_header(markWord::always_locked_prototype());
-  }
+  ValueKlass(const ClassFileParser& parser);
 
   ValueKlassFixedBlock* valueklass_static_block() const {
     address adr_jf = adr_value_fields_klasses();
@@ -153,7 +141,7 @@
     *(int*)adr_first_field_offset() = offset;
   }
 
-  int get_exact_size_in_bytes() {
+  int get_exact_size_in_bytes() const {
     return *(int*)adr_exact_size_in_bytes();
   }
 
@@ -188,10 +176,7 @@
   oop indirect_mirror() const { return java_lang_Class::indirect_type_mirror(java_mirror()); }
 
   // Casting from Klass*
-  static ValueKlass* cast(Klass* k) {
-    assert(k->is_value(), "cast to ValueKlass");
-    return (ValueKlass*) k;
-  }
+  static ValueKlass* cast(Klass* k);
 
   // Use this to return the size of an instance in heap words
   // Implementation is currently simple because all value types are allocated
@@ -209,15 +194,8 @@
   // minimum number of bytes occupied by nonstatic fields, HeapWord aligned or pow2
   int raw_value_byte_size();
 
-  address data_for_oop(oop o) const {
-    return ((address) (void*) o) + first_field_offset();
-  }
-
-  oop oop_for_data(address data) const {
-    oop o = (oop) (data - first_field_offset());
-    assert(oopDesc::is_oop(o, false), "Not an oop");
-    return o;
-  }
+  address data_for_oop(oop o) const;
+  oop oop_for_data(address data) const;
 
   // Query if h/w provides atomic load/store
   bool is_atomic();
@@ -227,17 +205,18 @@
   bool contains_oops() const { return nonstatic_oop_map_count() > 0; }
   int nonstatic_oop_count();
 
-  // Prototype general store methods...
+  // General store methods
+  //
+  // Normally loads and store methods would be found in *Oops classes, but since values can be
+  // "in-lined" (flattened) into containing oops, these methods reside here in ValueKlass.
+  //
+  // "value_copy_*_to_new_*" assume new memory (i.e. IS_DEST_UNINITIALIZED for write barriers)
+
+  void value_copy_payload_to_new_oop(void* src, oop dst);
+  void value_copy_oop_to_new_oop(oop src, oop dst);
+  void value_copy_oop_to_new_payload(oop src, void* dst);
 
-  // copy the fields, with no concern for GC barriers
-  void raw_field_copy(void* src, void* dst, size_t raw_byte_size);
-
-  void value_store(void* src, void* dst, bool dst_is_heap, bool dst_uninitialized) {
-    value_store(src, dst, nonstatic_field_size() << LogBytesPerHeapOop, dst_is_heap, dst_uninitialized);
-  }
-
-  // store the value of this klass contained with src into dst, raw data ptr
-  void value_store(void* src, void* dst, size_t raw_byte_size, bool dst_is_heap, bool dst_uninitialized);
+  void value_copy_oop_to_payload(oop src, void* dst);
 
   // oop iterate raw value type data pointer (where oop_addr may not be an oop, but backing/array-element)
   template <typename T, class OopClosureType>
@@ -298,14 +277,7 @@
     indirect_mirror()->obj_field_put(default_value_offset(), val);
   }
 
-  oop default_value() {
-    oop val = java_mirror()->obj_field_acquire(default_value_offset());
-    assert(oopDesc::is_oop(val), "Sanity check");
-    assert(val->is_value(), "Sanity check");
-    assert(val->klass() == this, "sanity check");
-    return val;
-  }
-
+  oop default_value();
   void deallocate_contents(ClassLoaderData* loader_data);
   static void cleanup(ValueKlass* ik) ;
 
--- old/src/hotspot/share/oops/valueKlass.inline.hpp	2019-09-26 16:22:18.957740157 +0200
+++ new/src/hotspot/share/oops/valueKlass.inline.hpp	2019-09-26 16:22:18.693735628 +0200
@@ -31,6 +31,38 @@
 #include "oops/valueKlass.hpp"
 #include "utilities/macros.hpp"
 
+inline ValueKlass* ValueKlass::cast(Klass* k) {
+  assert(k->is_value(), "cast to ValueKlass");
+  return (ValueKlass*) k;
+}
+
+inline address ValueKlass::data_for_oop(oop o) const {
+  return ((address) (void*) o) + first_field_offset();
+}
+
+inline oop ValueKlass::oop_for_data(address data) const {
+  oop o = (oop) (data - first_field_offset());
+  assert(oopDesc::is_oop(o, false), "Not an oop");
+  return o;
+}
+
+inline void ValueKlass::value_copy_payload_to_new_oop(void* src, oop dst) {
+  HeapAccess<IS_DEST_UNINITIALIZED>::value_copy(src, data_for_oop(dst), this);
+}
+
+inline void ValueKlass::value_copy_oop_to_new_oop(oop src, oop dst) {
+  HeapAccess<IS_DEST_UNINITIALIZED>::value_copy(data_for_oop(src), data_for_oop(dst), this);
+}
+
+inline void ValueKlass::value_copy_oop_to_new_payload(oop src, void* dst) {
+  HeapAccess<IS_DEST_UNINITIALIZED>::value_copy(data_for_oop(src), dst, this);
+}
+
+inline void ValueKlass::value_copy_oop_to_payload(oop src, void* dst) {
+  HeapAccess<>::value_copy(data_for_oop(src), dst, this);
+}
+
+
 template <typename T, class OopClosureType>
 void ValueKlass::oop_iterate_specialized(const address oop_addr, OopClosureType* closure) {
   OopMapBlock* map = start_of_nonstatic_oop_maps();
--- old/src/hotspot/share/opto/runtime.cpp	2019-09-26 16:22:19.681752578 +0200
+++ new/src/hotspot/share/opto/runtime.cpp	2019-09-26 16:22:19.389747568 +0200
@@ -1744,14 +1744,7 @@
 
 JRT_LEAF(void, OptoRuntime::load_unknown_value(valueArrayOopDesc* array, int index, instanceOopDesc* buffer))
 {
-  Klass* klass = array->klass();
-  assert(klass->is_valueArray_klass(), "expected value array oop");
-
-  ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
-  ValueKlass* vklass = vaklass->element_klass();
-  void* src = array->value_at_addr(index, vaklass->layout_helper());
-  vklass->value_store(src, vklass->data_for_oop(buffer),
-                        vaklass->element_byte_size(), true, false);
+  array->value_copy_from_index(index, buffer);
 }
 JRT_END
 
@@ -1777,15 +1770,7 @@
 JRT_LEAF(void, OptoRuntime::store_unknown_value(instanceOopDesc* buffer, valueArrayOopDesc* array, int index))
 {
   assert(buffer != NULL, "can't store null into flat array");
-  Klass* klass = array->klass();
-  assert(klass->is_valueArray_klass(), "expected value array");
-  assert(ArrayKlass::cast(klass)->element_klass() == buffer->klass(), "Store type incorrect");
-
-  ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass);
-  ValueKlass* vklass = vaklass->element_klass();
-  const int lh = vaklass->layout_helper();
-  vklass->value_store(vklass->data_for_oop(buffer), array->value_at_addr(index, lh),
-                      vaklass->element_byte_size(), true, false);
+  array->value_copy_to_index(buffer, index);
 }
 JRT_END
 
--- old/src/hotspot/share/prims/jni.cpp	2019-09-26 16:22:20.349764038 +0200
+++ new/src/hotspot/share/prims/jni.cpp	2019-09-26 16:22:20.085759509 +0200
@@ -58,7 +58,7 @@
 #include "oops/symbol.hpp"
 #include "oops/typeArrayKlass.hpp"
 #include "oops/typeArrayOop.inline.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "prims/jniCheck.hpp"
 #include "prims/jniExport.hpp"
 #include "prims/jniFastGetField.hpp"
--- old/src/hotspot/share/prims/unsafe.cpp	2019-09-26 16:22:20.985774949 +0200
+++ new/src/hotspot/share/prims/unsafe.cpp	2019-09-26 16:22:20.761771106 +0200
@@ -39,8 +39,8 @@
 #include "oops/oop.inline.hpp"
 #include "oops/typeArrayOop.inline.hpp"
 #include "oops/valueArrayKlass.hpp"
-#include "oops/valueArrayOop.hpp"
 #include "oops/valueArrayOop.inline.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "prims/unsafe.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
@@ -368,9 +368,7 @@
   Handle base_h(THREAD, base);
   oop v = vk->allocate_instance(CHECK_NULL); // allocate instance
   vk->initialize(CHECK_NULL); // If field is a default value, value class might not be initialized yet
-  vk->value_store(((address)(oopDesc*)base_h()) + offset,
-                  vk->data_for_oop(v),
-                  true, true);
+  vk->value_copy_payload_to_new_oop(((address)(oopDesc*)base_h()) + offset, v);
   return JNIHandles::make_local(env, v);
 } UNSAFE_END
 
@@ -381,8 +379,7 @@
   assert(!base->is_value() || base->mark().is_larval_state(), "must be an object instance or a larval value");
   assert_and_log_unsafe_value_access(base, offset, vk);
   oop v = JNIHandles::resolve(value);
-  vk->value_store(vk->data_for_oop(v),
-                 ((address)(oopDesc*)base) + offset, true, true);
+  vk->value_copy_oop_to_payload(v, ((address)(oopDesc*)base) + offset);
 } UNSAFE_END
 
 UNSAFE_ENTRY(jobject, Unsafe_MakePrivateBuffer(JNIEnv *env, jobject unsafe, jobject value)) {
@@ -391,7 +388,7 @@
   Handle vh(THREAD, v);
   ValueKlass* vk = ValueKlass::cast(v->klass());
   instanceOop new_value = vk->allocate_instance(CHECK_NULL);
-  vk->value_store(vk->data_for_oop(vh()), vk->data_for_oop(new_value), true, false);
+  vk->value_copy_oop_to_new_oop(vh(),  new_value);
   markWord mark = new_value->mark();
   new_value->set_mark(mark.enter_larval_state());
   return JNIHandles::make_local(env, new_value);
--- old/src/hotspot/share/runtime/deoptimization.cpp	2019-09-26 16:22:21.677786821 +0200
+++ new/src/hotspot/share/runtime/deoptimization.cpp	2019-09-26 16:22:21.417782361 +0200
@@ -47,7 +47,7 @@
 #include "oops/typeArrayOop.inline.hpp"
 #include "oops/valueArrayKlass.hpp"
 #include "oops/valueArrayOop.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "oops/verifyOopClosure.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/biasedLocking.hpp"
--- old/src/hotspot/share/runtime/reflection.cpp	2019-09-26 16:22:22.381798899 +0200
+++ new/src/hotspot/share/runtime/reflection.cpp	2019-09-26 16:22:22.109794233 +0200
@@ -40,7 +40,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "oops/typeArrayOop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "runtime/arguments.hpp"
--- old/src/hotspot/share/runtime/sharedRuntime.cpp	2019-09-26 16:22:22.969808986 +0200
+++ new/src/hotspot/share/runtime/sharedRuntime.cpp	2019-09-26 16:22:22.749805212 +0200
@@ -54,7 +54,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "prims/forte.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/methodHandles.hpp"
--- old/src/hotspot/share/runtime/signature.cpp	2019-09-26 16:22:23.661820858 +0200
+++ new/src/hotspot/share/runtime/signature.cpp	2019-09-26 16:22:23.385816123 +0200
@@ -32,7 +32,7 @@
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayKlass.hpp"
-#include "oops/valueKlass.hpp"
+#include "oops/valueKlass.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/signature.hpp"
 
--- old/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueOops.java	2019-09-26 16:22:24.329832318 +0200
+++ new/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueOops.java	2019-09-26 16:22:24.085828132 +0200
@@ -34,9 +34,8 @@
 import jdk.experimental.value.MethodHandleBuilder;
 
 /**
- * @test ValueOops
- * @requires vm.gc == null
- * @requires vm.opt.ExplicitGCInvokesConcurrent != true
+ * @test ValueOops_int_Serial
+ * @requires vm.gc.Serial
  * @summary Test embedding oops into Value types
  * @modules java.base/jdk.experimental.bytecode
  *          java.base/jdk.experimental.value
@@ -48,24 +47,107 @@
  * @run main/othervm -Xint -XX:+UseSerialGC -Xmx128m
  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  *                   runtime.valhalla.valuetypes.ValueOops
+ */
+
+/**
+ * @test ValueOops_int_G1
+ * @requires vm.gc.G1
+ * @summary Test embedding oops into Value types
+ * @modules java.base/jdk.experimental.bytecode
+ *          java.base/jdk.experimental.value
+ * @library /test/lib
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                   sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main/othervm -Xint  -XX:+UseG1GC -Xmx128m
  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  *                   runtime.valhalla.valuetypes.ValueOops 100
+ */
+
+/**
+ * @test ValueOops_int_Parallel
+ * @requires vm.gc.Parallel
+ * @summary Test embedding oops into Value types
+ * @modules java.base/jdk.experimental.bytecode
+ *          java.base/jdk.experimental.value
+ * @library /test/lib
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                   sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main/othervm -Xint -XX:+UseParallelGC -Xmx128m
  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  *                   runtime.valhalla.valuetypes.ValueOops
+ */
+
+/**
+ * @test ValueOops_int_Z
+ * @requires vm.gc.Z
+ * @summary Test embedding oops into Value types
+ * @modules java.base/jdk.experimental.bytecode
+ *          java.base/jdk.experimental.value
+ * @library /test/lib
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                   sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xint -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx128m
+ *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *                   runtime.valhalla.valuetypes.ValueOops
+ */
+
+/**
+ * @test ValueOops_comp_serial
+ * @requires vm.gc.Serial
+ * @summary Test embedding oops into Value types
+ * @modules java.base/jdk.experimental.bytecode
+ *          java.base/jdk.experimental.value
+ * @library /test/lib
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                   sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main/othervm -Xcomp -XX:+UseSerialGC -Xmx128m
  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  *                   runtime.valhalla.valuetypes.ValueOops
+ */
+
+/**
+ * @test ValueOops_comp_G1
+ * @requires vm.gc.G1
+ * @summary Test embedding oops into Value types
+ * @modules java.base/jdk.experimental.bytecode
+ *          java.base/jdk.experimental.value
+ * @library /test/lib
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                   sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main/othervm -Xcomp -XX:+UseG1GC -Xmx128m
  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  *                   runtime.valhalla.valuetypes.ValueOops 100
+ */
+
+/**
+ * @test ValueOops_comp_Parallel
+ * @requires vm.gc.Parallel
+ * @summary Test embedding oops into Value types
+ * @modules java.base/jdk.experimental.bytecode
+ *          java.base/jdk.experimental.value
+ * @library /test/lib
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java
+ * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                   sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main/othervm -Xcomp -XX:+UseParallelGC -Xmx128m
  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  *                   runtime.valhalla.valuetypes.ValueOops
  */
 public class ValueOops {
 
+    // Xcomp with ZGC missing until C1 and C2 barrier code is in place (JDK-8231498)
+
     // Extra debug: -XX:+VerifyOops -XX:+VerifyStack -XX:+VerifyLastFrame -XX:+VerifyBeforeGC -XX:+VerifyAfterGC -XX:+VerifyDuringGC -XX:VerifySubSet=threads,heap
     // Even more debugging: -XX:+TraceNewOopMapGeneration -Xlog:gc*=info