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 ParallelScavengeRefProcProxyTask;
64 friend class ParMarkBitMap;
65 friend class PSParallelCompact;
66 friend class FillDensePrefixAndCompactionTask;
67 friend class PCAddThreadRootsMarkingTaskClosure;
68
69 private:
70 typedef OverflowTaskQueue<ScannerTask, mtGC> PSMarkTaskQueue;
71 typedef GenericTaskQueueSet<PSMarkTaskQueue, mtGC> PSMarkTasksQueueSet;
72 typedef OverflowTaskQueue<size_t, mtGC> RegionTaskQueue;
73 typedef GenericTaskQueueSet<RegionTaskQueue, mtGC> RegionTaskQueueSet;
74
75 static ParCompactionManager** _manager_array;
76 static PSMarkTasksQueueSet* _marking_stacks;
77 static ObjectStartArray* _start_array;
78 static RegionTaskQueueSet* _region_task_queues;
79 static PSOldGen* _old_gen;
80
81 static PartialArrayStateManager* _partial_array_state_manager;
82 PartialArraySplitter _partial_array_splitter;
83
84 PSMarkTaskQueue _marking_stack;
85
86 size_t _next_shadow_region;
87
88 PCMarkAndPushClosure _mark_and_push_closure;
89 // Is there a way to reuse the _oop_stack for the
90 // saving empty regions? For now just create a different
91 // type of TaskQueue.
92 RegionTaskQueue _region_stack;
93
94 static PreservedMarksSet* _preserved_marks_set;
95 PreservedMarks* _preserved_marks;
96
97 static ParMarkBitMap* _mark_bitmap;
98
99 // Contains currently free shadow regions. We use it in
100 // a LIFO fashion for better data locality and utilization.
101 static GrowableArray<size_t>* _shadow_region_array;
102
103 // Provides mutual exclusive access of _shadow_region_array.
104 // See pop/push_shadow_region_mt_safe() below
105 static Monitor* _shadow_region_monitor;
106
107 StringDedup::Requests _string_dedup_requests;
108
109 static PSOldGen* old_gen() { return _old_gen; }
110 static ObjectStartArray* start_array() { return _start_array; }
111 static PSMarkTasksQueueSet* marking_stacks() { return _marking_stacks; }
112
113 static void initialize(ParMarkBitMap* mbm);
114
115 ParCompactionManager(PreservedMarks* preserved_marks,
116 ReferenceProcessor* ref_processor,
117 uint parallel_gc_threads);
118
119 // Array of task queues. Needed by the task terminator.
120 static RegionTaskQueueSet* region_task_queues() { return _region_task_queues; }
121
122 inline PSMarkTaskQueue* marking_stack() { return &_marking_stack; }
123 void push_objArray(objArrayOop obj);
124
125 // To collect per-region live-words in a worker local cache in order to
126 // reduce threads contention.
127 class MarkingStatsCache : public CHeapObj<mtGC> {
128 constexpr static size_t num_entries = 1024;
129 static_assert(is_power_of_2(num_entries), "inv");
130 static_assert(num_entries > 0, "inv");
131
132 constexpr static size_t entry_mask = num_entries - 1;
133
134 struct CacheEntry {
135 size_t region_id;
136 size_t live_words;
137 };
138
139 CacheEntry entries[num_entries] = {};
140
141 inline void push(size_t region_id, size_t live_words);
142
143 public:
144 inline void push(oop obj, size_t live_words);
145
146 inline void evict(size_t index);
147
148 inline void evict_all();
149 };
150
151 MarkingStatsCache* _marking_stats_cache;
152
153 #if TASKQUEUE_STATS
154 static void print_and_reset_taskqueue_stats();
155 PartialArrayTaskStats* partial_array_task_stats();
156 #endif // TASKQUEUE_STATS
157
158 public:
159 static const size_t InvalidShadow = ~0;
160 static size_t pop_shadow_region_mt_safe(PSParallelCompact::RegionData* region_ptr);
161 static void push_shadow_region_mt_safe(size_t shadow_region);
162 static void push_shadow_region(size_t shadow_region);
163 static void remove_all_shadow_regions();
164
165 inline size_t next_shadow_region() { return _next_shadow_region; }
166 inline void set_next_shadow_region(size_t record) { _next_shadow_region = record; }
167 inline size_t move_next_shadow_region_by(size_t workers) {
168 _next_shadow_region += workers;
169 return next_shadow_region();
170 }
171
172 void flush_string_dedup_requests() {
173 _string_dedup_requests.flush();
174 }
175
176 static void flush_all_string_dedup_requests();
177
178 RegionTaskQueue* region_stack() { return &_region_stack; }
179
180 // Get the compaction manager when doing evacuation work from the VM thread.
181 // Simply use the first compaction manager here.
182 static ParCompactionManager* get_vmthread_cm() { return _manager_array[0]; }
183
184 PreservedMarks* preserved_marks() const {
185 return _preserved_marks;
186 }
187
188 ParMarkBitMap* mark_bitmap() { return _mark_bitmap; }
189
190 // Save for later processing. Must not fail.
191 inline void push_region(size_t index);
192
193 // Check mark and maybe push on marking stack.
194 template <typename T> inline void mark_and_push(T* p);
195
196 // Access function for compaction managers
197 static ParCompactionManager* gc_thread_compaction_manager(uint index);
198
199 static bool steal(int queue_num, ScannerTask& t);
200 static bool steal(int queue_num, size_t& region);
201
202 // Process tasks remaining on marking stack
203 void follow_marking_stacks();
204 inline bool marking_stack_empty() const;
205
206 // Process tasks remaining on any stack
207 void drain_region_stacks();
208
209 inline void follow_contents(const ScannerTask& task, bool stolen);
210 inline void follow_array(objArrayOop array, size_t start, size_t end);
211 void process_array_chunk(PartialArrayState* state, bool stolen);
212
213 class FollowStackClosure: public VoidClosure {
214 private:
215 ParCompactionManager* _compaction_manager;
216 TaskTerminator* _terminator;
217 uint _worker_id;
218 public:
219 FollowStackClosure(ParCompactionManager* cm, TaskTerminator* terminator, uint worker_id)
220 : _compaction_manager(cm), _terminator(terminator), _worker_id(worker_id) { }
221 virtual void do_void();
222 };
223
224 inline void create_marking_stats_cache();
225
226 inline void flush_and_destroy_marking_stats_cache();
227
228 // Called after marking.
229 static void verify_all_marking_stack_empty() NOT_DEBUG_RETURN;
230
231 // Region staks hold regions in from-space; called after compaction.
232 static void verify_all_region_stack_empty() NOT_DEBUG_RETURN;
233 };
234
235 bool ParCompactionManager::marking_stack_empty() const {
236 return _marking_stack.is_empty();
237 }
238
239 #endif // SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP