8198285: More consistent Access API for arraycopy
authorrkennke
Mon, 04 Jun 2018 23:01:48 +0200
changeset 50389 7e8c0409a747
parent 50388 55fac6146d31
child 50390 f4c4a86d1c12
8198285: More consistent Access API for arraycopy Reviewed-by: eosterlund, shade
src/hotspot/share/classfile/javaClasses.cpp
src/hotspot/share/classfile/systemDictionaryShared.cpp
src/hotspot/share/gc/shared/barrierSet.hpp
src/hotspot/share/gc/shared/modRefBarrierSet.hpp
src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp
src/hotspot/share/oops/access.hpp
src/hotspot/share/oops/access.inline.hpp
src/hotspot/share/oops/accessBackend.cpp
src/hotspot/share/oops/accessBackend.hpp
src/hotspot/share/oops/accessBackend.inline.hpp
src/hotspot/share/oops/arrayOop.hpp
src/hotspot/share/oops/objArrayKlass.cpp
src/hotspot/share/oops/objArrayKlass.hpp
src/hotspot/share/oops/typeArrayKlass.cpp
src/hotspot/share/oops/typeArrayOop.hpp
src/hotspot/share/oops/typeArrayOop.inline.hpp
src/hotspot/share/opto/runtime.cpp
src/hotspot/share/prims/jni.cpp
src/hotspot/share/prims/unsafe.cpp
src/hotspot/share/runtime/stubRoutines.cpp
--- a/src/hotspot/share/classfile/javaClasses.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -310,7 +310,8 @@
   Handle h_obj = basic_create(length, is_latin1, CHECK_NH);
   if (length > 0) {
     if (!has_multibyte) {
-      strncpy((char*)value(h_obj())->byte_at_addr(0), utf8_str, length);
+      const jbyte* src = reinterpret_cast<const jbyte*>(utf8_str);
+      ArrayAccess<>::arraycopy_from_native(src, value(h_obj()), typeArrayOopDesc::element_offset<jbyte>(0), length);
     } else if (is_latin1) {
       UTF8::convert_to_unicode(utf8_str, value(h_obj())->byte_at_addr(0), length);
     } else {
@@ -356,7 +357,8 @@
   Handle h_obj = basic_create(length, is_latin1, CHECK_NH);
   if (length > 0) {
     if (!has_multibyte) {
-      strncpy((char*)value(h_obj())->byte_at_addr(0), utf8_str, length);
+      const jbyte* src = reinterpret_cast<const jbyte*>(utf8_str);
+      ArrayAccess<>::arraycopy_from_native(src, value(h_obj()), typeArrayOopDesc::element_offset<jbyte>(0), length);
     } else if (is_latin1) {
       UTF8::convert_to_unicode(utf8_str, value(h_obj())->byte_at_addr(0), length);
     } else {
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -87,8 +87,8 @@
     assert(src != NULL, "No Manifest data");
     typeArrayOop buf = oopFactory::new_byteArray(size, CHECK_NH);
     typeArrayHandle bufhandle(THREAD, buf);
-    char* dst = (char*)(buf->byte_at_addr(0));
-    memcpy(dst, src, (size_t)size);
+    ArrayAccess<>::arraycopy_from_native(reinterpret_cast<const jbyte*>(src),
+                                         buf, typeArrayOopDesc::element_offset<jbyte>(0), size);
 
     Handle bais = JavaCalls::construct_new_instance(SystemDictionary::ByteArrayInputStream_klass(),
                       vmSymbols::byte_array_void_signature(),
--- a/src/hotspot/share/gc/shared/barrierSet.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/gc/shared/barrierSet.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -213,8 +213,12 @@
     }
 
     template <typename T>
-    static void arraycopy_in_heap(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
-      Raw::arraycopy(src_obj, dst_obj, src, dst, length);
+    static void arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                  arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                  size_t length) {
+      Raw::arraycopy(src_obj, src_offset_in_bytes, src_raw,
+                     dst_obj, dst_offset_in_bytes, dst_raw,
+                     length);
     }
 
     // Heap oop accesses. These accessors get resolved when
@@ -257,8 +261,12 @@
     }
 
     template <typename T>
-    static bool oop_arraycopy_in_heap(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
-      return Raw::oop_arraycopy(src_obj, dst_obj, src, dst, length);
+    static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                      arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                      size_t length) {
+      return Raw::oop_arraycopy(src_obj, src_offset_in_bytes, src_raw,
+                                dst_obj, dst_offset_in_bytes, dst_raw,
+                                length);
     }
 
     // Off-heap oop accesses. These accessors get resolved when
--- a/src/hotspot/share/gc/shared/modRefBarrierSet.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/gc/shared/modRefBarrierSet.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -83,7 +83,9 @@
     static oop oop_atomic_xchg_in_heap(oop new_value, T* addr);
 
     template <typename T>
-    static bool oop_arraycopy_in_heap(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length);
+    static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                      arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                      size_t length);
 
     static void clone_in_heap(oop src, oop dst, size_t size);
 
--- a/src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -91,35 +91,41 @@
 template <DecoratorSet decorators, typename BarrierSetT>
 template <typename T>
 inline bool ModRefBarrierSet::AccessBarrier<decorators, BarrierSetT>::
-oop_arraycopy_in_heap(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
+oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                      arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                      size_t length) {
   BarrierSetT *bs = barrier_set_cast<BarrierSetT>(barrier_set());
 
+  src_raw = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw);
+  dst_raw = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw);
+
   if (!HasDecorator<decorators, ARRAYCOPY_CHECKCAST>::value) {
     // Optimized covariant case
-    bs->write_ref_array_pre(dst, length,
+    bs->write_ref_array_pre(dst_raw, length,
                             HasDecorator<decorators, AS_DEST_NOT_INITIALIZED>::value);
-    Raw::oop_arraycopy(src_obj, dst_obj, src, dst, length);
-    bs->write_ref_array((HeapWord*)dst, length);
+    Raw::oop_arraycopy(NULL, 0, src_raw, NULL, 0, dst_raw, length);
+    bs->write_ref_array((HeapWord*)dst_raw, length);
   } else {
+    assert(dst_obj != NULL, "better have an actual oop");
     Klass* bound = objArrayOop(dst_obj)->element_klass();
-    T* from = src;
+    T* from = const_cast<T*>(src_raw);
     T* end = from + length;
-    for (T* p = dst; from < end; from++, p++) {
+    for (T* p = dst_raw; from < end; from++, p++) {
       T element = *from;
       if (oopDesc::is_instanceof_or_null(CompressedOops::decode(element), bound)) {
         bs->template write_ref_field_pre<decorators>(p);
         *p = element;
       } else {
         // We must do a barrier to cover the partial copy.
-        const size_t pd = pointer_delta(p, dst, (size_t)heapOopSize);
+        const size_t pd = pointer_delta(p, dst_raw, (size_t)heapOopSize);
         // pointer delta is scaled to number of elements (length field in
         // objArrayOop) which we assume is 32 bit.
         assert(pd == (size_t)(int)pd, "length field overflow");
-        bs->write_ref_array((HeapWord*)dst, pd);
+        bs->write_ref_array((HeapWord*)dst_raw, pd);
         return false;
       }
     }
-    bs->write_ref_array((HeapWord*)dst, length);
+    bs->write_ref_array((HeapWord*)dst_raw, length);
   }
   return true;
 }
--- a/src/hotspot/share/oops/access.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/access.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -55,7 +55,7 @@
 // * atomic_cmpxchg_at: Atomically compare-and-swap a new value at an internal pointer address if previous value matched the compared value.
 // * atomic_xchg: Atomically swap a new value at an address if previous value matched the compared value.
 // * 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.
+// * 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.
 // * resolve: Resolve a stable to-space invariant oop that is guaranteed not to relocate its payload until a subsequent thread transition.
 // * equals: Object equality, e.g. when different copies of the same objects are in use (from-space vs. to-space)
@@ -130,6 +130,29 @@
   static const DecoratorSet atomic_xchg_mo_decorators = MO_SEQ_CST;
   static const DecoratorSet atomic_cmpxchg_mo_decorators = MO_RELAXED | MO_SEQ_CST;
 
+protected:
+  template <typename T>
+  static inline bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
+                                   arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                   size_t length) {
+    verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |  IN_HEAP_ARRAY |
+                      AS_DECORATOR_MASK>();
+    return AccessInternal::arraycopy<decorators | INTERNAL_VALUE_IS_OOP>(src_obj, src_offset_in_bytes, src_raw,
+                                                                         dst_obj, dst_offset_in_bytes, dst_raw,
+                                                                         length);
+  }
+
+  template <typename T>
+  static inline void arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
+                               arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                               size_t length) {
+    verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP | IN_HEAP_ARRAY |
+                      AS_DECORATOR_MASK>();
+    AccessInternal::arraycopy<decorators>(src_obj, src_offset_in_bytes, src_raw,
+                                          dst_obj, dst_offset_in_bytes, dst_raw,
+                                          length);
+  }
+
 public:
   // Primitive heap accesses
   static inline AccessInternal::LoadAtProxy<decorators> load_at(oop base, ptrdiff_t offset) {
@@ -155,13 +178,6 @@
     return AccessInternal::atomic_xchg_at<decorators>(new_value, base, offset);
   }
 
