1 /* 2 * Copyright (c) 2017, 2023, 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_OOPS_ACCESS_INLINE_HPP 26 #define SHARE_OOPS_ACCESS_INLINE_HPP 27 28 #include "oops/access.hpp" 29 30 #include "gc/shared/barrierSet.inline.hpp" 31 #include "gc/shared/barrierSetConfig.inline.hpp" 32 #include "oops/accessBackend.inline.hpp" 33 34 // This file outlines the last 2 steps of the template pipeline of accesses going through 35 // the Access API. 36 // * Step 5.a: Barrier resolution. This step is invoked the first time a runtime-dispatch 37 // happens for an access. The appropriate BarrierSet::AccessBarrier accessor 38 // is resolved, then the function pointer is updated to that accessor for 39 // future invocations. 40 // * Step 5.b: Post-runtime dispatch. This step now casts previously unknown types such 41 // as the address type of an oop on the heap (is it oop* or narrowOop*) to 42 // the appropriate type. It also splits sufficiently orthogonal accesses into 43 // different functions, such as whether the access involves oops or primitives 44 // and whether the access is performed on the heap or outside. Then the 45 // appropriate BarrierSet::AccessBarrier is called to perform the access. 46 47 namespace AccessInternal { 48 // Step 5.b: Post-runtime dispatch. 49 // This class is the last step before calling the BarrierSet::AccessBarrier. 50 // Here we make sure to figure out types that were not known prior to the 51 // runtime dispatch, such as whether an oop on the heap is oop or narrowOop. 52 // We also split orthogonal barriers such as handling primitives vs oops 53 // and on-heap vs off-heap into different calls to the barrier set. 54 template <class GCBarrierType, BarrierType type, DecoratorSet decorators> 55 struct PostRuntimeDispatch: public AllStatic { }; 56 57 template <class GCBarrierType, DecoratorSet decorators> 58 struct PostRuntimeDispatch<GCBarrierType, BARRIER_STORE, decorators>: public AllStatic { 59 template <typename T> 60 static void access_barrier(void* addr, T value) { 61 GCBarrierType::store_in_heap(reinterpret_cast<T*>(addr), value); 62 } 63 64 static void oop_access_barrier(void* addr, oop value) { 65 typedef typename HeapOopType<decorators>::type OopType; 66 if (HasDecorator<decorators, IN_HEAP>::value) { 67 GCBarrierType::oop_store_in_heap(reinterpret_cast<OopType*>(addr), value); 68 } else { 69 GCBarrierType::oop_store_not_in_heap(reinterpret_cast<OopType*>(addr), value); 70 } 71 } 72 }; 73 74 template <class GCBarrierType, DecoratorSet decorators> 75 struct PostRuntimeDispatch<GCBarrierType, BARRIER_LOAD, decorators>: public AllStatic { 76 template <typename T> 77 static T access_barrier(void* addr) { 78 return GCBarrierType::load_in_heap(reinterpret_cast<T*>(addr)); 79 } 80 81 static oop oop_access_barrier(void* addr) { 82 typedef typename HeapOopType<decorators>::type OopType; 83 if (HasDecorator<decorators, IN_HEAP>::value) { 84 return GCBarrierType::oop_load_in_heap(reinterpret_cast<OopType*>(addr)); 85 } else { 86 return GCBarrierType::oop_load_not_in_heap(reinterpret_cast<OopType*>(addr)); 87 } 88 } 89 }; 90 91 template <class GCBarrierType, DecoratorSet decorators> 92 struct PostRuntimeDispatch<GCBarrierType, BARRIER_ATOMIC_XCHG, decorators>: public AllStatic { 93 template <typename T> 94 static T access_barrier(void* addr, T new_value) { 95 return GCBarrierType::atomic_xchg_in_heap(reinterpret_cast<T*>(addr), new_value); 96 } 97 98 static oop oop_access_barrier(void* addr, oop new_value) { 99 typedef typename HeapOopType<decorators>::type OopType; 100 if (HasDecorator<decorators, IN_HEAP>::value) { 101 return GCBarrierType::oop_atomic_xchg_in_heap(reinterpret_cast<OopType*>(addr), new_value); 102 } else { 103 return GCBarrierType::oop_atomic_xchg_not_in_heap(reinterpret_cast<OopType*>(addr), new_value); 104 } 105 } 106 }; 107 108 template <class GCBarrierType, DecoratorSet decorators> 109 struct PostRuntimeDispatch<GCBarrierType, BARRIER_ATOMIC_CMPXCHG, decorators>: public AllStatic { 110 template <typename T> 111 static T access_barrier(void* addr, T compare_value, T new_value) { 112 return GCBarrierType::atomic_cmpxchg_in_heap(reinterpret_cast<T*>(addr), compare_value, new_value); 113 } 114 115 static oop oop_access_barrier(void* addr, oop compare_value, oop new_value) { 116 typedef typename HeapOopType<decorators>::type OopType; 117 if (HasDecorator<decorators, IN_HEAP>::value) { 118 return GCBarrierType::oop_atomic_cmpxchg_in_heap(reinterpret_cast<OopType*>(addr), compare_value, new_value); 119 } else { 120 return GCBarrierType::oop_atomic_cmpxchg_not_in_heap(reinterpret_cast<OopType*>(addr), compare_value, new_value); 121 } 122 } 123 }; 124 125 template <class GCBarrierType, DecoratorSet decorators> 126 struct PostRuntimeDispatch<GCBarrierType, BARRIER_ARRAYCOPY, decorators>: public AllStatic { 127 template <typename T> 128 static bool access_barrier(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, 129 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, 130 size_t length) { 131 GCBarrierType::arraycopy_in_heap(src_obj, src_offset_in_bytes, src_raw, 132 dst_obj, dst_offset_in_bytes, dst_raw, 133 length); 134 return true; 135 } 136 137 template <typename T> 138 static bool oop_access_barrier(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, 139 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, 140 size_t length) { 141 typedef typename HeapOopType<decorators>::type OopType; 142 return GCBarrierType::oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, reinterpret_cast<OopType*>(src_raw), 143 dst_obj, dst_offset_in_bytes, reinterpret_cast<OopType*>(dst_raw), 144 length); 145 } 146 }; 147 148 template <class GCBarrierType, DecoratorSet decorators> 149 struct PostRuntimeDispatch<GCBarrierType, BARRIER_STORE_AT, decorators>: public AllStatic { 150 template <typename T> 151 static void access_barrier(oop base, ptrdiff_t offset, T value) { 152 GCBarrierType::store_in_heap_at(base, offset, value); 153 } 154 155 static void oop_access_barrier(oop base, ptrdiff_t offset, oop value) { 156 GCBarrierType::oop_store_in_heap_at(base, offset, value); 157 } 158 }; 159 160 template <class GCBarrierType, DecoratorSet decorators> 161 struct PostRuntimeDispatch<GCBarrierType, BARRIER_LOAD_AT, decorators>: public AllStatic { 162 template <typename T> 163 static T access_barrier(oop base, ptrdiff_t offset) { 164 return GCBarrierType::template load_in_heap_at<T>(base, offset); 165 } 166 167 static oop oop_access_barrier(oop base, ptrdiff_t offset) { 168 return GCBarrierType::oop_load_in_heap_at(base, offset); 169 } 170 }; 171 172 template <class GCBarrierType, DecoratorSet decorators> 173 struct PostRuntimeDispatch<GCBarrierType, BARRIER_ATOMIC_XCHG_AT, decorators>: public AllStatic { 174 template <typename T> 175 static T access_barrier(oop base, ptrdiff_t offset, T new_value) { 176 return GCBarrierType::atomic_xchg_in_heap_at(base, offset, new_value); 177 } 178 179 static oop oop_access_barrier(oop base, ptrdiff_t offset, oop new_value) { 180 return GCBarrierType::oop_atomic_xchg_in_heap_at(base, offset, new_value); 181 } 182 }; 183 184 template <class GCBarrierType, DecoratorSet decorators> 185 struct PostRuntimeDispatch<GCBarrierType, BARRIER_ATOMIC_CMPXCHG_AT, decorators>: public AllStatic { 186 template <typename T> 187 static T access_barrier(oop base, ptrdiff_t offset, T compare_value, T new_value) { 188 return GCBarrierType::atomic_cmpxchg_in_heap_at(base, offset, compare_value, new_value); 189 } 190 191 static oop oop_access_barrier(oop base, ptrdiff_t offset, oop compare_value, oop new_value) { 192 return GCBarrierType::oop_atomic_cmpxchg_in_heap_at(base, offset, compare_value, new_value); 193 } 194 }; 195 196 template <class GCBarrierType, DecoratorSet decorators> 197 struct PostRuntimeDispatch<GCBarrierType, BARRIER_CLONE, decorators>: public AllStatic { 198 static void access_barrier(oop src, oop dst, size_t size) { 199 GCBarrierType::clone_in_heap(src, dst, size); 200 } 201 }; 202 203 // Resolving accessors with barriers from the barrier set happens in two steps. 204 // 1. Expand paths with runtime-decorators, e.g. is UseCompressedOops on or off. 205 // 2. Expand paths for each BarrierSet available in the system. 206 template <DecoratorSet decorators, typename FunctionPointerT, BarrierType barrier_type> 207 struct BarrierResolver: public AllStatic { 208 template <DecoratorSet ds> 209 static typename EnableIf< 210 HasDecorator<ds, INTERNAL_VALUE_IS_OOP>::value, 211 FunctionPointerT>::type 212 resolve_barrier_gc() { 213 BarrierSet* bs = BarrierSet::barrier_set(); 214 assert(bs != nullptr, "GC barriers invoked before BarrierSet is set"); 215 switch (bs->kind()) { 216 #define BARRIER_SET_RESOLVE_BARRIER_CLOSURE(bs_name) \ 217 case BarrierSet::bs_name: { \ 218 return PostRuntimeDispatch<typename BarrierSet::GetType<BarrierSet::bs_name>::type:: \ 219 AccessBarrier<ds>, barrier_type, ds>::oop_access_barrier; \ 220 } \ 221 break; 222 FOR_EACH_CONCRETE_BARRIER_SET_DO(BARRIER_SET_RESOLVE_BARRIER_CLOSURE) 223 #undef BARRIER_SET_RESOLVE_BARRIER_CLOSURE 224 225 default: 226 fatal("BarrierSet AccessBarrier resolving not implemented"); 227 return nullptr; 228 }; 229 } 230 231 template <DecoratorSet ds> 232 static typename EnableIf< 233 !HasDecorator<ds, INTERNAL_VALUE_IS_OOP>::value, 234 FunctionPointerT>::type 235 resolve_barrier_gc() { 236 BarrierSet* bs = BarrierSet::barrier_set(); 237 assert(bs != nullptr, "GC barriers invoked before BarrierSet is set"); 238 switch (bs->kind()) { 239 #define BARRIER_SET_RESOLVE_BARRIER_CLOSURE(bs_name) \ 240 case BarrierSet::bs_name: { \ 241 return PostRuntimeDispatch<typename BarrierSet::GetType<BarrierSet::bs_name>::type:: \ 242 AccessBarrier<ds>, barrier_type, ds>::access_barrier; \ 243 } \ 244 break; 245 FOR_EACH_CONCRETE_BARRIER_SET_DO(BARRIER_SET_RESOLVE_BARRIER_CLOSURE) 246 #undef BARRIER_SET_RESOLVE_BARRIER_CLOSURE 247 248 default: 249 fatal("BarrierSet AccessBarrier resolving not implemented"); 250 return nullptr; 251 }; 252 } 253 254 static FunctionPointerT resolve_barrier_rt() { 255 if (UseCompressedOops) { 256 const DecoratorSet expanded_decorators = decorators | INTERNAL_RT_USE_COMPRESSED_OOPS; 257 return resolve_barrier_gc<expanded_decorators>(); 258 } else { 259 return resolve_barrier_gc<decorators>(); 260 } 261 } 262 263 static FunctionPointerT resolve_barrier() { 264 return resolve_barrier_rt(); 265 } 266 }; 267 268 // Step 5.a: Barrier resolution 269 // The RuntimeDispatch class is responsible for performing a runtime dispatch of the 270 // accessor. This is required when the access either depends on whether compressed oops 271 // is being used, or it depends on which GC implementation was chosen (e.g. requires GC 272 // barriers). The way it works is that a function pointer initially pointing to an 273 // accessor resolution function gets called for each access. Upon first invocation, 274 // it resolves which accessor to be used in future invocations and patches the 275 // function pointer to this new accessor. 276 277 template <DecoratorSet decorators, typename T> 278 void RuntimeDispatch<decorators, T, BARRIER_STORE>::store_init(void* addr, T value) { 279 func_t function = BarrierResolver<decorators, func_t, BARRIER_STORE>::resolve_barrier(); 280 _store_func = function; 281 function(addr, value); 282 } 283 284 template <DecoratorSet decorators, typename T> 285 void RuntimeDispatch<decorators, T, BARRIER_STORE_AT>::store_at_init(oop base, ptrdiff_t offset, T value) { 286 func_t function = BarrierResolver<decorators, func_t, BARRIER_STORE_AT>::resolve_barrier(); 287 _store_at_func = function; 288 function(base, offset, value); 289 } 290 291 template <DecoratorSet decorators, typename T> 292 T RuntimeDispatch<decorators, T, BARRIER_LOAD>::load_init(void* addr) { 293 func_t function = BarrierResolver<decorators, func_t, BARRIER_LOAD>::resolve_barrier(); 294 _load_func = function; 295 return function(addr); 296 } 297 298 template <DecoratorSet decorators, typename T> 299 T RuntimeDispatch<decorators, T, BARRIER_LOAD_AT>::load_at_init(oop base, ptrdiff_t offset) { 300 func_t function = BarrierResolver<decorators, func_t, BARRIER_LOAD_AT>::resolve_barrier(); 301 _load_at_func = function; 302 return function(base, offset); 303 } 304 305 template <DecoratorSet decorators, typename T> 306 T RuntimeDispatch<decorators, T, BARRIER_ATOMIC_CMPXCHG>::atomic_cmpxchg_init(void* addr, T compare_value, T new_value) { 307 func_t function = BarrierResolver<decorators, func_t, BARRIER_ATOMIC_CMPXCHG>::resolve_barrier(); 308 _atomic_cmpxchg_func = function; 309 return function(addr, compare_value, new_value); 310 } 311 312 template <DecoratorSet decorators, typename T> 313 T RuntimeDispatch<decorators, T, BARRIER_ATOMIC_CMPXCHG_AT>::atomic_cmpxchg_at_init(oop base, ptrdiff_t offset, T compare_value, T new_value) { 314 func_t function = BarrierResolver<decorators, func_t, BARRIER_ATOMIC_CMPXCHG_AT>::resolve_barrier(); 315 _atomic_cmpxchg_at_func = function; 316 return function(base, offset, compare_value, new_value); 317 } 318 319 template <DecoratorSet decorators, typename T> 320 T RuntimeDispatch<decorators, T, BARRIER_ATOMIC_XCHG>::atomic_xchg_init(void* addr, T new_value) { 321 func_t function = BarrierResolver<decorators, func_t, BARRIER_ATOMIC_XCHG>::resolve_barrier(); 322 _atomic_xchg_func = function; 323 return function(addr, new_value); 324 } 325 326 template <DecoratorSet decorators, typename T> 327 T RuntimeDispatch<decorators, T, BARRIER_ATOMIC_XCHG_AT>::atomic_xchg_at_init(oop base, ptrdiff_t offset, T new_value) { 328 func_t function = BarrierResolver<decorators, func_t, BARRIER_ATOMIC_XCHG_AT>::resolve_barrier(); 329 _atomic_xchg_at_func = function; 330 return function(base, offset, new_value); 331 } 332 333 template <DecoratorSet decorators, typename T> 334 bool RuntimeDispatch<decorators, T, BARRIER_ARRAYCOPY>::arraycopy_init(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw, 335 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw, 336 size_t length) { 337 func_t function = BarrierResolver<decorators, func_t, BARRIER_ARRAYCOPY>::resolve_barrier(); 338 _arraycopy_func = function; 339 return function(src_obj, src_offset_in_bytes, src_raw, 340 dst_obj, dst_offset_in_bytes, dst_raw, 341 length); 342 } 343 344 template <DecoratorSet decorators, typename T> 345 void RuntimeDispatch<decorators, T, BARRIER_CLONE>::clone_init(oop src, oop dst, size_t size) { 346 func_t function = BarrierResolver<decorators, func_t, BARRIER_CLONE>::resolve_barrier(); 347 _clone_func = function; 348 function(src, dst, size); 349 } 350 } 351 352 #endif // SHARE_OOPS_ACCESS_INLINE_HPP