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()) {
 85         if (!region->is_trash()) {
 86           ShenandoahMark::mark_through_ref<oop, OLD>(p, _queue, NULL, _mark_context, false);
 87         } else {
 88           ++_trashed_oops;
 89         }
 90       }
 91     }
 92   }
 93 };
 94 
 95 class ShenandoahPurgeSATBTask : public AbstractGangTask {
 96 private:
 97   ShenandoahObjToScanQueueSet* _mark_queues;
 98 
 99 public:
100   volatile size_t _trashed_oops;
101 
102   explicit ShenandoahPurgeSATBTask(ShenandoahObjToScanQueueSet* queues) :
103     AbstractGangTask("Purge SATB"),
104     _mark_queues(queues),
105     _trashed_oops(0) {
106     Threads::change_thread_claim_token();
107   }
108 
109   ~ShenandoahPurgeSATBTask() {
110     if (_trashed_oops > 0) {
111       log_info(gc)("Purged " SIZE_FORMAT " oops from old generation SATB buffers.", _trashed_oops);
112     }
113   }
114 
115   void work(uint worker_id) {
116     ShenandoahParallelWorkerSession worker_session(worker_id);
117     ShenandoahSATBMarkQueueSet &satb_queues = ShenandoahBarrierSet::satb_mark_queue_set();
118     ShenandoahFlushAllSATB flusher(satb_queues);
119     Threads::threads_do(&flusher);
120 
121     ShenandoahObjToScanQueue* mark_queue = _mark_queues->queue(worker_id);
122     ShenandoahProcessOldSATB processor(mark_queue);
123     while (satb_queues.apply_closure_to_completed_buffer(&processor)) {}
124 
125     Atomic::add(&_trashed_oops, processor._trashed_oops);
126   }
127 };
128 
129 ShenandoahOldGeneration::ShenandoahOldGeneration(uint max_queues, size_t max_capacity, size_t soft_max_capacity)
130   : ShenandoahGeneration(OLD, max_queues, max_capacity, soft_max_capacity) {
131   // Always clear references for old generation
132   ref_processor()->set_soft_reference_policy(true);
133 }
134 
135 const char* ShenandoahOldGeneration::name() const {
136   return "OLD";
137 }
138 
139 bool ShenandoahOldGeneration::contains(ShenandoahHeapRegion* region) const {
140   return region->affiliation() != YOUNG_GENERATION;
141 }
142 
143 void ShenandoahOldGeneration::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* cl) {
144   ShenandoahGenerationRegionClosure<OLD> old_regions(cl);
145   ShenandoahHeap::heap()->parallel_heap_region_iterate(&old_regions);
146 }
147 
148 void ShenandoahOldGeneration::heap_region_iterate(ShenandoahHeapRegionClosure* cl) {
149   ShenandoahGenerationRegionClosure<OLD> old_regions(cl);
150   ShenandoahHeap::heap()->heap_region_iterate(&old_regions);
151 }
152 
153 void ShenandoahOldGeneration::set_concurrent_mark_in_progress(bool in_progress) {
154   ShenandoahHeap::heap()->set_concurrent_old_mark_in_progress(in_progress);
155 }
156 
157 bool ShenandoahOldGeneration::is_concurrent_mark_in_progress() {
158   return ShenandoahHeap::heap()->is_concurrent_old_mark_in_progress();
159 }
160 
161 void ShenandoahOldGeneration::purge_satb_buffers(bool abandon) {
162   ShenandoahHeap *heap = ShenandoahHeap::heap();
163   shenandoah_assert_safepoint();
164   assert(heap->is_concurrent_old_mark_in_progress(), "Only necessary during old marking.");
165 
166   if (abandon) {
167     ShenandoahBarrierSet::satb_mark_queue_set().abandon_partial_marking();
168   } else {
169     uint nworkers = heap->workers()->active_workers();
170     StrongRootsScope scope(nworkers);
171 
172     ShenandoahPurgeSATBTask purge_satb_task(task_queues());
173     heap->workers()->run_task(&purge_satb_task);
174   }
175 }
176 
177 bool ShenandoahOldGeneration::contains(oop obj) const {
178   return ShenandoahHeap::heap()->is_in_old(obj);
179 }
180 
181 bool ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent) {
182   ShenandoahHeap* heap = ShenandoahHeap::heap();
183   assert(!heap->is_full_gc_in_progress(), "Only for concurrent and degenerated GC");
184 
185   {
186     ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_update_region_states : ShenandoahPhaseTimings::degen_gc_final_update_region_states);
187     ShenandoahFinalMarkUpdateRegionStateClosure cl(complete_marking_context());
188 
189     parallel_heap_region_iterate(&cl);
190     heap->assert_pinned_region_status();
191   }
192 
193   {
194     ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::choose_cset : ShenandoahPhaseTimings::degen_gc_choose_cset);
195     ShenandoahHeapLocker locker(heap->lock());
196     heuristics()->choose_collection_set(nullptr, nullptr);
197   }
198 
199   {
200     ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset);
201     ShenandoahHeapLocker locker(heap->lock());
202     heap->free_set()->rebuild();
203   }
204   return false;
205 }
206 
207 ShenandoahHeuristics* ShenandoahOldGeneration::initialize_heuristics(ShenandoahMode* gc_mode) {
208   assert(ShenandoahOldGCHeuristics != NULL, "ShenandoahOldGCHeuristics should not equal NULL");
209   ShenandoahHeuristics* trigger;
210   if (strcmp(ShenandoahOldGCHeuristics, "static") == 0) {
211     trigger = new ShenandoahStaticHeuristics(this);
212   } else if (strcmp(ShenandoahOldGCHeuristics, "adaptive") == 0) {
213     trigger = new ShenandoahAdaptiveHeuristics(this);
214   } else if (strcmp(ShenandoahOldGCHeuristics, "compact") == 0) {
215     trigger = new ShenandoahCompactHeuristics(this);
216   } else {
217     vm_exit_during_initialization("Unknown -XX:ShenandoahOldGCHeuristics option (must be one of: static, adaptive, compact)");
218     ShouldNotReachHere();
219     return NULL;
220   }
221   trigger->set_guaranteed_gc_interval(ShenandoahGuaranteedOldGCInterval);
222   _heuristics = new ShenandoahOldHeuristics(this, trigger);
223   return _heuristics;
224 }