1 /*
  2  * Copyright (c) 2021, Amazon.com, Inc. 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 
 26 #include "precompiled.hpp"
 27 
 28 #include "gc/shared/strongRootsScope.hpp"
 29 #include "gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp"
 30 #include "gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.hpp"
 31 #include "gc/shenandoah/heuristics/shenandoahCompactHeuristics.hpp"
 32 #include "gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp"
 33 #include "gc/shenandoah/shenandoahAsserts.hpp"
 34 #include "gc/shenandoah/shenandoahFreeSet.hpp"
 35 #include "gc/shenandoah/shenandoahHeap.hpp"
 36 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
 37 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
 38 #include "gc/shenandoah/shenandoahMarkClosures.hpp"
 39 #include "gc/shenandoah/shenandoahMark.inline.hpp"
 40 #include "gc/shenandoah/shenandoahOldGeneration.hpp"
 41 #include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
 42 #include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
 43 #include "gc/shenandoah/shenandoahStringDedup.hpp"
 44 #include "gc/shenandoah/shenandoahUtils.hpp"
 45 
 46 class ShenandoahFlushAllSATB : public ThreadClosure {
 47  private:
 48   SATBMarkQueueSet& _satb_qset;
 49   uintx _claim_token;
 50 
 51  public:
 52   explicit ShenandoahFlushAllSATB(SATBMarkQueueSet& satb_qset) :
 53     _satb_qset(satb_qset),
 54     _claim_token(Threads::thread_claim_token()) { }
 55 
 56   void do_thread(Thread* thread) {
 57     if (thread->claim_threads_do(true, _claim_token)) {
 58       // Transfer any partial buffer to the qset for completed buffer processing.
 59       _satb_qset.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(thread));
 60     }
 61   }
 62 };
 63 
 64 class ShenandoahProcessOldSATB : public SATBBufferClosure {
 65  private:
 66   ShenandoahObjToScanQueue* _queue;
 67   ShenandoahHeap* _heap;
 68   ShenandoahMarkingContext* const _mark_context;
 69 
 70  public:
 71   size_t _trashed_oops;
 72 
 73   explicit ShenandoahProcessOldSATB(ShenandoahObjToScanQueue* q) :
 74     _queue(q),
 75     _heap(ShenandoahHeap::heap()),
 76     _mark_context(_heap->marking_context()),
 77     _trashed_oops(0) {}
 78 
 79   void do_buffer(void **buffer, size_t size) {
 80     assert(size == 0 || !_heap->has_forwarded_objects() || _heap->is_concurrent_old_mark_in_progress(), "Forwarded objects are not expected here");
 81     for (size_t i = 0; i < size; ++i) {
 82       oop *p = (oop *) &buffer[i];
 83       ShenandoahHeapRegion* region = _heap->heap_region_containing(*p);
 84       if (region->is_old() && region->is_active()) {
 85           ShenandoahMark::mark_through_ref<oop, OLD>(p, _queue, NULL, _mark_context, false);
 86       } else {
 87         ++_trashed_oops;
 88       }
 89     }
 90   }
 91 };
 92 
 93 class ShenandoahPurgeSATBTask : public WorkerTask {
 94 private:
 95   ShenandoahObjToScanQueueSet* _mark_queues;
 96 
 97 public:
 98   volatile size_t _trashed_oops;
 99 
100   explicit ShenandoahPurgeSATBTask(ShenandoahObjToScanQueueSet* queues) :
101     WorkerTask("Purge SATB"),
102     _mark_queues(queues),
103     _trashed_oops(0) {
104     Threads::change_thread_claim_token();
105   }
106 
107   ~ShenandoahPurgeSATBTask() {
108     if (_trashed_oops > 0) {
109       log_info(gc)("Purged " SIZE_FORMAT " oops from old generation SATB buffers.", _trashed_oops);
110     }
111   }
112 
113   void work(uint worker_id) {
114     ShenandoahParallelWorkerSession worker_session(worker_id);
115     ShenandoahSATBMarkQueueSet &satb_queues = ShenandoahBarrierSet::satb_mark_queue_set();
116     ShenandoahFlushAllSATB flusher(satb_queues);
117     Threads::threads_do(&flusher);
118 
119     ShenandoahObjToScanQueue* mark_queue = _mark_queues->queue(worker_id);
120     ShenandoahProcessOldSATB processor(mark_queue);
121     while (satb_queues.apply_closure_to_completed_buffer(&processor)) {}
122 
123     Atomic::add(&_trashed_oops, processor._trashed_oops);
124   }
125 };
126 
127 ShenandoahOldGeneration::ShenandoahOldGeneration(uint max_queues, size_t max_capacity, size_t soft_max_capacity)
128   : ShenandoahGeneration(OLD, max_queues, max_capacity, soft_max_capacity) {
129   // Always clear references for old generation
130   ref_processor()->set_soft_reference_policy(true);
131 }
132 
133 const char* ShenandoahOldGeneration::name() const {
134   return "OLD";
135 }
136 
137 bool ShenandoahOldGeneration::contains(ShenandoahHeapRegion* region) const {
138   return region->affiliation() != YOUNG_GENERATION;
139 }
140 
141 void ShenandoahOldGeneration::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* cl) {
142   ShenandoahGenerationRegionClosure<OLD> old_regions(cl);
143   ShenandoahHeap::heap()->parallel_heap_region_iterate(&old_regions);
144 }
145 
146 void ShenandoahOldGeneration::heap_region_iterate(ShenandoahHeapRegionClosure* cl) {
147   ShenandoahGenerationRegionClosure<OLD> old_regions(cl);
148   ShenandoahHeap::heap()->heap_region_iterate(&old_regions);
149 }
150 
151 void ShenandoahOldGeneration::set_concurrent_mark_in_progress(bool in_progress) {
152   ShenandoahHeap::heap()->set_concurrent_old_mark_in_progress(in_progress);
153 }
154 
155 bool ShenandoahOldGeneration::is_concurrent_mark_in_progress() {
156   return ShenandoahHeap::heap()->is_concurrent_old_mark_in_progress();
157 }
158 
159 void ShenandoahOldGeneration::cancel_marking() {
160   if (is_concurrent_mark_in_progress()) {
161     log_info(gc)("Abandon satb buffers.");
162     ShenandoahBarrierSet::satb_mark_queue_set().abandon_partial_marking();
163   }
164 
165   ShenandoahGeneration::cancel_marking();
166 }
167 
168 void ShenandoahOldGeneration::transfer_pointers_from_satb() {
169   ShenandoahHeap* heap = ShenandoahHeap::heap();
170   shenandoah_assert_safepoint();
171   assert(heap->is_concurrent_old_mark_in_progress(), "Only necessary during old marking.");
172   log_info(gc)("Transfer satb buffers.");
173   uint nworkers = heap->workers()->active_workers();
174   StrongRootsScope scope(nworkers);
175 
176   ShenandoahPurgeSATBTask purge_satb_task(task_queues());
177   heap->workers()->run_task(&purge_satb_task);
178 }
179 
180 bool ShenandoahOldGeneration::contains(oop obj) const {
181   return ShenandoahHeap::heap()->is_in_old(obj);
182 }
183 
184 void ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent) {
185   ShenandoahHeap* heap = ShenandoahHeap::heap();
186   assert(!heap->is_full_gc_in_progress(), "Only for concurrent and degenerated GC");
187 
188   {
189     ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_update_region_states : ShenandoahPhaseTimings::degen_gc_final_update_region_states);
190     ShenandoahFinalMarkUpdateRegionStateClosure cl(complete_marking_context());
191 
192     parallel_heap_region_iterate(&cl);
193     heap->assert_pinned_region_status();
194   }
195 
196   {
197     ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::choose_cset : ShenandoahPhaseTimings::degen_gc_choose_cset);
198     ShenandoahHeapLocker locker(heap->lock());
199     heuristics()->choose_collection_set(nullptr, nullptr);
200   }
201 
202   {
203     ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset);
204     ShenandoahHeapLocker locker(heap->lock());
205     heap->free_set()->rebuild();
206   }
207 }
208 
209 ShenandoahHeuristics* ShenandoahOldGeneration::initialize_heuristics(ShenandoahMode* gc_mode) {
210   assert(ShenandoahOldGCHeuristics != NULL, "ShenandoahOldGCHeuristics should not equal NULL");
211   ShenandoahHeuristics* trigger;
212   if (strcmp(ShenandoahOldGCHeuristics, "static") == 0) {
213     trigger = new ShenandoahStaticHeuristics(this);
214   } else if (strcmp(ShenandoahOldGCHeuristics, "adaptive") == 0) {
215     trigger = new ShenandoahAdaptiveHeuristics(this);
216   } else if (strcmp(ShenandoahOldGCHeuristics, "compact") == 0) {
217     trigger = new ShenandoahCompactHeuristics(this);
218   } else {
219     vm_exit_during_initialization("Unknown -XX:ShenandoahOldGCHeuristics option (must be one of: static, adaptive, compact)");
220     ShouldNotReachHere();
221     return NULL;
222   }
223   trigger->set_guaranteed_gc_interval(ShenandoahGuaranteedOldGCInterval);
224   _heuristics = new ShenandoahOldHeuristics(this, trigger);
225   return _heuristics;
226 }