-  template <typename T>
-  static inline void arraycopy(arrayOop src_obj, arrayOop dst_obj, T *src, T *dst, size_t length) {
-    verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
-                      AS_DECORATOR_MASK>();
-    AccessInternal::arraycopy<decorators>(src_obj, dst_obj, src, dst, length);
-  }
-
   // Oop heap accesses
   static inline AccessInternal::OopLoadAtProxy<decorators> oop_load_at(oop base, ptrdiff_t offset) {
     verify_heap_oop_decorators<load_mo_decorators>();
@@ -193,12 +209,6 @@
     return AccessInternal::atomic_xchg_at<decorators | INTERNAL_VALUE_IS_OOP>(new_oop_value, base, offset);
   }
 
-  template <typename T>
-  static inline bool oop_arraycopy(arrayOop src_obj, arrayOop dst_obj, T *src, T *dst, size_t length) {
-    verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP | AS_DECORATOR_MASK>();
-    return AccessInternal::arraycopy<decorators | INTERNAL_VALUE_IS_OOP>(src_obj, dst_obj, src, dst, length);
-  }
-
   // Clone an object from src to dst
   static inline void clone(oop src, oop dst, size_t size) {
     verify_decorators<IN_HEAP>();
@@ -288,6 +298,55 @@
 template <DecoratorSet decorators = INTERNAL_EMPTY>
 class RootAccess: public Access<IN_ROOT | decorators> {};
 
+// Helper for array access.
+template <DecoratorSet decorators = INTERNAL_EMPTY>
+class ArrayAccess: public HeapAccess<IN_HEAP_ARRAY | decorators> {
+  typedef HeapAccess<IN_HEAP_ARRAY | decorators> AccessT;
+public:
+  template <typename T>
+  static inline void arraycopy(arrayOop src_obj, size_t src_offset_in_bytes,
+                               arrayOop dst_obj, size_t dst_offset_in_bytes,
+                               size_t length) {
+    AccessT::arraycopy(src_obj, src_offset_in_bytes, reinterpret_cast<const T*>(NULL),
+                       dst_obj, dst_offset_in_bytes, reinterpret_cast<T*>(NULL),
+                       length);
+  }
+
+  template <typename T>
+  static inline void arraycopy_to_native(arrayOop src_obj, size_t src_offset_in_bytes,
+                                         T* dst,
+                                         size_t length) {
+    AccessT::arraycopy(src_obj, src_offset_in_bytes, reinterpret_cast<const T*>(NULL),
+                       NULL, 0, dst,
+                       length);
+  }
+
+  template <typename T>
+  static inline void arraycopy_from_native(const T* src,
+                                           arrayOop dst_obj, size_t dst_offset_in_bytes,
+                                           size_t length) {
+    AccessT::arraycopy(NULL, 0, src,
+                       dst_obj, dst_offset_in_bytes, reinterpret_cast<T*>(NULL),
+                       length);
+  }
+
+  static inline bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes,
+                                   arrayOop dst_obj, size_t dst_offset_in_bytes,
+                                   size_t length) {
+    return AccessT::oop_arraycopy(src_obj, src_offset_in_bytes, reinterpret_cast<const HeapWord*>(NULL),
+                                  dst_obj, dst_offset_in_bytes, reinterpret_cast<HeapWord*>(NULL),
+                                  length);
+  }
+
+  template <typename T>
+  static inline bool oop_arraycopy_raw(T* src, T* dst, size_t length) {
+    return AccessT::oop_arraycopy(NULL, 0, src,
+                                  NULL, 0, dst,
+                                  length);
+  }
+
+};
+
 template <DecoratorSet decorators>
 template <DecoratorSet expected_decorators>
 void Access<decorators>::verify_decorators() {
--- a/src/hotspot/share/oops/access.inline.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/access.inline.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -123,17 +123,23 @@
   template <class GCBarrierType, DecoratorSet decorators>
   struct PostRuntimeDispatch<GCBarrierType, BARRIER_ARRAYCOPY, decorators>: public AllStatic {
     template <typename T>
-    static bool access_barrier(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
-      GCBarrierType::arraycopy_in_heap(src_obj, dst_obj, src, dst, length);
+    static bool access_barrier(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                               arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                               size_t length) {
+      GCBarrierType::arraycopy_in_heap(src_obj, src_offset_in_bytes, src_raw,
+                                       dst_obj, dst_offset_in_bytes, dst_raw,
+                                       length);
       return true;
     }
 
     template <typename T>
-    static bool oop_access_barrier(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
+    static bool oop_access_barrier(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                   arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                   size_t length) {
       typedef typename HeapOopType<decorators>::type OopType;
-      return GCBarrierType::oop_arraycopy_in_heap(src_obj, dst_obj,
-                                                  reinterpret_cast<OopType*>(src),
-                                                  reinterpret_cast<OopType*>(dst), length);
+      return GCBarrierType::oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, reinterpret_cast<OopType*>(src_raw),
+                                                  dst_obj, dst_offset_in_bytes, reinterpret_cast<OopType*>(dst_raw),
+                                                  length);
     }
   };
 
@@ -337,10 +343,14 @@
   }
 
   template <DecoratorSet decorators, typename T>
-  bool RuntimeDispatch<decorators, T, BARRIER_ARRAYCOPY>::arraycopy_init(arrayOop src_obj, arrayOop dst_obj, T *src, T* dst, size_t length) {
+  bool RuntimeDispatch<decorators, T, BARRIER_ARRAYCOPY>::arraycopy_init(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                                                         arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                                                         size_t length) {
     func_t function = BarrierResolver<decorators, func_t, BARRIER_ARRAYCOPY>::resolve_barrier();
     _arraycopy_func = function;
-    return function(src_obj, dst_obj, src, dst, length);
+    return function(src_obj, src_offset_in_bytes, src_raw,
+                    dst_obj, dst_offset_in_bytes, dst_raw,
+                    length);
   }
 
   template <DecoratorSet decorators, typename T>
--- a/src/hotspot/share/oops/accessBackend.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/accessBackend.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -105,11 +105,21 @@
   }
 
   template<>
+  void arraycopy_conjoint<jboolean>(jboolean* src, jboolean* dst, size_t length) {
+    Copy::conjoint_jbytes(reinterpret_cast<jbyte*>(src), reinterpret_cast<jbyte*>(dst), length);
+  }
+
+  template<>
   void arraycopy_conjoint<jbyte>(jbyte* src, jbyte* dst, size_t length) {
     Copy::conjoint_jbytes(src, dst, length);
   }
 
   template<>
+  void arraycopy_conjoint<jchar>(jchar* src, jchar* dst, size_t length) {
+    Copy::conjoint_jshorts_atomic(reinterpret_cast<jshort*>(src), reinterpret_cast<jshort*>(dst), length);
+  }
+
+  template<>
   void arraycopy_conjoint<jshort>(jshort* src, jshort* dst, size_t length) {
     Copy::conjoint_jshorts_atomic(src, dst, length);
   }
@@ -120,11 +130,21 @@
   }
 
   template<>
