1 /*
  2  * Copyright (c) 2017, 2026, 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 #include "classfile/classLoaderData.hpp"
 26 #include "classfile/classLoaderDataGraph.hpp"
 27 #include "gc/g1/g1FullGCMarker.inline.hpp"
 28 #include "gc/shared/partialArraySplitter.inline.hpp"
 29 #include "gc/shared/partialArrayState.hpp"
 30 #include "gc/shared/referenceProcessor.hpp"
 31 #include "gc/shared/taskTerminator.hpp"
 32 #include "gc/shared/verifyOption.hpp"
 33 #include "memory/iterator.inline.hpp"
 34 
 35 G1FullGCMarker::G1FullGCMarker(G1FullCollector* collector,
 36                                uint worker_id,
 37                                G1RegionMarkStats* mark_stats) :
 38     _collector(collector),
 39     _worker_id(worker_id),
 40     _bitmap(collector->mark_bitmap()),
 41     _task_queue(),
 42     _partial_array_splitter(collector->partial_array_state_manager(), collector->workers()),
 43     _mark_closure(worker_id, this, ClassLoaderData::_claim_stw_fullgc_mark, G1CollectedHeap::heap()->ref_processor_stw()),
 44     _stack_closure(this),
 45     _cld_closure(mark_closure(), ClassLoaderData::_claim_stw_fullgc_mark),
 46     _mark_stats_cache(mark_stats, G1RegionMarkStatsCache::RegionMarkStatsCacheSize) {
 47   ClassLoaderDataGraph::verify_claimed_marks_cleared(ClassLoaderData::_claim_stw_fullgc_mark);
 48   _mark_stats_cache.reset();
 49 }
 50 
 51 G1FullGCMarker::~G1FullGCMarker() {
 52   assert(is_task_queue_empty(), "Must be empty at this point");
 53 }
 54 
 55 void G1FullGCMarker::process_partial_array(PartialArrayState* state, bool stolen) {
 56   // Access state before release by claim().
 57   objArrayOop obj_array = objArrayOop(state->source());
 58   PartialArraySplitter::Claim claim =
 59     _partial_array_splitter.claim(state, task_queue(), stolen);
 60   process_array_chunk(obj_array, claim._start, claim._end);
 61 }
 62 
 63 static uintx calc_array_stride(uint array_len, uint num_threads) {
 64   precond(num_threads > 0);
 65 
 66   const size_t stride = (array_len + num_threads - 1) / num_threads;
 67   return clamp(stride, ArrayMarkingMinStride, ObjArrayMarkingStride);
 68 }
 69 
 70 void G1FullGCMarker::start_partial_array_processing(objArrayOop obj) {
 71   precond(obj->is_array_with_oops());
 72   mark_closure()->do_klass(obj->klass());
 73 
 74   // Don't push empty arrays to avoid unnecessary work.
 75   const int array_length = obj->length();
 76 
 77   if (array_length == 0) {
 78     return;
 79   }
 80 
 81   const uintx stride = calc_array_stride(array_length, _collector->workers());
 82   const size_t initial_chunk_size = _partial_array_splitter.start(task_queue(), obj, nullptr, array_length, stride);
 83 
 84   process_array_chunk(obj, 0, initial_chunk_size);
 85 }
 86 
 87 void G1FullGCMarker::complete_marking(G1ScannerTasksQueueSet* task_queues,
 88                                       TaskTerminator* terminator) {
 89   do {
 90     process_marking_stacks();
 91     ScannerTask stolen_task;
 92     if (task_queues->steal(_worker_id, stolen_task)) {
 93       dispatch_task(stolen_task, true);
 94     }
 95   } while (!is_task_queue_empty() || !terminator->offer_termination());
 96 }
 97 
 98 void G1FullGCMarker::flush_mark_stats_cache() {
 99   _mark_stats_cache.evict_all();
100 }