1 /* 2 * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_VM_RUNTIME_ACCESSBACKEND_HPP 26 #define SHARE_VM_RUNTIME_ACCESSBACKEND_HPP 27 28 #include "metaprogramming/conditional.hpp" 29 #include "metaprogramming/enableIf.hpp" 30 #include "metaprogramming/integralConstant.hpp" 31 #include "metaprogramming/isSame.hpp" 32 #include "utilities/debug.hpp" 33 #include "utilities/globalDefinitions.hpp" 34 35 // This metafunction returns either oop or narrowOop depending on whether 36 // an access needs to use compressed oops or not. 37 template <DecoratorSet decorators> 38 struct HeapOopType: AllStatic { 39 static const bool needs_oop_compress = HasDecorator<decorators, INTERNAL_CONVERT_COMPRESSED_OOP>::value && 40 HasDecorator<decorators, INTERNAL_RT_USE_COMPRESSED_OOPS>::value; 41 typedef typename Conditional<needs_oop_compress, narrowOop, oop>::type type; 42 }; 43 44 namespace AccessInternal { 45 enum BarrierType { 46 BARRIER_STORE, 47 BARRIER_STORE_AT, 48 BARRIER_LOAD, 49 BARRIER_LOAD_AT, 50 BARRIER_ATOMIC_CMPXCHG, 51 BARRIER_ATOMIC_CMPXCHG_AT, 52 BARRIER_ATOMIC_XCHG, 53 BARRIER_ATOMIC_XCHG_AT, 54 BARRIER_ARRAYCOPY, 55 BARRIER_CLONE, 56 BARRIER_RESOLVE 57 }; 58 59 template <DecoratorSet decorators, typename T> 60 struct MustConvertCompressedOop: public IntegralConstant<bool, 61 HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::value && 62 IsSame<typename HeapOopType<decorators>::type, narrowOop>::value && 63 IsSame<T, oop>::value> {}; 64 65 // This metafunction returns an appropriate oop type if the value is oop-like 66 // and otherwise returns the same type T. 67 template <DecoratorSet decorators, typename T> 68 struct EncodedType: AllStatic { 69 typedef typename Conditional< 70 HasDecorator<decorators, INTERNAL_VALUE_IS_OOP>::value, 71 typename HeapOopType<decorators>::type, T>::type type; 72 }; 73 74 template <DecoratorSet decorators> 75 inline typename HeapOopType<decorators>::type* 76 oop_field_addr(oop base, ptrdiff_t byte_offset) { 77 return reinterpret_cast<typename HeapOopType<decorators>::type*>( 78 reinterpret_cast<intptr_t>((void*)base) + byte_offset); 79 } 80 81 // This metafunction returns whether it is possible for a type T to require 82 // locking to support wide atomics or not. 83 template <typename T> 84 #ifdef SUPPORTS_NATIVE_CX8 85 struct PossiblyLockedAccess: public IntegralConstant<bool, false> {}; 86 #else 87 struct PossiblyLockedAccess: public IntegralConstant<bool, (sizeof(T) > 4)> {}; 88 #endif 89 90 template <DecoratorSet decorators, typename T> 91 struct AccessFunctionTypes { 92 typedef T (*load_at_func_t)(oop base, ptrdiff_t offset); 93 typedef void (*store_at_func_t)(oop base, ptrdiff_t offset, T value); 94 typedef T (*atomic_cmpxchg_at_func_t)(T new_value, oop base, ptrdiff_t offset, T compare_value); 95 typedef T (*atomic_xchg_at_func_t)(T new_value, oop base, ptrdiff_t offset); 96 97 typedef T (*load_func_t)(void* addr); 98 typedef void (*store_func_t)(void* addr, T value); 99 typedef T (*atomic_cmpxchg_func_t)(T new_value, void* addr, T compare_value); 100 typedef T (*atomic_xchg_func_t)(T new_value, void* addr); 101 102 typedef bool (*arraycopy_func_t)(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length); 103 typedef void (*clone_func_t)(oop src, oop dst, size_t size); 104 typedef oop (*resolve_func_t)(oop obj); 105 }; 106 107 template <DecoratorSet decorators> 108 struct AccessFunctionTypes<decorators, void> { 109 typedef bool (*arraycopy_func_t)(arrayOop src_obj, arrayOop dst_obj, void* src, void* dst, size_t length); 110 }; 111 112 template <DecoratorSet decorators, typename T, BarrierType barrier> struct AccessFunction {}; 113 114 #define ACCESS_GENERATE_ACCESS_FUNCTION(bt, func) \ 115 template <DecoratorSet decorators, typename T> \ 116 struct AccessFunction<decorators, T, bt>: AllStatic{ \ 117 typedef typename AccessFunctionTypes<decorators, T>::func type; \ 118 } 119 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_STORE, store_func_t); 120 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_STORE_AT, store_at_func_t); 121 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_LOAD, load_func_t); 122 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_LOAD_AT, load_at_func_t); 123 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_CMPXCHG, atomic_cmpxchg_func_t); 124 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_CMPXCHG_AT, atomic_cmpxchg_at_func_t); 125 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_XCHG, atomic_xchg_func_t); 126 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ATOMIC_XCHG_AT, atomic_xchg_at_func_t); 127 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ARRAYCOPY, arraycopy_func_t); 128 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_CLONE, clone_func_t); 129 ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_RESOLVE, resolve_func_t); 130 #undef ACCESS_GENERATE_ACCESS_FUNCTION 131 132 template <DecoratorSet decorators, typename T, BarrierType barrier_type> 133 typename AccessFunction<decorators, T, barrier_type>::type resolve_barrier(); 134 135 template <DecoratorSet decorators, typename T, BarrierType barrier_type> 136 typename AccessFunction<decorators, T, barrier_type>::type resolve_oop_barrier(); 137 138 class AccessLocker { 139 public: 140 AccessLocker(); 141 ~AccessLocker(); 142 }; 143 bool wide_atomic_needs_locking(); 144 145 void* field_addr(oop base, ptrdiff_t offset); 146 147 // Forward calls to Copy:: in the cpp file to reduce dependencies and allow 148 // faster build times, given how frequently included access is. 149 void arraycopy_arrayof_conjoint_oops(void* src, void* dst, size_t length); 150 void arraycopy_conjoint_oops(oop* src, oop* dst, size_t length); 151 void arraycopy_conjoint_oops(narrowOop* src, narrowOop* dst, size_t length); 152 153 void arraycopy_disjoint_words(void* src, void* dst, size_t length); 154 void arraycopy_disjoint_words_atomic(void* src, void* dst, size_t length); 155 156 template<typename T> 157 void arraycopy_conjoint(T* src, T* dst, size_t length); 158 template<typename T> 159 void arraycopy_arrayof_conjoint(T* src, T* dst, size_t length); 160 template<typename T> 161 void arraycopy_conjoint_atomic(T* src, T* dst, size_t length); 162 } 163 164 // This mask specifies what decorators are relevant for raw accesses. When passing 165 // accesses to the raw layer, irrelevant decorators are removed. 166 const DecoratorSet RAW_DECORATOR_MASK = INTERNAL_DECORATOR_MASK | MO_DECORATOR_MASK | 167 ARRAYCOPY_DECORATOR_MASK | OOP_DECORATOR_MASK; 168 169 // The RawAccessBarrier performs raw accesses with additional knowledge of 170 // memory ordering, so that OrderAccess/Atomic is called when necessary. 171 // It additionally handles compressed oops, and hence is not completely "raw" 172 // strictly speaking. 173 template <DecoratorSet decorators> 174 class RawAccessBarrier: public AllStatic { 175 protected: 176 static inline void* field_addr(oop base, ptrdiff_t byte_offset) { 177 return AccessInternal::field_addr(base, byte_offset); 178 } 179 180 protected: 181 // Only encode if INTERNAL_VALUE_IS_OOP 182 template <DecoratorSet idecorators, typename T> 183 static inline typename EnableIf< 184 AccessInternal::MustConvertCompressedOop<idecorators, T>::value, 185 typename HeapOopType<idecorators>::type>::type 186 encode_internal(T value); 187 188 template <DecoratorSet idecorators, typename T> 189 static inline typename EnableIf< 190 !AccessInternal::MustConvertCompressedOop<idecorators, T>::value, T>::type 191 encode_internal(T value) { 192 return value; 193 } 194 195 template <typename T> 196 static inline typename AccessInternal::EncodedType<decorators, T>::type 197 encode(T value) { 198 return encode_internal<decorators, T>(value); 199 } 200 201 // Only decode if INTERNAL_VALUE_IS_OOP 202 template <DecoratorSet idecorators, typename T> 203 static inline typename EnableIf< 204 AccessInternal::MustConvertCompressedOop<idecorators, T>::value, T>::type 205 decode_internal(typename HeapOopType<idecorators>::type value); 206 207 template <DecoratorSet idecorators, typename T> 208 static inline typename EnableIf< 209 !AccessInternal::MustConvertCompressedOop<idecorators, T>::value, T>::type 210 decode_internal(T value) { 211 return value; 212 } 213 214 template <typename T> 215 static inline T decode(typename AccessInternal::EncodedType<decorators, T>::type value) { 216 return decode_internal<decorators, T>(value); 217 } 218 219 protected: 220 template <DecoratorSet ds, typename T> 221 static typename EnableIf< 222 HasDecorator<ds, MO_SEQ_CST>::value, T>::type 223 load_internal(void* addr); 224 225 template <DecoratorSet ds, typename T> 226 static typename EnableIf< 227 HasDecorator<ds, MO_ACQUIRE>::value, T>::type 228 load_internal(void* addr); 229 230 template <DecoratorSet ds, typename T> 231 static typename EnableIf< 232 HasDecorator<ds, MO_RELAXED>::value, T>::type 233 load_internal(void* addr); 234 235 template <DecoratorSet ds, typename T> 236 static inline typename EnableIf< 237 HasDecorator<ds, MO_VOLATILE>::value, T>::type 238 load_internal(void* addr) { 239 return *reinterpret_cast<const volatile T*>(addr); 240 } 241 242 template <DecoratorSet ds, typename T> 243 static inline typename EnableIf< 244 HasDecorator<ds, MO_UNORDERED>::value, T>::type 245 load_internal(void* addr) { 246 return *reinterpret_cast<const T*>(addr); 247 } 248 249 template <DecoratorSet ds, typename T> 250 static typename EnableIf< 251 HasDecorator<ds, MO_SEQ_CST>::value>::type 252 store_internal(void* addr, T value); 253 254 template <DecoratorSet ds, typename T> 255 static typename EnableIf< 256 HasDecorator<ds, MO_RELEASE>::value>::type 257 store_internal(void* addr, T value); 258 259 template <DecoratorSet ds, typename T> 260 static typename EnableIf< 261 HasDecorator<ds, MO_RELAXED>::value>::type 262 store_internal(void* addr, T value); 263 264 template <DecoratorSet ds, typename T> 265 static inline typename EnableIf< 266 HasDecorator<ds, MO_VOLATILE>::value>::type 267 store_internal(void* addr, T value) { 268 (void)const_cast<T&>(*reinterpret_cast<volatile T*>(addr) = value); 269 } 270 271 template <DecoratorSet ds, typename T> 272 static inline typename EnableIf< 273 HasDecorator<ds, MO_UNORDERED>::value>::type 274 store_internal(void* addr, T value) { 275 *reinterpret_cast<T*>(addr) = value; 276 } 277 278 template <DecoratorSet ds, typename T> 279 static typename EnableIf< 280 HasDecorator<ds, MO_SEQ_CST>::value, T>::type 281 atomic_cmpxchg_internal(T new_value, void* addr, T compare_value); 282 283 template <DecoratorSet ds, typename T> 284 static typename EnableIf< 285 HasDecorator<ds, MO_RELAXED>::value, T>::type 286 atomic_cmpxchg_internal(T new_value, void* addr, T compare_value); 287 288 template <DecoratorSet ds, typename T> 289 static typename EnableIf< 290 HasDecorator<ds, MO_SEQ_CST>::value, T>::type 291 atomic_xchg_internal(T new_value, void* addr); 292 293 // The following *_locked mechanisms serve the purpose of handling atomic operations 294 // that are larger than a machine can handle, and then possibly opt for using 295 // a slower path using a mutex to perform the operation. 296 297 template <DecoratorSet ds, typename T> 298 static inline typename EnableIf< 299 !AccessInternal::PossiblyLockedAccess<T>::value, T>::type 300 atomic_cmpxchg_maybe_locked(T new_value, void* addr, T compare_value) { 301 return atomic_cmpxchg_internal<ds>(new_value, addr, compare_value); 302 } 303 304 template <DecoratorSet ds, typename T> 305 static typename EnableIf< 306 AccessInternal::PossiblyLockedAccess<T>::value, T>::type 307 atomic_cmpxchg_maybe_locked(T new_value, void* addr, T compare_value); 308 309 template <DecoratorSet ds, typename T> 310 static inline typename EnableIf< 311 !AccessInternal::PossiblyLockedAccess<T>::value, T>::type 312 atomic_xchg_maybe_locked(T new_value, void* addr) { 313 return atomic_xchg_internal<ds>(new_value, addr); 314 } 315 316 template <DecoratorSet ds, typename T> 317 static typename EnableIf< 318 AccessInternal::PossiblyLockedAccess<T>::value, T>::type 319 atomic_xchg_maybe_locked(T new_value, void* addr); 320 321 public: 322 template <typename T> 323 static inline void store(void* addr, T value) { 324 store_internal<decorators>(addr, value); 325 } 326 327 template <typename T> 328 static inline T load(void* addr) { 329 return load_internal<decorators, T>(addr); 330 } 331 332 template <typename T> 333 static inline T atomic_cmpxchg(T new_value, void* addr, T compare_value) { 334 return atomic_cmpxchg_maybe_locked<decorators>(new_value, addr, compare_value); 335 } 336 337 template <typename T> 338 static inline T atomic_xchg(T new_value, void* addr) { 339 return atomic_xchg_maybe_locked<decorators>(new_value, addr); 340 } 341 342 template <typename T> 343 static bool arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length); 344 345 template <typename T> 346 static void oop_store(void* addr, T value); 347 template <typename T> 348 static void oop_store_at(oop base, ptrdiff_t offset, T value); 349 350 template <typename T> 351 static T oop_load(void* addr); 352 template <typename T> 353 static T oop_load_at(oop base, ptrdiff_t offset); 354 355 template <typename T> 356 static T oop_atomic_cmpxchg(T new_value, void* addr, T compare_value); 357 template <typename T> 358 static T oop_atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value); 359 360 template <typename T> 361 static T oop_atomic_xchg(T new_value, void* addr); 362 template <typename T> 363 static T oop_atomic_xchg_at(T new_value, oop base, ptrdiff_t offset); 364 365 template <typename T> 366 static void store_at(oop base, ptrdiff_t offset, T value) { 367 store(field_addr(base, offset), value); 368 } 369 370 template <typename T> 371 static T load_at(oop base, ptrdiff_t offset) { 372 return load<T>(field_addr(base, offset)); 373 } 374 375 template <typename T> 376 static T atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { 377 return atomic_cmpxchg(new_value, field_addr(base, offset), compare_value); 378 } 379 380 template <typename T> 381 static T atomic_xchg_at(T new_value, oop base, ptrdiff_t offset) { 382 return atomic_xchg(new_value, field_addr(base, offset)); 383 } 384 385 template <typename T> 386 static bool oop_arraycopy(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length); 387 static bool oop_arraycopy(arrayOop src_obj, arrayOop dst_obj, HeapWord* src, HeapWord* dst, size_t length); 388 389 static void clone(oop src, oop dst, size_t size); 390 391 static oop resolve(oop obj) { return obj; } 392 }; 393 394 #endif // SHARE_VM_RUNTIME_ACCESSBACKEND_HPP