1 /*
2 * Copyright (c) 2021, Red Hat, Inc. All rights reserved.
3 * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
4 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 *
7 * This code is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 only, as
9 * published by the Free Software Foundation.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 */
26
27
28 #include "gc/shenandoah/shenandoahAsserts.hpp"
29 #include "gc/shenandoah/shenandoahClosures.inline.hpp"
30 #include "gc/shenandoah/shenandoahCodeRoots.hpp"
31 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
32 #include "gc/shenandoah/shenandoahStackWatermark.hpp"
33 #include "gc/shenandoah/shenandoahUtils.hpp"
34 #include "runtime/safepointVerifiers.hpp"
35
36 uint32_t ShenandoahStackWatermark::_epoch_id = 1;
37
38 ShenandoahOnStackNMethodClosure::ShenandoahOnStackNMethodClosure() :
39 _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {}
40
41 void ShenandoahOnStackNMethodClosure::do_nmethod(nmethod* nm) {
42 assert(nm != nullptr, "Sanity");
43 const bool result = _bs_nm->nmethod_entry_barrier(nm);
44 assert(result, "NMethod on-stack must be alive");
45 }
46
47 ThreadLocalAllocStats& ShenandoahStackWatermark::stats() {
48 return _stats;
49 }
50
51 uint32_t ShenandoahStackWatermark::epoch_id() const {
52 return _epoch_id;
53 }
54
55 void ShenandoahStackWatermark::change_epoch_id() {
56 shenandoah_assert_safepoint();
57 _epoch_id++;
58 }
59
60 ShenandoahStackWatermark::ShenandoahStackWatermark(JavaThread* jt) :
61 StackWatermark(jt, StackWatermarkKind::gc, _epoch_id),
62 _heap(ShenandoahHeap::heap()),
63 _stats(),
64 _no_op_cl(),
65 _keep_alive_cl(),
66 _evac_update_oop_cl(),
67 _nm_cl() {}
68
69 OopClosure* ShenandoahStackWatermark::closure_from_context(void* context) {
70 if (context != nullptr) {
71 assert(_heap->is_concurrent_weak_root_in_progress() ||
72 _heap->is_concurrent_mark_in_progress(),
73 "Only these two phases");
74 assert(Thread::current()->is_Worker_thread(), "Unexpected thread passing in context: " PTR_FORMAT, p2i(context));
75 return reinterpret_cast<OopClosure*>(context);
76 } else {
77 if (_heap->is_concurrent_weak_root_in_progress() && _heap->is_evacuation_in_progress()) {
78 return &_evac_update_oop_cl;
79 } else if (_heap->is_concurrent_mark_in_progress()) {
80 return &_keep_alive_cl;
81 } else {
82 return &_no_op_cl;
83 }
84 }
85 }
86
87 void ShenandoahStackWatermark::start_processing_impl(void* context) {
88 NoSafepointVerifier nsv;
89
90 ShenandoahHeap* const heap = ShenandoahHeap::heap();
91 if (_heap->is_concurrent_weak_root_in_progress() && heap->is_evacuation_in_progress()) {
92 // Retire the TLABs, which will force threads to reacquire their TLABs.
93 // This is needed for two reasons. Strong one: new allocations would be with new freeset,
94 // which would be outside the collection set, so no cset writes would happen there.
95 // Weaker one: new allocations would happen past update watermark, and so less work would
96 // be needed for reference updates (would update the large filler instead).
97 retire_tlab();
98 } else if (heap->is_concurrent_mark_in_progress()) {
99 // We need to reset all TLABs because they might be below the TAMS, and we need to mark
100 // the objects in them. Do not let mutators allocate any new objects in their current TLABs.
101 // It is also a good place to resize the TLAB sizes for future allocations.
102 retire_tlab();
103 } else {
104 // Can be here for updating barriers. No TLAB retirement is needed.
105 }
106
107 // Process the non-frame part of the thread
108 _jt->oops_do_no_frames(closure_from_context(context), &_nm_cl);
109
110 // Publishes the processing start to concurrent threads
111 StackWatermark::start_processing_impl(context);
112 }
113
114 void ShenandoahStackWatermark::retire_tlab() {
115 // Retire TLAB
116 if (UseTLAB) {
117 _stats.reset();
118 _jt->retire_tlab(&_stats);
119 if (ResizeTLAB) {
120 _jt->tlab().resize();
121 }
122 }
123 }
124
125 void ShenandoahStackWatermark::process(const frame& fr, RegisterMap& register_map, void* context) {
126 OopClosure* oops = closure_from_context(context);
127 assert(oops != nullptr, "Should not get to here");
128 ShenandoahHeap* const heap = ShenandoahHeap::heap();
129 fr.oops_do(oops, &_nm_cl, ®ister_map, DerivedPointerIterationMode::_directly);
130 }