40 // e.g. strength of references, strength of GC barriers, or whether compression should be applied or not.
41 // Some decorators are set at buildtime, such as whether primitives require GC barriers or not, others
42 // at callsites such as whether an access is in the heap or not, and others are resolved at runtime
43 // such as GC-specific barriers and encoding/decoding compressed oops. For more information about what
44 // decorators are available, cf. oops/accessDecorators.hpp.
45 // By pipelining handling of these decorators, the design of the Access API allows separation of concern
46 // over the different orthogonal concerns of decorators, while providing a powerful way of
47 // expressing these orthogonal semantic properties in a unified way.
48 //
49 // == OPERATIONS ==
50 // * load: Load a value from an address.
51 // * load_at: Load a value from an internal pointer relative to a base object.
52 // * store: Store a value at an address.
53 // * store_at: Store a value in an internal pointer relative to a base object.
54 // * atomic_cmpxchg: Atomically compare-and-swap a new value at an address if previous value matched the compared value.
55 // * atomic_cmpxchg_at: Atomically compare-and-swap a new value at an internal pointer address if previous value matched the compared value.
56 // * atomic_xchg: Atomically swap a new value at an address without checking the previous value.
57 // * atomic_xchg_at: Atomically swap a new value at an internal pointer address without checking the previous value.
58 // * arraycopy: Copy data from one heap array to another heap array. The ArrayAccess class has convenience functions for this.
59 // * clone: Clone the contents of an object to a newly allocated object.
60 //
61 // == IMPLEMENTATION ==
62 // Each access goes through the following steps in a template pipeline.
63 // There are essentially 5 steps for each access:
64 // * Step 1: Set default decorators and decay types. This step gets rid of CV qualifiers
65 // and sets default decorators to sensible values.
66 // * Step 2: Reduce types. This step makes sure there is only a single T type and not
67 // multiple types. The P type of the address and T type of the value must
68 // match.
69 // * Step 3: Pre-runtime dispatch. This step checks whether a runtime call can be
70 // avoided, and in that case avoids it (calling raw accesses or
71 // primitive accesses in a build that does not require primitive GC barriers)
72 // * Step 4: Runtime-dispatch. This step performs a runtime dispatch to the corresponding
73 // BarrierSet::AccessBarrier accessor that attaches GC-required barriers
74 // to the access.
75 // * Step 5.a: Barrier resolution. This step is invoked the first time a runtime-dispatch
76 // happens for an access. The appropriate BarrierSet::AccessBarrier accessor
77 // is resolved, then the function pointer is updated to that accessor for
78 // future invocations.
79 // * Step 5.b: Post-runtime dispatch. This step now casts previously unknown types such
80 // as the address type of an oop on the heap (is it oop* or narrowOop*) to
81 // the appropriate type. It also splits sufficiently orthogonal accesses into
82 // different functions, such as whether the access involves oops or primitives
83 // and whether the access is performed on the heap or outside. Then the
84 // appropriate BarrierSet::AccessBarrier is called to perform the access.
85 //
86 // The implementation of step 1-4 resides in accessBackend.hpp, to allow selected
87 // accesses to be accessible from only access.hpp, as opposed to access.inline.hpp.
88 // Steps 5.a and 5.b require knowledge about the GC backends, and therefore needs to
89 // include the various GC backend .inline.hpp headers. Their implementation resides in
90 // access.inline.hpp.
91
92 template <DecoratorSet decorators = DECORATORS_NONE>
93 class Access: public AllStatic {
94 // This function asserts that if an access gets passed in a decorator outside
95 // of the expected_decorators, then something is wrong. It additionally checks
96 // the consistency of the decorators so that supposedly disjoint decorators are indeed
97 // disjoint. For example, an access can not be both in heap and on root at the
98 // same time.
99 template <DecoratorSet expected_decorators>
100 static void verify_decorators();
101
102 template <DecoratorSet expected_mo_decorators>
103 static void verify_primitive_decorators() {
104 const DecoratorSet primitive_decorators = (AS_DECORATOR_MASK ^ AS_NO_KEEPALIVE) |
105 IN_HEAP | IS_ARRAY;
106 verify_decorators<expected_mo_decorators | primitive_decorators>();
107 }
108
109 template <DecoratorSet expected_mo_decorators>
110 static void verify_oop_decorators() {
111 const DecoratorSet oop_decorators = AS_DECORATOR_MASK | IN_DECORATOR_MASK |
112 (ON_DECORATOR_MASK ^ ON_UNKNOWN_OOP_REF) | // no unknown oop refs outside of the heap
113 IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
114 verify_decorators<expected_mo_decorators | oop_decorators>();
115 }
116
117 template <DecoratorSet expected_mo_decorators>
118 static void verify_heap_oop_decorators() {
119 const DecoratorSet heap_oop_decorators = AS_DECORATOR_MASK | ON_DECORATOR_MASK |
120 IN_HEAP | IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
121 verify_decorators<expected_mo_decorators | heap_oop_decorators>();
122 }
123
124 static const DecoratorSet load_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_ACQUIRE | MO_SEQ_CST;
125 static const DecoratorSet store_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_RELEASE | MO_SEQ_CST;
126 static const DecoratorSet atomic_xchg_mo_decorators = MO_SEQ_CST;
127 static const DecoratorSet atomic_cmpxchg_mo_decorators = MO_RELAXED | MO_SEQ_CST;
128
129 protected:
130 template <typename T>
131 static inline bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
132 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
133 size_t length) {
134 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
135 AS_DECORATOR_MASK | IS_ARRAY | IS_DEST_UNINITIALIZED>();
136 return AccessInternal::arraycopy<decorators | INTERNAL_VALUE_IS_OOP>(src_obj, src_offset_in_bytes, src_raw,
137 dst_obj, dst_offset_in_bytes, dst_raw,
138 length);
139 }
140
141 template <typename T>
142 static inline void arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
143 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
144 size_t length) {
145 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
146 AS_DECORATOR_MASK | IS_ARRAY>();
147 AccessInternal::arraycopy<decorators>(src_obj, src_offset_in_bytes, src_raw,
148 dst_obj, dst_offset_in_bytes, dst_raw,
149 length);
150 }
151
152 public:
153 // Primitive heap accesses
154 static inline AccessInternal::LoadAtProxy<decorators> load_at(oop base, ptrdiff_t offset) {
155 verify_primitive_decorators<load_mo_decorators>();
156 return AccessInternal::LoadAtProxy<decorators>(base, offset);
157 }
158
194 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
195 OopType new_oop_value = new_value;
196 OopType compare_oop_value = compare_value;
197 return AccessInternal::atomic_cmpxchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, compare_oop_value, new_oop_value);
198 }
199
200 template <typename T>
201 static inline T oop_atomic_xchg_at(oop base, ptrdiff_t offset, T new_value) {
202 verify_heap_oop_decorators<atomic_xchg_mo_decorators>();
203 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
204 OopType new_oop_value = new_value;
205 return AccessInternal::atomic_xchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, new_oop_value);
206 }
207
208 // Clone an object from src to dst
209 static inline void clone(oop src, oop dst, size_t size) {
210 verify_decorators<IN_HEAP>();
211 AccessInternal::clone<decorators>(src, dst, size);
212 }
213
214 // Primitive accesses
215 template <typename P>
216 static inline P load(P* addr) {
217 verify_primitive_decorators<load_mo_decorators>();
218 return AccessInternal::load<decorators, P, P>(addr);
219 }
220
221 template <typename P, typename T>
222 static inline void store(P* addr, T value) {
223 verify_primitive_decorators<store_mo_decorators>();
224 AccessInternal::store<decorators>(addr, value);
225 }
226
227 template <typename P, typename T>
228 static inline T atomic_cmpxchg(P* addr, T compare_value, T new_value) {
229 verify_primitive_decorators<atomic_cmpxchg_mo_decorators>();
230 return AccessInternal::atomic_cmpxchg<decorators>(addr, compare_value, new_value);
231 }
232
233 template <typename P, typename T>
304 }
305
306 template <typename T>
307 static inline void arraycopy_to_native(arrayOop src_obj, size_t src_offset_in_bytes,
308 T* dst,
309 size_t length) {
310 AccessT::arraycopy(src_obj, src_offset_in_bytes, static_cast<const T*>(nullptr),
311 nullptr, 0, dst,
312 length);
313 }
314
315 template <typename T>
316 static inline void arraycopy_from_native(const T* src,
317 arrayOop dst_obj, size_t dst_offset_in_bytes,
318 size_t length) {
319 AccessT::arraycopy(nullptr, 0, src,
320 dst_obj, dst_offset_in_bytes, static_cast<T*>(nullptr),
321 length);
322 }
323
324 static inline bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes,
325 arrayOop dst_obj, size_t dst_offset_in_bytes,
326 size_t length) {
327 return AccessT::oop_arraycopy(src_obj, src_offset_in_bytes, static_cast<const HeapWord*>(nullptr),
328 dst_obj, dst_offset_in_bytes, static_cast<HeapWord*>(nullptr),
329 length);
330 }
331
332 template <typename T>
333 static inline bool oop_arraycopy_raw(T* src, T* dst, size_t length) {
334 return AccessT::oop_arraycopy(nullptr, 0, src,
335 nullptr, 0, dst,
336 length);
337 }
338
339 };
340
341 template <DecoratorSet decorators>
342 template <DecoratorSet expected_decorators>
343 void Access<decorators>::verify_decorators() {
344 STATIC_ASSERT((~expected_decorators & decorators) == 0); // unexpected decorator used
345 const DecoratorSet barrier_strength_decorators = decorators & AS_DECORATOR_MASK;
346 STATIC_ASSERT(barrier_strength_decorators == 0 || ( // make sure barrier strength decorators are disjoint if set
347 (barrier_strength_decorators ^ AS_NO_KEEPALIVE) == 0 ||
348 (barrier_strength_decorators ^ AS_RAW) == 0 ||
349 (barrier_strength_decorators ^ AS_NORMAL) == 0
350 ));
351 const DecoratorSet ref_strength_decorators = decorators & ON_DECORATOR_MASK;
352 STATIC_ASSERT(ref_strength_decorators == 0 || ( // make sure ref strength decorators are disjoint if set
353 (ref_strength_decorators ^ ON_STRONG_OOP_REF) == 0 ||
354 (ref_strength_decorators ^ ON_WEAK_OOP_REF) == 0 ||
355 (ref_strength_decorators ^ ON_PHANTOM_OOP_REF) == 0 ||
356 (ref_strength_decorators ^ ON_UNKNOWN_OOP_REF) == 0
|
40 // e.g. strength of references, strength of GC barriers, or whether compression should be applied or not.
41 // Some decorators are set at buildtime, such as whether primitives require GC barriers or not, others
42 // at callsites such as whether an access is in the heap or not, and others are resolved at runtime
43 // such as GC-specific barriers and encoding/decoding compressed oops. For more information about what
44 // decorators are available, cf. oops/accessDecorators.hpp.
45 // By pipelining handling of these decorators, the design of the Access API allows separation of concern
46 // over the different orthogonal concerns of decorators, while providing a powerful way of
47 // expressing these orthogonal semantic properties in a unified way.
48 //
49 // == OPERATIONS ==
50 // * load: Load a value from an address.
51 // * load_at: Load a value from an internal pointer relative to a base object.
52 // * store: Store a value at an address.
53 // * store_at: Store a value in an internal pointer relative to a base object.
54 // * atomic_cmpxchg: Atomically compare-and-swap a new value at an address if previous value matched the compared value.
55 // * atomic_cmpxchg_at: Atomically compare-and-swap a new value at an internal pointer address if previous value matched the compared value.
56 // * atomic_xchg: Atomically swap a new value at an address without checking the previous value.
57 // * atomic_xchg_at: Atomically swap a new value at an internal pointer address without checking the previous value.
58 // * arraycopy: Copy data from one heap array to another heap array. The ArrayAccess class has convenience functions for this.
59 // * clone: Clone the contents of an object to a newly allocated object.
60 // * value_copy: Copy the contents of a value type from one heap address to another
61 //
62 // == IMPLEMENTATION ==
63 // Each access goes through the following steps in a template pipeline.
64 // There are essentially 5 steps for each access:
65 // * Step 1: Set default decorators and decay types. This step gets rid of CV qualifiers
66 // and sets default decorators to sensible values.
67 // * Step 2: Reduce types. This step makes sure there is only a single T type and not
68 // multiple types. The P type of the address and T type of the value must
69 // match.
70 // * Step 3: Pre-runtime dispatch. This step checks whether a runtime call can be
71 // avoided, and in that case avoids it (calling raw accesses or
72 // primitive accesses in a build that does not require primitive GC barriers)
73 // * Step 4: Runtime-dispatch. This step performs a runtime dispatch to the corresponding
74 // BarrierSet::AccessBarrier accessor that attaches GC-required barriers
75 // to the access.
76 // * Step 5.a: Barrier resolution. This step is invoked the first time a runtime-dispatch
77 // happens for an access. The appropriate BarrierSet::AccessBarrier accessor
78 // is resolved, then the function pointer is updated to that accessor for
79 // future invocations.
80 // * Step 5.b: Post-runtime dispatch. This step now casts previously unknown types such
81 // as the address type of an oop on the heap (is it oop* or narrowOop*) to
82 // the appropriate type. It also splits sufficiently orthogonal accesses into
83 // different functions, such as whether the access involves oops or primitives
84 // and whether the access is performed on the heap or outside. Then the
85 // appropriate BarrierSet::AccessBarrier is called to perform the access.
86 //
87 // The implementation of step 1-4 resides in accessBackend.hpp, to allow selected
88 // accesses to be accessible from only access.hpp, as opposed to access.inline.hpp.
89 // Steps 5.a and 5.b require knowledge about the GC backends, and therefore needs to
90 // include the various GC backend .inline.hpp headers. Their implementation resides in
91 // access.inline.hpp.
92
93 class InlineKlass;
94
95 template <DecoratorSet decorators = DECORATORS_NONE>
96 class Access: public AllStatic {
97 // This function asserts that if an access gets passed in a decorator outside
98 // of the expected_decorators, then something is wrong. It additionally checks
99 // the consistency of the decorators so that supposedly disjoint decorators are indeed
100 // disjoint. For example, an access can not be both in heap and on root at the
101 // same time.
102 template <DecoratorSet expected_decorators>
103 static void verify_decorators();
104
105 template <DecoratorSet expected_mo_decorators>
106 static void verify_primitive_decorators() {
107 const DecoratorSet primitive_decorators = (AS_DECORATOR_MASK ^ AS_NO_KEEPALIVE) |
108 IN_HEAP | IS_ARRAY;
109 verify_decorators<expected_mo_decorators | primitive_decorators>();
110 }
111
112 template <DecoratorSet expected_mo_decorators>
113 static void verify_oop_decorators() {
114 const DecoratorSet oop_decorators = AS_DECORATOR_MASK | IN_DECORATOR_MASK |
115 (ON_DECORATOR_MASK ^ ON_UNKNOWN_OOP_REF) | // no unknown oop refs outside of the heap
116 IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
117 verify_decorators<expected_mo_decorators | oop_decorators>();
118 }
119
120 template <DecoratorSet expected_mo_decorators>
121 static void verify_heap_oop_decorators() {
122 const DecoratorSet heap_oop_decorators = AS_DECORATOR_MASK | ON_DECORATOR_MASK |
123 IN_HEAP | IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
124 verify_decorators<expected_mo_decorators | heap_oop_decorators>();
125 }
126
127 template <DecoratorSet expected_mo_decorators>
128 static void verify_heap_value_decorators() {
129 const DecoratorSet heap_value_decorators = IN_HEAP | IS_DEST_UNINITIALIZED;
130 verify_decorators<expected_mo_decorators | heap_value_decorators>();
131 }
132
133 static const DecoratorSet load_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_ACQUIRE | MO_SEQ_CST;
134 static const DecoratorSet store_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_RELEASE | MO_SEQ_CST;
135 static const DecoratorSet atomic_xchg_mo_decorators = MO_SEQ_CST;
136 static const DecoratorSet atomic_cmpxchg_mo_decorators = MO_RELAXED | MO_SEQ_CST;
137
138 protected:
139 template <typename T>
140 static inline void oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
141 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
142 size_t length) {
143 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
144 AS_DECORATOR_MASK | IS_ARRAY | IS_DEST_UNINITIALIZED>();
145 AccessInternal::arraycopy<decorators | INTERNAL_VALUE_IS_OOP>(src_obj, src_offset_in_bytes, src_raw,
146 dst_obj, dst_offset_in_bytes, dst_raw,
147 length);
148 }
149
150 template <typename T>
151 static inline void arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
152 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
153 size_t length) {
154 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
155 AS_DECORATOR_MASK | IS_ARRAY>();
156 AccessInternal::arraycopy<decorators>(src_obj, src_offset_in_bytes, src_raw,
157 dst_obj, dst_offset_in_bytes, dst_raw,
158 length);
159 }
160
161 public:
162 // Primitive heap accesses
163 static inline AccessInternal::LoadAtProxy<decorators> load_at(oop base, ptrdiff_t offset) {
164 verify_primitive_decorators<load_mo_decorators>();
165 return AccessInternal::LoadAtProxy<decorators>(base, offset);
166 }
167
203 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
204 OopType new_oop_value = new_value;
205 OopType compare_oop_value = compare_value;
206 return AccessInternal::atomic_cmpxchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, compare_oop_value, new_oop_value);
207 }
208
209 template <typename T>
210 static inline T oop_atomic_xchg_at(oop base, ptrdiff_t offset, T new_value) {
211 verify_heap_oop_decorators<atomic_xchg_mo_decorators>();
212 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
213 OopType new_oop_value = new_value;
214 return AccessInternal::atomic_xchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, new_oop_value);
215 }
216
217 // Clone an object from src to dst
218 static inline void clone(oop src, oop dst, size_t size) {
219 verify_decorators<IN_HEAP>();
220 AccessInternal::clone<decorators>(src, dst, size);
221 }
222
223 // inline type heap access (when flat)...
224
225 // Copy value type data from src to dst
226 static inline void value_copy(void* src, void* dst, InlineKlass* md) {
227 verify_heap_value_decorators<IN_HEAP>();
228 AccessInternal::value_copy<decorators>(src, dst, md);
229 }
230
231 // Primitive accesses
232 template <typename P>
233 static inline P load(P* addr) {
234 verify_primitive_decorators<load_mo_decorators>();
235 return AccessInternal::load<decorators, P, P>(addr);
236 }
237
238 template <typename P, typename T>
239 static inline void store(P* addr, T value) {
240 verify_primitive_decorators<store_mo_decorators>();
241 AccessInternal::store<decorators>(addr, value);
242 }
243
244 template <typename P, typename T>
245 static inline T atomic_cmpxchg(P* addr, T compare_value, T new_value) {
246 verify_primitive_decorators<atomic_cmpxchg_mo_decorators>();
247 return AccessInternal::atomic_cmpxchg<decorators>(addr, compare_value, new_value);
248 }
249
250 template <typename P, typename T>
321 }
322
323 template <typename T>
324 static inline void arraycopy_to_native(arrayOop src_obj, size_t src_offset_in_bytes,
325 T* dst,
326 size_t length) {
327 AccessT::arraycopy(src_obj, src_offset_in_bytes, static_cast<const T*>(nullptr),
328 nullptr, 0, dst,
329 length);
330 }
331
332 template <typename T>
333 static inline void arraycopy_from_native(const T* src,
334 arrayOop dst_obj, size_t dst_offset_in_bytes,
335 size_t length) {
336 AccessT::arraycopy(nullptr, 0, src,
337 dst_obj, dst_offset_in_bytes, static_cast<T*>(nullptr),
338 length);
339 }
340
341 static inline void 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 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 AccessT::oop_arraycopy(nullptr, 0, src,
352 nullptr, 0, dst,
353 length);
354 }
355
356 };
357
358 template <DecoratorSet decorators>
359 template <DecoratorSet expected_decorators>
360 void Access<decorators>::verify_decorators() {
361 STATIC_ASSERT((~expected_decorators & decorators) == 0); // unexpected decorator used
362 const DecoratorSet barrier_strength_decorators = decorators & AS_DECORATOR_MASK;
363 STATIC_ASSERT(barrier_strength_decorators == 0 || ( // make sure barrier strength decorators are disjoint if set
364 (barrier_strength_decorators ^ AS_NO_KEEPALIVE) == 0 ||
365 (barrier_strength_decorators ^ AS_RAW) == 0 ||
366 (barrier_strength_decorators ^ AS_NORMAL) == 0
367 ));
368 const DecoratorSet ref_strength_decorators = decorators & ON_DECORATOR_MASK;
369 STATIC_ASSERT(ref_strength_decorators == 0 || ( // make sure ref strength decorators are disjoint if set
370 (ref_strength_decorators ^ ON_STRONG_OOP_REF) == 0 ||
371 (ref_strength_decorators ^ ON_WEAK_OOP_REF) == 0 ||
372 (ref_strength_decorators ^ ON_PHANTOM_OOP_REF) == 0 ||
373 (ref_strength_decorators ^ ON_UNKNOWN_OOP_REF) == 0
|