1 /*
2  * Copyright (c) 2014, 2021, 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_G1_G1PARSCANTHREADSTATE_HPP
26 #define SHARE_GC_G1_G1PARSCANTHREADSTATE_HPP
27 
28 #include "gc/g1/g1CardTable.hpp"
29 #include "gc/g1/g1CollectedHeap.hpp"
30 #include "gc/g1/g1RedirtyCardsQueue.hpp"
31 #include "gc/g1/g1OopClosures.hpp"
32 #include "gc/g1/g1RemSet.hpp"
33 #include "gc/g1/heapRegionRemSet.hpp"
34 #include "gc/shared/ageTable.hpp"
35 #include "gc/shared/partialArrayTaskStepper.hpp"
36 #include "gc/shared/stringdedup/stringDedup.hpp"
37 #include "gc/shared/taskqueue.hpp"
38 #include "memory/allocation.hpp"
39 #include "oops/oop.hpp"
40 #include "utilities/ticks.hpp"
41 
42 class G1OopStarChunkedList;
43 class G1PLABAllocator;
44 class G1EvacuationRootClosures;
45 class HeapRegion;
46 class outputStream;
47 
48 class G1ParScanThreadState : public CHeapObj<mtGC> {
49   G1CollectedHeap* _g1h;
50   G1ScannerTasksQueue* _task_queue;
51   G1RedirtyCardsLocalQueueSet _rdc_local_qset;
52   G1CardTable* _ct;
53   G1EvacuationRootClosures* _closures;
54 
55   G1PLABAllocator* _plab_allocator;
56 
57   AgeTable _age_table;
58   G1HeapRegionAttr _dest[G1HeapRegionAttr::Num];
59   // Local tenuring threshold.
60   uint _tenuring_threshold;
61   G1ScanEvacuatedObjClosure  _scanner;
62 
63   uint _worker_id;
64 
65   // Remember the last enqueued card to avoid enqueuing the same card over and over;
66   // since we only ever scan a card once, this is sufficient.
67   size_t _last_enqueued_card;
68 
69   // Upper and lower threshold to start and end work queue draining.
70   uint const _stack_trim_upper_threshold;
71   uint const _stack_trim_lower_threshold;
72 
73   Tickspan _trim_ticks;
74   // Map from young-age-index (0 == not young, 1 is youngest) to
75   // surviving words. base is what we get back from the malloc call
76   size_t* _surviving_young_words_base;
77   // this points into the array, as we use the first few entries for padding
78   size_t* _surviving_young_words;
79   // Number of elements in the array above.
80   size_t _surviving_words_length;
81   // Indicates whether in the last generation (old) there is no more space
82   // available for allocation.
83   bool _old_gen_is_full;
84   // Size (in elements) of a partial objArray task chunk.
85   int _partial_objarray_chunk_size;
86   PartialArrayTaskStepper _partial_array_stepper;
87   StringDedup::Requests _string_dedup_requests;
88 
ct()89   G1CardTable* ct() { return _ct; }
90 
dest(G1HeapRegionAttr original) const91   G1HeapRegionAttr dest(G1HeapRegionAttr original) const {
92     assert(original.is_valid(),
93            "Original region attr invalid: %s", original.get_type_str());
94     assert(_dest[original.type()].is_valid_gen(),
95            "Dest region attr is invalid: %s", _dest[original.type()].get_type_str());
96     return _dest[original.type()];
97   }
98 
99   size_t _num_optional_regions;
100   G1OopStarChunkedList* _oops_into_optional_regions;
101 
102   G1NUMA* _numa;
103 
104   // Records how many object allocations happened at each node during copy to survivor.
105   // Only starts recording when log of gc+heap+numa is enabled and its data is
106   // transferred when flushed.
107   size_t* _obj_alloc_stat;
108 
109 public:
110   G1ParScanThreadState(G1CollectedHeap* g1h,
111                        G1RedirtyCardsQueueSet* rdcqs,
112                        uint worker_id,
113                        uint n_workers,
114                        size_t young_cset_length,
115                        size_t optional_cset_length);
116   virtual ~G1ParScanThreadState();
117 
set_ref_discoverer(ReferenceDiscoverer * rd)118   void set_ref_discoverer(ReferenceDiscoverer* rd) { _scanner.set_ref_discoverer(rd); }
119 
120 #ifdef ASSERT
queue_is_empty() const121   bool queue_is_empty() const { return _task_queue->is_empty(); }
122 #endif
123 
124   void verify_task(narrowOop* task) const NOT_DEBUG_RETURN;
125   void verify_task(oop* task) const NOT_DEBUG_RETURN;
126   void verify_task(PartialArrayScanTask task) const NOT_DEBUG_RETURN;
127   void verify_task(ScannerTask task) const NOT_DEBUG_RETURN;
128 
129   void push_on_queue(ScannerTask task);
130 
enqueue_card_if_tracked(G1HeapRegionAttr region_attr,T * p,oop o)131   template <class T> void enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o) {
132     assert(!HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already.");
133     assert(!_g1h->heap_region_containing(p)->is_young(), "Should have filtered out from-young references already.");
134 
135 #ifdef ASSERT
136     HeapRegion* const hr_obj = _g1h->heap_region_containing(o);
137     assert(region_attr.needs_remset_update() == hr_obj->rem_set()->is_tracked(),
138            "State flag indicating remset tracking disagrees (%s) with actual remembered set (%s) for region %u",
139            BOOL_TO_STR(region_attr.needs_remset_update()),
140            BOOL_TO_STR(hr_obj->rem_set()->is_tracked()),
141            hr_obj->hrm_index());
142 #endif
143     if (!region_attr.needs_remset_update()) {
144       return;
145     }
146     size_t card_index = ct()->index_for(p);
147     // If the card hasn't been added to the buffer, do it.
148     if (_last_enqueued_card != card_index) {
149       _rdc_local_qset.enqueue(ct()->byte_for_index(card_index));
150       _last_enqueued_card = card_index;
151     }
152   }
153 
closures()154   G1EvacuationRootClosures* closures() { return _closures; }
worker_id()155   uint worker_id() { return _worker_id; }
156 
157   size_t lab_waste_words() const;
158   size_t lab_undo_waste_words() const;
159 
160   // Pass locally gathered statistics to global state. Returns the total number of
161   // HeapWords copied.
162   size_t flush(size_t* surviving_young_words);
163 
164 private:
165   void do_partial_array(PartialArrayScanTask task);
166   void start_partial_objarray(G1HeapRegionAttr dest_dir, oop from, oop to);
167 
168   HeapWord* allocate_copy_slow(G1HeapRegionAttr* dest_attr,
169                                oop old,
170                                size_t word_sz,
171                                uint age,
172                                uint node_index);
173 
174   void undo_allocation(G1HeapRegionAttr dest_addr,
175                        HeapWord* obj_ptr,
176                        size_t word_sz,
177                        uint node_index);
178 
179   oop do_copy_to_survivor_space(G1HeapRegionAttr region_attr,
180                                 oop obj,
181                                 markWord old_mark);
182 
183   // This method is applied to the fields of the objects that have just been copied.
184   template <class T> void do_oop_evac(T* p);
185 
186   void dispatch_task(ScannerTask task);
187 
188   // Tries to allocate word_sz in the PLAB of the next "generation" after trying to
189   // allocate into dest. Previous_plab_refill_failed indicates whether previous
190   // PLAB refill for the original (source) object failed.
191   // Returns a non-NULL pointer if successful, and updates dest if required.
192   // Also determines whether we should continue to try to allocate into the various
193   // generations or just end trying to allocate.
194   HeapWord* allocate_in_next_plab(G1HeapRegionAttr* dest,
195                                   size_t word_sz,
196                                   bool previous_plab_refill_failed,
197                                   uint node_index);
198 
199   inline G1HeapRegionAttr next_region_attr(G1HeapRegionAttr const region_attr, markWord const m, uint& age);
200 
201   void report_promotion_event(G1HeapRegionAttr const dest_attr,
202                               oop const old, size_t word_sz, uint age,
203                               HeapWord * const obj_ptr, uint node_index) const;
204 
205   void trim_queue_to_threshold(uint threshold);
206 
207   inline bool needs_partial_trimming() const;
208 
209   // NUMA statistics related methods.
210   void initialize_numa_stats();
211   void flush_numa_stats();
212   inline void update_numa_stats(uint node_index);
213 
214 public:
215   oop copy_to_survivor_space(G1HeapRegionAttr region_attr, oop obj, markWord old_mark);
216 
217   inline void trim_queue();
218   inline void trim_queue_partially();
219   void steal_and_trim_queue(G1ScannerTasksQueueSet *task_queues);
220 
221   Tickspan trim_ticks() const;
222   void reset_trim_ticks();
223 
224   // An attempt to evacuate "obj" has failed; take necessary steps.
225   oop handle_evacuation_failure_par(oop obj, markWord m);
226 
227   template <typename T>
228   inline void remember_root_into_optional_region(T* p);
229   template <typename T>
230   inline void remember_reference_into_optional_region(T* p);
231 
232   inline G1OopStarChunkedList* oops_into_optional_region(const HeapRegion* hr);
233 };
234 
235 class G1ParScanThreadStateSet : public StackObj {
236   G1CollectedHeap* _g1h;
237   G1RedirtyCardsQueueSet* _rdcqs;
238   G1ParScanThreadState** _states;
239   size_t* _surviving_young_words_total;
240   size_t _young_cset_length;
241   size_t _optional_cset_length;
242   uint _n_workers;
243   bool _flushed;
244 
245  public:
246   G1ParScanThreadStateSet(G1CollectedHeap* g1h,
247                           G1RedirtyCardsQueueSet* rdcqs,
248                           uint n_workers,
249                           size_t young_cset_length,
250                           size_t optional_cset_length);
251   ~G1ParScanThreadStateSet();
252 
253   void flush();
254   void record_unused_optional_region(HeapRegion* hr);
255 
256   G1ParScanThreadState* state_for_worker(uint worker_id);
257 
258   const size_t* surviving_young_words() const;
259 };
260 
261 #endif // SHARE_GC_G1_G1PARSCANTHREADSTATE_HPP
262