54 // * atomic_xchg: Atomically swap a new value at an 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. |
55 // * atomic_xchg_at: Atomically swap a new value at an internal pointer 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. |
56 // * arraycopy: Copy data from one heap array to another heap array. |
58 // * arraycopy: Copy data from one heap array to another heap array. |
57 // * clone: Clone the contents of an object to a newly allocated object. |
59 // * clone: Clone the contents of an object to a newly allocated object. |
58 // * resolve: Resolve a stable to-space invariant oop that is guaranteed not to relocate its payload until a subsequent thread transition. |
60 // * resolve: Resolve a stable to-space invariant oop that is guaranteed not to relocate its payload until a subsequent thread transition. |
59 |
61 // * equals: Object equality, e.g. when different copies of the same objects are in use (from-space vs. to-space) |
60 typedef uint64_t DecoratorSet; |
|
61 |
|
62 // == Internal Decorators - do not use == |
|
63 // * INTERNAL_EMPTY: This is the name for the empty decorator set (in absence of other decorators). |
|
64 // * INTERNAL_CONVERT_COMPRESSED_OOPS: This is an oop access that will require converting an oop |
|
65 // to a narrowOop or vice versa, if UseCompressedOops is known to be set. |
|
66 // * INTERNAL_VALUE_IS_OOP: Remember that the involved access is on oop rather than primitive. |
|
67 const DecoratorSet INTERNAL_EMPTY = UCONST64(0); |
|
68 const DecoratorSet INTERNAL_CONVERT_COMPRESSED_OOP = UCONST64(1) << 1; |
|
69 const DecoratorSet INTERNAL_VALUE_IS_OOP = UCONST64(1) << 2; |
|
70 |
|
71 // == Internal build-time Decorators == |
|
72 // * INTERNAL_BT_BARRIER_ON_PRIMITIVES: This is set in the barrierSetConfig.hpp file. |
|
73 // * INTERNAL_BT_TO_SPACE_INVARIANT: This is set in the barrierSetConfig.hpp file iff |
|
74 // no GC is bundled in the build that is to-space invariant. |
|
75 const DecoratorSet INTERNAL_BT_BARRIER_ON_PRIMITIVES = UCONST64(1) << 3; |
|
76 const DecoratorSet INTERNAL_BT_TO_SPACE_INVARIANT = UCONST64(1) << 4; |
|
77 |
|
78 // == Internal run-time Decorators == |
|
79 // * INTERNAL_RT_USE_COMPRESSED_OOPS: This decorator will be set in runtime resolved |
|
80 // access backends iff UseCompressedOops is true. |
|
81 const DecoratorSet INTERNAL_RT_USE_COMPRESSED_OOPS = UCONST64(1) << 5; |
|
82 |
|
83 const DecoratorSet INTERNAL_DECORATOR_MASK = INTERNAL_CONVERT_COMPRESSED_OOP | INTERNAL_VALUE_IS_OOP | |
|
84 INTERNAL_BT_BARRIER_ON_PRIMITIVES | INTERNAL_RT_USE_COMPRESSED_OOPS; |
|
85 |
|
86 // == Memory Ordering Decorators == |
|
87 // The memory ordering decorators can be described in the following way: |
|
88 // === Decorator Rules === |
|
89 // The different types of memory ordering guarantees have a strict order of strength. |
|
90 // Explicitly specifying the stronger ordering implies that the guarantees of the weaker |
|
91 // property holds too. The names come from the C++11 atomic operations, and typically |
|
92 // have a JMM equivalent property. |
|
93 // The equivalence may be viewed like this: |
|
94 // MO_UNORDERED is equivalent to JMM plain. |
|
95 // MO_VOLATILE has no equivalence in JMM, because it's a C++ thing. |
|
96 // MO_RELAXED is equivalent to JMM opaque. |
|
97 // MO_ACQUIRE is equivalent to JMM acquire. |
|
98 // MO_RELEASE is equivalent to JMM release. |
|
99 // MO_SEQ_CST is equivalent to JMM volatile. |
|
100 // |
62 // |
101 // === Stores === |
63 // == IMPLEMENTATION == |
102 // * MO_UNORDERED (Default): No guarantees. |
64 // Each access goes through the following steps in a template pipeline. |
103 // - The compiler and hardware are free to reorder aggressively. And they will. |
65 // There are essentially 5 steps for each access: |
104 // * MO_VOLATILE: Volatile stores (in the C++ sense). |
66 // * Step 1: Set default decorators and decay types. This step gets rid of CV qualifiers |
105 // - The stores are not reordered by the compiler (but possibly the HW) w.r.t. other |
67 // and sets default decorators to sensible values. |
106 // volatile accesses in program order (but possibly non-volatile accesses). |
68 // * Step 2: Reduce types. This step makes sure there is only a single T type and not |
107 // * MO_RELAXED: Relaxed atomic stores. |
69 // multiple types. The P type of the address and T type of the value must |
108 // - The stores are atomic. |
70 // match. |
109 // - Guarantees from volatile stores hold. |
71 // * Step 3: Pre-runtime dispatch. This step checks whether a runtime call can be |
110 // * MO_RELEASE: Releasing stores. |
72 // avoided, and in that case avoids it (calling raw accesses or |
111 // - The releasing store will make its preceding memory accesses observable to memory accesses |
73 // primitive accesses in a build that does not require primitive GC barriers) |
112 // subsequent to an acquiring load observing this releasing store. |
74 // * Step 4: Runtime-dispatch. This step performs a runtime dispatch to the corresponding |
113 // - Guarantees from relaxed stores hold. |
75 // BarrierSet::AccessBarrier accessor that attaches GC-required barriers |
114 // * MO_SEQ_CST: Sequentially consistent stores. |
76 // to the access. |
115 // - The stores are observed in the same order by MO_SEQ_CST loads on other processors |
77 // * Step 5.a: Barrier resolution. This step is invoked the first time a runtime-dispatch |
116 // - Preceding loads and stores in program order are not reordered with subsequent loads and stores in program order. |
78 // happens for an access. The appropriate BarrierSet::AccessBarrier accessor |
117 // - Guarantees from releasing stores hold. |
79 // is resolved, then the function pointer is updated to that accessor for |
118 // === Loads === |
80 // future invocations. |
119 // * MO_UNORDERED (Default): No guarantees |
81 // * Step 5.b: Post-runtime dispatch. This step now casts previously unknown types such |
120 // - The compiler and hardware are free to reorder aggressively. And they will. |
82 // as the address type of an oop on the heap (is it oop* or narrowOop*) to |
121 // * MO_VOLATILE: Volatile loads (in the C++ sense). |
83 // the appropriate type. It also splits sufficiently orthogonal accesses into |
122 // - The loads are not reordered by the compiler (but possibly the HW) w.r.t. other |
84 // different functions, such as whether the access involves oops or primitives |
123 // volatile accesses in program order (but possibly non-volatile accesses). |
85 // and whether the access is performed on the heap or outside. Then the |
124 // * MO_RELAXED: Relaxed atomic loads. |
86 // appropriate BarrierSet::AccessBarrier is called to perform the access. |
125 // - The stores are atomic. |
87 // |
126 // - Guarantees from volatile loads hold. |
88 // The implementation of step 1-4 resides in in accessBackend.hpp, to allow selected |
127 // * MO_ACQUIRE: Acquiring loads. |
89 // accesses to be accessible from only access.hpp, as opposed to access.inline.hpp. |
128 // - An acquiring load will make subsequent memory accesses observe the memory accesses |
90 // Steps 5.a and 5.b require knowledge about the GC backends, and therefore needs to |
129 // preceding the releasing store that the acquiring load observed. |
91 // include the various GC backend .inline.hpp headers. Their implementation resides in |
130 // - Guarantees from relaxed loads hold. |
92 // access.inline.hpp. The accesses that are allowed through the access.hpp file |
131 // * MO_SEQ_CST: Sequentially consistent loads. |
93 // must be instantiated in access.cpp using the INSTANTIATE_HPP_ACCESS macro. |
132 // - These loads observe MO_SEQ_CST stores in the same order on other processors |
|
133 // - Preceding loads and stores in program order are not reordered with subsequent loads and stores in program order. |
|
134 // - Guarantees from acquiring loads hold. |
|
135 // === Atomic Cmpxchg === |
|
136 // * MO_RELAXED: Atomic but relaxed cmpxchg. |
|
137 // - Guarantees from MO_RELAXED loads and MO_RELAXED stores hold unconditionally. |
|
138 // * MO_SEQ_CST: Sequentially consistent cmpxchg. |
|
139 // - Guarantees from MO_SEQ_CST loads and MO_SEQ_CST stores hold unconditionally. |
|
140 // === Atomic Xchg === |
|
141 // * MO_RELAXED: Atomic but relaxed atomic xchg. |
|
142 // - Guarantees from MO_RELAXED loads and MO_RELAXED stores hold. |
|
143 // * MO_SEQ_CST: Sequentially consistent xchg. |
|
144 // - Guarantees from MO_SEQ_CST loads and MO_SEQ_CST stores hold. |
|
145 const DecoratorSet MO_UNORDERED = UCONST64(1) << 6; |
|
146 const DecoratorSet MO_VOLATILE = UCONST64(1) << 7; |
|
147 const DecoratorSet MO_RELAXED = UCONST64(1) << 8; |
|
148 const DecoratorSet MO_ACQUIRE = UCONST64(1) << 9; |
|
149 const DecoratorSet MO_RELEASE = UCONST64(1) << 10; |
|
150 const DecoratorSet MO_SEQ_CST = UCONST64(1) << 11; |
|
151 const DecoratorSet MO_DECORATOR_MASK = MO_UNORDERED | MO_VOLATILE | MO_RELAXED | |
|
152 MO_ACQUIRE | MO_RELEASE | MO_SEQ_CST; |
|
153 |
|
154 // === Barrier Strength Decorators === |
|
155 // * AS_RAW: The access will translate into a raw memory access, hence ignoring all semantic concerns |
|
156 // except memory ordering and compressed oops. This will bypass runtime function pointer dispatching |
|
157 // in the pipeline and hardwire to raw accesses without going trough the GC access barriers. |
|
158 // - Accesses on oop* translate to raw memory accesses without runtime checks |
|
159 // - Accesses on narrowOop* translate to encoded/decoded memory accesses without runtime checks |
|
160 // - Accesses on HeapWord* translate to a runtime check choosing one of the above |
|
161 // - Accesses on other types translate to raw memory accesses without runtime checks |
|
162 // * AS_DEST_NOT_INITIALIZED: This property can be important to e.g. SATB barriers by |
|
163 // marking that the previous value is uninitialized nonsense rather than a real value. |
|
164 // * AS_NO_KEEPALIVE: The barrier is used only on oop references and will not keep any involved objects |
|
165 // alive, regardless of the type of reference being accessed. It will however perform the memory access |
|
166 // in a consistent way w.r.t. e.g. concurrent compaction, so that the right field is being accessed, |
|
167 // or maintain, e.g. intergenerational or interregional pointers if applicable. This should be used with |
|
168 // extreme caution in isolated scopes. |
|
169 // * AS_NORMAL: The accesses will be resolved to an accessor on the BarrierSet class, giving the |
|
170 // responsibility of performing the access and what barriers to be performed to the GC. This is the default. |
|
171 // Note that primitive accesses will only be resolved on the barrier set if the appropriate build-time |
|
172 // decorator for enabling primitive barriers is enabled for the build. |
|
173 const DecoratorSet AS_RAW = UCONST64(1) << 12; |
|
174 const DecoratorSet AS_DEST_NOT_INITIALIZED = UCONST64(1) << 13; |
|
175 const DecoratorSet AS_NO_KEEPALIVE = UCONST64(1) << 14; |
|
176 const DecoratorSet AS_NORMAL = UCONST64(1) << 15; |
|
177 const DecoratorSet AS_DECORATOR_MASK = AS_RAW | AS_DEST_NOT_INITIALIZED | |
|
178 AS_NO_KEEPALIVE | AS_NORMAL; |
|
179 |
|
180 // === Reference Strength Decorators === |
|
181 // These decorators only apply to accesses on oop-like types (oop/narrowOop). |
|
182 // * ON_STRONG_OOP_REF: Memory access is performed on a strongly reachable reference. |
|
183 // * ON_WEAK_OOP_REF: The memory access is performed on a weakly reachable reference. |
|
184 // * ON_PHANTOM_OOP_REF: The memory access is performed on a phantomly reachable reference. |
|
185 // This is the same ring of strength as jweak and weak oops in the VM. |
|
186 // * ON_UNKNOWN_OOP_REF: The memory access is performed on a reference of unknown strength. |
|
187 // This could for example come from the unsafe API. |
|
188 // * Default (no explicit reference strength specified): ON_STRONG_OOP_REF |
|
189 const DecoratorSet ON_STRONG_OOP_REF = UCONST64(1) << 16; |
|
190 const DecoratorSet ON_WEAK_OOP_REF = UCONST64(1) << 17; |
|
191 const DecoratorSet ON_PHANTOM_OOP_REF = UCONST64(1) << 18; |
|
192 const DecoratorSet ON_UNKNOWN_OOP_REF = UCONST64(1) << 19; |
|
193 const DecoratorSet ON_DECORATOR_MASK = ON_STRONG_OOP_REF | ON_WEAK_OOP_REF | |
|
194 ON_PHANTOM_OOP_REF | ON_UNKNOWN_OOP_REF; |
|
195 |
|
196 // === Access Location === |
|
197 // Accesses can take place in, e.g. the heap, old or young generation and different native roots. |
|
198 // The location is important to the GC as it may imply different actions. The following decorators are used: |
|
199 // * IN_HEAP: The access is performed in the heap. Many barriers such as card marking will |
|
200 // be omitted if this decorator is not set. |
|
201 // * IN_HEAP_ARRAY: The access is performed on a heap allocated array. This is sometimes a special case |
|
202 // for some GCs, and implies that it is an IN_HEAP. |
|
203 // * IN_ROOT: The access is performed in an off-heap data structure pointing into the Java heap. |
|
204 // * IN_CONCURRENT_ROOT: The access is performed in an off-heap data structure pointing into the Java heap, |
|
205 // but is notably not scanned during safepoints. This is sometimes a special case for some GCs and |
|
206 // implies that it is also an IN_ROOT. |
|
207 const DecoratorSet IN_HEAP = UCONST64(1) << 20; |
|
208 const DecoratorSet IN_HEAP_ARRAY = UCONST64(1) << 21; |
|
209 const DecoratorSet IN_ROOT = UCONST64(1) << 22; |
|
210 const DecoratorSet IN_CONCURRENT_ROOT = UCONST64(1) << 23; |
|
211 const DecoratorSet IN_ARCHIVE_ROOT = UCONST64(1) << 24; |
|
212 const DecoratorSet IN_DECORATOR_MASK = IN_HEAP | IN_HEAP_ARRAY | |
|
213 IN_ROOT | IN_CONCURRENT_ROOT | |
|
214 IN_ARCHIVE_ROOT; |
|
215 |
|
216 // == Value Decorators == |
|
217 // * OOP_NOT_NULL: This property can make certain barriers faster such as compressing oops. |
|
218 const DecoratorSet OOP_NOT_NULL = UCONST64(1) << 25; |
|
219 const DecoratorSet OOP_DECORATOR_MASK = OOP_NOT_NULL; |
|
220 |
|
221 // == Arraycopy Decorators == |
|
222 // * ARRAYCOPY_CHECKCAST: This property means that the class of the objects in source |
|
223 // are not guaranteed to be subclasses of the class of the destination array. This requires |
|
224 // a check-cast barrier during the copying operation. If this is not set, it is assumed |
|
225 // that the array is covariant: (the source array type is-a destination array type) |
|
226 // * ARRAYCOPY_DISJOINT: This property means that it is known that the two array ranges |
|
227 // are disjoint. |
|
228 // * ARRAYCOPY_ARRAYOF: The copy is in the arrayof form. |
|
229 // * ARRAYCOPY_ATOMIC: The accesses have to be atomic over the size of its elements. |
|
230 // * ARRAYCOPY_ALIGNED: The accesses have to be aligned on a HeapWord. |
|
231 const DecoratorSet ARRAYCOPY_CHECKCAST = UCONST64(1) << 26; |
|
232 const DecoratorSet ARRAYCOPY_DISJOINT = UCONST64(1) << 27; |
|
233 const DecoratorSet ARRAYCOPY_ARRAYOF = UCONST64(1) << 28; |
|
234 const DecoratorSet ARRAYCOPY_ATOMIC = UCONST64(1) << 29; |
|
235 const DecoratorSet ARRAYCOPY_ALIGNED = UCONST64(1) << 30; |
|
236 const DecoratorSet ARRAYCOPY_DECORATOR_MASK = ARRAYCOPY_CHECKCAST | ARRAYCOPY_DISJOINT | |
|
237 ARRAYCOPY_DISJOINT | ARRAYCOPY_ARRAYOF | |
|
238 ARRAYCOPY_ATOMIC | ARRAYCOPY_ALIGNED; |
|
239 |
|
240 // The HasDecorator trait can help at compile-time determining whether a decorator set |
|
241 // has an intersection with a certain other decorator set |
|
242 template <DecoratorSet decorators, DecoratorSet decorator> |
|
243 struct HasDecorator: public IntegralConstant<bool, (decorators & decorator) != 0> {}; |
|
244 |
|
245 namespace AccessInternal { |
|
246 template <typename T> |
|
247 struct OopOrNarrowOopInternal: AllStatic { |
|
248 typedef oop type; |
|
249 }; |
|
250 |
|
251 template <> |
|
252 struct OopOrNarrowOopInternal<narrowOop>: AllStatic { |
|
253 typedef narrowOop type; |
|
254 }; |
|
255 |
|
256 // This metafunction returns a canonicalized oop/narrowOop type for a passed |
|
257 // in oop-like types passed in from oop_* overloads where the user has sworn |
|
258 // that the passed in values should be oop-like (e.g. oop, oopDesc*, arrayOop, |
|
259 // narrowOoop, instanceOopDesc*, and random other things). |
|
260 // In the oop_* overloads, it must hold that if the passed in type T is not |
|
261 // narrowOop, then it by contract has to be one of many oop-like types implicitly |
|
262 // convertible to oop, and hence returns oop as the canonical oop type. |
|
263 // If it turns out it was not, then the implicit conversion to oop will fail |
|
264 // to compile, as desired. |
|
265 template <typename T> |
|
266 struct OopOrNarrowOop: AllStatic { |
|
267 typedef typename OopOrNarrowOopInternal<typename Decay<T>::type>::type type; |
|
268 }; |
|
269 |
|
270 inline void* field_addr(oop base, ptrdiff_t byte_offset) { |
|
271 return reinterpret_cast<void*>(reinterpret_cast<intptr_t>((void*)base) + byte_offset); |
|
272 } |
|
273 |
|
274 template <DecoratorSet decorators, typename T> |
|
275 void store_at(oop base, ptrdiff_t offset, T value); |
|
276 |
|
277 template <DecoratorSet decorators, typename T> |
|
278 T load_at(oop base, ptrdiff_t offset); |
|
279 |
|
280 template <DecoratorSet decorators, typename T> |
|
281 T atomic_cmpxchg_at(T new_value, oop base, ptrdiff_t offset, T compare_value); |
|
282 |
|
283 template <DecoratorSet decorators, typename T> |
|
284 T atomic_xchg_at(T new_value, oop base, ptrdiff_t offset); |
|
285 |
|
286 template <DecoratorSet decorators, typename P, typename T> |
|
287 void store(P* addr, T value); |
|
288 |
|
289 template <DecoratorSet decorators, typename P, typename T> |
|
290 T load(P* addr); |
|
291 |
|
292 template <DecoratorSet decorators, typename P, typename T> |
|
293 T atomic_cmpxchg(T new_value, P* addr, T compare_value); |
|
294 |
|
295 template <DecoratorSet decorators, typename P, typename T> |
|
296 T atomic_xchg(T new_value, P* addr); |
|
297 |
|
298 template <DecoratorSet decorators, typename T> |
|
299 bool arraycopy(arrayOop src_obj, arrayOop dst_obj, T *src, T *dst, size_t length); |
|
300 |
|
301 template <DecoratorSet decorators> |
|
302 void clone(oop src, oop dst, size_t size); |
|
303 |
|
304 template <DecoratorSet decorators> |
|
305 oop resolve(oop src); |
|
306 |
|
307 // Infer the type that should be returned from a load. |
|
308 template <typename P, DecoratorSet decorators> |
|
309 class OopLoadProxy: public StackObj { |
|
310 private: |
|
311 P *const _addr; |
|
312 public: |
|
313 OopLoadProxy(P* addr) : _addr(addr) {} |
|
314 |
|
315 inline operator oop() { |
|
316 return load<decorators | INTERNAL_VALUE_IS_OOP, P, oop>(_addr); |
|
317 } |
|
318 |
|
319 inline operator narrowOop() { |
|
320 return load<decorators | INTERNAL_VALUE_IS_OOP, P, narrowOop>(_addr); |
|
321 } |
|
322 |
|
323 template <typename T> |
|
324 inline bool operator ==(const T& other) const { |
|
325 return load<decorators | INTERNAL_VALUE_IS_OOP, P, T>(_addr) == other; |
|
326 } |
|
327 |
|
328 template <typename T> |
|
329 inline bool operator !=(const T& other) const { |
|
330 return load<decorators | INTERNAL_VALUE_IS_OOP, P, T>(_addr) != other; |
|
331 } |
|
332 }; |
|
333 |
|
334 // Infer the type that should be returned from a load_at. |
|
335 template <DecoratorSet decorators> |
|
336 class LoadAtProxy: public StackObj { |
|
337 private: |
|
338 const oop _base; |
|
339 const ptrdiff_t _offset; |
|
340 public: |
|
341 LoadAtProxy(oop base, ptrdiff_t offset) : _base(base), _offset(offset) {} |
|
342 |
|
343 template <typename T> |
|
344 inline operator T() const { |
|
345 return load_at<decorators, T>(_base, _offset); |
|
346 } |
|
347 |
|
348 template <typename T> |
|
349 inline bool operator ==(const T& other) const { return load_at<decorators, T>(_base, _offset) == other; } |
|
350 |
|
351 template <typename T> |
|
352 inline bool operator !=(const T& other) const { return load_at<decorators, T>(_base, _offset) != other; } |
|
353 }; |
|
354 |
|
355 template <DecoratorSet decorators> |
|
356 class OopLoadAtProxy: public StackObj { |
|
357 private: |
|
358 const oop _base; |
|
359 const ptrdiff_t _offset; |
|
360 public: |
|
361 OopLoadAtProxy(oop base, ptrdiff_t offset) : _base(base), _offset(offset) {} |
|
362 |
|
363 inline operator oop() const { |
|
364 return load_at<decorators | INTERNAL_VALUE_IS_OOP, oop>(_base, _offset); |
|
365 } |
|
366 |
|
367 inline operator narrowOop() const { |
|
368 return load_at<decorators | INTERNAL_VALUE_IS_OOP, narrowOop>(_base, _offset); |
|
369 } |
|
370 |
|
371 template <typename T> |
|
372 inline bool operator ==(const T& other) const { |
|
373 return load_at<decorators | INTERNAL_VALUE_IS_OOP, T>(_base, _offset) == other; |
|
374 } |
|
375 |
|
376 template <typename T> |
|
377 inline bool operator !=(const T& other) const { |
|
378 return load_at<decorators | INTERNAL_VALUE_IS_OOP, T>(_base, _offset) != other; |
|
379 } |
|
380 }; |
|
381 } |
|
382 |
94 |
383 template <DecoratorSet decorators = INTERNAL_EMPTY> |
95 template <DecoratorSet decorators = INTERNAL_EMPTY> |
384 class Access: public AllStatic { |
96 class Access: public AllStatic { |
385 // This function asserts that if an access gets passed in a decorator outside |
97 // This function asserts that if an access gets passed in a decorator outside |
386 // of the expected_decorators, then something is wrong. It additionally checks |
98 // of the expected_decorators, then something is wrong. It additionally checks |