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