+  void arraycopy_conjoint<jfloat>(jfloat* src, jfloat* dst, size_t length) {
+    Copy::conjoint_jints_atomic(reinterpret_cast<jint*>(src), reinterpret_cast<jint*>(dst), length);
+  }
+
+  template<>
   void arraycopy_conjoint<jlong>(jlong* src, jlong* dst, size_t length) {
     Copy::conjoint_jlongs_atomic(src, dst, length);
   }
 
   template<>
+  void arraycopy_conjoint<jdouble>(jdouble* src, jdouble* dst, size_t length) {
+    Copy::conjoint_jlongs_atomic(reinterpret_cast<jlong*>(src), reinterpret_cast<jlong*>(dst), length);
+  }
+
+  template<>
   void arraycopy_arrayof_conjoint<jbyte>(jbyte* src, jbyte* dst, size_t length) {
     Copy::arrayof_conjoint_jbytes(reinterpret_cast<HeapWord*>(src),
                                   reinterpret_cast<HeapWord*>(dst),
--- a/src/hotspot/share/oops/accessBackend.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/accessBackend.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -110,7 +110,9 @@
     typedef T (*atomic_cmpxchg_func_t)(T new_value, void* addr, T compare_value);
     typedef T (*atomic_xchg_func_t)(T new_value, void* addr);
 
-    typedef bool (*arraycopy_func_t)(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length);
+    typedef bool (*arraycopy_func_t)(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                     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 oop (*resolve_func_t)(oop obj);
     typedef bool (*equals_func_t)(oop o1, oop o2);
@@ -118,7 +120,9 @@
 
   template <DecoratorSet decorators>
   struct AccessFunctionTypes<decorators, void> {
-    typedef bool (*arraycopy_func_t)(arrayOop src_obj, arrayOop dst_obj, void* src, void* dst, size_t length);
+    typedef bool (*arraycopy_func_t)(arrayOop src_obj, size_t src_offset_in_bytes, void* src,
+                                     arrayOop dst_obj, size_t dst_offset_in_bytes, void* dst,
+                                     size_t length);
   };
 
   template <DecoratorSet decorators, typename T, BarrierType barrier> struct AccessFunction {};
@@ -256,7 +260,7 @@
   static inline typename EnableIf<
     HasDecorator<ds, MO_UNORDERED>::value, T>::type
   load_internal(void* addr) {
-    return *reinterpret_cast<const T*>(addr);
+    return *reinterpret_cast<T*>(addr);
   }
 
   template <DecoratorSet ds, typename T>
@@ -353,7 +357,9 @@
   }
 
   template <typename T>
-  static bool arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length);
+  static bool arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                        arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                        size_t length);
 
   template <typename T>
   static void oop_store(void* addr, T value);
@@ -396,7 +402,9 @@
   }
 
   template <typename T>
-  static bool oop_arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length);
+  static bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                            arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                            size_t length);
 
   static void clone(oop src, oop dst, size_t size);
 
@@ -559,10 +567,16 @@
     typedef typename AccessFunction<decorators, T, BARRIER_ARRAYCOPY>::type func_t;
     static func_t _arraycopy_func;
 
-    static bool arraycopy_init(arrayOop src_obj, arrayOop dst_obj, T *src, T* dst, size_t length);
+    static bool arraycopy_init(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                               arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                               size_t length);
 
-    static inline bool arraycopy(arrayOop src_obj, arrayOop dst_obj, T *src, T* dst, size_t length) {
-      return _arraycopy_func(src_obj, dst_obj, src, dst, length);
+    static inline bool arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                 size_t length) {
+      return _arraycopy_func(src_obj, src_offset_in_bytes, src_raw,
+                             dst_obj, dst_offset_in_bytes, dst_raw,
+                             length);
     }
   };
 
@@ -900,37 +914,55 @@
     template <DecoratorSet decorators, typename T>
     inline static typename EnableIf<
       HasDecorator<decorators, AS_RAW>::value && CanHardwireRaw<decorators>::value, bool>::type
-    arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
+    arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+              arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+              size_t length) {
       typedef RawAccessBarrier<decorators & RAW_DECORATOR_MASK> Raw;
       if (HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::value) {
-        return Raw::oop_arraycopy(src_obj, dst_obj, src, dst, length);
+        return Raw::oop_arraycopy(src_obj, src_offset_in_bytes, src_raw,
+                                  dst_obj, dst_offset_in_bytes, dst_raw,
+                                  length);
       } else {
-        return Raw::arraycopy(src_obj, dst_obj, src, dst, length);
+        return Raw::arraycopy(src_obj, src_offset_in_bytes, src_raw,
+                              dst_obj, dst_offset_in_bytes, dst_raw,
+                              length);
       }
     }
 
     template <DecoratorSet decorators, typename T>
     inline static typename EnableIf<
       HasDecorator<decorators, AS_RAW>::value && !CanHardwireRaw<decorators>::value, bool>::type
-    arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
+    arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+              arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+              size_t length) {
       if (UseCompressedOops) {
         const DecoratorSet expanded_decorators = decorators | convert_compressed_oops;
-        return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, dst_obj, src, dst, length);
+        return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw,
+                                                                  dst_obj, dst_offset_in_bytes, dst_raw,
+                                                                  length);
       } else {
         const DecoratorSet expanded_decorators = decorators & ~convert_compressed_oops;
-        return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, dst_obj, src, dst, length);
+        return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw,
+                                                                  dst_obj, dst_offset_in_bytes, dst_raw,
+                                                                  length);
       }
     }
 
     template <DecoratorSet decorators, typename T>
     inline static typename EnableIf<
       !HasDecorator<decorators, AS_RAW>::value, bool>::type
-    arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
+    arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+              arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+              size_t length) {
       if (is_hardwired_primitive<decorators>()) {
         const DecoratorSet expanded_decorators = decorators | AS_RAW;
-        return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, dst_obj, src, dst, length);
+        return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw,
+                                                                  dst_obj, dst_offset_in_bytes, dst_raw,
+                                                                  length);
       } else {
-        return RuntimeDispatch<decorators, T, BARRIER_ARRAYCOPY>::arraycopy(src_obj, dst_obj, src, dst, length);
+        return RuntimeDispatch<decorators, T, BARRIER_ARRAYCOPY>::arraycopy(src_obj, src_offset_in_bytes, src_raw,
+                                                                            dst_obj, dst_offset_in_bytes, dst_raw,
+                                                                            length);
       }
     }
 
@@ -1092,21 +1124,33 @@
   }
 
   template <DecoratorSet decorators, typename T>
-  inline bool arraycopy_reduce_types(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
-    return PreRuntimeDispatch::arraycopy<decorators>(src_obj, dst_obj, src, dst, length);
+  inline bool arraycopy_reduce_types(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                     arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                     size_t length) {
+    return PreRuntimeDispatch::arraycopy<decorators>(src_obj, src_offset_in_bytes, src_raw,
+                                                     dst_obj, dst_offset_in_bytes, dst_raw,
+                                                     length);
   }
 
   template <DecoratorSet decorators>
-  inline bool arraycopy_reduce_types(arrayOop src_obj, arrayOop dst_obj, HeapWord* src, HeapWord* dst, size_t length) {
+  inline bool arraycopy_reduce_types(arrayOop src_obj, size_t src_offset_in_bytes, HeapWord* src_raw,
+                                     arrayOop dst_obj, size_t dst_offset_in_bytes, HeapWord* dst_raw,
+                                     size_t length) {
     const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP;
-    return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, dst_obj, src, dst, length);
+    return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw,
+                                                              dst_obj, dst_offset_in_bytes, dst_raw,
+                                                              length);
   }
 
   template <DecoratorSet decorators>
-  inline bool arraycopy_reduce_types(arrayOop src_obj, arrayOop dst_obj, narrowOop* src, narrowOop* dst, size_t length) {
+  inline bool arraycopy_reduce_types(arrayOop src_obj, size_t src_offset_in_bytes, narrowOop* src_raw,
+                                     arrayOop dst_obj, size_t dst_offset_in_bytes, narrowOop* dst_raw,
+                                     size_t length) {
     const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP |
                                              INTERNAL_RT_USE_COMPRESSED_OOPS;
-    return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, dst_obj, src, dst, length);
+    return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw,
+                                                              dst_obj, dst_offset_in_bytes, dst_raw,
+                                                              length);
   }
 
   // Step 1: Set default decorators. This step remembers if a type was volatile
@@ -1239,15 +1283,16 @@
   }
 
   template <DecoratorSet decorators, typename T>
-  inline bool arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
+  inline bool arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
+                        arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                        size_t length) {
     STATIC_ASSERT((HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::value ||
                    (IsSame<T, void>::value || IsIntegral<T>::value) ||
                     IsFloatingPoint<T>::value)); // arraycopy allows type erased void elements
     typedef typename Decay<T>::type DecayedT;
     const DecoratorSet expanded_decorators = DecoratorFixup<decorators | IN_HEAP_ARRAY | IN_HEAP>::value;
-    return arraycopy_reduce_types<expanded_decorators>(src_obj, dst_obj,
-                                                       const_cast<DecayedT*>(src),
-                                                       const_cast<DecayedT*>(dst),
+    return arraycopy_reduce_types<expanded_decorators>(src_obj, src_offset_in_bytes, const_cast<DecayedT*>(src_raw),
+                                                       dst_obj, dst_offset_in_bytes, const_cast<DecayedT*>(dst_raw),
                                                        length);
   }
 
--- a/src/hotspot/share/oops/accessBackend.inline.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/accessBackend.inline.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -118,8 +118,12 @@
 
 template <DecoratorSet decorators>
 template <typename T>
-inline bool RawAccessBarrier<decorators>::oop_arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
-  return arraycopy(src_obj, dst_obj, src, dst, length);
+inline bool RawAccessBarrier<decorators>::oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                                        arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                                        size_t length) {
+  return arraycopy(src_obj, src_offset_in_bytes, src_raw,
+                   dst_obj, dst_offset_in_bytes, dst_raw,
+                   length);
 }
 
 template <DecoratorSet decorators>
@@ -247,35 +251,45 @@
   template <DecoratorSet decorators, typename T>
   static inline typename EnableIf<
   HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::value>::type
-  arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
+  arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+            arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+            size_t length) {
+
+    src_raw = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw);
+    dst_raw = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw);
+
     // We do not check for ARRAYCOPY_ATOMIC for oops, because they are unconditionally always atomic.
     if (HasDecorator<decorators, ARRAYCOPY_ARRAYOF>::value) {
-      AccessInternal::arraycopy_arrayof_conjoint_oops(src, dst, length);
+      AccessInternal::arraycopy_arrayof_conjoint_oops(src_raw, dst_raw, length);
     } else {
       typedef typename HeapOopType<decorators>::type OopType;
-      AccessInternal::arraycopy_conjoint_oops(reinterpret_cast<OopType*>(src),
-                                              reinterpret_cast<OopType*>(dst), length);
+      AccessInternal::arraycopy_conjoint_oops(reinterpret_cast<OopType*>(src_raw),
+                                              reinterpret_cast<OopType*>(dst_raw), length);
     }
   }
 
   template <DecoratorSet decorators, typename T>
   static inline typename EnableIf<
     !HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::value>::type
-  arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
+  arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length) {
+
+    src_raw = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw);
+    dst_raw = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw);
+
     if (HasDecorator<decorators, ARRAYCOPY_ARRAYOF>::value) {
-      AccessInternal::arraycopy_arrayof_conjoint(src, dst, length);
+      AccessInternal::arraycopy_arrayof_conjoint(const_cast<T*>(src_raw), dst_raw, length);
     } else if (HasDecorator<decorators, ARRAYCOPY_DISJOINT>::value && sizeof(T) == HeapWordSize) {
       // There is only a disjoint optimization for word granularity copying
       if (HasDecorator<decorators, ARRAYCOPY_ATOMIC>::value) {
-        AccessInternal::arraycopy_disjoint_words_atomic(src, dst, length);
+        AccessInternal::arraycopy_disjoint_words_atomic(const_cast<T*>(src_raw), dst_raw, length);
       } else {
-        AccessInternal::arraycopy_disjoint_words(src, dst, length);
+        AccessInternal::arraycopy_disjoint_words(const_cast<T*>(src_raw), dst_raw, length);
       }
     } else {
       if (HasDecorator<decorators, ARRAYCOPY_ATOMIC>::value) {
-        AccessInternal::arraycopy_conjoint_atomic(src, dst, length);
+        AccessInternal::arraycopy_conjoint_atomic(const_cast<T*>(src_raw), dst_raw, length);
       } else {
-        AccessInternal::arraycopy_conjoint(src, dst, length);
+        AccessInternal::arraycopy_conjoint(const_cast<T*>(src_raw), dst_raw, length);
       }
     }
   }
@@ -283,19 +297,29 @@
   template <DecoratorSet decorators>
   static inline typename EnableIf<
     !HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::value>::type
-  arraycopy(arrayOop src_obj, arrayOop dst_obj, void* src, void* dst, size_t length) {
+  arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const void* src_raw,
+            arrayOop dst_obj, size_t dst_offset_in_bytes, void* dst_raw,
+            size_t length) {
+
+    src_raw = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw);
+    dst_raw = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw);
+
     if (HasDecorator<decorators, ARRAYCOPY_ATOMIC>::value) {
-      AccessInternal::arraycopy_conjoint_atomic(src, dst, length);
+      AccessInternal::arraycopy_conjoint_atomic(const_cast<void*>(src_raw), dst_raw, length);
     } else {
-      AccessInternal::arraycopy_conjoint(src, dst, length);
+      AccessInternal::arraycopy_conjoint(const_cast<void*>(src_raw), dst_raw, length);
     }
   }
 };
 
 template <DecoratorSet decorators>
 template <typename T>
-inline bool RawAccessBarrier<decorators>::arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
-  RawAccessBarrierArrayCopy::arraycopy<decorators>(src_obj, dst_obj, src, dst, length);
+inline bool RawAccessBarrier<decorators>::arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
+                                                    arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
+                                                    size_t length) {
+  RawAccessBarrierArrayCopy::arraycopy<decorators>(src_obj, src_offset_in_bytes, src_raw,
+                                                   dst_obj, dst_offset_in_bytes, dst_raw,
+                                                   length);
   return true;
 }
 
--- a/src/hotspot/share/oops/arrayOop.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/arrayOop.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -88,6 +88,18 @@
   inline void* base(BasicType type) const;
   inline void* base_raw(BasicType type) const; // GC barrier invariant
 
+  template <typename T>
+  static T* obj_offset_to_raw(arrayOop obj, size_t offset_in_bytes, T* raw) {
+    if (obj != NULL) {
+      assert(raw == NULL, "either raw or in-heap");
+      char* base = reinterpret_cast<char*>((void*) obj);
+      raw = reinterpret_cast<T*>(base + offset_in_bytes);
+    } else {
+      assert(raw != NULL, "either raw or in-heap");
+    }
+    return raw;
+  }
+
   // Tells whether index is within bounds.
   bool is_within_bounds(int index) const        { return 0 <= index && index < length(); }
 
--- a/src/hotspot/share/oops/objArrayKlass.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/objArrayKlass.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -218,23 +218,23 @@
 }
 
 // Either oop or narrowOop depending on UseCompressedOops.
