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 if previous value matched the compared value.
57 // * atomic_xchg_at: Atomically swap a new value at an internal pointer address if previous value matched the compared 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 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. The accesses that are allowed through the access.hpp file
91 // must be instantiated in access.cpp using the INSTANTIATE_HPP_ACCESS macro.
92
93 template <DecoratorSet decorators = DECORATORS_NONE>
94 class Access: public AllStatic {
95 // This function asserts that if an access gets passed in a decorator outside
96 // of the expected_decorators, then something is wrong. It additionally checks
97 // the consistency of the decorators so that supposedly disjoint decorators are indeed
98 // disjoint. For example, an access can not be both in heap and on root at the
99 // same time.
100 template <DecoratorSet expected_decorators>
101 static void verify_decorators();
102
103 template <DecoratorSet expected_mo_decorators>
104 static void verify_primitive_decorators() {
105 const DecoratorSet primitive_decorators = (AS_DECORATOR_MASK ^ AS_NO_KEEPALIVE) |
106 IN_HEAP | IS_ARRAY;
107 verify_decorators<expected_mo_decorators | primitive_decorators>();
108 }
109
110 template <DecoratorSet expected_mo_decorators>
111 static void verify_oop_decorators() {
112 const DecoratorSet oop_decorators = AS_DECORATOR_MASK | IN_DECORATOR_MASK |
113 (ON_DECORATOR_MASK ^ ON_UNKNOWN_OOP_REF) | // no unknown oop refs outside of the heap
114 IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
115 verify_decorators<expected_mo_decorators | oop_decorators>();
116 }
117
118 template <DecoratorSet expected_mo_decorators>
119 static void verify_heap_oop_decorators() {
120 const DecoratorSet heap_oop_decorators = AS_DECORATOR_MASK | ON_DECORATOR_MASK |
121 IN_HEAP | IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
122 verify_decorators<expected_mo_decorators | heap_oop_decorators>();
123 }
124
125 static const DecoratorSet load_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_ACQUIRE | MO_SEQ_CST;
126 static const DecoratorSet store_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_RELEASE | MO_SEQ_CST;
127 static const DecoratorSet atomic_xchg_mo_decorators = MO_SEQ_CST;
128 static const DecoratorSet atomic_cmpxchg_mo_decorators = MO_RELAXED | MO_SEQ_CST;
129
130 protected:
131 template <typename T>
132 static inline bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
133 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
134 size_t length) {
135 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
136 AS_DECORATOR_MASK | IS_ARRAY | IS_DEST_UNINITIALIZED>();
137 return AccessInternal::arraycopy<decorators | INTERNAL_VALUE_IS_OOP>(src_obj, src_offset_in_bytes, src_raw,
138 dst_obj, dst_offset_in_bytes, dst_raw,
139 length);
140 }
141
142 template <typename T>
143 static inline void arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
144 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
145 size_t length) {
146 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
147 AS_DECORATOR_MASK | IS_ARRAY>();
148 AccessInternal::arraycopy<decorators>(src_obj, src_offset_in_bytes, src_raw,
149 dst_obj, dst_offset_in_bytes, dst_raw,
150 length);
151 }
152
153 public:
154 // Primitive heap accesses
155 static inline AccessInternal::LoadAtProxy<decorators> load_at(oop base, ptrdiff_t offset) {
156 verify_primitive_decorators<load_mo_decorators>();
157 return AccessInternal::LoadAtProxy<decorators>(base, offset);
158 }
159
195 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
196 OopType new_oop_value = new_value;
197 OopType compare_oop_value = compare_value;
198 return AccessInternal::atomic_cmpxchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, compare_oop_value, new_oop_value);
199 }
200
201 template <typename T>
202 static inline T oop_atomic_xchg_at(oop base, ptrdiff_t offset, T new_value) {
203 verify_heap_oop_decorators<atomic_xchg_mo_decorators>();
204 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
205 OopType new_oop_value = new_value;
206 return AccessInternal::atomic_xchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, new_oop_value);
207 }
208
209 // Clone an object from src to dst
210 static inline void clone(oop src, oop dst, size_t size) {
211 verify_decorators<IN_HEAP>();
212 AccessInternal::clone<decorators>(src, dst, size);
213 }
214
215 // Primitive accesses
216 template <typename P>
217 static inline P load(P* addr) {
218 verify_primitive_decorators<load_mo_decorators>();
219 return AccessInternal::load<decorators, P, P>(addr);
220 }
221
222 template <typename P, typename T>
223 static inline void store(P* addr, T value) {
224 verify_primitive_decorators<store_mo_decorators>();
225 AccessInternal::store<decorators>(addr, value);
226 }
227
228 template <typename P, typename T>
229 static inline T atomic_cmpxchg(P* addr, T compare_value, T new_value) {
230 verify_primitive_decorators<atomic_cmpxchg_mo_decorators>();
231 return AccessInternal::atomic_cmpxchg<decorators>(addr, compare_value, new_value);
232 }
233
234 template <typename P, typename T>
305 }
306
307 template <typename T>
308 static inline void arraycopy_to_native(arrayOop src_obj, size_t src_offset_in_bytes,
309 T* dst,
310 size_t length) {
311 AccessT::arraycopy(src_obj, src_offset_in_bytes, static_cast<const T*>(nullptr),
312 nullptr, 0, dst,
313 length);
314 }
315
316 template <typename T>
317 static inline void arraycopy_from_native(const T* src,
318 arrayOop dst_obj, size_t dst_offset_in_bytes,
319 size_t length) {
320 AccessT::arraycopy(nullptr, 0, src,
321 dst_obj, dst_offset_in_bytes, static_cast<T*>(nullptr),
322 length);
323 }
324
325 static inline bool oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes,
326 arrayOop dst_obj, size_t dst_offset_in_bytes,
327 size_t length) {
328 return AccessT::oop_arraycopy(src_obj, src_offset_in_bytes, static_cast<const HeapWord*>(nullptr),
329 dst_obj, dst_offset_in_bytes, static_cast<HeapWord*>(nullptr),
330 length);
331 }
332
333 template <typename T>
334 static inline bool oop_arraycopy_raw(T* src, T* dst, size_t length) {
335 return AccessT::oop_arraycopy(nullptr, 0, src,
336 nullptr, 0, dst,
337 length);
338 }
339
340 };
341
342 template <DecoratorSet decorators>
343 template <DecoratorSet expected_decorators>
344 void Access<decorators>::verify_decorators() {
345 STATIC_ASSERT((~expected_decorators & decorators) == 0); // unexpected decorator used
346 const DecoratorSet barrier_strength_decorators = decorators & AS_DECORATOR_MASK;
347 STATIC_ASSERT(barrier_strength_decorators == 0 || ( // make sure barrier strength decorators are disjoint if set
348 (barrier_strength_decorators ^ AS_NO_KEEPALIVE) == 0 ||
349 (barrier_strength_decorators ^ AS_RAW) == 0 ||
350 (barrier_strength_decorators ^ AS_NORMAL) == 0
351 ));
352 const DecoratorSet ref_strength_decorators = decorators & ON_DECORATOR_MASK;
353 STATIC_ASSERT(ref_strength_decorators == 0 || ( // make sure ref strength decorators are disjoint if set
354 (ref_strength_decorators ^ ON_STRONG_OOP_REF) == 0 ||
355 (ref_strength_decorators ^ ON_WEAK_OOP_REF) == 0 ||
356 (ref_strength_decorators ^ ON_PHANTOM_OOP_REF) == 0 ||
357 (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 if previous value matched the compared value.
57 // * atomic_xchg_at: Atomically swap a new value at an internal pointer address if previous value matched the compared 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 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. The accesses that are allowed through the access.hpp file
92 // must be instantiated in access.cpp using the INSTANTIATE_HPP_ACCESS macro.
93
94 class InlineKlass;
95
96 template <DecoratorSet decorators = DECORATORS_NONE>
97 class Access: public AllStatic {
98 // This function asserts that if an access gets passed in a decorator outside
99 // of the expected_decorators, then something is wrong. It additionally checks
100 // the consistency of the decorators so that supposedly disjoint decorators are indeed
101 // disjoint. For example, an access can not be both in heap and on root at the
102 // same time.
103 template <DecoratorSet expected_decorators>
104 static void verify_decorators();
105
106 template <DecoratorSet expected_mo_decorators>
107 static void verify_primitive_decorators() {
108 const DecoratorSet primitive_decorators = (AS_DECORATOR_MASK ^ AS_NO_KEEPALIVE) |
109 IN_HEAP | IS_ARRAY;
110 verify_decorators<expected_mo_decorators | primitive_decorators>();
111 }
112
113 template <DecoratorSet expected_mo_decorators>
114 static void verify_oop_decorators() {
115 const DecoratorSet oop_decorators = AS_DECORATOR_MASK | IN_DECORATOR_MASK |
116 (ON_DECORATOR_MASK ^ ON_UNKNOWN_OOP_REF) | // no unknown oop refs outside of the heap
117 IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
118 verify_decorators<expected_mo_decorators | oop_decorators>();
119 }
120
121 template <DecoratorSet expected_mo_decorators>
122 static void verify_heap_oop_decorators() {
123 const DecoratorSet heap_oop_decorators = AS_DECORATOR_MASK | ON_DECORATOR_MASK |
124 IN_HEAP | IS_ARRAY | IS_NOT_NULL | IS_DEST_UNINITIALIZED;
125 verify_decorators<expected_mo_decorators | heap_oop_decorators>();
126 }
127
128 template <DecoratorSet expected_mo_decorators>
129 static void verify_heap_value_decorators() {
130 const DecoratorSet heap_value_decorators = IN_HEAP | IS_DEST_UNINITIALIZED;
131 verify_decorators<expected_mo_decorators | heap_value_decorators>();
132 }
133
134 static const DecoratorSet load_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_ACQUIRE | MO_SEQ_CST;
135 static const DecoratorSet store_mo_decorators = MO_UNORDERED | MO_RELAXED | MO_RELEASE | MO_SEQ_CST;
136 static const DecoratorSet atomic_xchg_mo_decorators = MO_SEQ_CST;
137 static const DecoratorSet atomic_cmpxchg_mo_decorators = MO_RELAXED | MO_SEQ_CST;
138
139 protected:
140 template <typename T>
141 static inline void oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
142 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
143 size_t length) {
144 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
145 AS_DECORATOR_MASK | IS_ARRAY | IS_DEST_UNINITIALIZED>();
146 AccessInternal::arraycopy<decorators | INTERNAL_VALUE_IS_OOP>(src_obj, src_offset_in_bytes, src_raw,
147 dst_obj, dst_offset_in_bytes, dst_raw,
148 length);
149 }
150
151 template <typename T>
152 static inline void arraycopy(arrayOop src_obj, size_t src_offset_in_bytes, const T* src_raw,
153 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
154 size_t length) {
155 verify_decorators<ARRAYCOPY_DECORATOR_MASK | IN_HEAP |
156 AS_DECORATOR_MASK | IS_ARRAY>();
157 AccessInternal::arraycopy<decorators>(src_obj, src_offset_in_bytes, src_raw,
158 dst_obj, dst_offset_in_bytes, dst_raw,
159 length);
160 }
161
162 public:
163 // Primitive heap accesses
164 static inline AccessInternal::LoadAtProxy<decorators> load_at(oop base, ptrdiff_t offset) {
165 verify_primitive_decorators<load_mo_decorators>();
166 return AccessInternal::LoadAtProxy<decorators>(base, offset);
167 }
168
204 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
205 OopType new_oop_value = new_value;
206 OopType compare_oop_value = compare_value;
207 return AccessInternal::atomic_cmpxchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, compare_oop_value, new_oop_value);
208 }
209
210 template <typename T>
211 static inline T oop_atomic_xchg_at(oop base, ptrdiff_t offset, T new_value) {
212 verify_heap_oop_decorators<atomic_xchg_mo_decorators>();
213 typedef typename AccessInternal::OopOrNarrowOop<T>::type OopType;
214 OopType new_oop_value = new_value;
215 return AccessInternal::atomic_xchg_at<decorators | INTERNAL_VALUE_IS_OOP>(base, offset, new_oop_value);
216 }
217
218 // Clone an object from src to dst
219 static inline void clone(oop src, oop dst, size_t size) {
220 verify_decorators<IN_HEAP>();
221 AccessInternal::clone<decorators>(src, dst, size);
222 }
223
224 // inline type heap access (when flat)...
225
226 // Copy value type data from src to dst
227 static inline void value_copy(void* src, void* dst, InlineKlass* md) {
228 verify_heap_value_decorators<IN_HEAP>();
229 AccessInternal::value_copy<decorators>(src, dst, md);
230 }
231
232 // Primitive accesses
233 template <typename P>
234 static inline P load(P* addr) {
235 verify_primitive_decorators<load_mo_decorators>();
236 return AccessInternal::load<decorators, P, P>(addr);
237 }
238
239 template <typename P, typename T>
240 static inline void store(P* addr, T value) {
241 verify_primitive_decorators<store_mo_decorators>();
242 AccessInternal::store<decorators>(addr, value);
243 }
244
245 template <typename P, typename T>
246 static inline T atomic_cmpxchg(P* addr, T compare_value, T new_value) {
247 verify_primitive_decorators<atomic_cmpxchg_mo_decorators>();
248 return AccessInternal::atomic_cmpxchg<decorators>(addr, compare_value, new_value);
249 }
250
251 template <typename P, typename T>
322 }
323
324 template <typename T>
325 static inline void arraycopy_to_native(arrayOop src_obj, size_t src_offset_in_bytes,
326 T* dst,
327 size_t length) {
328 AccessT::arraycopy(src_obj, src_offset_in_bytes, static_cast<const T*>(nullptr),
329 nullptr, 0, dst,
330 length);
331 }
332
333 template <typename T>
334 static inline void arraycopy_from_native(const T* src,
335 arrayOop dst_obj, size_t dst_offset_in_bytes,
336 size_t length) {
337 AccessT::arraycopy(nullptr, 0, src,
338 dst_obj, dst_offset_in_bytes, static_cast<T*>(nullptr),
339 length);
340 }
341
342 static inline void oop_arraycopy(arrayOop src_obj, size_t src_offset_in_bytes,
343 arrayOop dst_obj, size_t dst_offset_in_bytes,
344 size_t length) {
345 AccessT::oop_arraycopy(src_obj, src_offset_in_bytes, static_cast<const HeapWord*>(nullptr),
346 dst_obj, dst_offset_in_bytes, static_cast<HeapWord*>(nullptr),
347 length);
348 }
349
350 template <typename T>
351 static inline void oop_arraycopy_raw(T* src, T* dst, size_t length) {
352 AccessT::oop_arraycopy(nullptr, 0, src,
353 nullptr, 0, dst,
354 length);
355 }
356
357 };
358
359 template <DecoratorSet decorators>
360 template <DecoratorSet expected_decorators>
361 void Access<decorators>::verify_decorators() {
362 STATIC_ASSERT((~expected_decorators & decorators) == 0); // unexpected decorator used
363 const DecoratorSet barrier_strength_decorators = decorators & AS_DECORATOR_MASK;
364 STATIC_ASSERT(barrier_strength_decorators == 0 || ( // make sure barrier strength decorators are disjoint if set
365 (barrier_strength_decorators ^ AS_NO_KEEPALIVE) == 0 ||
366 (barrier_strength_decorators ^ AS_RAW) == 0 ||
367 (barrier_strength_decorators ^ AS_NORMAL) == 0
368 ));
369 const DecoratorSet ref_strength_decorators = decorators & ON_DECORATOR_MASK;
370 STATIC_ASSERT(ref_strength_decorators == 0 || ( // make sure ref strength decorators are disjoint if set
371 (ref_strength_decorators ^ ON_STRONG_OOP_REF) == 0 ||
372 (ref_strength_decorators ^ ON_WEAK_OOP_REF) == 0 ||
373 (ref_strength_decorators ^ ON_PHANTOM_OOP_REF) == 0 ||
374 (ref_strength_decorators ^ ON_UNKNOWN_OOP_REF) == 0
|