/* * 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_VM_RUNTIME_ACCESSBACKEND_HPP #define SHARE_VM_RUNTIME_ACCESSBACKEND_HPP #include "metaprogramming/conditional.hpp" #include "metaprogramming/enableIf.hpp" #include "metaprogramming/integralConstant.hpp" #include "metaprogramming/isSame.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 }; 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, arrayOop dst_obj, T* src, T* dst, size_t length); typedef void (*clone_func_t)(oop src, oop dst, size_t size); typedef oop (*resolve_func_t)(oop obj); }; 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); #undef ACCESS_GENERATE_ACCESS_FUNCTION template typename AccessFunction::type resolve_barrier(); template typename AccessFunction::type resolve_oop_barrier(); class AccessLocker VALUE_OBJ_CLASS_SPEC { 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 | OOP_DECORATOR_MASK; // 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 s, arrayOop d, T* src, T* dst, 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, arrayOop dst_obj, T* src, T* dst, size_t length); static bool oop_arraycopy(arrayOop src_obj, arrayOop dst_obj, HeapWord* src, HeapWord* dst, size_t length); static void clone(oop src, oop dst, size_t size); static oop resolve(oop obj) { return obj; } }; #endif // SHARE_VM_RUNTIME_ACCESSBACKEND_HPP