mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8373801: Adopt arraycopy OopCopyResult from the lworld branch
Reviewed-by: jsikstro, tschatzl, aboldtch
This commit is contained in:
parent
45cf042099
commit
53e77d21c2
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user