8373801: Adopt arraycopy OopCopyResult from the lworld branch

Reviewed-by: jsikstro, tschatzl, aboldtch
This commit is contained in:
Stefan Karlsson 2025-12-19 10:52:43 +00:00
parent 45cf042099
commit 53e77d21c2
12 changed files with 179 additions and 129 deletions

View File

@ -281,9 +281,9 @@ public:
}
template <typename T>
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

View File

@ -34,15 +34,16 @@
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline bool BarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators, BarrierSetT>::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<decorators, ARRAYCOPY_CHECKCAST>::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<decorators, BarrierSetT>::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

View File

@ -104,9 +104,9 @@ public:
static oop oop_atomic_xchg_in_heap(T* addr, oop new_value);
template <typename T>
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);

View File

@ -99,7 +99,7 @@ oop_atomic_xchg_in_heap(T* addr, oop new_value) {
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
inline bool CardTableBarrierSet::AccessBarrier<decorators, BarrierSetT>::
inline OopCopyResult CardTableBarrierSet::AccessBarrier<decorators, BarrierSetT>::
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 <DecoratorSet decorators, typename BarrierSetT>

View File

@ -173,9 +173,9 @@ public:
static oop oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value);
template <typename T>
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);

View File

@ -382,15 +382,15 @@ void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::clone_in_heap
template <DecoratorSet decorators, typename BarrierSetT>
template <typename T>
bool ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators, BarrierSetT>::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);
}

View File

@ -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);

View File

@ -328,48 +328,56 @@ inline zaddress ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_copy_on
}
template <DecoratorSet decorators, typename BarrierSetT>
inline void ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_copy_one(zpointer* dst, zpointer* src) {
inline OopCopyResult ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
inline bool ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_copy_one_check_cast(zpointer* dst, zpointer* src, Klass* dst_klass) {
inline OopCopyResult ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
inline bool ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_arraycopy_in_heap_check_cast(zpointer* dst, zpointer* src, size_t length, Klass* dst_klass) {
inline OopCopyResult ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
inline bool ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_arraycopy_in_heap_no_check_cast(zpointer* dst, zpointer* src, size_t length) {
inline OopCopyResult ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_arraycopy_in_heap_no_check_cast(zpointer* dst, zpointer* src, size_t length) {
const bool is_disjoint = HasDecorator<decorators, ARRAYCOPY_DISJOINT>::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<decorators, BarrierSetT>::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 <DecoratorSet decorators, typename BarrierSetT>
inline bool ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::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<decorators, BarrierSetT>::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<decorators, ARRAYCOPY_CHECKCAST>::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 <DecoratorSet decorators, typename BarrierSetT>

View File

@ -128,9 +128,9 @@ class Access: public AllStatic {
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) {
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<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
AS_DECORATOR_MASK | IS_ARRAY | IS_DEST_UNINITIALIZED>();
return AccessInternal::arraycopy<decorators | INTERNAL_VALUE_IS_OOP>(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<const HeapWord*>(nullptr),
dst_obj, dst_offset_in_bytes, static_cast<HeapWord*>(nullptr),
length);
}
template <typename T>
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");
}
};

View File

@ -125,19 +125,19 @@ namespace AccessInternal {
template <class GCBarrierType, DecoratorSet decorators>
struct PostRuntimeDispatch<GCBarrierType, BARRIER_ARRAYCOPY, decorators>: public AllStatic {
template <typename T>
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 <typename T>
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<decorators>::type OopType;
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),
@ -331,9 +331,9 @@ namespace AccessInternal {
}
template <DecoratorSet decorators, typename T>
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) {
OopCopyResult 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, src_offset_in_bytes, src_raw,

View File

@ -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 <DecoratorSet decorators>
@ -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 <DecoratorSet decorators>
struct AccessFunctionTypes<decorators, void> {
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 <DecoratorSet decorators, typename T, BarrierType barrier> struct AccessFunction {};
@ -505,13 +512,13 @@ namespace AccessInternal {
typedef typename AccessFunction<decorators, T, BARRIER_ARRAYCOPY>::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 <DecoratorSet decorators, typename T>
inline static typename EnableIf<
HasDecorator<decorators, AS_RAW>::value && CanHardwireRaw<decorators>::value, bool>::type
HasDecorator<decorators, AS_RAW>::value && CanHardwireRaw<decorators>::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<decorators & RAW_DECORATOR_MASK> Raw;
if (HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::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 <DecoratorSet decorators, typename T>
inline static typename EnableIf<
HasDecorator<decorators, AS_RAW>::value && !CanHardwireRaw<decorators>::value, bool>::type
HasDecorator<decorators, AS_RAW>::value && !CanHardwireRaw<decorators>::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 <DecoratorSet decorators, typename T>
inline static typename EnableIf<
!HasDecorator<decorators, AS_RAW>::value, bool>::type
!HasDecorator<decorators, AS_RAW>::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 <DecoratorSet decorators, typename T>
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<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, 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<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw,
dst_obj, dst_offset_in_bytes, dst_raw,
@ -1020,9 +1029,9 @@ namespace AccessInternal {
}
template <DecoratorSet decorators>
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<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw,
@ -1160,9 +1169,9 @@ namespace AccessInternal {
}
template <DecoratorSet decorators, typename T>
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<decorators, INTERNAL_VALUE_IS_OOP>::value ||
(std::is_same<T, void>::value || std::is_integral<T>::value) ||
std::is_floating_point<T>::value)); // arraycopy allows type erased void elements

View File

@ -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<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 (!ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::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<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::
oop_arraycopy(s, src_offset, d, dst_offset, length);
} else {
return ArrayAccess<ARRAYCOPY_DISJOINT>::
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();
}
}
}