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