-template <class T> void ObjArrayKlass::do_copy(arrayOop s, T* src,
-                               arrayOop d, T* dst, int length, TRAPS) {
+void ObjArrayKlass::do_copy(arrayOop s, size_t src_offset,
+                            arrayOop d, size_t dst_offset, int length, TRAPS) {
   if (oopDesc::equals(s, d)) {
     // since source and destination are equal we do not need conversion checks.
     assert(length > 0, "sanity check");
-    HeapAccess<>::oop_arraycopy(s, d, src, dst, length);
+    ArrayAccess<>::oop_arraycopy(s, src_offset, d, dst_offset, length);
   } else {
     // We have to make sure all elements conform to the destination array
     Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass();
     Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass();
     if (stype == bound || stype->is_subtype_of(bound)) {
       // elements are guaranteed to be subtypes, so no check necessary
-      HeapAccess<ARRAYCOPY_DISJOINT>::oop_arraycopy(s, d, src, dst, length);
+      ArrayAccess<ARRAYCOPY_DISJOINT>::oop_arraycopy(s, src_offset, d, dst_offset, length);
     } else {
       // slow case: need individual subtype checks
       // note: don't use obj_at_put below because it includes a redundant store check
-      if (!HeapAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::oop_arraycopy(s, d, src, dst, length)) {
+      if (!ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::oop_arraycopy(s, src_offset, d, dst_offset, length)) {
         THROW(vmSymbols::java_lang_ArrayStoreException());
       }
     }
@@ -289,13 +289,21 @@
     return;
   }
   if (UseCompressedOops) {
-    narrowOop* const src = objArrayOop(s)->obj_at_addr<narrowOop>(src_pos);
-    narrowOop* const dst = objArrayOop(d)->obj_at_addr<narrowOop>(dst_pos);
-    do_copy<narrowOop>(s, src, d, dst, length, CHECK);
+    size_t src_offset = (size_t) objArrayOopDesc::obj_at_offset<narrowOop>(src_pos);
+    size_t dst_offset = (size_t) objArrayOopDesc::obj_at_offset<narrowOop>(dst_pos);
+    assert(arrayOopDesc::obj_offset_to_raw<narrowOop>(s, src_offset, NULL) ==
+           objArrayOop(s)->obj_at_addr<narrowOop>(src_pos), "sanity");
+    assert(arrayOopDesc::obj_offset_to_raw<narrowOop>(d, dst_offset, NULL) ==
+           objArrayOop(d)->obj_at_addr<narrowOop>(dst_pos), "sanity");
+    do_copy(s, src_offset, d, dst_offset, length, CHECK);
   } else {
-    oop* const src = objArrayOop(s)->obj_at_addr<oop>(src_pos);
-    oop* const dst = objArrayOop(d)->obj_at_addr<oop>(dst_pos);
-    do_copy<oop> (s, src, d, dst, length, CHECK);
+    size_t src_offset = (size_t) objArrayOopDesc::obj_at_offset<oop>(src_pos);
+    size_t dst_offset = (size_t) objArrayOopDesc::obj_at_offset<oop>(dst_pos);
+    assert(arrayOopDesc::obj_offset_to_raw<oop>(s, src_offset, NULL) ==
+           objArrayOop(s)->obj_at_addr<oop>(src_pos), "sanity");
+    assert(arrayOopDesc::obj_offset_to_raw<oop>(d, dst_offset, NULL) ==
+           objArrayOop(d)->obj_at_addr<oop>(dst_pos), "sanity");
+    do_copy(s, src_offset, d, dst_offset, length, CHECK);
   }
 }
 
--- a/src/hotspot/share/oops/objArrayKlass.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/objArrayKlass.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -88,8 +88,9 @@
  private:
   // Either oop or narrowOop depending on UseCompressedOops.
   // must be called from within ObjArrayKlass.cpp
-  template <class T> void do_copy(arrayOop s, T* src, arrayOop d,
-                                  T* dst, int length, TRAPS);
+  void do_copy(arrayOop s, size_t src_offset,
+               arrayOop d, size_t dst_offset,
+               int length, TRAPS);
  protected:
   // Returns the ObjArrayKlass for n'th dimension.
   virtual Klass* array_klass_impl(bool or_null, int n, TRAPS);
--- a/src/hotspot/share/oops/typeArrayKlass.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/typeArrayKlass.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -175,10 +175,9 @@
 
   // This is an attempt to make the copy_array fast.
   int l2es = log2_element_size();
-  int ihs = array_header_in_bytes() / wordSize;
-  void* src = (char*) (s->base(element_type())) + ((size_t)src_pos << l2es);
-  void* dst = (char*) (d->base(element_type())) + ((size_t)dst_pos << l2es);
-  HeapAccess<ARRAYCOPY_ATOMIC>::arraycopy(s, d, src, dst, (size_t)length << l2es);
+  size_t src_offset = arrayOopDesc::base_offset_in_bytes(element_type()) + ((size_t)src_pos << l2es);
+  size_t dst_offset = arrayOopDesc::base_offset_in_bytes(element_type()) + ((size_t)dst_pos << l2es);
+  ArrayAccess<ARRAYCOPY_ATOMIC>::arraycopy<void>(s, src_offset, d, dst_offset, (size_t)length << l2es);
 }
 
 // create a klass of array holding typeArrays
--- a/src/hotspot/share/oops/typeArrayOop.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/typeArrayOop.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -32,12 +32,22 @@
 // It is used for arrays of {characters, singles, doubles, bytes, shorts, integers, longs}
 #include <limits.h>
 
+namespace TypeToBT {
+  template<typename T> BasicType to_basic_type();
+  template<> inline BasicType to_basic_type<jboolean>() { return T_BOOLEAN; }
+  template<> inline BasicType to_basic_type<jbyte>()    { return T_BYTE;    }
+  template<> inline BasicType to_basic_type<jchar>()    { return T_CHAR;    }
+  template<> inline BasicType to_basic_type<jshort>()   { return T_SHORT;   }
+  template<> inline BasicType to_basic_type<jint>()     { return T_INT;     }
+  template<> inline BasicType to_basic_type<jlong>()    { return T_LONG;    }
+  template<> inline BasicType to_basic_type<jfloat>()   { return T_FLOAT;   }
+  template<> inline BasicType to_basic_type<jdouble>()  { return T_DOUBLE;  }
+};
+
 class typeArrayOopDesc : public arrayOopDesc {
 private:
-  template <class T>
-  static ptrdiff_t element_offset(BasicType bt, int index) {
-    return arrayOopDesc::base_offset_in_bytes(bt) + sizeof(T) * index;
-  }
+  template <typename T>
+  static BasicType bt() { return TypeToBT::to_basic_type<T>(); }
 
  protected:
   jchar*    char_base()   const;
@@ -52,6 +62,11 @@
   friend class TypeArrayKlass;
 
  public:
+  template <typename T>
+  static ptrdiff_t element_offset(int index) {
+    return arrayOopDesc::base_offset_in_bytes(bt<T>()) + sizeof(T) * index;
+  }
+
   jbyte* byte_at_addr(int which) const;
   jboolean* bool_at_addr(int which) const;
   jchar* char_at_addr(int which) const;
--- a/src/hotspot/share/oops/typeArrayOop.inline.hpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/oops/typeArrayOop.inline.hpp	Mon Jun 04 23:01:48 2018 +0200
@@ -90,92 +90,92 @@
 }
 
 inline jbyte typeArrayOopDesc::byte_at(int which) const {
-  ptrdiff_t offset = element_offset<jbyte>(T_BYTE, which);
+  ptrdiff_t offset = element_offset<jbyte>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::byte_at_put(int which, jbyte contents) {
-  ptrdiff_t offset = element_offset<jbyte>(T_BYTE, which);
+  ptrdiff_t offset = element_offset<jbyte>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
 inline jboolean typeArrayOopDesc::bool_at(int which) const {
-  ptrdiff_t offset = element_offset<jboolean>(T_BOOLEAN, which);
+  ptrdiff_t offset = element_offset<jboolean>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::bool_at_put(int which, jboolean contents) {
-  ptrdiff_t offset = element_offset<jboolean>(T_BOOLEAN, which);
+  ptrdiff_t offset = element_offset<jboolean>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, jboolean(contents & 1));
 }
 
 inline jchar typeArrayOopDesc::char_at(int which) const {
-  ptrdiff_t offset = element_offset<jchar>(T_CHAR, which);
+  ptrdiff_t offset = element_offset<jchar>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::char_at_put(int which, jchar contents) {
-  ptrdiff_t offset = element_offset<jchar>(T_CHAR, which);
+  ptrdiff_t offset = element_offset<jchar>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
 inline jint typeArrayOopDesc::int_at(int which) const {
-  ptrdiff_t offset = element_offset<jint>(T_INT, which);
+  ptrdiff_t offset = element_offset<jint>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::int_at_put(int which, jint contents) {
-  ptrdiff_t offset = element_offset<jint>(T_INT, which);
+  ptrdiff_t offset = element_offset<jint>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
 inline jshort typeArrayOopDesc::short_at(int which) const {
-  ptrdiff_t offset = element_offset<jshort>(T_SHORT, which);
+  ptrdiff_t offset = element_offset<jshort>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::short_at_put(int which, jshort contents) {
-  ptrdiff_t offset = element_offset<jshort>(T_SHORT, which);
+  ptrdiff_t offset = element_offset<jshort>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
 inline jushort typeArrayOopDesc::ushort_at(int which) const {
-  ptrdiff_t offset = element_offset<jushort>(T_SHORT, which);
+  ptrdiff_t offset = element_offset<jushort>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::ushort_at_put(int which, jushort contents) {
-  ptrdiff_t offset = element_offset<jushort>(T_SHORT, which);
+  ptrdiff_t offset = element_offset<jushort>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
 inline jlong typeArrayOopDesc::long_at(int which) const {
-  ptrdiff_t offset = element_offset<jlong>(T_LONG, which);
+  ptrdiff_t offset = element_offset<jlong>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::long_at_put(int which, jlong contents) {
-  ptrdiff_t offset = element_offset<jlong>(T_LONG, which);
+  ptrdiff_t offset = element_offset<jlong>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
 inline jfloat typeArrayOopDesc::float_at(int which) const {
-  ptrdiff_t offset = element_offset<jfloat>(T_FLOAT, which);
+  ptrdiff_t offset = element_offset<jfloat>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::float_at_put(int which, jfloat contents) {
-  ptrdiff_t offset = element_offset<jfloat>(T_FLOAT, which);
+  ptrdiff_t offset = element_offset<jfloat>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
 inline jdouble typeArrayOopDesc::double_at(int which) const {
-  ptrdiff_t offset = element_offset<jdouble>(T_DOUBLE, which);
+  ptrdiff_t offset = element_offset<jdouble>(which);
   return HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::double_at_put(int which, jdouble contents) {
-  ptrdiff_t offset = element_offset<jdouble>(T_DOUBLE, which);
+  ptrdiff_t offset = element_offset<jdouble>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
 inline jbyte typeArrayOopDesc::byte_at_acquire(int which) const {
-  ptrdiff_t offset = element_offset<jbyte>(T_BYTE, which);
+  ptrdiff_t offset = element_offset<jbyte>(which);
   return HeapAccess<MO_ACQUIRE | IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::release_byte_at_put(int which, jbyte contents) {
-  ptrdiff_t offset = element_offset<jbyte>(T_BYTE, which);
+  ptrdiff_t offset = element_offset<jbyte>(which);
   HeapAccess<MO_RELEASE | IN_HEAP_ARRAY>::store_at(as_oop(), offset, contents);
 }
 
@@ -184,20 +184,20 @@
 // casting
 #ifdef _LP64
 inline Symbol* typeArrayOopDesc::symbol_at(int which) const {
-  ptrdiff_t offset = element_offset<jlong>(T_LONG, which);
+  ptrdiff_t offset = element_offset<jlong>(which);
   return (Symbol*)(jlong) HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::symbol_at_put(int which, Symbol* contents) {
-  ptrdiff_t offset = element_offset<jlong>(T_LONG, which);
+  ptrdiff_t offset = element_offset<jlong>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, (jlong)contents);
 }
 #else
 inline Symbol* typeArrayOopDesc::symbol_at(int which) const {
-  ptrdiff_t offset = element_offset<jint>(T_INT, which);
+  ptrdiff_t offset = element_offset<jint>(which);
   return (Symbol*)(jint) HeapAccess<IN_HEAP_ARRAY>::load_at(as_oop(), offset);
 }
 inline void typeArrayOopDesc::symbol_at_put(int which, Symbol* contents) {
-  ptrdiff_t offset = element_offset<jint>(T_INT, which);
+  ptrdiff_t offset = element_offset<jint>(which);
   HeapAccess<IN_HEAP_ARRAY>::store_at(as_oop(), offset, (jint)contents);
 }
 #endif // _LP64
--- a/src/hotspot/share/opto/runtime.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/opto/runtime.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -393,9 +393,9 @@
   ResourceMark rm;
   jint len = dims->length();
   assert(len > 0, "Dimensions array should contain data");
-  jint *j_dims = typeArrayOop(dims)->int_at_addr(0);
   jint *c_dims = NEW_RESOURCE_ARRAY(jint, len);
-  Copy::conjoint_jints_atomic(j_dims, c_dims, len);
+  ArrayAccess<>::arraycopy_to_native<>(dims, typeArrayOopDesc::element_offset<jint>(0),
+                                       c_dims, len);
 
   Handle holder(THREAD, elem_type->klass_holder()); // keep the klass alive
   oop obj = ArrayKlass::cast(elem_type)->multi_allocate(len, c_dims, THREAD);
--- a/src/hotspot/share/prims/jni.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/prims/jni.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -2466,7 +2466,8 @@
     if (buf != NULL) {
       if (s_len > 0) {
         if (!is_latin1) {
-          memcpy(buf, s_value->char_at_addr(0), sizeof(jchar)*s_len);
+          ArrayAccess<>::arraycopy_to_native(s_value, (size_t) typeArrayOopDesc::element_offset<jchar>(0),
+                                             buf, s_len);
         } else {
           for (int i = 0; i < s_len; i++) {
             buf[i] = ((jchar) s_value->byte_at(i)) & 0xff;
@@ -2722,7 +2723,8 @@
     result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtInternal); \
     if (result != NULL) {                                                \
       /* copy the array to the c chunk */                                \
-      memcpy(result, a->Tag##_at_addr(0), sizeof(ElementType)*len);      \
+      ArrayAccess<>::arraycopy_to_native(a, typeArrayOopDesc::element_offset<ElementType>(0), \
+                                         result, len);                   \
       if (isCopy) {                                                      \
         *isCopy = JNI_TRUE;                                              \
       }                                                                  \
@@ -2771,7 +2773,7 @@
   int len = a->length(); \
   if (len != 0) {   /* Empty array:  nothing to free or copy. */  \
     if ((mode == 0) || (mode == JNI_COMMIT)) { \
-      memcpy(a->Tag##_at_addr(0), buf, sizeof(ElementType)*len); \
+      ArrayAccess<>::arraycopy_from_native(buf, a, typeArrayOopDesc::element_offset<ElementType>(0), len); \
     } \
     if ((mode == 0) || (mode == JNI_ABORT)) { \
       FreeHeap(buf); \
@@ -2822,10 +2824,7 @@
     THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \
   } else { \
     if (len > 0) { \
-      int sc = TypeArrayKlass::cast(src->klass())->log2_element_size(); \
-      memcpy((u_char*) buf, \
-             (u_char*) src->Tag##_at_addr(start), \
-             len << sc);                          \
+      ArrayAccess<>::arraycopy_to_native(src, typeArrayOopDesc::element_offset<ElementType>(start), buf, len); \
     } \
   } \
 JNI_END
@@ -2872,10 +2871,7 @@
     THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \
   } else { \
     if (len > 0) { \
-      int sc = TypeArrayKlass::cast(dst->klass())->log2_element_size(); \
-      memcpy((u_char*) dst->Tag##_at_addr(start), \
-             (u_char*) buf, \
-             len << sc);    \
+      ArrayAccess<>::arraycopy_from_native(buf, dst, typeArrayOopDesc::element_offset<ElementType>(start), len); \
     } \
   } \
 JNI_END
@@ -3111,7 +3107,8 @@
       typeArrayOop s_value = java_lang_String::value(s);
       bool is_latin1 = java_lang_String::is_latin1(s);
       if (!is_latin1) {
-        memcpy(buf, s_value->char_at_addr(start), sizeof(jchar)*len);
+        ArrayAccess<>::arraycopy_to_native(s_value, typeArrayOopDesc::element_offset<jchar>(start),
+                                           buf, len);
       } else {
         for (int i = 0; i < len; i++) {
           buf[i] = ((jchar) s_value->byte_at(i + start)) & 0xff;
--- a/src/hotspot/share/prims/unsafe.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/prims/unsafe.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -762,8 +762,8 @@
   // caller responsible to free it:
   *temp_alloc = class_bytes;
 
-  jbyte* array_base = typeArrayOop(JNIHandles::resolve_non_null(data))->byte_at_addr(0);
-  Copy::conjoint_jbytes(array_base, class_bytes, length);
+  ArrayAccess<>::arraycopy_to_native(arrayOop(JNIHandles::resolve_non_null(data)), typeArrayOopDesc::element_offset<jbyte>(0),
+                                     reinterpret_cast<jbyte*>(class_bytes), length);
 
   objArrayHandle cp_patches_h;
   if (cp_patches_jh != NULL) {
--- a/src/hotspot/share/runtime/stubRoutines.cpp	Mon Jun 04 22:03:10 2018 +0200
+++ b/src/hotspot/share/runtime/stubRoutines.cpp	Mon Jun 04 23:01:48 2018 +0200
@@ -410,7 +410,7 @@
   SharedRuntime::_oop_array_copy_ctr++;        // Slow-path oop array copy
 #endif // !PRODUCT
   assert(count != 0, "count should be non-zero");
-  HeapAccess<>::oop_arraycopy(NULL, NULL, (HeapWord*)src, (HeapWord*)dest, count);
+  ArrayAccess<>::oop_arraycopy_raw((HeapWord*)src, (HeapWord*)dest, count);
 JRT_END
 
 JRT_LEAF(void, StubRoutines::oop_copy_uninit(oop* src, oop* dest, size_t count))
@@ -418,7 +418,7 @@
   SharedRuntime::_oop_array_copy_ctr++;        // Slow-path oop array copy
 #endif // !PRODUCT
   assert(count != 0, "count should be non-zero");
-  HeapAccess<AS_DEST_NOT_INITIALIZED>::oop_arraycopy(NULL, NULL, (HeapWord*)src, (HeapWord*)dest, count);
+  ArrayAccess<AS_DEST_NOT_INITIALIZED>::oop_arraycopy_raw((HeapWord*)src, (HeapWord*)dest, count);
 JRT_END
 
 JRT_LEAF(void, StubRoutines::arrayof_jbyte_copy(HeapWord* src, HeapWord* dest, size_t count))
@@ -454,7 +454,7 @@
   SharedRuntime::_oop_array_copy_ctr++;        // Slow-path oop array copy
 #endif // !PRODUCT
   assert(count != 0, "count should be non-zero");
-  HeapAccess<ARRAYCOPY_ARRAYOF>::oop_arraycopy(NULL, NULL, src, dest, count);
+  ArrayAccess<ARRAYCOPY_ARRAYOF>::oop_arraycopy_raw(src, dest, count);
 JRT_END
 
 JRT_LEAF(void, StubRoutines::arrayof_oop_copy_uninit(HeapWord* src, HeapWord* dest, size_t count))
@@ -462,7 +462,7 @@
   SharedRuntime::_oop_array_copy_ctr++;        // Slow-path oop array copy
 #endif // !PRODUCT
   assert(count != 0, "count should be non-zero");
-  HeapAccess<ARRAYCOPY_ARRAYOF | AS_DEST_NOT_INITIALIZED>::oop_arraycopy(NULL, NULL, src, dest, count);
+  ArrayAccess<ARRAYCOPY_ARRAYOF | AS_DEST_NOT_INITIALIZED>::oop_arraycopy_raw(src, dest, count);
 JRT_END
 
 address StubRoutines::select_fill_function(BasicType t, bool aligned, const char* &name) {