1 /*
2 * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #ifndef SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP
26 #define SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP
27
28 #include "classfile/classLoaderData.hpp"
29 #include "gc/parallel/psParallelCompact.hpp"
30 #include "gc/shared/partialArraySplitter.hpp"
31 #include "gc/shared/partialArrayState.hpp"
32 #include "gc/shared/partialArrayTaskStats.hpp"
33 #include "gc/shared/preservedMarks.hpp"
34 #include "gc/shared/stringdedup/stringDedup.hpp"
35 #include "gc/shared/taskqueue.hpp"
36 #include "gc/shared/taskTerminator.hpp"
37 #include "memory/allocation.hpp"
38 #include "utilities/stack.hpp"
39
40 class MutableSpace;
41 class PSOldGen;
42 class ParCompactionManager;
43 class ObjectStartArray;
44 class ParallelCompactData;
45 class ParMarkBitMap;
46
47 class PCMarkAndPushClosure: public ClaimMetadataVisitingOopIterateClosure {
48 ParCompactionManager* _compaction_manager;
49
50 template <typename T> void do_oop_work(T* p);
51 public:
52 PCMarkAndPushClosure(ParCompactionManager* cm, ReferenceProcessor* rp) :
53 ClaimMetadataVisitingOopIterateClosure(ClassLoaderData::_claim_stw_fullgc_mark, rp),
54 _compaction_manager(cm) { }
55
56 virtual void do_oop(oop* p) { do_oop_work(p); }
57 virtual void do_oop(narrowOop* p) { do_oop_work(p); }
58 };
59
60 class ParCompactionManager : public CHeapObj<mtGC> {
61 friend class MarkFromRootsTask;
62 friend class ParallelCompactRefProcProxyTask;
63 friend class ParMarkBitMap;
64 friend class PSParallelCompact;
65 friend class FillDensePrefixAndCompactionTask;
66 friend class PCAddThreadRootsMarkingTaskClosure;
67
68 private:
69 typedef OverflowTaskQueue<ScannerTask, mtGC> PSMarkTaskQueue;
70 typedef GenericTaskQueueSet<PSMarkTaskQueue, mtGC> PSMarkTasksQueueSet;
71 typedef OverflowTaskQueue<size_t, mtGC> RegionTaskQueue;
72 typedef GenericTaskQueueSet<RegionTaskQueue, mtGC> RegionTaskQueueSet;
73
74 static ParCompactionManager** _manager_array;
75 static PSMarkTasksQueueSet* _marking_stacks;
76 static ObjectStartArray* _start_array;
77 static RegionTaskQueueSet* _region_task_queues;
78 static PSOldGen* _old_gen;
79
80 static PartialArrayStateManager* _partial_array_state_manager;
81 PartialArraySplitter _partial_array_splitter;
82
83 PSMarkTaskQueue _marking_stack;
84
85 size_t _next_shadow_region;
86
87 PCMarkAndPushClosure _mark_and_push_closure;
88 // Is there a way to reuse the _oop_stack for the
89 // saving empty regions? For now just create a different
90 // type of TaskQueue.
91 RegionTaskQueue _region_stack;
92
93 static PreservedMarksSet* _preserved_marks_set;
94 PreservedMarks* _preserved_marks;
95
96 static ParMarkBitMap* _mark_bitmap;
97
98 // Contains currently free shadow regions. We use it in
99 // a LIFO fashion for better data locality and utilization.
100 static GrowableArray<size_t>* _shadow_region_array;
101
102 // Provides mutual exclusive access of _shadow_region_array.
103 // See pop/push_shadow_region_mt_safe() below
104 static Monitor* _shadow_region_monitor;
105
106 StringDedup::Requests _string_dedup_requests;
107
108 static PSOldGen* old_gen() { return _old_gen; }
109 static ObjectStartArray* start_array() { return _start_array; }
110 static PSMarkTasksQueueSet* marking_stacks() { return _marking_stacks; }
111
112 static void initialize(ParMarkBitMap* mbm);
113
114 ParCompactionManager(PreservedMarks* preserved_marks,
115 ReferenceProcessor* ref_processor,
116 uint parallel_gc_threads);
117
118 // Array of task queues. Needed by the task terminator.
119 static RegionTaskQueueSet* region_task_queues() { return _region_task_queues; }
120
121 inline PSMarkTaskQueue* marking_stack() { return &_marking_stack; }
122 void push_objArray(objArrayOop obj);
123
124 // To collect per-region live-words in a worker local cache in order to
125 // reduce threads contention.
126 class MarkingStatsCache : public CHeapObj<mtGC> {
127 constexpr static size_t num_entries = 1024;
128 static_assert(is_power_of_2(num_entries), "inv");
129 static_assert(num_entries > 0, "inv");
130
131 constexpr static size_t entry_mask = num_entries - 1;
132
133 struct CacheEntry {
134 size_t region_id;
135 size_t live_words;
136 };
137
138 CacheEntry entries[num_entries] = {};
139
140 inline void push(size_t region_id, size_t live_words);
141
142 public:
143 inline void push(oop obj, size_t live_words);
144
145 inline void evict(size_t index);
146
147 inline void evict_all();
148 };
149
150 MarkingStatsCache* _marking_stats_cache;
151
152 #if TASKQUEUE_STATS
153 static void print_and_reset_taskqueue_stats();
154 PartialArrayTaskStats* partial_array_task_stats();
155 #endif // TASKQUEUE_STATS
156
157 public:
158 static const size_t InvalidShadow = ~0;
159 static size_t pop_shadow_region_mt_safe(PSParallelCompact::RegionData* region_ptr);
160 static void push_shadow_region_mt_safe(size_t shadow_region);
161 static void push_shadow_region(size_t shadow_region);
162 static void remove_all_shadow_regions();
163
164 inline size_t next_shadow_region() { return _next_shadow_region; }
165 inline void set_next_shadow_region(size_t record) { _next_shadow_region = record; }
166 inline size_t move_next_shadow_region_by(size_t workers) {
167 _next_shadow_region += workers;
168 return next_shadow_region();
169 }
170
171 void flush_string_dedup_requests() {
172 _string_dedup_requests.flush();
173 }
174
175 static void flush_all_string_dedup_requests();
176
177 RegionTaskQueue* region_stack() { return &_region_stack; }
178
179 // Get the compaction manager when doing evacuation work from the VM thread.
180 // Simply use the first compaction manager here.
181 static ParCompactionManager* get_vmthread_cm() { return _manager_array[0]; }
182
183 PreservedMarks* preserved_marks() const {
184 return _preserved_marks;
185 }
186
187 ParMarkBitMap* mark_bitmap() { return _mark_bitmap; }
188
189 // Save for later processing. Must not fail.
190 inline void push_region(size_t index);
191
192 // Check mark and maybe push on marking stack.
193 template <typename T> inline void mark_and_push(T* p);
194
195 // Access function for compaction managers
196 static ParCompactionManager* gc_thread_compaction_manager(uint index);
197
198 static bool steal(int queue_num, ScannerTask& t);
199 static bool steal(int queue_num, size_t& region);
200
201 // Process tasks remaining on marking stack
202 void follow_marking_stacks();
203 inline bool marking_stack_empty() const;
204
205 // Process tasks remaining on any stack
206 void drain_region_stacks();
207
208 inline void follow_contents(const ScannerTask& task, bool stolen);
209 inline void follow_array(objArrayOop array, size_t start, size_t end);
210 void process_array_chunk(PartialArrayState* state, bool stolen);
211
212 class FollowStackClosure: public VoidClosure {
213 private:
214 ParCompactionManager* _compaction_manager;
215 TaskTerminator* _terminator;
216 uint _worker_id;
217 public:
218 FollowStackClosure(ParCompactionManager* cm, TaskTerminator* terminator, uint worker_id)
219 : _compaction_manager(cm), _terminator(terminator), _worker_id(worker_id) { }
220 virtual void do_void();
221 };
222
223 inline void create_marking_stats_cache();
224
225 inline void flush_and_destroy_marking_stats_cache();
226
227 // Called after marking.
228 static void verify_all_marking_stack_empty() NOT_DEBUG_RETURN;
229
230 // Region staks hold regions in from-space; called after compaction.
231 static void verify_all_region_stack_empty() NOT_DEBUG_RETURN;
232 };
233
234 bool ParCompactionManager::marking_stack_empty() const {
235 return _marking_stack.is_empty();
236 }
237
238 #endif // SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP