OpenJDK / valhalla / valhalla
changeset 56255:966737ceafe7 lworld
8229539: [lworld] Incorrect result of sorting test with -XX:ValueArrayElemMaxFlatSize=0
line wrap: on
line diff
--- a/src/hotspot/share/gc/shared/barrierSet.cpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/gc/shared/barrierSet.cpp Fri Aug 30 09:59:15 2019 +0200 @@ -25,6 +25,8 @@ #include "precompiled.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" +#include "memory/resourceArea.hpp" +#include "oops/objArrayKlass.inline.hpp" #include "runtime/thread.hpp" #include "utilities/debug.hpp" #include "utilities/macros.hpp" @@ -49,6 +51,32 @@ _barrier_set->on_thread_create(Thread::current()); } +void BarrierSet::throw_array_null_pointer_store_exception(arrayOop src, arrayOop dst, TRAPS) { + Klass* bound = ObjArrayKlass::cast(dst->klass())->element_klass(); + stringStream ss; + ss.print("arraycopy: can not copy null values into %s[]", + bound->external_name()); + THROW_MSG(vmSymbols::java_lang_NullPointerException(), ss.as_string()); +} + +void BarrierSet::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()); +} + // Called from init.cpp void gc_barrier_stubs_init() { BarrierSet* bs = BarrierSet::barrier_set();
--- a/src/hotspot/share/gc/shared/barrierSet.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/gc/shared/barrierSet.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -30,6 +30,7 @@ #include "oops/access.hpp" #include "oops/accessBackend.hpp" #include "oops/oopsHierarchy.hpp" +#include "utilities/exceptions.hpp" #include "utilities/fakeRttiSupport.hpp" #include "utilities/macros.hpp" @@ -121,6 +122,9 @@ return COMPILER2_PRESENT(new BarrierSetC2T()) NOT_COMPILER2(NULL); } + static void throw_array_null_pointer_store_exception(arrayOop src, arrayOop dst, TRAPS); + static void throw_array_store_exception(arrayOop src, arrayOop dst, TRAPS); + public: // Support for optimizing compilers to call the barrier set on slow path allocations // that did not enter a TLAB. Used for e.g. ReduceInitialCardMarks. @@ -283,7 +287,7 @@ } template <typename T> - static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, + static void 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);
--- a/src/hotspot/share/gc/shared/barrierSet.inline.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/gc/shared/barrierSet.inline.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -33,28 +33,34 @@ 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, +inline void 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) { + if ((!HasDecorator<decorators, ARRAYCOPY_CHECKCAST>::value) && + (!HasDecorator<decorators, ARRAYCOPY_NOTNULL>::value)) { // Covariant, copy without checks - return Raw::oop_arraycopy(NULL, 0, src, NULL, 0, dst, length); + Raw::oop_arraycopy(NULL, 0, src, NULL, 0, dst, length); + return; } // Copy each element with checking casts Klass* const dst_klass = objArrayOop(dst_obj)->element_klass(); 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; + if (HasDecorator<decorators, ARRAYCOPY_NOTNULL>::value && CompressedOops::is_null(elem)) { + throw_array_null_pointer_store_exception(src_obj, dst_obj, Thread::current()); + return; + } + if (HasDecorator<decorators, ARRAYCOPY_CHECKCAST>::value && + (!oopDesc::is_instanceof_or_null(CompressedOops::decode(elem), dst_klass))) { + throw_array_store_exception(src_obj, dst_obj, Thread::current()); + return; } *dst = elem; } - - return true; } #endif // SHARE_GC_SHARED_BARRIERSET_INLINE_HPP
--- a/src/hotspot/share/gc/shared/modRefBarrierSet.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/gc/shared/modRefBarrierSet.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -68,7 +68,6 @@ protected: virtual void write_ref_array_work(MemRegion mr) = 0; - public: // The ModRef abstraction introduces pre and post barriers template <DecoratorSet decorators, typename BarrierSetT> @@ -84,10 +83,14 @@ static oop oop_atomic_xchg_in_heap(oop new_value, T* addr); template <typename T> - static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, + static void 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); - + private: + // Failing checkcast or check null during copy, still needs barrier + template <typename T> + static inline void oop_arraycopy_partial_barrier(BarrierSetT *bs, T* dst_raw, T* p); + public: static void clone_in_heap(oop src, oop dst, size_t size); static void oop_store_in_heap_at(oop base, ptrdiff_t offset, oop value) {
--- a/src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -90,7 +90,18 @@ template <DecoratorSet decorators, typename BarrierSetT> template <typename T> -inline bool ModRefBarrierSet::AccessBarrier<decorators, BarrierSetT>:: +inline void ModRefBarrierSet::AccessBarrier<decorators, BarrierSetT>:: +oop_arraycopy_partial_barrier(BarrierSetT *bs, T* dst_raw, T* p) { + 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_raw, pd); +} + +template <DecoratorSet decorators, typename BarrierSetT> +template <typename T> +inline void ModRefBarrierSet::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) { @@ -99,7 +110,8 @@ 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) { + if ((!HasDecorator<decorators, ARRAYCOPY_CHECKCAST>::value) && + (!HasDecorator<decorators, ARRAYCOPY_NOTNULL>::value)) { // Optimized covariant case bs->write_ref_array_pre(dst_raw, length, HasDecorator<decorators, IS_DEST_UNINITIALIZED>::value); @@ -112,22 +124,24 @@ T* end = from + length; 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_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_raw, pd); - return false; + // Apply any required checks + if (HasDecorator<decorators, ARRAYCOPY_NOTNULL>::value && CompressedOops::is_null(element)) { + oop_arraycopy_partial_barrier(bs, dst_raw, p); + throw_array_null_pointer_store_exception(src_obj, dst_obj, Thread::current()); + return; } + if (HasDecorator<decorators, ARRAYCOPY_CHECKCAST>::value && + (!oopDesc::is_instanceof_or_null(CompressedOops::decode(element), bound))) { + oop_arraycopy_partial_barrier(bs, dst_raw, p); + throw_array_store_exception(src_obj, dst_obj, Thread::current()); + return; + } + // write + bs->template write_ref_field_pre<decorators>(p); + *p = element; } bs->write_ref_array((HeapWord*)dst_raw, length); } - return true; } template <DecoratorSet decorators, typename BarrierSetT>
--- a/src/hotspot/share/gc/z/zBarrierSet.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/gc/z/zBarrierSet.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -78,7 +78,7 @@ static oop oop_atomic_xchg_in_heap_at(oop new_value, oop base, ptrdiff_t offset); template <typename T> - static bool oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, + static void 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);
--- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -170,32 +170,38 @@ template <DecoratorSet decorators, typename BarrierSetT> template <typename T> -inline bool ZBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, +inline void ZBarrierSet::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) { + if ((!HasDecorator<decorators, ARRAYCOPY_CHECKCAST>::value) && + (!HasDecorator<decorators, ARRAYCOPY_NOTNULL>::value)) { // No check cast, bulk barrier and bulk copy ZBarrier::load_barrier_on_oop_array(src, length); - return Raw::oop_arraycopy_in_heap(NULL, 0, src, NULL, 0, dst, length); + Raw::oop_arraycopy_in_heap(NULL, 0, src, NULL, 0, dst, length); + return; } // Check cast and copy each elements Klass* const dst_klass = objArrayOop(dst_obj)->element_klass(); for (const T* const end = src + length; src < end; src++, dst++) { const oop elem = ZBarrier::load_barrier_on_oop_field(src); - if (!oopDesc::is_instanceof_or_null(elem, dst_klass)) { + if (HasDecorator<decorators, ARRAYCOPY_NOTNULL>::value && elem == NULL) { + throw_array_null_pointer_store_exception(src_obj, dst_obj, Thread::current()); + return; + } + if (HasDecorator<decorators, ARRAYCOPY_CHECKCAST>::value && + (!oopDesc::is_instanceof_or_null(elem, dst_klass))) { // Check cast failed - return false; + throw_array_store_exception(src_obj, dst_obj, Thread::current()); + return; } // Cast is safe, since we know it's never a narrowOop *(oop*)dst = elem; } - - return true; } template <DecoratorSet decorators, typename BarrierSetT>
--- a/src/hotspot/share/oops/access.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/oops/access.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -131,14 +131,14 @@ protected: template <typename T> - static inline bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw, + static inline void 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, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + 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> @@ -329,19 +329,19 @@ length); } - static inline bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, + static inline void 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); + 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); + static inline void oop_arraycopy_raw(T* src, T* dst, size_t length) { + AccessT::oop_arraycopy(NULL, 0, src, + NULL, 0, dst, + length); } };
--- a/src/hotspot/share/oops/access.inline.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/oops/access.inline.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -124,23 +124,22 @@ 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, + static void 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, size_t src_offset_in_bytes, T* src_raw, + static void 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), - length); + 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); } }; @@ -344,14 +343,14 @@ } 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, + void 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, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + 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.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/oops/accessBackend.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -110,7 +110,7 @@ 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, size_t src_offset_in_bytes, T* src_raw, + typedef void (*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); @@ -120,7 +120,7 @@ template <DecoratorSet decorators> struct AccessFunctionTypes<decorators, void> { - typedef bool (*arraycopy_func_t)(arrayOop src_obj, size_t src_offset_in_bytes, void* src, + typedef void (*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); }; @@ -357,7 +357,7 @@ } template <typename T> - static bool arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, + static void 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); @@ -402,7 +402,7 @@ } template <typename T> - static bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, + static void 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); @@ -567,11 +567,11 @@ 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, + static void 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, + static inline void 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, @@ -913,56 +913,56 @@ 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, void>::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); } } 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, void>::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) { if (UseCompressedOops) { const DecoratorSet expanded_decorators = decorators | convert_compressed_oops; - return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + 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, src_offset_in_bytes, src_raw, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + 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 + !HasDecorator<decorators, AS_RAW>::value, void>::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) { if (is_hardwired_primitive<decorators>()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; - return PreRuntimeDispatch::arraycopy<expanded_decorators>(src_obj, src_offset_in_bytes, src_raw, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + 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, src_offset_in_bytes, src_raw, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + RuntimeDispatch<decorators, T, BARRIER_ARRAYCOPY>::arraycopy(src_obj, src_offset_in_bytes, src_raw, + dst_obj, dst_offset_in_bytes, dst_raw, + length); } } @@ -1124,33 +1124,33 @@ } template <DecoratorSet decorators, typename T> - inline bool arraycopy_reduce_types(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, + inline void 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); + 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, + inline void 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, - length); + 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, size_t src_offset_in_bytes, narrowOop* src_raw, + inline void 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, - dst_obj, dst_offset_in_bytes, dst_raw, - length); + 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 @@ -1283,7 +1283,7 @@ } template <DecoratorSet decorators, typename T> - inline bool arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw, + 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) { STATIC_ASSERT((HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::value || @@ -1291,9 +1291,9 @@ IsFloatingPoint<T>::value)); // arraycopy allows type erased void elements typedef typename Decay<T>::type DecayedT; const DecoratorSet expanded_decorators = DecoratorFixup<decorators | IS_ARRAY | IN_HEAP>::value; - 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); + 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); } template <DecoratorSet decorators>
--- a/src/hotspot/share/oops/accessBackend.inline.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/oops/accessBackend.inline.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -118,12 +118,12 @@ template <DecoratorSet decorators> template <typename T> -inline bool RawAccessBarrier<decorators>::oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, +inline void 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); + arraycopy(src_obj, src_offset_in_bytes, src_raw, + dst_obj, dst_offset_in_bytes, dst_raw, + length); } template <DecoratorSet decorators> @@ -334,13 +334,12 @@ template <DecoratorSet decorators> template <typename T> -inline bool RawAccessBarrier<decorators>::arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, +inline void 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; } template <DecoratorSet decorators>
--- a/src/hotspot/share/oops/accessDecorators.hpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/oops/accessDecorators.hpp Fri Aug 30 09:59:15 2019 +0200 @@ -200,29 +200,33 @@ // are not guaranteed to be subclasses of the class of the destination array. This requires // a check-cast barrier during the copying operation. If this is not set, it is assumed // that the array is covariant: (the source array type is-a destination array type) +// * ARRAYCOPY_NOTNULL: This property means that the source array may contain null elements +// but the destination does not allow null elements (i.e. throw NPE) // * ARRAYCOPY_DISJOINT: This property means that it is known that the two array ranges // are disjoint. // * ARRAYCOPY_ARRAYOF: The copy is in the arrayof form. // * ARRAYCOPY_ATOMIC: The accesses have to be atomic over the size of its elements. // * ARRAYCOPY_ALIGNED: The accesses have to be aligned on a HeapWord. const DecoratorSet ARRAYCOPY_CHECKCAST = UCONST64(1) << 24; -const DecoratorSet ARRAYCOPY_DISJOINT = UCONST64(1) << 25; -const DecoratorSet ARRAYCOPY_ARRAYOF = UCONST64(1) << 26; -const DecoratorSet ARRAYCOPY_ATOMIC = UCONST64(1) << 27; -const DecoratorSet ARRAYCOPY_ALIGNED = UCONST64(1) << 28; -const DecoratorSet ARRAYCOPY_DECORATOR_MASK = ARRAYCOPY_CHECKCAST | ARRAYCOPY_DISJOINT | - ARRAYCOPY_DISJOINT | ARRAYCOPY_ARRAYOF | - ARRAYCOPY_ATOMIC | ARRAYCOPY_ALIGNED; +const DecoratorSet ARRAYCOPY_NOTNULL = UCONST64(1) << 25; +const DecoratorSet ARRAYCOPY_DISJOINT = UCONST64(1) << 26; +const DecoratorSet ARRAYCOPY_ARRAYOF = UCONST64(1) << 27; +const DecoratorSet ARRAYCOPY_ATOMIC = UCONST64(1) << 28; +const DecoratorSet ARRAYCOPY_ALIGNED = UCONST64(1) << 29; +const DecoratorSet ARRAYCOPY_DECORATOR_MASK = ARRAYCOPY_CHECKCAST | ARRAYCOPY_NOTNULL | + ARRAYCOPY_DISJOINT | ARRAYCOPY_DISJOINT | + ARRAYCOPY_ARRAYOF | ARRAYCOPY_ATOMIC | + ARRAYCOPY_ALIGNED; // == Resolve barrier decorators == // * ACCESS_READ: Indicate that the resolved object is accessed read-only. This allows the GC // backend to use weaker and more efficient barriers. // * ACCESS_WRITE: Indicate that the resolved object is used for write access. -const DecoratorSet ACCESS_READ = UCONST64(1) << 29; -const DecoratorSet ACCESS_WRITE = UCONST64(1) << 30; +const DecoratorSet ACCESS_READ = UCONST64(1) << 30; +const DecoratorSet ACCESS_WRITE = UCONST64(1) << 31; // Keep track of the last decorator. -const DecoratorSet DECORATOR_LAST = UCONST64(1) << 30; +const DecoratorSet DECORATOR_LAST = UCONST64(1) << 31; namespace AccessInternal { // This class adds implied decorators that follow according to decorator rules.
--- a/src/hotspot/share/oops/objArrayKlass.cpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/oops/objArrayKlass.cpp Fri Aug 30 09:59:15 2019 +0200 @@ -233,26 +233,20 @@ // 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(); + // Perform null check if dst is null-free but src has no such guarantee + bool null_check = ((!ArrayKlass::cast(s->klass())->storage_properties().is_null_free()) && + ArrayKlass::cast(d->klass())->storage_properties().is_null_free()); 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); + if (null_check) { + ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_NOTNULL>::oop_arraycopy(s, src_offset, d, dst_offset, length); + } else { + 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()); + if (null_check) { + ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST | ARRAYCOPY_NOTNULL>::oop_arraycopy(s, src_offset, d, dst_offset, length); + } else { + ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::oop_arraycopy(s, src_offset, d, dst_offset, length); } } } @@ -320,28 +314,7 @@ if (length==0) { return; } - if (EnableValhalla && ArrayKlass::cast(d->klass())->element_klass()->is_value()) { - assert(d->is_objArray(), "Expected objArray"); - ValueKlass* d_elem_vklass = ValueKlass::cast(ArrayKlass::cast(d->klass())->element_klass()); - objArrayOop da = objArrayOop(d); - objArrayOop sa = objArrayOop(s); - int src_end = src_pos + length; - bool null_free = ArrayKlass::cast(s->klass())->storage_properties().is_null_free() || - ArrayKlass::cast(d->klass())->storage_properties().is_null_free(); - while (src_pos < src_end) { - oop se = sa->obj_at(src_pos); - if (null_free && se == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - // Check exact type per element - if (se != NULL && se->klass() != d_elem_vklass) { - THROW(vmSymbols::java_lang_ArrayStoreException()); - } - da->obj_at_put(dst_pos, se); // TODO: review with ValueArrayKlass::copy_array and Access API - dst_pos++; - src_pos++; - } - } else if (UseCompressedOops) { + if (UseCompressedOops) { 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) ==
--- a/src/hotspot/share/oops/valueArrayKlass.cpp Sun Aug 25 15:47:20 2019 +0530 +++ b/src/hotspot/share/oops/valueArrayKlass.cpp Fri Aug 30 09:59:15 2019 +0200 @@ -184,6 +184,12 @@ return element_klass()->protection_domain(); } +// Temp hack having this here: need to move towards Access API +static bool needs_backwards_copy(arrayOop s, int src_pos, + arrayOop d, int dst_pos, int length) { + return oopDesc::equals(s, d) && (dst_pos > src_pos) && (dst_pos - src_pos) < length; +} + void ValueArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS) { @@ -236,10 +242,21 @@ if (contains_oops()) { int elem_incr = 1 << log2_element_size(); address src_end = src + (length << log2_element_size()); - while (src < src_end) { - s_elem_vklass->value_store(src, dst, element_byte_size(), true, false); - src += elem_incr; - dst += elem_incr; + if (needs_backwards_copy(s, src_pos, d, dst_pos, length)) { + swap(src, src_end); + dst = dst + (length << log2_element_size()); + do { + src -= elem_incr; + dst -= elem_incr; + s_elem_vklass->value_store(src, dst, element_byte_size(), true, false); + } while (src > src_end); + } else { + address src_end = src + (length << log2_element_size()); + while (src < src_end) { + s_elem_vklass->value_store(src, dst, element_byte_size(), true, false); + src += elem_incr; + dst += elem_incr; + } } } else { // we are basically a type array...don't bother limiting element copy
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/Long8Value.java Sun Aug 25 15:47:20 2019 +0530 +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Long8Value.java Fri Aug 30 09:59:15 2019 +0200 @@ -36,15 +36,15 @@ final long longField7; final long longField8; - private Long8Value() { - longField1 = 0; - longField2 = 0; - longField3 = 0; - longField4 = 0; - longField5 = 0; - longField6 = 0; - longField7 = 0; - longField8 = 0; + private Long8Value(long l1, long l2, long l3, long l4, long l5, long l6, long l7, long l8) { + longField1 = l1; + longField2 = l2; + longField3 = l3; + longField4 = l4; + longField5 = l5; + longField6 = l6; + longField7 = l7; + longField8 = l8; } public long getLongField1() { return longField1; } @@ -64,16 +64,7 @@ long long6, long long7, long long8) { - Long8Value l8v = Long8Value.default; - l8v = __WithField(l8v.longField1, long1); - l8v = __WithField(l8v.longField2, long2); - l8v = __WithField(l8v.longField3, long3); - l8v = __WithField(l8v.longField4, long4); - l8v = __WithField(l8v.longField5, long5); - l8v = __WithField(l8v.longField6, long6); - l8v = __WithField(l8v.longField7, long7); - l8v = __WithField(l8v.longField8, long8); - return l8v; + return new Long8Value(long1, long2, long3, long4, long5, long6, long7, long8); } static void check(Long8Value value,
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/Person.java Sun Aug 25 15:47:20 2019 +0530 +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Person.java Fri Aug 30 09:59:15 2019 +0200 @@ -29,10 +29,10 @@ final String firstName; final String lastName; - private Person() { - id = 0; - firstName = null; - lastName = null; + private Person(int id, String firstName, String lastName) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; } public int getId() { return id; } @@ -44,10 +44,6 @@ } static Person create(int id, String firstName, String lastName) { - Person p = Person.default; - p = __WithField(p.id, id); - p = __WithField(p.firstName, firstName); - p = __WithField(p.lastName, lastName); - return p; + return new Person(id, firstName, lastName); } }
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/Point.java Sun Aug 25 15:47:20 2019 +0530 +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Point.java Fri Aug 30 09:59:15 2019 +0200 @@ -26,9 +26,9 @@ final int x; final int y; - private Point() { - x = 0; - y = 0; + private Point(int x, int y) { + this.x = x; + this.y = y; } public int getX() { return x; } @@ -51,9 +51,6 @@ } public static Point createPoint(int x, int y) { - Point p = Point.default; - p = __WithField(p.x, x); - p = __WithField(p.y, y); - return p; + return new Point(x, y); } }
--- a/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java Sun Aug 25 15:47:20 2019 +0530 +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java Fri Aug 30 09:59:15 2019 +0200 @@ -34,7 +34,7 @@ * @test ValueTypeArray * @summary Plain array test for Inline Types * @library /test/lib - * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator -XDallowFlattenabilityModifiers -XDallowGenericsOverValues ValueTypeArray.java Point.java Long8Value.java Person.java + * @compile -XDallowGenericsOverValues ValueTypeArray.java Point.java Long8Value.java Person.java * @run main/othervm -Xint -XX:ValueArrayElemMaxFlatSize=-1 runtime.valhalla.valuetypes.ValueTypeArray * @run main/othervm -Xint -XX:ValueArrayElemMaxFlatSize=0 runtime.valhalla.valuetypes.ValueTypeArray * @run main/othervm -Xcomp -XX:ValueArrayElemMaxFlatSize=-1 runtime.valhalla.valuetypes.ValueTypeArray @@ -109,28 +109,43 @@ assertTrue(gotNpe, "Expected NullPointerException"); Point[] points = createSimplePointArray(); + System.gc(); // check that VTs survive GC checkSimplePointArray(points); - System.gc(); // check that VTs survive GC assertTrue(points instanceof Point[], "Instance of"); + testSimplePointArrayCopy(); + } + + void testSimplePointArrayCopy() { + Point[] points = createSimplePointArray(); Point[] pointsCopy = new Point[points.length]; System.arraycopy(points, 0, pointsCopy, 0, points.length); checkSimplePointArray(pointsCopy); + + // Conjoint, overlap...left + System.arraycopy(points, 0, points, 1, 2); + checkArrayElementsEqual(points, new Point[] { pointsCopy[0], pointsCopy[0], pointsCopy[1], pointsCopy[3] }); + + // Conjoint, overlap...right + points = createSimplePointArray(); + System.arraycopy(points, 2, points, 1, 2); + checkArrayElementsEqual(points, new Point[] { pointsCopy[0], pointsCopy[2], pointsCopy[3], pointsCopy[3] }); } static Point[] createSimplePointArray() { - Point[] ps = new Point[2]; - assertEquals(ps.length, 2, "Length"); + Point[] ps = new Point[4]; + assertEquals(ps.length, 4, "Length"); ps.toString(); ps[0] = Point.createPoint(1, 2); ps[1] = Point.createPoint(3, 4); + ps[2] = Point.createPoint(5, 6); + ps[3] = Point.createPoint(7, 8); boolean sawOob = false; try { - ps[2] = Point.createPoint(0, 0); + ps[ps.length] = Point.createPoint(0, 0); } catch (ArrayIndexOutOfBoundsException aioobe) { sawOob = true; } assertTrue(sawOob, "Didn't see AIOOBE"); - System.gc(); // check that VTs survive GC return ps; } @@ -139,6 +154,10 @@ assertEquals(points[0].y, 2, "invalid 0 point y value"); assertEquals(points[1].x, 3, "invalid 1 point x value"); assertEquals(points[1].y, 4, "invalid 1 point y value"); + assertEquals(points[2].x, 5, "invalid 2 point x value"); + assertEquals(points[2].y, 6, "invalid 2 point y value"); + assertEquals(points[3].x, 7, "invalid 3 point x value"); + assertEquals(points[3].y, 8, "invalid 3 point y value"); } void testLong8Array() { @@ -213,7 +232,8 @@ static final inline class MyInt implements Comparable<MyInt?> { final int value; - private MyInt() { value = 0; } + private MyInt() { this(0); } + private MyInt(int v) { value = v; } public int getValue() { return value; } public String toString() { return "MyInt: " + getValue(); } public int compareTo(MyInt? that) { return Integer.compare(this.getValue(), that.getValue()); } @@ -225,9 +245,7 @@ } public static MyInt create(int v) { - MyInt mi = MyInt.default; - mi = __WithField(mi.value, v); - return mi; + return new MyInt(v); } // Null-able fields here are a temp hack to avoid ClassCircularityError @@ -426,9 +444,10 @@ final MyInt x; final MyInt y; - private MyPoint() { - x = (MyInt) MyInt.ZERO; - y = x; + private MyPoint() { this(0, 0); } + private MyPoint(int x, int y) { + this.x = new MyInt(x); + this.y = new MyInt(y); } public boolean equals(Object that) { if (that instanceof MyPoint) { @@ -438,15 +457,10 @@ return false; } static MyPoint create(int x) { - MyPoint mp = MyPoint.default; - mp = __WithField(mp.x, MyInt.create(x)); - return mp; + return new MyPoint(x, x); } static MyPoint create(int x, int y) { - MyPoint mp = MyPoint.default; - mp = __WithField(mp.x, MyInt.create(x)); - mp = __WithField(mp.y, MyInt.create(y)); - return mp; + return new MyPoint(x, y); } static final MyPoint? ORIGIN = create(0); }