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 }