/* * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #ifndef SHARE_OOPS_ACCESSBACKEND_HPP #define SHARE_OOPS_ACCESSBACKEND_HPP #include "gc/shared/barrierSetConfig.hpp" #include "memory/allocation.hpp" #include "metaprogramming/conditional.hpp" #include "metaprogramming/decay.hpp" #include "metaprogramming/enableIf.hpp" #include "metaprogramming/integralConstant.hpp" #include "metaprogramming/isFloatingPoint.hpp" #include "metaprogramming/isIntegral.hpp" #include "metaprogramming/isPointer.hpp" #include "metaprogramming/isSame.hpp" #include "metaprogramming/isVolatile.hpp" #include "oops/accessDecorators.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" // This metafunction returns either oop or narrowOop depending on whether // an access needs to use compressed oops or not. template struct HeapOopType: AllStatic { static const bool needs_oop_compress = HasDecorator::value && HasDecorator::value; typedef typename Conditional::type type; }; namespace AccessInternal { enum BarrierType { BARRIER_STORE, BARRIER_STORE_AT, BARRIER_LOAD, BARRIER_LOAD_AT, BARRIER_ATOMIC_CMPXCHG, BARRIER_ATOMIC_CMPXCHG_AT, BARRIER_ATOMIC_XCHG, BARRIER_ATOMIC_XCHG_AT, BARRIER_ARRAYCOPY, BARRIER_CLONE, BARRIER_RESOLVE, BARRIER_EQUALS }; template struct MustConvertCompressedOop: public IntegralConstant::value && IsSame::type, narrowOop>::value && IsSame::value> {}; // This metafunction returns an appropriate oop type if the value is oop-like // and otherwise returns the same type T. template struct EncodedType: AllStatic { typedef typename Conditional< HasDecorator::value, typename HeapOopType::type, T>::type type; }; template inline typename HeapOopType::type* oop_field_addr(oop base, ptrdiff_t byte_offset) { return reinterpret_cast::type*>( reinterpret_cast((void*)base) + byte_offset); } // This metafunction returns whether it is possible for a type T to require // locking to support wide atomics or not. template #ifdef SUPPORTS_NATIVE_CX8 struct PossiblyLockedAccess: public IntegralConstant {}; #else struct PossiblyLockedAccess: public IntegralConstant 4)> {}; #endif template struct AccessFunctionTypes { typedef T (*load_at_func_t)(oop base, ptrdiff_t offset); typedef void (*store_at_func_t)(oop base, ptrdiff_t offset, T value); typedef T (*atomic_cmpxchg_at_func_t)(T new_value, oop base, ptrdiff_t offset, T compare_value); typedef T (*atomic_xchg_at_func_t)(T new_value, oop base, ptrdiff_t offset); typedef T (*load_func_t)(void* addr); typedef void (*store_func_t)(void* addr, T value); 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, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length); typedef void (*clone_func_t)(oop src, oop dst, size_t size); typedef oop (*resolve_func_t)(oop obj); typedef bool (*equals_func_t)(oop o1, oop o2); }; template struct AccessFunctionTypes { typedef bool (*arraycopy_func_t)(arrayOop src_obj, size_t src_offset_in_bytes, void* src, arrayOop dst_obj, size_t dst_offset_in_bytes, void* dst, size_t length); }; template struct AccessFunction {}; #define ACCESS_GENERATE_ACCESS_FUNCTION(bt, func) \ template \ struct AccessFunction: AllStatic{ \ typedef typename AccessFunctionTypes::func type; \ } ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_STORE, store_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_STORE_AT, store_at_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_LOAD, load_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_LOAD_AT, load_at_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_CMPXCHG, atomic_cmpxchg_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_CMPXCHG_AT, atomic_cmpxchg_at_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_XCHG, atomic_xchg_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_XCHG_AT, atomic_xchg_at_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ARRAYCOPY, arraycopy_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_CLONE, clone_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_RESOLVE, resolve_func_t); ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_EQUALS, equals_func_t); #undef ACCESS_GENERATE_ACCESS_FUNCTION template typename AccessFunction::type resolve_barrier(); template typename AccessFunction::type resolve_oop_barrier(); class AccessLocker { public: AccessLocker(); ~AccessLocker(); }; bool wide_atomic_needs_locking(); void* field_addr(oop base, ptrdiff_t offset); // Forward calls to Copy:: in the cpp file to reduce dependencies and allow // faster build times, given how frequently included access is. void arraycopy_arrayof_conjoint_oops(void* src, void* dst, size_t length); void arraycopy_conjoint_oops(oop* src, oop* dst, size_t length); void arraycopy_conjoint_oops(narrowOop* src, narrowOop* dst, size_t length); void arraycopy_disjoint_words(void* src, void* dst, size_t length); void arraycopy_disjoint_words_atomic(void* src, void* dst, size_t length); template void arraycopy_conjoint(T* src, T* dst, size_t length); template void arraycopy_arrayof_conjoint(T* src, T* dst, size_t length); template void arraycopy_conjoint_atomic(T* src, T* dst, size_t length); } // This mask specifies what decorators are relevant for raw accesses. When passing // accesses to the raw layer, irrelevant decorators are removed. const DecoratorSet RAW_DECORATOR_MASK = INTERNAL_DECORATOR_MASK | MO_DECORATOR_MASK | ARRAYCOPY_DECORATOR_MASK | IS_NOT_NULL; // The RawAccessBarrier performs raw accesses with additional knowledge of // memory ordering, so that OrderAccess/Atomic is called when necessary. // It additionally handles compressed oops, and hence is not completely "raw" // strictly speaking. template class RawAccessBarrier: public AllStatic { protected: static inline void* field_addr(oop base, ptrdiff_t byte_offset) { return AccessInternal::field_addr(base, byte_offset); } protected: // Only encode if INTERNAL_VALUE_IS_OOP template static inline typename EnableIf< AccessInternal::MustConvertCompressedOop::value, typename HeapOopType::type>::type encode_internal(T value); template static inline typename EnableIf< !AccessInternal::MustConvertCompressedOop::value, T>::type encode_internal(T value) { return value; } template static inline typename AccessInternal::EncodedType::type encode(T value) { return encode_internal(value); } // Only decode if INTERNAL_VALUE_IS_OOP template static inline typename EnableIf< AccessInternal::MustConvertCompressedOop::value, T>::type decode_internal(typename HeapOopType::type value); template static inline typename EnableIf< !AccessInternal::MustConvertCompressedOop::value, T>::type decode_internal(T value) { return value; } template static inline T decode(typename AccessInternal::EncodedType::type value) { return decode_internal(value); } protected: template static typename EnableIf< HasDecorator::value, T>::type load_internal(void* addr); template static typename EnableIf< HasDecorator::value, T>::type load_internal(void* addr); template static typename EnableIf< HasDecorator::value, T>::type load_internal(void* addr); template static inline typename EnableIf< HasDecorator::value, T>::type load_internal(void* addr) { return *reinterpret_cast(addr); } template static inline typename EnableIf< HasDecorator::value, T>::type load_internal(void* addr) { return *reinterpret_cast(addr); } template static typename EnableIf< HasDecorator::value>::type store_internal(void* addr, T value); template static typename EnableIf< HasDecorator::value>::type store_internal(void* addr, T value); template static typename EnableIf< HasDecorator::value>::type store_internal(void* addr, T value); template static inline typename EnableIf< HasDecorator::value>::type store_internal(void* addr, T value) { (void)const_cast(*reinterpret_cast(addr) = value); } template static inline typename EnableIf< HasDecorator::value>::type store_internal(void* addr, T value) { *reinterpret_cast(addr) = value; } template static typename EnableIf< HasDecorator::value, T>::type atomic_cmpxchg_internal(T new_value, void* addr, T compare_value); template static typename EnableIf< HasDecorator::value, T>::type atomic_cmpxchg_internal(T new_value, void* addr, T compare_value); template static typename EnableIf< HasDecorator::value, T>::type atomic_xchg_internal(T new_value, void* addr); // The following *_locked mechanisms serve the purpose of handling atomic operations // that are larger than a machine can handle, and then possibly opt for using // a slower path using a mutex to perform the operation. template static inline typename EnableIf< !AccessInternal::PossiblyLockedAccess::value, T>::type atomic_cmpxchg_maybe_locked(T new_value, void* addr, T compare_value) { return atomic_cmpxchg_internal(new_value, addr, compare_value); } template static typename EnableIf< AccessInternal::PossiblyLockedAccess::value, T>::type atomic_cmpxchg_maybe_locked(T new_value, void* addr, T compare_value); template static inline typename EnableIf< !AccessInternal::PossiblyLockedAccess::value, T>::type atomic_xchg_maybe_locked(T new_value, void* addr) { return atomic_xchg_internal(new_value, addr); } template static typename EnableIf< AccessInternal::PossiblyLockedAccess::value, T>::type atomic_xchg_maybe_locked(T new_value, void* addr); public: template static inline void store(void* addr, T value) { store_internal(addr, value); } template static inline T load(void* addr) { return load_internal(addr); } template static inline T atomic_cmpxchg(T new_value, void* addr, T compare_value) { return atomic_cmpxchg_maybe_locked(new_value, addr, compare_value); } template static inline T atomic_xchg(T new_value, void* addr) { return atomic_xchg_maybe_locked(new_value, addr); } template static bool arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length); template static void oop_store(void* addr, T value); template static void oop_store_at(oop base, ptrdiff_t offset, T value); template static T oop_load(void* addr); template static T oop_load_at(oop base, ptrdiff_t offset); template static T oop_atomic_cmpxchg(T new_value, void* addr, T compare_value); template static T oop_atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value); template static T oop_atomic_xchg(T new_value, void* addr); template static T oop_atomic_xchg_at(T new_value, oop base, ptrdiff_t offset); template static void store_at(oop base, ptrdiff_t offset, T value) { store(field_addr(base, offset), value); } template static T load_at(oop base, ptrdiff_t offset) { return load(field_addr(base, offset)); } template static T atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { return atomic_cmpxchg(new_value, field_addr(base, offset), compare_value); } template static T atomic_xchg_at(T new_value, oop base, ptrdiff_t offset) { return atomic_xchg(new_value, field_addr(base, offset)); } template static bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length); static void clone(oop src, oop dst, size_t size); static oop resolve(oop obj) { return obj; } static bool equals(oop o1, oop o2) { return (void*) o1 == (void*) o2; } }; // Below is the implementation of the first 4 steps of the template pipeline: // * Step 1: Set default decorators and decay types. This step gets rid of CV qualifiers // and sets default decorators to sensible values. // * Step 2: Reduce types. This step makes sure there is only a single T type and not // multiple types. The P type of the address and T type of the value must // match. // * Step 3: Pre-runtime dispatch. This step checks whether a runtime call can be // avoided, and in that case avoids it (calling raw accesses or // primitive accesses in a build that does not require primitive GC barriers) // * Step 4: Runtime-dispatch. This step performs a runtime dispatch to the corresponding // BarrierSet::AccessBarrier accessor that attaches GC-required barriers // to the access. namespace AccessInternal { template struct OopOrNarrowOopInternal: AllStatic { typedef oop type; }; template <> struct OopOrNarrowOopInternal: AllStatic { typedef narrowOop type; }; // This metafunction returns a canonicalized oop/narrowOop type for a passed // in oop-like types passed in from oop_* overloads where the user has sworn // that the passed in values should be oop-like (e.g. oop, oopDesc*, arrayOop, // narrowOoop, instanceOopDesc*, and random other things). // In the oop_* overloads, it must hold that if the passed in type T is not // narrowOop, then it by contract has to be one of many oop-like types implicitly // convertible to oop, and hence returns oop as the canonical oop type. // If it turns out it was not, then the implicit conversion to oop will fail // to compile, as desired. template struct OopOrNarrowOop: AllStatic { typedef typename OopOrNarrowOopInternal::type>::type type; }; inline void* field_addr(oop base, ptrdiff_t byte_offset) { return reinterpret_cast(reinterpret_cast((void*)base) + byte_offset); } // Step 4: Runtime dispatch // The RuntimeDispatch class is responsible for performing a runtime dispatch of the // accessor. This is required when the access either depends on whether compressed oops // is being used, or it depends on which GC implementation was chosen (e.g. requires GC // barriers). The way it works is that a function pointer initially pointing to an // accessor resolution function gets called for each access. Upon first invocation, // it resolves which accessor to be used in future invocations and patches the // function pointer to this new accessor. template struct RuntimeDispatch: AllStatic {}; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _store_func; static void store_init(void* addr, T value); static inline void store(void* addr, T value) { _store_func(addr, value); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _store_at_func; static void store_at_init(oop base, ptrdiff_t offset, T value); static inline void store_at(oop base, ptrdiff_t offset, T value) { _store_at_func(base, offset, value); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _load_func; static T load_init(void* addr); static inline T load(void* addr) { return _load_func(addr); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _load_at_func; static T load_at_init(oop base, ptrdiff_t offset); static inline T load_at(oop base, ptrdiff_t offset) { return _load_at_func(base, offset); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _atomic_cmpxchg_func; static T atomic_cmpxchg_init(T new_value, void* addr, T compare_value); static inline T atomic_cmpxchg(T new_value, void* addr, T compare_value) { return _atomic_cmpxchg_func(new_value, addr, compare_value); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _atomic_cmpxchg_at_func; static T atomic_cmpxchg_at_init(T new_value, oop base, ptrdiff_t offset, T compare_value); static inline T atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { return _atomic_cmpxchg_at_func(new_value, base, offset, compare_value); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _atomic_xchg_func; static T atomic_xchg_init(T new_value, void* addr); static inline T atomic_xchg(T new_value, void* addr) { return _atomic_xchg_func(new_value, addr); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _atomic_xchg_at_func; static T atomic_xchg_at_init(T new_value, oop base, ptrdiff_t offset); static inline T atomic_xchg_at(T new_value, oop base, ptrdiff_t offset) { return _atomic_xchg_at_func(new_value, base, offset); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _arraycopy_func; static bool arraycopy_init(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length); static inline bool arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length) { return _arraycopy_func(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _clone_func; static void clone_init(oop src, oop dst, size_t size); static inline void clone(oop src, oop dst, size_t size) { _clone_func(src, dst, size); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _resolve_func; static oop resolve_init(oop obj); static inline oop resolve(oop obj) { return _resolve_func(obj); } }; template struct RuntimeDispatch: AllStatic { typedef typename AccessFunction::type func_t; static func_t _equals_func; static bool equals_init(oop o1, oop o2); static inline bool equals(oop o1, oop o2) { return _equals_func(o1, o2); } }; // Initialize the function pointers to point to the resolving function. template typename AccessFunction::type RuntimeDispatch::_store_func = &store_init; template typename AccessFunction::type RuntimeDispatch::_store_at_func = &store_at_init; template typename AccessFunction::type RuntimeDispatch::_load_func = &load_init; template typename AccessFunction::type RuntimeDispatch::_load_at_func = &load_at_init; template typename AccessFunction::type RuntimeDispatch::_atomic_cmpxchg_func = &atomic_cmpxchg_init; template typename AccessFunction::type RuntimeDispatch::_atomic_cmpxchg_at_func = &atomic_cmpxchg_at_init; template typename AccessFunction::type RuntimeDispatch::_atomic_xchg_func = &atomic_xchg_init; template typename AccessFunction::type RuntimeDispatch::_atomic_xchg_at_func = &atomic_xchg_at_init; template typename AccessFunction::type RuntimeDispatch::_arraycopy_func = &arraycopy_init; template typename AccessFunction::type RuntimeDispatch::_clone_func = &clone_init; template typename AccessFunction::type RuntimeDispatch::_resolve_func = &resolve_init; template typename AccessFunction::type RuntimeDispatch::_equals_func = &equals_init; // Step 3: Pre-runtime dispatching. // The PreRuntimeDispatch class is responsible for filtering the barrier strength // decorators. That is, for AS_RAW, it hardwires the accesses without a runtime // dispatch point. Otherwise it goes through a runtime check if hardwiring was // not possible. struct PreRuntimeDispatch: AllStatic { template struct CanHardwireRaw: public IntegralConstant< bool, !HasDecorator::value || // primitive access !HasDecorator::value || // don't care about compressed oops (oop* address) HasDecorator::value> // we can infer we use compressed oops (narrowOop* address) {}; static const DecoratorSet convert_compressed_oops = INTERNAL_RT_USE_COMPRESSED_OOPS | INTERNAL_CONVERT_COMPRESSED_OOP; template static bool is_hardwired_primitive() { return !HasDecorator::value && !HasDecorator::value; } template inline static typename EnableIf< HasDecorator::value && CanHardwireRaw::value>::type store(void* addr, T value) { typedef RawAccessBarrier Raw; if (HasDecorator::value) { Raw::oop_store(addr, value); } else { Raw::store(addr, value); } } template inline static typename EnableIf< HasDecorator::value && !CanHardwireRaw::value>::type store(void* addr, T value) { if (UseCompressedOops) { const DecoratorSet expanded_decorators = decorators | convert_compressed_oops; PreRuntimeDispatch::store(addr, value); } else { const DecoratorSet expanded_decorators = decorators & ~convert_compressed_oops; PreRuntimeDispatch::store(addr, value); } } template inline static typename EnableIf< !HasDecorator::value>::type store(void* addr, T value) { if (is_hardwired_primitive()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; PreRuntimeDispatch::store(addr, value); } else { RuntimeDispatch::store(addr, value); } } template inline static typename EnableIf< HasDecorator::value>::type store_at(oop base, ptrdiff_t offset, T value) { store(field_addr(base, offset), value); } template inline static typename EnableIf< !HasDecorator::value>::type store_at(oop base, ptrdiff_t offset, T value) { if (is_hardwired_primitive()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; PreRuntimeDispatch::store_at(base, offset, value); } else { RuntimeDispatch::store_at(base, offset, value); } } template inline static typename EnableIf< HasDecorator::value && CanHardwireRaw::value, T>::type load(void* addr) { typedef RawAccessBarrier Raw; if (HasDecorator::value) { return Raw::template oop_load(addr); } else { return Raw::template load(addr); } } template inline static typename EnableIf< HasDecorator::value && !CanHardwireRaw::value, T>::type load(void* addr) { if (UseCompressedOops) { const DecoratorSet expanded_decorators = decorators | convert_compressed_oops; return PreRuntimeDispatch::load(addr); } else { const DecoratorSet expanded_decorators = decorators & ~convert_compressed_oops; return PreRuntimeDispatch::load(addr); } } template inline static typename EnableIf< !HasDecorator::value, T>::type load(void* addr) { if (is_hardwired_primitive()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; return PreRuntimeDispatch::load(addr); } else { return RuntimeDispatch::load(addr); } } template inline static typename EnableIf< HasDecorator::value, T>::type load_at(oop base, ptrdiff_t offset) { return load(field_addr(base, offset)); } template inline static typename EnableIf< !HasDecorator::value, T>::type load_at(oop base, ptrdiff_t offset) { if (is_hardwired_primitive()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; return PreRuntimeDispatch::load_at(base, offset); } else { return RuntimeDispatch::load_at(base, offset); } } template inline static typename EnableIf< HasDecorator::value && CanHardwireRaw::value, T>::type atomic_cmpxchg(T new_value, void* addr, T compare_value) { typedef RawAccessBarrier Raw; if (HasDecorator::value) { return Raw::oop_atomic_cmpxchg(new_value, addr, compare_value); } else { return Raw::atomic_cmpxchg(new_value, addr, compare_value); } } template inline static typename EnableIf< HasDecorator::value && !CanHardwireRaw::value, T>::type atomic_cmpxchg(T new_value, void* addr, T compare_value) { if (UseCompressedOops) { const DecoratorSet expanded_decorators = decorators | convert_compressed_oops; return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value); } else { const DecoratorSet expanded_decorators = decorators & ~convert_compressed_oops; return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value); } } template inline static typename EnableIf< !HasDecorator::value, T>::type atomic_cmpxchg(T new_value, void* addr, T compare_value) { if (is_hardwired_primitive()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value); } else { return RuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value); } } template inline static typename EnableIf< HasDecorator::value, T>::type atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { return atomic_cmpxchg(new_value, field_addr(base, offset), compare_value); } template inline static typename EnableIf< !HasDecorator::value, T>::type atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { if (is_hardwired_primitive()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; return PreRuntimeDispatch::atomic_cmpxchg_at(new_value, base, offset, compare_value); } else { return RuntimeDispatch::atomic_cmpxchg_at(new_value, base, offset, compare_value); } } template inline static typename EnableIf< HasDecorator::value && CanHardwireRaw::value, T>::type atomic_xchg(T new_value, void* addr) { typedef RawAccessBarrier Raw; if (HasDecorator::value) { return Raw::oop_atomic_xchg(new_value, addr); } else { return Raw::atomic_xchg(new_value, addr); } } template inline static typename EnableIf< HasDecorator::value && !CanHardwireRaw::value, T>::type atomic_xchg(T new_value, void* addr) { if (UseCompressedOops) { const DecoratorSet expanded_decorators = decorators | convert_compressed_oops; return PreRuntimeDispatch::atomic_xchg(new_value, addr); } else { const DecoratorSet expanded_decorators = decorators & ~convert_compressed_oops; return PreRuntimeDispatch::atomic_xchg(new_value, addr); } } template inline static typename EnableIf< !HasDecorator::value, T>::type atomic_xchg(T new_value, void* addr) { if (is_hardwired_primitive()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; return PreRuntimeDispatch::atomic_xchg(new_value, addr); } else { return RuntimeDispatch::atomic_xchg(new_value, addr); } } template inline static typename EnableIf< HasDecorator::value, T>::type atomic_xchg_at(T new_value, oop base, ptrdiff_t offset) { return atomic_xchg(new_value, field_addr(base, offset)); } template inline static typename EnableIf< !HasDecorator::value, T>::type atomic_xchg_at(T new_value, oop base, ptrdiff_t offset) { if (is_hardwired_primitive()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; return PreRuntimeDispatch::atomic_xchg(new_value, base, offset); } else { return RuntimeDispatch::atomic_xchg_at(new_value, base, offset); } } template inline static typename EnableIf< HasDecorator::value && CanHardwireRaw::value, bool>::type arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length) { typedef RawAccessBarrier Raw; if (HasDecorator::value) { return Raw::oop_arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } else { return Raw::arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } } template inline static typename EnableIf< HasDecorator::value && !CanHardwireRaw::value, bool>::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(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(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } } template inline static typename EnableIf< !HasDecorator::value, bool>::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()) { const DecoratorSet expanded_decorators = decorators | AS_RAW; return PreRuntimeDispatch::arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } else { return RuntimeDispatch::arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } } template inline static typename EnableIf< HasDecorator::value>::type clone(oop src, oop dst, size_t size) { typedef RawAccessBarrier Raw; Raw::clone(src, dst, size); } template inline static typename EnableIf< !HasDecorator::value>::type clone(oop src, oop dst, size_t size) { RuntimeDispatch::clone(src, dst, size); } template inline static typename EnableIf< HasDecorator::value, oop>::type resolve(oop obj) { typedef RawAccessBarrier Raw; return Raw::resolve(obj); } template inline static typename EnableIf< !HasDecorator::value, oop>::type resolve(oop obj) { return RuntimeDispatch::resolve(obj); } template inline static typename EnableIf< HasDecorator::value, bool>::type equals(oop o1, oop o2) { typedef RawAccessBarrier Raw; return Raw::equals(o1, o2); } template inline static typename EnableIf< !HasDecorator::value, bool>::type equals(oop o1, oop o2) { return RuntimeDispatch::equals(o1, o2); } }; // Step 2: Reduce types. // Enforce that for non-oop types, T and P have to be strictly the same. // P is the type of the address and T is the type of the values. // As for oop types, it is allow to send T in {narrowOop, oop} and // P in {narrowOop, oop, HeapWord*}. The following rules apply according to // the subsequent table. (columns are P, rows are T) // | | HeapWord | oop | narrowOop | // | oop | rt-comp | hw-none | hw-comp | // | narrowOop | x | x | hw-none | // // x means not allowed // rt-comp means it must be checked at runtime whether the oop is compressed. // hw-none means it is statically known the oop will not be compressed. // hw-comp means it is statically known the oop will be compressed. template inline void store_reduce_types(T* addr, T value) { PreRuntimeDispatch::store(addr, value); } template inline void store_reduce_types(narrowOop* addr, oop value) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS; PreRuntimeDispatch::store(addr, value); } template inline void store_reduce_types(narrowOop* addr, narrowOop value) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS; PreRuntimeDispatch::store(addr, value); } template inline void store_reduce_types(HeapWord* addr, oop value) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP; PreRuntimeDispatch::store(addr, value); } template inline T atomic_cmpxchg_reduce_types(T new_value, T* addr, T compare_value) { return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value); } template inline oop atomic_cmpxchg_reduce_types(oop new_value, narrowOop* addr, oop compare_value) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS; return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value); } template inline narrowOop atomic_cmpxchg_reduce_types(narrowOop new_value, narrowOop* addr, narrowOop compare_value) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS; return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value); } template inline oop atomic_cmpxchg_reduce_types(oop new_value, HeapWord* addr, oop compare_value) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP; return PreRuntimeDispatch::atomic_cmpxchg(new_value, addr, compare_value); } template inline T atomic_xchg_reduce_types(T new_value, T* addr) { const DecoratorSet expanded_decorators = decorators; return PreRuntimeDispatch::atomic_xchg(new_value, addr); } template inline oop atomic_xchg_reduce_types(oop new_value, narrowOop* addr) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS; return PreRuntimeDispatch::atomic_xchg(new_value, addr); } template inline narrowOop atomic_xchg_reduce_types(narrowOop new_value, narrowOop* addr) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS; return PreRuntimeDispatch::atomic_xchg(new_value, addr); } template inline oop atomic_xchg_reduce_types(oop new_value, HeapWord* addr) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP; return PreRuntimeDispatch::atomic_xchg(new_value, addr); } template inline T load_reduce_types(T* addr) { return PreRuntimeDispatch::load(addr); } template inline typename OopOrNarrowOop::type load_reduce_types(narrowOop* addr) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS; return PreRuntimeDispatch::load::type>(addr); } template inline oop load_reduce_types(HeapWord* addr) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP; return PreRuntimeDispatch::load(addr); } template inline bool arraycopy_reduce_types(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length) { return PreRuntimeDispatch::arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } template inline bool arraycopy_reduce_types(arrayOop src_obj, size_t src_offset_in_bytes, HeapWord* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, HeapWord* dst_raw, size_t length) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP; return PreRuntimeDispatch::arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } template inline bool arraycopy_reduce_types(arrayOop src_obj, size_t src_offset_in_bytes, narrowOop* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, narrowOop* dst_raw, size_t length) { const DecoratorSet expanded_decorators = decorators | INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_RT_USE_COMPRESSED_OOPS; return PreRuntimeDispatch::arraycopy(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length); } // Step 1: Set default decorators. This step remembers if a type was volatile // and then sets the MO_VOLATILE decorator by default. Otherwise, a default // memory ordering is set for the access, and the implied decorator rules // are applied to select sensible defaults for decorators that have not been // explicitly set. For example, default object referent strength is set to strong. // This step also decays the types passed in (e.g. getting rid of CV qualifiers // and references from the types). This step also perform some type verification // that the passed in types make sense. template static void verify_types(){ // If this fails to compile, then you have sent in something that is // not recognized as a valid primitive type to a primitive Access function. STATIC_ASSERT((HasDecorator::value || // oops have already been validated (IsPointer::value || IsIntegral::value) || IsFloatingPoint::value)); // not allowed primitive type } template inline void store(P* addr, T value) { verify_types(); typedef typename Decay

::type DecayedP; typedef typename Decay::type DecayedT; DecayedT decayed_value = value; // If a volatile address is passed in but no memory ordering decorator, // set the memory ordering to MO_VOLATILE by default. const DecoratorSet expanded_decorators = DecoratorFixup< (IsVolatile

::value && !HasDecorator::value) ? (MO_VOLATILE | decorators) : decorators>::value; store_reduce_types(const_cast(addr), decayed_value); } template inline void store_at(oop base, ptrdiff_t offset, T value) { verify_types(); typedef typename Decay::type DecayedT; DecayedT decayed_value = value; const DecoratorSet expanded_decorators = DecoratorFixup::value ? INTERNAL_CONVERT_COMPRESSED_OOP : INTERNAL_EMPTY)>::value; PreRuntimeDispatch::store_at(base, offset, decayed_value); } template inline T load(P* addr) { verify_types(); typedef typename Decay

::type DecayedP; typedef typename Conditional::value, typename OopOrNarrowOop::type, typename Decay::type>::type DecayedT; // If a volatile address is passed in but no memory ordering decorator, // set the memory ordering to MO_VOLATILE by default. const DecoratorSet expanded_decorators = DecoratorFixup< (IsVolatile

::value && !HasDecorator::value) ? (MO_VOLATILE | decorators) : decorators>::value; return load_reduce_types(const_cast(addr)); } template inline T load_at(oop base, ptrdiff_t offset) { verify_types(); typedef typename Conditional::value, typename OopOrNarrowOop::type, typename Decay::type>::type DecayedT; // Expand the decorators (figure out sensible defaults) // Potentially remember if we need compressed oop awareness const DecoratorSet expanded_decorators = DecoratorFixup::value ? INTERNAL_CONVERT_COMPRESSED_OOP : INTERNAL_EMPTY)>::value; return PreRuntimeDispatch::load_at(base, offset); } template inline T atomic_cmpxchg(T new_value, P* addr, T compare_value) { verify_types(); typedef typename Decay

::type DecayedP; typedef typename Decay::type DecayedT; DecayedT new_decayed_value = new_value; DecayedT compare_decayed_value = compare_value; const DecoratorSet expanded_decorators = DecoratorFixup< (!HasDecorator::value) ? (MO_SEQ_CST | decorators) : decorators>::value; return atomic_cmpxchg_reduce_types(new_decayed_value, const_cast(addr), compare_decayed_value); } template inline T atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { verify_types(); typedef typename Decay::type DecayedT; DecayedT new_decayed_value = new_value; DecayedT compare_decayed_value = compare_value; // Determine default memory ordering const DecoratorSet expanded_decorators = DecoratorFixup< (!HasDecorator::value) ? (MO_SEQ_CST | decorators) : decorators>::value; // Potentially remember that we need compressed oop awareness const DecoratorSet final_decorators = expanded_decorators | (HasDecorator::value ? INTERNAL_CONVERT_COMPRESSED_OOP : INTERNAL_EMPTY); return PreRuntimeDispatch::atomic_cmpxchg_at(new_decayed_value, base, offset, compare_decayed_value); } template inline T atomic_xchg(T new_value, P* addr) { verify_types(); typedef typename Decay

::type DecayedP; typedef typename Decay::type DecayedT; DecayedT new_decayed_value = new_value; // atomic_xchg is only available in SEQ_CST flavour. const DecoratorSet expanded_decorators = DecoratorFixup::value; return atomic_xchg_reduce_types(new_decayed_value, const_cast(addr)); } template inline T atomic_xchg_at(T new_value, oop base, ptrdiff_t offset) { verify_types(); typedef typename Decay::type DecayedT; DecayedT new_decayed_value = new_value; // atomic_xchg is only available in SEQ_CST flavour. const DecoratorSet expanded_decorators = DecoratorFixup::value ? INTERNAL_CONVERT_COMPRESSED_OOP : INTERNAL_EMPTY)>::value; return PreRuntimeDispatch::atomic_xchg_at(new_decayed_value, base, offset); } template inline bool arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw, arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, size_t length) { STATIC_ASSERT((HasDecorator::value || (IsSame::value || IsIntegral::value) || IsFloatingPoint::value)); // arraycopy allows type erased void elements typedef typename Decay::type DecayedT; const DecoratorSet expanded_decorators = DecoratorFixup::value; return arraycopy_reduce_types(src_obj, src_offset_in_bytes, const_cast(src_raw), dst_obj, dst_offset_in_bytes, const_cast(dst_raw), length); } template inline void clone(oop src, oop dst, size_t size) { const DecoratorSet expanded_decorators = DecoratorFixup::value; PreRuntimeDispatch::clone(src, dst, size); } template inline oop resolve(oop obj) { const DecoratorSet expanded_decorators = DecoratorFixup::value; return PreRuntimeDispatch::resolve(obj); } template inline bool equals(oop o1, oop o2) { const DecoratorSet expanded_decorators = DecoratorFixup::value; return PreRuntimeDispatch::equals(o1, o2); } // Infer the type that should be returned from an Access::oop_load. template class OopLoadProxy: public StackObj { private: P *const _addr; public: OopLoadProxy(P* addr) : _addr(addr) {} inline operator oop() { return load(_addr); } inline operator narrowOop() { return load(_addr); } template inline bool operator ==(const T& other) const { return load(_addr) == other; } template inline bool operator !=(const T& other) const { return load(_addr) != other; } }; // Infer the type that should be returned from an Access::load_at. template class LoadAtProxy: public StackObj { private: const oop _base; const ptrdiff_t _offset; public: LoadAtProxy(oop base, ptrdiff_t offset) : _base(base), _offset(offset) {} template inline operator T() const { return load_at(_base, _offset); } template inline bool operator ==(const T& other) const { return load_at(_base, _offset) == other; } template inline bool operator !=(const T& other) const { return load_at(_base, _offset) != other; } }; // Infer the type that should be returned from an Access::oop_load_at. template class OopLoadAtProxy: public StackObj { private: const oop _base; const ptrdiff_t _offset; public: OopLoadAtProxy(oop base, ptrdiff_t offset) : _base(base), _offset(offset) {} inline operator oop() const { return load_at(_base, _offset); } inline operator narrowOop() const { return load_at(_base, _offset); } template inline bool operator ==(const T& other) const { return load_at(_base, _offset) == other; } template inline bool operator !=(const T& other) const { return load_at(_base, _offset) != other; } }; } #endif // SHARE_OOPS_ACCESSBACKEND_HPP