From 53e77d21c2308daad7d4aecf05da56609ed0291c Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 19 Dec 2025 10:52:43 +0000 Subject: [PATCH] 8373801: Adopt arraycopy OopCopyResult from the lworld branch Reviewed-by: jsikstro, tschatzl, aboldtch --- src/hotspot/share/gc/shared/barrierSet.hpp | 6 +- .../share/gc/shared/barrierSet.inline.hpp | 13 ++-- .../share/gc/shared/cardTableBarrierSet.hpp | 6 +- .../gc/shared/cardTableBarrierSet.inline.hpp | 7 +- .../gc/shenandoah/shenandoahBarrierSet.hpp | 6 +- .../shenandoahBarrierSet.inline.hpp | 8 +- src/hotspot/share/gc/z/zBarrierSet.hpp | 27 +++---- src/hotspot/share/gc/z/zBarrierSet.inline.hpp | 52 ++++++++----- src/hotspot/share/oops/access.hpp | 25 ++++--- src/hotspot/share/oops/access.inline.hpp | 20 ++--- src/hotspot/share/oops/accessBackend.hpp | 75 +++++++++++-------- src/hotspot/share/oops/objArrayKlass.cpp | 63 ++++++++++------ 12 files changed, 179 insertions(+), 129 deletions(-) diff --git a/src/hotspot/share/gc/shared/barrierSet.hpp b/src/hotspot/share/gc/shared/barrierSet.hpp index 2040ec32ea0..4edbb1a68a7 100644 --- a/src/hotspot/share/gc/shared/barrierSet.hpp +++ b/src/hotspot/share/gc/shared/barrierSet.hpp @@ -281,9 +281,9 @@ public: } template - 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 OopCopyResult 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); // Off-heap oop accesses. These accessors get resolved when // IN_HEAP is not set (e.g. when using the NativeAccess API), it is diff --git a/src/hotspot/share/gc/shared/barrierSet.inline.hpp b/src/hotspot/share/gc/shared/barrierSet.inline.hpp index 8b314bb5995..eaa673114ab 100644 --- a/src/hotspot/share/gc/shared/barrierSet.inline.hpp +++ b/src/hotspot/share/gc/shared/barrierSet.inline.hpp @@ -34,15 +34,16 @@ template template -inline bool BarrierSet::AccessBarrier::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) { +inline OopCopyResult BarrierSet::AccessBarrier::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) { T* src = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw); T* dst = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw); if (!HasDecorator::value) { // Covariant, copy without checks - return Raw::oop_arraycopy(nullptr, 0, src, nullptr, 0, dst, length); + Raw::oop_arraycopy(nullptr, 0, src, nullptr, 0, dst, length); + return OopCopyResult::ok; } // Copy each element with checking casts @@ -50,12 +51,12 @@ inline bool BarrierSet::AccessBarrier::oop_arraycopy_in for (const T* const end = src + length; src < end; src++, dst++) { const T elem = *src; if (!oopDesc::is_instanceof_or_null(CompressedOops::decode(elem), dst_klass)) { - return false; + return OopCopyResult::failed_check_class_cast; } *dst = elem; } - return true; + return OopCopyResult::ok; } #endif // SHARE_GC_SHARED_BARRIERSET_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp index dea36098673..5c581da1252 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp @@ -104,9 +104,9 @@ public: static oop oop_atomic_xchg_in_heap(T* addr, oop new_value); template - 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 OopCopyResult 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); diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp index 7fc3fee1e7c..ea539a70be5 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp @@ -99,7 +99,7 @@ oop_atomic_xchg_in_heap(T* addr, oop new_value) { template template -inline bool CardTableBarrierSet::AccessBarrier:: +inline OopCopyResult CardTableBarrierSet::AccessBarrier:: 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) { @@ -131,12 +131,13 @@ oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, // objArrayOop) which we assume is 32 bit. assert(pd == (size_t)(int)pd, "length field overflow"); bs->write_ref_array((HeapWord*)dst_raw, pd); - return false; + return OopCopyResult::failed_check_class_cast; } } bs->write_ref_array((HeapWord*)dst_raw, length); } - return true; + + return OopCopyResult::ok; } template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 7db478a781a..28765605267 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -173,9 +173,9 @@ public: static oop oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value); template - 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 OopCopyResult 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); // Clone barrier support static void clone_in_heap(oop src, oop dst, size_t size); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index 32388ce6ca8..f4b35e29b09 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -382,15 +382,15 @@ void ShenandoahBarrierSet::AccessBarrier::clone_in_heap template template -bool ShenandoahBarrierSet::AccessBarrier::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) { +OopCopyResult ShenandoahBarrierSet::AccessBarrier::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) { T* src = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw); T* dst = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw); ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set(); bs->arraycopy_barrier(src, dst, length); - bool result = Raw::oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); + OopCopyResult result = Raw::oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); if (ShenandoahCardBarrier) { bs->write_ref_array((HeapWord*) dst, length); } diff --git a/src/hotspot/share/gc/z/zBarrierSet.hpp b/src/hotspot/share/gc/z/zBarrierSet.hpp index 502cc36d380..8764c66d900 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.hpp @@ -88,6 +88,7 @@ public: static void store_barrier_native_with_healing(zpointer* p); static void store_barrier_native_without_healing(zpointer* p); + [[noreturn]] static void unsupported(); static zaddress load_barrier(narrowOop* p, zpointer o) { unsupported(); return zaddress::null; } static zaddress load_barrier_on_unknown_oop_ref(oop base, ptrdiff_t offset, narrowOop* p, zpointer o) { unsupported(); return zaddress::null; } @@ -98,11 +99,11 @@ public: static void store_barrier_native_without_healing(narrowOop* p) { unsupported(); } static zaddress oop_copy_one_barriers(zpointer* dst, zpointer* src); - static bool oop_copy_one_check_cast(zpointer* dst, zpointer* src, Klass* dst_klass); - static void oop_copy_one(zpointer* dst, zpointer* src); + static OopCopyResult oop_copy_one_check_cast(zpointer* dst, zpointer* src, Klass* dst_klass); + static OopCopyResult oop_copy_one(zpointer* dst, zpointer* src); - static bool oop_arraycopy_in_heap_check_cast(zpointer* dst, zpointer* src, size_t length, Klass* dst_klass); - static bool oop_arraycopy_in_heap_no_check_cast(zpointer* dst, zpointer* src, size_t length); + static OopCopyResult oop_arraycopy_in_heap_check_cast(zpointer* dst, zpointer* src, size_t length, Klass* dst_klass); + static OopCopyResult oop_arraycopy_in_heap_no_check_cast(zpointer* dst, zpointer* src, size_t length); public: // @@ -134,19 +135,19 @@ public: static oop oop_atomic_xchg_in_heap(narrowOop* p, oop new_value) { unsupported(); return nullptr; } static oop oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value); - static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, zpointer* src_raw, - arrayOop dst_obj, size_t dst_offset_in_bytes, zpointer* dst_raw, - size_t length); - static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, oop* src_raw, - arrayOop dst_obj, size_t dst_offset_in_bytes, oop* dst_raw, - size_t length) { + static OopCopyResult oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, zpointer* src_raw, + arrayOop dst_obj, size_t dst_offset_in_bytes, zpointer* dst_raw, + size_t length); + static OopCopyResult oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, oop* src_raw, + arrayOop dst_obj, size_t dst_offset_in_bytes, oop* dst_raw, + size_t length) { return oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, (zpointer*)src_raw, dst_obj, dst_offset_in_bytes, (zpointer*)dst_raw, length); } - static bool oop_arraycopy_in_heap(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) { unsupported(); return false; } + static OopCopyResult oop_arraycopy_in_heap(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) { unsupported(); } static void clone_in_heap(oop src, oop dst, size_t size); diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp index 9973b1d0131..d99aa561764 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp @@ -328,48 +328,56 @@ inline zaddress ZBarrierSet::AccessBarrier::oop_copy_on } template -inline void ZBarrierSet::AccessBarrier::oop_copy_one(zpointer* dst, zpointer* src) { +inline OopCopyResult ZBarrierSet::AccessBarrier::oop_copy_one(zpointer* dst, zpointer* src) { const zaddress obj = oop_copy_one_barriers(dst, src); + // Future location for null-restriction check and failure reporting + AtomicAccess::store(dst, ZAddress::store_good(obj)); + + return OopCopyResult::ok; } template -inline bool ZBarrierSet::AccessBarrier::oop_copy_one_check_cast(zpointer* dst, zpointer* src, Klass* dst_klass) { +inline OopCopyResult ZBarrierSet::AccessBarrier::oop_copy_one_check_cast(zpointer* dst, zpointer* src, Klass* dst_klass) { const zaddress obj = oop_copy_one_barriers(dst, src); if (!oopDesc::is_instanceof_or_null(to_oop(obj), dst_klass)) { // Check cast failed - return false; + return OopCopyResult::failed_check_class_cast; } AtomicAccess::store(dst, ZAddress::store_good(obj)); - return true; + return OopCopyResult::ok; } template -inline bool ZBarrierSet::AccessBarrier::oop_arraycopy_in_heap_check_cast(zpointer* dst, zpointer* src, size_t length, Klass* dst_klass) { +inline OopCopyResult ZBarrierSet::AccessBarrier::oop_arraycopy_in_heap_check_cast(zpointer* dst, zpointer* src, size_t length, Klass* dst_klass) { // Check cast and copy each elements for (const zpointer* const end = src + length; src < end; src++, dst++) { - if (!oop_copy_one_check_cast(dst, src, dst_klass)) { - // Check cast failed - return false; + const OopCopyResult result = oop_copy_one_check_cast(dst, src, dst_klass); + if (result != OopCopyResult::ok) { + return result; } } - return true; + return OopCopyResult::ok; } template -inline bool ZBarrierSet::AccessBarrier::oop_arraycopy_in_heap_no_check_cast(zpointer* dst, zpointer* src, size_t length) { +inline OopCopyResult ZBarrierSet::AccessBarrier::oop_arraycopy_in_heap_no_check_cast(zpointer* dst, zpointer* src, size_t length) { const bool is_disjoint = HasDecorator::value; if (is_disjoint || src > dst) { for (const zpointer* const end = src + length; src < end; src++, dst++) { - oop_copy_one(dst, src); + const OopCopyResult result = oop_copy_one(dst, src); + if (result != OopCopyResult::ok) { + return result; + } } - return true; + + return OopCopyResult::ok; } if (src < dst) { @@ -377,28 +385,32 @@ inline bool ZBarrierSet::AccessBarrier::oop_arraycopy_i src += length - 1; dst += length - 1; for ( ; src >= end; src--, dst--) { - oop_copy_one(dst, src); + const OopCopyResult result = oop_copy_one(dst, src); + if (result != OopCopyResult::ok) { + return result; + } } - return true; + + return OopCopyResult::ok; } // src and dst are the same; nothing to do - return true; + return OopCopyResult::ok; } template -inline bool ZBarrierSet::AccessBarrier::oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, zpointer* src_raw, - arrayOop dst_obj, size_t dst_offset_in_bytes, zpointer* dst_raw, - size_t length) { +inline OopCopyResult ZBarrierSet::AccessBarrier::oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, zpointer* src_raw, + arrayOop dst_obj, size_t dst_offset_in_bytes, zpointer* dst_raw, + size_t length) { zpointer* const src = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw); zpointer* const dst = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw); if (HasDecorator::value) { Klass* const dst_klass = objArrayOop(dst_obj)->element_klass(); return oop_arraycopy_in_heap_check_cast(dst, src, length, dst_klass); + } else { + return oop_arraycopy_in_heap_no_check_cast(dst, src, length); } - - return oop_arraycopy_in_heap_no_check_cast(dst, src, length); } template diff --git a/src/hotspot/share/oops/access.hpp b/src/hotspot/share/oops/access.hpp index 917627f445e..f10682fdf42 100644 --- a/src/hotspot/share/oops/access.hpp +++ b/src/hotspot/share/oops/access.hpp @@ -128,9 +128,9 @@ class Access: public AllStatic { protected: template - 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) { + static inline OopCopyResult 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(); return AccessInternal::arraycopy(src_obj, src_offset_in_bytes, src_raw, @@ -316,19 +316,24 @@ public: 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) { + [[nodiscard]] // The caller is responsible to throw an exception on failure + static inline OopCopyResult 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, static_cast(nullptr), dst_obj, dst_offset_in_bytes, static_cast(nullptr), length); } template - static inline bool oop_arraycopy_raw(T* src, T* dst, size_t length) { - return AccessT::oop_arraycopy(nullptr, 0, src, - nullptr, 0, dst, - length); + static inline void oop_arraycopy_raw(T* src, T* dst, size_t length) { + static_assert((decorators & ARRAYCOPY_CHECKCAST) == 0); + + OopCopyResult result = AccessT::oop_arraycopy(nullptr, 0, src, + nullptr, 0, dst, + length); + + assert(result == OopCopyResult::ok, "Should never fail"); } }; diff --git a/src/hotspot/share/oops/access.inline.hpp b/src/hotspot/share/oops/access.inline.hpp index da3d54c4902..b71ed4460fc 100644 --- a/src/hotspot/share/oops/access.inline.hpp +++ b/src/hotspot/share/oops/access.inline.hpp @@ -125,19 +125,19 @@ namespace AccessInternal { template struct PostRuntimeDispatch: public AllStatic { template - 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) { + static OopCopyResult 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; + return OopCopyResult::ok; } template - 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) { + static OopCopyResult 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::type OopType; return GCBarrierType::oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, reinterpret_cast(src_raw), dst_obj, dst_offset_in_bytes, reinterpret_cast(dst_raw), @@ -331,9 +331,9 @@ namespace AccessInternal { } template - bool RuntimeDispatch::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) { + OopCopyResult RuntimeDispatch::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::resolve_barrier(); _arraycopy_func = function; return function(src_obj, src_offset_in_bytes, src_raw, diff --git a/src/hotspot/share/oops/accessBackend.hpp b/src/hotspot/share/oops/accessBackend.hpp index f4f4f906efd..03f5fc05729 100644 --- a/src/hotspot/share/oops/accessBackend.hpp +++ b/src/hotspot/share/oops/accessBackend.hpp @@ -35,6 +35,13 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +// Result from oop_arraycopy +enum class OopCopyResult { + ok, // oop array copy sucessful + failed_check_class_cast, // oop array copy failed subtype check (ARRAYCOPY_CHECKCAST) + failed_check_null // oop array copy failed null check (ARRAYCOPY_NOTNULL) +}; + // This metafunction returns either oop or narrowOop depending on whether // an access needs to use compressed oops or not. template @@ -92,17 +99,17 @@ namespace AccessInternal { typedef T (*atomic_cmpxchg_func_t)(void* addr, T compare_value, T new_value); typedef T (*atomic_xchg_func_t)(void* addr, T new_value); - 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 OopCopyResult (*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); }; template struct AccessFunctionTypes { - 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); + typedef OopCopyResult (*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 struct AccessFunction {}; @@ -505,13 +512,13 @@ namespace AccessInternal { typedef typename AccessFunction::type func_t; static func_t _arraycopy_func; - 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 OopCopyResult 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, 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 OopCopyResult 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) { assert_access_thread_state(); return _arraycopy_func(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, @@ -820,25 +827,27 @@ namespace AccessInternal { template inline static typename EnableIf< - HasDecorator::value && CanHardwireRaw::value, bool>::type + HasDecorator::value && CanHardwireRaw::value, OopCopyResult>::type 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 Raw; if (HasDecorator::value) { - return Raw::oop_arraycopy(src_obj, src_offset_in_bytes, src_raw, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + 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, src_offset_in_bytes, src_raw, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + Raw::arraycopy(src_obj, src_offset_in_bytes, src_raw, + dst_obj, dst_offset_in_bytes, dst_raw, + length); } + + return OopCopyResult::ok; } template inline static typename EnableIf< - HasDecorator::value && !CanHardwireRaw::value, bool>::type + HasDecorator::value && !CanHardwireRaw::value, OopCopyResult>::type 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) { @@ -857,7 +866,7 @@ namespace AccessInternal { template inline static typename EnableIf< - !HasDecorator::value, bool>::type + !HasDecorator::value, OopCopyResult>::type 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) { @@ -1001,18 +1010,18 @@ namespace AccessInternal { } template - 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) { + inline OopCopyResult 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(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } template - 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) { + inline OopCopyResult 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(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, @@ -1020,9 +1029,9 @@ namespace AccessInternal { } template - 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) { + inline OopCopyResult 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(src_obj, src_offset_in_bytes, src_raw, @@ -1160,9 +1169,9 @@ namespace AccessInternal { } template - 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) { + inline OopCopyResult 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::value || (std::is_same::value || std::is_integral::value) || std::is_floating_point::value)); // arraycopy allows type erased void elements diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index ba2bc7f889f..2bbe898adbd 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -185,38 +185,59 @@ oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) { return h_array(); } +static void throw_array_store_exception(arrayOop src, arrayOop dst, TRAPS) { + ResourceMark rm(THREAD); + Klass* bound = ObjArrayKlass::cast(dst->klass())->element_klass(); + Klass* stype = ObjArrayKlass::cast(src->klass())->element_klass(); + stringStream ss; + if (!bound->is_subtype_of(stype)) { + ss.print("arraycopy: type mismatch: can not copy %s[] into %s[]", + stype->external_name(), bound->external_name()); + } else { + // oop_arraycopy should return the index in the source array that + // contains the problematic oop. + ss.print("arraycopy: element type mismatch: can not cast one of the elements" + " of %s[] to the type of the destination array, %s", + stype->external_name(), bound->external_name()); + } + THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); +} + // Either oop or narrowOop depending on UseCompressedOops. void ObjArrayKlass::do_copy(arrayOop s, size_t src_offset, arrayOop d, size_t dst_offset, int length, TRAPS) { if (s == d) { // since source and destination are equal we do not need conversion checks. assert(length > 0, "sanity check"); - ArrayAccess<>::oop_arraycopy(s, src_offset, d, dst_offset, length); + OopCopyResult result = ArrayAccess<>::oop_arraycopy(s, src_offset, d, dst_offset, length); + assert(result == OopCopyResult::ok, "Should never fail"); } 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 - ArrayAccess::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 (!ArrayAccess::oop_arraycopy(s, src_offset, d, dst_offset, length)) { - ResourceMark rm(THREAD); - stringStream ss; - if (!bound->is_subtype_of(stype)) { - ss.print("arraycopy: type mismatch: can not copy %s[] into %s[]", - stype->external_name(), bound->external_name()); - } else { - // oop_arraycopy should return the index in the source array that - // contains the problematic oop. - ss.print("arraycopy: element type mismatch: can not cast one of the elements" - " of %s[] to the type of the destination array, %s", - stype->external_name(), bound->external_name()); - } - THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); + bool type_check = stype != bound && !stype->is_subtype_of(bound); + + auto arraycopy = [&] { + if (type_check) { + return ArrayAccess:: + oop_arraycopy(s, src_offset, d, dst_offset, length); + } else { + return ArrayAccess:: + oop_arraycopy(s, src_offset, d, dst_offset, length); } + }; + + OopCopyResult result = arraycopy(); + + switch (result) { + case OopCopyResult::ok: + // Done + break; + case OopCopyResult::failed_check_class_cast: + throw_array_store_exception(s, d, JavaThread::current()); + break; + default: + ShouldNotReachHere(); } } }