1 /*
2 * Copyright (c) 2017, 2025, 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_HPP
26 #define SHARE_OOPS_ACCESS_HPP
27
28 #include "memory/allStatic.hpp"
29 #include "oops/accessBackend.hpp"
30 #include "oops/accessDecorators.hpp"
31 #include "oops/oopsHierarchy.hpp"
32 #include "utilities/debug.hpp"
33 #include "utilities/globalDefinitions.hpp"
34
35 class ValuePayload;
36
37 // = GENERAL =
38 // Access is an API for performing accesses with declarative semantics. Each access can have a number of "decorators".
39 // A decorator is an attribute or property that affects the way a memory access is performed in some way.
40 // There are different groups of decorators. Some have to do with memory ordering, others to do with,
41 // e.g. strength of references, strength of GC barriers, or whether compression should be applied or not.
42 // Some decorators are set at buildtime, such as whether primitives require GC barriers or not, others
43 // at callsites such as whether an access is in the heap or not, and others are resolved at runtime
44 // such as GC-specific barriers and encoding/decoding compressed oops. For more information about what
45 // decorators are available, cf. oops/accessDecorators.hpp.
46 // By pipelining handling of these decorators, the design of the Access API allows separation of concern
47 // over the different orthogonal concerns of decorators, while providing a powerful way of
48 // expressing these orthogonal semantic properties in a unified way.
49 //
50 // == OPERATIONS ==
51 // * load: Load a value from an address.
52 // * load_at: Load a value from an internal pointer relative to a base object.
53 // * store: Store a value at an address.
54 // * store_at: Store a value in an internal pointer relative to a base object.
55 // * atomic_cmpxchg: Atomically compare-and-swap a new value at an address if previous value matched the compared value.
56 // * atomic_cmpxchg_at: Atomically compare-and-swap a new value at an internal pointer address if previous value matched the compared value.
57 // * atomic_xchg: Atomically swap a new value at an address without checking the previous value.
58 // * atomic_xchg_at: Atomically swap a new value at an internal pointer address without checking the previous value.
59 // * arraycopy: Copy data from one heap array to another heap array. The ArrayAccess class has convenience functions for this.
60 // * clone: Clone the contents of an object to a newly allocated object.
61 // * value_copy: Copy the contents of a value type from one heap address to another
62 //
63 // == IMPLEMENTATION ==
64 // Each access goes through the following steps in a template pipeline.
65 // There are essentially 5 steps for each access:
66 // * Step 1: Set default decorators and decay types. This step gets rid of CV qualifiers
67 // and sets default decorators to sensible values.
68 // * Step 2: Reduce types. This step makes sure there is only a single T type and not
69 // multiple types. The P type of the address and T type of the value must
70 // match.
71 // * Step 3: Pre-runtime dispatch. This step checks whether a runtime call can be
72 // avoided, and in that case avoids it (calling raw accesses or
73 // primitive accesses in a build that does not require primitive GC barriers)
74 // * Step 4: Runtime-dispatch. This step performs a runtime dispatch to the corresponding
75 // BarrierSet::AccessBarrier accessor that attaches GC-required barriers
76 // to the access.
77 // * Step 5.a: Barrier resolution. This step is invoked the first time a runtime-dispatch
78 // happens for an access. The appropriate BarrierSet::AccessBarrier accessor
79 // is resolved, then the function pointer is updated to that accessor for
80 // future invocations.
81 // * Step 5.b: Post-runtime dispatch. This step now casts previously unknown types such
82 // as the address type of an oop on the heap (is it oop* or narrowOop*) to
83 // the appropriate type. It also splits sufficiently orthogonal accesses into
84 // different functions, such as whether the access involves oops or primitives
85 // and whether the access is performed on the heap or outside. Then the
86 // appropriate BarrierSet::AccessBarrier is called to perform the access.
87 //
88 // The implementation of step 1-4 resides in accessBackend.hpp, to allow selected
89 // accesses to be accessible from only access.hpp, as opposed to access.inline.hpp.
90 // Steps 5.a and 5.b require knowledge about the GC backends, and therefore needs to
91 // include the various GC backend .inline.hpp headers. Their implementation resides in
92 // access.inline.hpp.
93
94 template <DecoratorSet decorators = DECORATORS_NONE>
95 class Access: public AllStatic {
96 // This function asserts that if an access gets passed in a decorator outside
97 // of the expected_decorators, then something is wrong. It additionally checks
98 // the consistency of the decorators so that supposedly disjoint decorators are indeed
99 // disjoint. For example, an access can not be both in heap and on root at the
100 // same time.
101 template <DecoratorSet expected_decorators>
102 static void verify_decorators();
103
104 template <DecoratorSet expected_mo_decorators>
105 static void verify_primitive_decorators() {
106 const DecoratorSet primitive_decorators = (AS_DECORATOR_MASK ^ AS_NO_KEEPALIVE) |
107 IN_HEAP | IS_ARRAY;
108 verify_decorators<expected_mo_decorators | primitive_decorators>();
109 }
110
111 template <DecoratorSet expected_mo_decorators>
112 static void verify_oop_decorators() {
113 const DecoratorSet oop_decorators = AS_DECORATOR_MASK | IN_DECORATOR_MASK |
114 (ON_DECORATOR_MASK ^ ON_UNKNOWN_OOP_REF) | // no unknown oop refs outside of the heap
115 IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
116 verify_decorators<expected_mo_decorators | oop_decorators>();
117 }
118
119 template <DecoratorSet expected_mo_decorators>
120 static void verify_heap_oop_decorators() {
121 const DecoratorSet heap_oop_decorators = AS_DECORATOR_MASK | ON_DECORATOR_MASK |
122 IN_HEAP | IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
123 verify_decorators<expected_mo_decorators | heap_oop_decorators>();
124 }
125
126 template <DecoratorSet expected_mo_decorators>
127 static void verify_heap_value_decorators() {
128 const DecoratorSet heap_value_decorators = IN_HEAP | IS_DEST_UNINITIALIZED;
129 verify_decorators<expected_mo_decorators | heap_value_decorators>();
130 }
131
132 static const DecoratorSet load_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_ACQUIRE | MO_SEQ_CST;
133 static const DecoratorSet store_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_RELEASE | MO_SEQ_CST;
134 static const DecoratorSet atomic_xchg_mo_decorators = MO_SEQ_CST;
135 static const DecoratorSet atomic_cmpxchg_mo_decorators = MO_RELAXED | MO_SEQ_CST;
136
137 protected:
138 template <typename T>
139 static inline OopCopyResult oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
140 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
141 size_t length) {
142 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
143 AS_DECORATOR_MASK | IS_ARRAY | IS_DEST_UNINITIALIZED>();
144 return AccessInternal::arraycopy<decorators | INTERNAL_VALUE_IS_OOP>(src_obj, src_offset_in_bytes, src_raw,
145 dst_obj, dst_offset_in_bytes, dst_raw,
146 length);
147 }
148
149 template <typename T>
150 static inline void arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
151 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
152 size_t length) {
153 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
154 AS_DECORATOR_MASK | IS_ARRAY>();
155 AccessInternal::arraycopy<decorators>(src_obj, src_offset_in_bytes, src_raw,
156 dst_obj, dst_offset_in_bytes, dst_raw,
157 length);
158 }
159
160 public:
161 // Primitive heap accesses
162 static inline AccessInternal::LoadAtProxy<decorators> load_at(oop base, ptrdiff_t offset) {
163 verify_primitive_decorators<load_mo_decorators>();
164 return AccessInternal::LoadAtProxy<decorators>(base, offset);
165 }
166
167 template <typename T>
168 static inline void store_at(oop base, ptrdiff_t offset, T value) {
169 verify_primitive_decorators<store_mo_decorators>();
170 AccessInternal::store_at<decorators>(base, offset, value);
171 }
172
173 template <typename T>
174 static inline T atomic_cmpxchg_at(oop base, ptrdiff_t offset, T compare_value, T new_value) {
175 verify_primitive_decorators<atomic_cmpxchg_mo_decorators>();
176 return AccessInternal::atomic_cmpxchg_at<decorators>(base, offset, compare_value, new_value);
177 }
178
179 template <typename T>
180 static inline T atomic_xchg_at(oop base, ptrdiff_t offset, T new_value) {
181 verify_primitive_decorators<atomic_xchg_mo_decorators>();
182 return AccessInternal::atomic_xchg_at<decorators>(base, offset, new_value);
183 }
184
185 // Oop heap accesses
186 static inline AccessInternal::OopLoadAtProxy<decorators> oop_load_at(oop base, ptrdiff_t offset) {
187 verify_heap_oop_decorators<load_mo_decorators>();
188 return AccessInternal::OopLoadAtProxy<decorators>(base, offset);
189 }
190
191 template <typename T>
192 static inline void oop_store_at(oop base, ptrdiff_t offset, T value) {
193 verify_heap_oop_decorators<store_mo_decorators>();
194 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
195 OopType oop_value = value;
196 AccessInternal::store_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, oop_value);
197 }
198
199 template <typename T>
200 static inline T oop_atomic_cmpxchg_at(oop base, ptrdiff_t offset, T compare_value, T new_value) {
201 verify_heap_oop_decorators<atomic_cmpxchg_mo_decorators>();
202 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
203 OopType new_oop_value = new_value;
204 OopType compare_oop_value = compare_value;
205 return AccessInternal::atomic_cmpxchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, compare_oop_value, new_oop_value);
206 }
207
208 template <typename T>
209 static inline T oop_atomic_xchg_at(oop base, ptrdiff_t offset, T new_value) {
210 verify_heap_oop_decorators<atomic_xchg_mo_decorators>();
211 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
212 OopType new_oop_value = new_value;
213 return AccessInternal::atomic_xchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, new_oop_value);
214 }
215
216 // Clone an object from src to dst
217 static inline void clone(oop src, oop dst, size_t size) {
218 verify_decorators<IN_HEAP>();
219 AccessInternal::clone<decorators>(src, dst, size);
220 }
221
222 // inline type heap access (when flat)...
223
224 // Copy value type data from src to dst
225 static inline void value_copy(const ValuePayload& src, const ValuePayload& dst) {
226 verify_heap_value_decorators<IN_HEAP>();
227 AccessInternal::value_copy<decorators>(src, dst);
228 }
229
230 static inline void value_store_null(const ValuePayload& dst) {
231 verify_heap_value_decorators<IN_HEAP>();
232 AccessInternal::value_store_null<decorators>(dst);
233 }
234
235 // Primitive accesses
236 template <typename P>
237 static inline P load(P* addr) {
238 verify_primitive_decorators<load_mo_decorators>();
239 return AccessInternal::load<decorators, P, P>(addr);
240 }
241
242 template <typename P, typename T>
243 static inline void store(P* addr, T value) {
244 verify_primitive_decorators<store_mo_decorators>();
245 AccessInternal::store<decorators>(addr, value);
246 }
247
248 template <typename P, typename T>
249 static inline T atomic_cmpxchg(P* addr, T compare_value, T new_value) {
250 verify_primitive_decorators<atomic_cmpxchg_mo_decorators>();
251 return AccessInternal::atomic_cmpxchg<decorators>(addr, compare_value, new_value);
252 }
253
254 template <typename P, typename T>
255 static inline T atomic_xchg(P* addr, T new_value) {
256 verify_primitive_decorators<atomic_xchg_mo_decorators>();
257 return AccessInternal::atomic_xchg<decorators>(addr, new_value);
258 }
259
260 // Oop accesses
261 template <typename P>
262 static inline AccessInternal::OopLoadProxy<P, decorators> oop_load(P* addr) {
263 verify_oop_decorators<load_mo_decorators>();
264 return AccessInternal::OopLoadProxy<P, decorators>(addr);
265 }
266
267 template <typename P, typename T>
268 static inline void oop_store(P* addr, T value) {
269 verify_oop_decorators<store_mo_decorators>();
270 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
271 OopType oop_value = value;
272 AccessInternal::store<decorators | INTERNAL_VALUE_IS_OOP>(addr, oop_value);
273 }
274
275 template <typename P, typename T>
276 static inline T oop_atomic_cmpxchg(P* addr, T compare_value, T new_value) {
277 verify_oop_decorators<atomic_cmpxchg_mo_decorators>();
278 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
279 OopType new_oop_value = new_value;
280 OopType compare_oop_value = compare_value;
281 return AccessInternal::atomic_cmpxchg<decorators | INTERNAL_VALUE_IS_OOP>(addr, compare_oop_value, new_oop_value);
282 }
283
284 template <typename P, typename T>
285 static inline T oop_atomic_xchg(P* addr, T new_value) {
286 verify_oop_decorators<atomic_xchg_mo_decorators>();
287 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
288 OopType new_oop_value = new_value;
289 return AccessInternal::atomic_xchg<decorators | INTERNAL_VALUE_IS_OOP>(addr, new_oop_value);
290 }
291 };
292
293 // Helper for performing raw accesses (knows only of memory ordering
294 // atomicity decorators as well as compressed oops).
295 template <DecoratorSet decorators = DECORATORS_NONE>
296 class RawAccess: public Access<AS_RAW | decorators> {};
297
298 // Helper for performing normal accesses on the heap. These accesses
299 // may resolve an accessor on a GC barrier set.
300 template <DecoratorSet decorators = DECORATORS_NONE>
301 class HeapAccess: public Access<IN_HEAP | decorators> {};
302
303 // Helper for performing normal accesses in roots. These accesses
304 // may resolve an accessor on a GC barrier set.
305 template <DecoratorSet decorators = DECORATORS_NONE>
306 class NativeAccess: public Access<IN_NATIVE | decorators> {};
307
308 // Helper for array access.
309 template <DecoratorSet decorators = DECORATORS_NONE>
310 class ArrayAccess: public HeapAccess<IS_ARRAY | decorators> {
311 typedef HeapAccess<IS_ARRAY | decorators> AccessT;
312 public:
313 template <typename T>
314 static inline void arraycopy(arrayOop src_obj, size_t src_offset_in_bytes,
315 arrayOop dst_obj, size_t dst_offset_in_bytes,
316 size_t length) {
317 AccessT::arraycopy(src_obj, src_offset_in_bytes, static_cast<const T*>(nullptr),
318 dst_obj, dst_offset_in_bytes, static_cast<T*>(nullptr),
319 length);
320 }
321
322 template <typename T>
323 static inline void arraycopy_to_native(arrayOop src_obj, size_t src_offset_in_bytes,
324 T* dst,
325 size_t length) {
326 AccessT::arraycopy(src_obj, src_offset_in_bytes, static_cast<const T*>(nullptr),
327 nullptr, 0, dst,
328 length);
329 }
330
331 template <typename T>
332 static inline void arraycopy_from_native(const T* src,
333 arrayOop dst_obj, size_t dst_offset_in_bytes,
334 size_t length) {
335 AccessT::arraycopy(nullptr, 0, src,
336 dst_obj, dst_offset_in_bytes, static_cast<T*>(nullptr),
337 length);
338 }
339
340 [[nodiscard]] // The caller is responsible to throw an exception on failure
341 static inline OopCopyResult oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes,
342 arrayOop dst_obj, size_t dst_offset_in_bytes,
343 size_t length) {
344 return AccessT::oop_arraycopy(src_obj, src_offset_in_bytes, static_cast<const HeapWord*>(nullptr),
345 dst_obj, dst_offset_in_bytes, static_cast<HeapWord*>(nullptr),
346 length);
347 }
348
349 template <typename T>
350 static inline void oop_arraycopy_raw(T* src, T* dst, size_t length) {
351 static_assert((decorators & ARRAYCOPY_CHECKCAST) == 0);
352 static_assert((decorators & ARRAYCOPY_NOTNULL) == 0);
353
354 OopCopyResult result = AccessT::oop_arraycopy(nullptr, 0, src,
355 nullptr, 0, dst,
356 length);
357
358 assert(result == OopCopyResult::ok, "Should never fail");
359 }
360
361 };
362
363 template <DecoratorSet decorators>
364 template <DecoratorSet expected_decorators>
365 void Access<decorators>::verify_decorators() {
366 STATIC_ASSERT((~expected_decorators & decorators) == 0); // unexpected decorator used
367 const DecoratorSet barrier_strength_decorators = decorators & AS_DECORATOR_MASK;
368 STATIC_ASSERT(barrier_strength_decorators == 0 || ( // make sure barrier strength decorators are disjoint if set
369 (barrier_strength_decorators ^ AS_NO_KEEPALIVE) == 0 ||
370 (barrier_strength_decorators ^ AS_RAW) == 0 ||
371 (barrier_strength_decorators ^ AS_NORMAL) == 0
372 ));
373 const DecoratorSet ref_strength_decorators = decorators & ON_DECORATOR_MASK;
374 STATIC_ASSERT(ref_strength_decorators == 0 || ( // make sure ref strength decorators are disjoint if set
375 (ref_strength_decorators ^ ON_STRONG_OOP_REF) == 0 ||
376 (ref_strength_decorators ^ ON_WEAK_OOP_REF) == 0 ||
377 (ref_strength_decorators ^ ON_PHANTOM_OOP_REF) == 0 ||
378 (ref_strength_decorators ^ ON_UNKNOWN_OOP_REF) == 0
379 ));
380 const DecoratorSet memory_ordering_decorators = decorators & MO_DECORATOR_MASK;
381 STATIC_ASSERT(memory_ordering_decorators == 0 || ( // make sure memory ordering decorators are disjoint if set
382 (memory_ordering_decorators ^ MO_UNORDERED) == 0 ||
383 (memory_ordering_decorators ^ MO_RELAXED) == 0 ||
384 (memory_ordering_decorators ^ MO_ACQUIRE) == 0 ||
385 (memory_ordering_decorators ^ MO_RELEASE) == 0 ||
386 (memory_ordering_decorators ^ MO_SEQ_CST) == 0
387 ));
388 const DecoratorSet location_decorators = decorators & IN_DECORATOR_MASK;
389 STATIC_ASSERT(location_decorators == 0 || ( // make sure location decorators are disjoint if set
390 (location_decorators ^ IN_NATIVE) == 0 ||
391 (location_decorators ^ IN_HEAP) == 0
392 ));
393 }
394
395 #endif // SHARE_OOPS_ACCESS_HPP