1 /*
2 * Copyright (c) 2015, 2022, Red Hat, Inc. All rights reserved.
3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP
27 #define SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP
28
29 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
30
31 #include "gc/shared/accessBarrierSupport.inline.hpp"
32 #include "gc/shared/cardTable.hpp"
33 #include "gc/shenandoah/mode/shenandoahMode.hpp"
34 #include "gc/shenandoah/shenandoahAsserts.hpp"
35 #include "gc/shenandoah/shenandoahCardTable.hpp"
36 #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp"
37 #include "gc/shenandoah/shenandoahForwarding.inline.hpp"
38 #include "gc/shenandoah/shenandoahGeneration.hpp"
39 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
40 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
41 #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
42 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
43 #include "memory/iterator.inline.hpp"
44 #include "oops/oop.inline.hpp"
45
46 inline oop ShenandoahBarrierSet::resolve_forwarded_not_null(oop p) {
47 return ShenandoahForwarding::get_forwardee(p);
48 }
49
50 inline oop ShenandoahBarrierSet::resolve_forwarded(oop p) {
51 if (p != nullptr) {
52 return resolve_forwarded_not_null(p);
53 } else {
54 return p;
55 }
56 }
57
58 template <DecoratorSet decorators, class T>
59 inline oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj, T* load_addr) {
60 assert(ShenandoahLoadRefBarrier, "Should be enabled");
61
62 constexpr bool on_weak = HasDecorator<decorators, ON_WEAK_OOP_REF>::value;
63 constexpr bool on_phantom = HasDecorator<decorators, ON_PHANTOM_OOP_REF>::value;
64
65 // Handle nulls. Strong loads filtered nulls with cset checks.
66 // Weak/phantom loads need to check for nulls here.
67 if (on_weak || on_phantom) {
68 if (obj == nullptr) {
69 return nullptr;
70 }
71 } else {
72 assert(obj != nullptr, "Should have been filtered before");
73 }
74
75 // Prevent resurrection of unreachable phantom (i.e. weak-native) references.
76 if (on_phantom &&
77 _heap->is_concurrent_weak_root_in_progress() &&
78 _heap->is_in_active_generation(obj) &&
79 !_heap->marking_context()->is_marked(obj)) {
80 return nullptr;
81 }
82
83 // Prevent resurrection of unreachable weak references.
84 if (on_weak &&
85 _heap->is_concurrent_weak_root_in_progress() &&
86 _heap->is_in_active_generation(obj) &&
87 !_heap->marking_context()->is_marked_strong(obj)) {
88 return nullptr;
89 }
90
91 // Weak/phantom loads need additional cset check.
92 if (on_phantom || on_weak) {
93 if (!_heap->has_forwarded_objects() || !_heap->in_collection_set(obj)) {
94 return obj;
95 }
96 } else {
97 shenandoah_assert_in_cset(load_addr, obj);
98 }
99
100 oop fwd = ShenandoahForwarding::get_forwardee_mutator(obj);
101 if (obj == fwd) {
102 assert(_heap->is_evacuation_in_progress(), "evac should be in progress");
103 Thread* const t = Thread::current();
104 fwd = _heap->evacuate_object(obj, t);
105 }
106
107 if (load_addr != nullptr && fwd != obj) {
108 // Since we are here and we know the load address, update the reference.
109 ShenandoahHeap::atomic_update_oop(fwd, load_addr, obj);
110 }
111
112 return fwd;
113 }
114
115 inline oop ShenandoahBarrierSet::load_reference_barrier(oop obj) {
116 if (!ShenandoahLoadRefBarrier) {
117 return obj;
118 }
119 if (_heap->has_forwarded_objects() && _heap->in_collection_set(obj)) {
120 // Subsumes null-check
121 assert(obj != nullptr, "cset check must have subsumed null-check");
122 oop fwd = resolve_forwarded_not_null(obj);
123 if (obj == fwd && _heap->is_evacuation_in_progress()) {
124 Thread* t = Thread::current();
125 return _heap->evacuate_object(obj, t);
126 }
127 return fwd;
128 }
129 return obj;
130 }
131
132 template <class T>
133 inline oop ShenandoahBarrierSet::load_reference_barrier(DecoratorSet decorators, oop obj, T* load_addr) {
134 if (obj == nullptr) {
135 return nullptr;
136 }
137
138 // Prevent resurrection of unreachable phantom (i.e. weak-native) references.
139 if ((decorators & ON_PHANTOM_OOP_REF) != 0 &&
140 _heap->is_concurrent_weak_root_in_progress() &&
141 _heap->is_in_active_generation(obj) &&
142 !_heap->marking_context()->is_marked(obj)) {
143 return nullptr;
144 }
145
146 // Prevent resurrection of unreachable weak references.
147 if ((decorators & ON_WEAK_OOP_REF) != 0 &&
148 _heap->is_concurrent_weak_root_in_progress() &&
149 _heap->is_in_active_generation(obj) &&
150 !_heap->marking_context()->is_marked_strong(obj)) {
151 return nullptr;
152 }
153
154 // Allow runtime to see unreachable objects that are visited during concurrent class-unloading.
155 if ((decorators & AS_NO_KEEPALIVE) != 0 &&
156 _heap->is_concurrent_weak_root_in_progress() &&
157 !_heap->marking_context()->is_marked(obj)) {
158 return obj;
159 }
160
161 oop fwd = load_reference_barrier(obj);
162 if (load_addr != nullptr && fwd != obj) {
163 // Since we are here and we know the load address, update the reference.
164 ShenandoahHeap::atomic_update_oop(fwd, load_addr, obj);
165 }
166
167 return fwd;
168 }
169
170 inline void ShenandoahBarrierSet::enqueue(oop obj) {
171 assert(obj != nullptr, "checked by caller");
172 assert(_satb_mark_queue_set.is_active(), "only get here when SATB active");
173
174 // Filter marked objects before hitting the SATB queues. The same predicate would
175 // be used by SATBMQ::filter to eliminate already marked objects downstream, but
176 // filtering here helps to avoid wasteful SATB queueing work to begin with.
177 if (!_heap->requires_marking(obj)) return;
178
179 SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(Thread::current());
180 _satb_mark_queue_set.enqueue_known_active(queue, obj);
181 }
182
183 template <DecoratorSet decorators, typename T>
184 inline void ShenandoahBarrierSet::satb_barrier(T *field) {
185 // Uninitialized and no-keepalive stores do not need barrier.
186 if (HasDecorator<decorators, IS_DEST_UNINITIALIZED>::value ||
187 HasDecorator<decorators, AS_NO_KEEPALIVE>::value) {
188 return;
189 }
190
191 // Stores to weak/phantom require no barrier. The original references would
192 // have been enqueued in the SATB buffer by the load barrier if they were needed.
193 if (HasDecorator<decorators, ON_WEAK_OOP_REF>::value ||
194 HasDecorator<decorators, ON_PHANTOM_OOP_REF>::value) {
195 return;
196 }
197
198 if (ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) {
199 T heap_oop = RawAccess<>::oop_load(field);
200 if (!CompressedOops::is_null(heap_oop)) {
201 enqueue(CompressedOops::decode(heap_oop));
202 }
203 }
204 }
205
206 inline void ShenandoahBarrierSet::satb_enqueue(oop value) {
207 if (value != nullptr && ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) {
208 enqueue(value);
209 }
210 }
211
212 inline void ShenandoahBarrierSet::keep_alive_if_weak(DecoratorSet decorators, oop value) {
213 assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known");
214 const bool on_strong_oop_ref = (decorators & ON_STRONG_OOP_REF) != 0;
215 const bool peek = (decorators & AS_NO_KEEPALIVE) != 0;
216 if (!peek && !on_strong_oop_ref) {
217 satb_enqueue(value);
218 }
219 }
220
221 template <DecoratorSet decorators, typename T>
222 inline void ShenandoahBarrierSet::write_ref_field_post(T* field) {
223 assert(ShenandoahCardBarrier, "Should have been checked by caller");
224 if (_heap->is_in_young(field)) {
225 // Young field stores do not require card mark.
226 return;
227 }
228 T heap_oop = RawAccess<>::oop_load(field);
229 if (CompressedOops::is_null(heap_oop)) {
230 // Null reference store do not require card mark.
231 return;
232 }
233 oop obj = CompressedOops::decode_not_null(heap_oop);
234 if (!_heap->is_in_young(obj)) {
235 // Not an old->young reference store.
236 return;
237 }
238 volatile CardTable::CardValue* byte = card_table()->byte_for(field);
239 *byte = CardTable::dirty_card_val();
240 }
241
242 template <typename T>
243 inline oop ShenandoahBarrierSet::oop_load(DecoratorSet decorators, T* addr) {
244 oop value = RawAccess<>::oop_load(addr);
245 value = load_reference_barrier(decorators, value, addr);
246 keep_alive_if_weak(decorators, value);
247 return value;
248 }
249
250 template <typename T>
251 inline oop ShenandoahBarrierSet::oop_cmpxchg(DecoratorSet decorators, T* addr, oop compare_value, oop new_value) {
252 shenandoah_assert_not_in_cset_except(nullptr, compare_value, (compare_value == nullptr || ShenandoahHeap::heap()->cancelled_gc()));
253 shenandoah_assert_not_in_cset_except(nullptr, new_value, (new_value == nullptr || ShenandoahHeap::heap()->cancelled_gc()));
254
255 // Handle the previous value through SATB, as we are about to perform the store.
256 oop prev = RawAccess<>::oop_load(addr);
257 satb_enqueue(prev);
258
259 // Perform LRB on location to fix it up for this and all following accesses.
260 // This guarantees there are no false negatives due to concurrent evacuation,
261 // and the value loaded later by CAS is sanitized by some LRB, or is null.
262 load_reference_barrier(decorators, prev, addr);
263
264 return RawAccess<>::oop_atomic_cmpxchg(addr, compare_value, new_value);
265 }
266
267 template <typename T>
268 inline oop ShenandoahBarrierSet::oop_xchg(DecoratorSet decorators, T* addr, oop new_value) {
269 shenandoah_assert_not_in_cset_except(nullptr, new_value, (new_value == nullptr || ShenandoahHeap::heap()->cancelled_gc()));
270
271 // Handle the previous value through SATB, as we are about to perform the store.
272 oop prev = RawAccess<>::oop_load(addr);
273 satb_enqueue(prev);
274
275 // Perform LRB on location to fix it up for this and all following accesses.
276 // This is purely opportunistic: we would not have any false negatives here.
277 // This guarantees the value loaded later by XCHG is sanitized by some LRB, or is null.
278 load_reference_barrier(decorators, prev, addr);
279
280 return RawAccess<>::oop_atomic_xchg(addr, new_value);
281 }
282
283 template <DecoratorSet decorators, typename BarrierSetT>
284 template <typename T>
285 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_not_in_heap(T* addr) {
286 assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "must be absent");
287 ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
288 return bs->oop_load(decorators, addr);
289 }
290
291 template <DecoratorSet decorators, typename BarrierSetT>
292 template <typename T>
293 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_in_heap(T* addr) {
294 assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "must be absent");
295 ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
296 return bs->oop_load(decorators, addr);
297 }
298
299 template <DecoratorSet decorators, typename BarrierSetT>
300 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_load_in_heap_at(oop base, ptrdiff_t offset) {
301 ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
302 DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset);
303 return bs->oop_load(resolved_decorators, AccessInternal::oop_field_addr<decorators>(base, offset));
304 }
305
306 template <DecoratorSet decorators, typename BarrierSetT>
307 template <typename T>
308 inline void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_store_common(T* addr, oop value) {
309 shenandoah_assert_marked_if(nullptr, value,
310 !CompressedOops::is_null(value) && ShenandoahHeap::heap()->is_evacuation_in_progress()
311 && !(ShenandoahHeap::heap()->active_generation()->is_young()
312 && ShenandoahHeap::heap()->heap_region_containing(value)->is_old()));
313 shenandoah_assert_not_in_cset_if(addr, value, value != nullptr && !ShenandoahHeap::heap()->cancelled_gc());
314 ShenandoahBarrierSet* const bs = ShenandoahBarrierSet::barrier_set();
315 bs->satb_barrier<decorators>(addr);
316 Raw::oop_store(addr, value);
317 }
318
319 template <DecoratorSet decorators, typename BarrierSetT>
320 template <typename T>
321 inline void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_store_not_in_heap(T* addr, oop value) {
322 assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known");
323 oop_store_common(addr, value);
324 }
325
326 template <DecoratorSet decorators, typename BarrierSetT>
327 template <typename T>
328 inline void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_store_in_heap(T* addr, oop value) {
329 shenandoah_assert_not_in_cset_loc_except(addr, ShenandoahHeap::heap()->cancelled_gc());
330 shenandoah_assert_not_forwarded_except (addr, value, value == nullptr || ShenandoahHeap::heap()->cancelled_gc() || !ShenandoahHeap::heap()->is_concurrent_mark_in_progress());
331
332 oop_store_common(addr, value);
333 if (ShenandoahCardBarrier) {
334 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
335 bs->write_ref_field_post<decorators>(addr);
336 }
337 }
338
339 template <DecoratorSet decorators, typename BarrierSetT>
340 inline void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_store_in_heap_at(oop base, ptrdiff_t offset, oop value) {
341 oop_store_in_heap(AccessInternal::oop_field_addr<decorators>(base, offset), value);
342 }
343
344 template <DecoratorSet decorators, typename BarrierSetT>
345 template <typename T>
346 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_cmpxchg_not_in_heap(T* addr, oop compare_value, oop new_value) {
347 assert((decorators & AS_NO_KEEPALIVE) == 0, "CAS only with keep-alive");
348 assert((decorators & ON_STRONG_OOP_REF) != 0, "CAS only for strong refs");
349 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
350 return bs->oop_cmpxchg(decorators, addr, compare_value, new_value);
351 }
352
353 template <DecoratorSet decorators, typename BarrierSetT>
354 template <typename T>
355 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_cmpxchg_in_heap(T* addr, oop compare_value, oop new_value) {
356 assert((decorators & AS_NO_KEEPALIVE) == 0, "CAS only with keep-alive");
357 assert((decorators & ON_STRONG_OOP_REF) != 0, "CAS only for strong refs");
358 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
359 oop result = bs->oop_cmpxchg(decorators, addr, compare_value, new_value);
360 if (ShenandoahCardBarrier) {
361 bs->write_ref_field_post<decorators>(addr);
362 }
363 return result;
364 }
365
366 template <DecoratorSet decorators, typename BarrierSetT>
367 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_cmpxchg_in_heap_at(oop base, ptrdiff_t offset, oop compare_value, oop new_value) {
368 assert((decorators & AS_NO_KEEPALIVE) == 0, "CAS only with keep-alive");
369 assert((decorators & (ON_STRONG_OOP_REF | ON_UNKNOWN_OOP_REF)) != 0, "CAS only for strong refs OR unknown refs (Unsafe)");
370 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
371
372 // Unsafe.compareAndExchange/Set come here with ON_UNKNOWN_OOP_REF set.
373 // These are normally strong refs, but one can use Unsafe on Reference.referent.
374 // We cannot deal with that case. If application does Unsafe operations on
375 // Reference.referent field, this likely breaks weak reference semantics already.
376 // We upgrade the access to strong in (sometimes futile) attempt to maintain heap
377 // integrity, and assert in debug builds for better diagnostics.
378 DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset);
379 assert((resolved_decorators & ON_STRONG_OOP_REF) != 0, "Application error: CAS on weak location");
380 resolved_decorators = (resolved_decorators & ~ON_DECORATOR_MASK) | ON_STRONG_OOP_REF;
381
382 auto addr = AccessInternal::oop_field_addr<decorators>(base, offset);
383 oop result = bs->oop_cmpxchg(resolved_decorators, addr, compare_value, new_value);
384 if (ShenandoahCardBarrier) {
385 bs->write_ref_field_post<decorators>(addr);
386 }
387 return result;
388 }
389
390 template <DecoratorSet decorators, typename BarrierSetT>
391 template <typename T>
392 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_xchg_not_in_heap(T* addr, oop new_value) {
393 assert((decorators & AS_NO_KEEPALIVE) == 0, "XCHG only with keep-alive");
394 assert((decorators & ON_STRONG_OOP_REF) != 0, "XCHG only for strong refs");
395 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
396 return bs->oop_xchg(decorators, addr, new_value);
397 }
398
399 template <DecoratorSet decorators, typename BarrierSetT>
400 template <typename T>
401 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_xchg_in_heap(T* addr, oop new_value) {
402 assert((decorators & AS_NO_KEEPALIVE) == 0, "XCHG only with keep-alive");
403 assert((decorators & ON_STRONG_OOP_REF) != 0, "XCHG only for strong refs");
404 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
405 oop result = bs->oop_xchg(decorators, addr, new_value);
406 if (ShenandoahCardBarrier) {
407 bs->write_ref_field_post<decorators>(addr);
408 }
409 return result;
410 }
411
412 template <DecoratorSet decorators, typename BarrierSetT>
413 inline oop ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_atomic_xchg_in_heap_at(oop base, ptrdiff_t offset, oop new_value) {
414 assert((decorators & AS_NO_KEEPALIVE) == 0, "XCHG only with keep-alive");
415 assert((decorators & (ON_STRONG_OOP_REF | ON_UNKNOWN_OOP_REF)) != 0, "XCHG only for strong refs OR unknown refs (Unsafe)");
416 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
417
418 // Unsafe.getAndSet comes here with ON_UNKNOWN_OOP_REF set.
419 // These are normally strong refs, but one can use Unsafe on Reference.referent.
420 // We cannot deal with that case. If application does Unsafe operations on
421 // Reference.referent field, this likely breaks weak reference semantics already.
422 // We upgrade the access to strong in (sometimes futile) attempt to maintain heap
423 // integrity, and assert in debug builds for better diagnostics.
424 DecoratorSet resolved_decorators = AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength<decorators>(base, offset);
425 assert((resolved_decorators & ON_STRONG_OOP_REF) != 0, "Application error: XCHG on weak location");
426 resolved_decorators = (resolved_decorators & ~ON_DECORATOR_MASK) | ON_STRONG_OOP_REF;
427
428 auto addr = AccessInternal::oop_field_addr<decorators>(base, offset);
429 oop result = bs->oop_xchg(resolved_decorators, addr, new_value);
430 if (ShenandoahCardBarrier) {
431 bs->write_ref_field_post<decorators>(addr);
432 }
433 return result;
434 }
435
436 // Clone barrier support
437 template <DecoratorSet decorators, typename BarrierSetT>
438 void ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::clone_in_heap(oop src, oop dst, size_t size) {
439 if (ShenandoahCloneBarrier) {
440 ShenandoahBarrierSet::barrier_set()->clone_barrier_runtime(src);
441 }
442 Raw::clone(src, dst, size);
443 }
444
445 template <DecoratorSet decorators, typename BarrierSetT>
446 template <typename T>
447 OopCopyResult ShenandoahBarrierSet::AccessBarrier<decorators, BarrierSetT>::oop_arraycopy_in_heap(arrayOop src_obj, size_t src_offset_in_bytes, T* src_raw,
448 arrayOop dst_obj, size_t dst_offset_in_bytes, T* dst_raw,
449 size_t length) {
450 T* src = arrayOopDesc::obj_offset_to_raw(src_obj, src_offset_in_bytes, src_raw);
451 T* dst = arrayOopDesc::obj_offset_to_raw(dst_obj, dst_offset_in_bytes, dst_raw);
452
453 ShenandoahBarrierSet* bs = ShenandoahBarrierSet::barrier_set();
454 bs->arraycopy_barrier(src, dst, length);
455 OopCopyResult result = Raw::oop_arraycopy_in_heap(src_obj, src_offset_in_bytes, src_raw, dst_obj, dst_offset_in_bytes, dst_raw, length);
456 if (ShenandoahCardBarrier) {
457 bs->write_ref_array((HeapWord*) dst, length);
458 }
459 return result;
460 }
461
462 template <class T, bool HAS_FWD, bool EVAC, bool ENQUEUE>
463 void ShenandoahBarrierSet::arraycopy_work(T* src, size_t count) {
464 // Young cycles are allowed to run when old marking is in progress. When old marking is in progress,
465 // this barrier will be called with ENQUEUE=true and HAS_FWD=false, even though the young generation
466 // may have forwarded objects.
467 assert(HAS_FWD == _heap->has_forwarded_objects() || _heap->is_concurrent_old_mark_in_progress(), "Forwarded object status is sane");
468 // This function cannot be called to handle marking and evacuation at the same time (they operate on
469 // different sides of the copy).
470 static_assert((HAS_FWD || EVAC) != ENQUEUE, "Cannot evacuate and mark both sides of copy.");
471
472 Thread* thread = Thread::current();
473 SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(thread);
474 ShenandoahMarkingContext* ctx = _heap->marking_context();
475 const ShenandoahCollectionSet* const cset = _heap->collection_set();
476 T* end = src + count;
477 for (T* elem_ptr = src; elem_ptr < end; elem_ptr++) {
478 T o = RawAccess<>::oop_load(elem_ptr);
479 if (!CompressedOops::is_null(o)) {
480 oop obj = CompressedOops::decode_not_null(o);
481 if (HAS_FWD && cset->is_in(obj)) {
482 oop fwd = resolve_forwarded_not_null(obj);
483 if (EVAC && obj == fwd) {
484 fwd = _heap->evacuate_object(obj, thread);
485 }
486 shenandoah_assert_forwarded_except(elem_ptr, obj, _heap->cancelled_gc());
487 ShenandoahHeap::atomic_update_oop(fwd, elem_ptr, o);
488 }
489 if (ENQUEUE && !ctx->is_marked_strong(obj)) {
490 _satb_mark_queue_set.enqueue_known_active(queue, obj);
491 }
492 }
493 }
494 }
495
496 template <class T>
497 void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count) {
498 if (count == 0) {
499 // No elements to copy, no need for barrier
500 return;
501 }
502
503 const char gc_state = ShenandoahThreadLocalData::gc_state(Thread::current());
504 if ((gc_state & ShenandoahHeap::MARKING) != 0) {
505 // If marking old or young, we must evaluate the SATB barrier. This will be the only
506 // action if we are not marking old. If we are marking old, we must still evaluate the
507 // load reference barrier for a young collection.
508 if (_heap->mode()->is_generational()) {
509 arraycopy_marking<true>(dst, count);
510 } else {
511 arraycopy_marking<false>(dst, count);
512 }
513 }
514
515 if ((gc_state & ShenandoahHeap::EVACUATION) != 0) {
516 assert((gc_state & ShenandoahHeap::YOUNG_MARKING) == 0, "Cannot be marking young during evacuation");
517 arraycopy_evacuation(src, count);
518 } else if ((gc_state & ShenandoahHeap::UPDATE_REFS) != 0) {
519 assert((gc_state & ShenandoahHeap::YOUNG_MARKING) == 0, "Cannot be marking young during update-refs");
520 arraycopy_update(src, count);
521 }
522 }
523
524 template <bool IS_GENERATIONAL, class T>
525 void ShenandoahBarrierSet::arraycopy_marking(T* dst, size_t count) {
526 assert(_heap->is_concurrent_mark_in_progress(), "only during marking");
527 if (ShenandoahSATBBarrier) {
528 if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast<HeapWord*>(dst)) ||
529 (IS_GENERATIONAL && _heap->heap_region_containing(dst)->is_old() && _heap->is_concurrent_young_mark_in_progress())) {
530 arraycopy_work<T, false, false, true>(dst, count);
531 }
532 }
533 }
534
535 inline bool ShenandoahBarrierSet::need_bulk_update(HeapWord* ary) {
536 return ary < _heap->heap_region_containing(ary)->get_update_watermark();
537 }
538
539 template <class T>
540 void ShenandoahBarrierSet::arraycopy_evacuation(T* src, size_t count) {
541 assert(_heap->is_evacuation_in_progress(), "only during evacuation");
542 if (need_bulk_update(reinterpret_cast<HeapWord*>(src))) {
543 arraycopy_work<T, true, true, false>(src, count);
544 }
545 }
546
547 template <class T>
548 void ShenandoahBarrierSet::arraycopy_update(T* src, size_t count) {
549 assert(_heap->is_update_refs_in_progress(), "only during update-refs");
550 if (need_bulk_update(reinterpret_cast<HeapWord*>(src))) {
551 arraycopy_work<T, true, false, false>(src, count);
552 }
553 }
554
555 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP