11/*
2- * Copyright (c) 2002, 2023 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2002, 2024 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
3131#include " gc/parallel/psScavenge.inline.hpp"
3232#include " gc/shared/continuationGCSupport.inline.hpp"
3333#include " gc/shared/gcTrace.hpp"
34+ #include " gc/shared/partialArrayState.hpp"
35+ #include " gc/shared/partialArrayTaskStepper.inline.hpp"
3436#include " gc/shared/preservedMarks.inline.hpp"
3537#include " gc/shared/taskqueue.inline.hpp"
3638#include " logging/log.hpp"
4244#include " memory/resourceArea.hpp"
4345#include " oops/access.inline.hpp"
4446#include " oops/compressedOops.inline.hpp"
47+ #include " utilities/checkedCast.hpp"
4548
4649PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = nullptr ;
4750PSPromotionManager::PSScannerTasksQueueSet* PSPromotionManager::_stack_array_depth = nullptr ;
4851PreservedMarksSet* PSPromotionManager::_preserved_marks_set = nullptr ;
4952PSOldGen* PSPromotionManager::_old_gen = nullptr ;
5053MutableSpace* PSPromotionManager::_young_space = nullptr ;
54+ PartialArrayStateAllocator* PSPromotionManager::_partial_array_state_allocator = nullptr ;
5155
5256void PSPromotionManager::initialize () {
5357 ParallelScavengeHeap* heap = ParallelScavengeHeap::heap ();
@@ -62,11 +66,16 @@ void PSPromotionManager::initialize() {
6266 assert (_manager_array == nullptr , " Attempt to initialize twice" );
6367 _manager_array = PaddedArray<PSPromotionManager, mtGC>::create_unfreeable (promotion_manager_num);
6468
69+ assert (_partial_array_state_allocator == nullptr , " Attempt to initialize twice" );
70+ _partial_array_state_allocator
71+ = new PartialArrayStateAllocator (ParallelGCThreads);
72+
6573 _stack_array_depth = new PSScannerTasksQueueSet (ParallelGCThreads);
6674
6775 // Create and register the PSPromotionManager(s) for the worker threads.
6876 for (uint i=0 ; i<ParallelGCThreads; i++) {
6977 stack_array_depth ()->register_queue (i, _manager_array[i].claimed_stack_depth ());
78+ _manager_array[i]._partial_array_state_allocator_index = i;
7079 }
7180 // The VMThread gets its own PSPromotionManager, which is not available
7281 // for work stealing.
@@ -124,6 +133,10 @@ bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) {
124133 manager->flush_labs ();
125134 manager->flush_string_dedup_requests ();
126135 }
136+ // All PartialArrayStates have been returned to the allocator, since the
137+ // claimed_stack_depths are all empty. Leave them there for use by future
138+ // collections.
139+
127140 if (!promotion_failure_occurred) {
128141 // If there was no promotion failure, the preserved mark stacks
129142 // should be empty.
@@ -172,7 +185,10 @@ void PSPromotionManager::reset_stats() {
172185}
173186#endif // TASKQUEUE_STATS
174187
175- PSPromotionManager::PSPromotionManager () {
188+ // Most members are initialized either by initialize() or reset().
189+ PSPromotionManager::PSPromotionManager ()
190+ : _partial_array_stepper(ParallelGCThreads, ParGCArrayScanChunk)
191+ {
176192 // We set the old lab's start array.
177193 _old_lab.set_start_array (old_gen ()->start_array ());
178194
@@ -182,9 +198,11 @@ PSPromotionManager::PSPromotionManager() {
182198 _target_stack_size = GCDrainStackTargetSize;
183199 }
184200
185- _array_chunk_size = ParGCArrayScanChunk;
201+ // Initialize to a bad value; fixed by initialize().
202+ _partial_array_state_allocator_index = UINT_MAX;
203+
186204 // let's choose 1.5x the chunk size
187- _min_array_size_for_chunking = 3 * _array_chunk_size / 2 ;
205+ _min_array_size_for_chunking = ( 3 * ParGCArrayScanChunk / 2 ) ;
188206
189207 _preserved_marks = nullptr ;
190208
@@ -277,37 +295,57 @@ template <class T> void PSPromotionManager::process_array_chunk_work(
277295 }
278296}
279297
280- void PSPromotionManager::process_array_chunk (PartialArrayScanTask task) {
281- assert (PSChunkLargeArrays, " invariant" );
282-
283- oop old = task.to_source_array ();
284- assert (old->is_objArray (), " invariant" );
285- assert (old->is_forwarded (), " invariant" );
286-
298+ void PSPromotionManager::process_array_chunk (PartialArrayState* state) {
287299 TASKQUEUE_STATS_ONLY (++_array_chunks_processed);
288300
289- oop const obj = old->forwardee ();
290-
291- int start;
292- int const end = arrayOop (old)->length ();
293- if (end > (int ) _min_array_size_for_chunking) {
294- // we'll chunk more
295- start = end - _array_chunk_size;
296- assert (start > 0 , " invariant" );
297- arrayOop (old)->set_length (start);
298- push_depth (ScannerTask (PartialArrayScanTask (old)));
299- TASKQUEUE_STATS_ONLY (++_array_chunk_pushes);
301+ // Claim a chunk. Push additional tasks before processing the claimed
302+ // chunk to allow other workers to steal while we're processing.
303+ PartialArrayTaskStepper::Step step = _partial_array_stepper.next (state);
304+ if (step._ncreate > 0 ) {
305+ state->add_references (step._ncreate );
306+ for (uint i = 0 ; i < step._ncreate ; ++i) {
307+ push_depth (ScannerTask (state));
308+ }
309+ TASKQUEUE_STATS_ONLY (_array_chunk_pushes += step._ncreate );
310+ }
311+ int start = checked_cast<int >(step._index );
312+ int end = checked_cast<int >(step._index + _partial_array_stepper.chunk_size ());
313+ assert (start < end, " invariant" );
314+ if (UseCompressedOops) {
315+ process_array_chunk_work<narrowOop>(state->destination (), start, end);
300316 } else {
301- // this is the final chunk for this array
302- start = 0 ;
303- int const actual_length = arrayOop (obj)->length ();
304- arrayOop (old)->set_length (actual_length);
317+ process_array_chunk_work<oop>(state->destination (), start, end);
305318 }
319+ // Release reference to state, now that we're done with it.
320+ _partial_array_state_allocator->release (_partial_array_state_allocator_index, state);
321+ }
306322
323+ void PSPromotionManager::push_objArray (oop old_obj, oop new_obj) {
324+ assert (old_obj->is_objArray (), " precondition" );
325+ assert (old_obj->is_forwarded (), " precondition" );
326+ assert (old_obj->forwardee () == new_obj, " precondition" );
327+ assert (new_obj->is_objArray (), " precondition" );
328+
329+ size_t array_length = objArrayOop (new_obj)->length ();
330+ PartialArrayTaskStepper::Step step = _partial_array_stepper.start (array_length);
331+
332+ if (step._ncreate > 0 ) {
333+ TASKQUEUE_STATS_ONLY (++_arrays_chunked);
334+ PartialArrayState* state =
335+ _partial_array_state_allocator->allocate (_partial_array_state_allocator_index,
336+ old_obj, new_obj,
337+ step._index ,
338+ array_length,
339+ step._ncreate );
340+ for (uint i = 0 ; i < step._ncreate ; ++i) {
341+ push_depth (ScannerTask (state));
342+ }
343+ TASKQUEUE_STATS_ONLY (_array_chunk_pushes += step._ncreate );
344+ }
307345 if (UseCompressedOops) {
308- process_array_chunk_work<narrowOop>(obj, start, end );
346+ process_array_chunk_work<narrowOop>(new_obj, 0 , checked_cast< int >(step. _index ) );
309347 } else {
310- process_array_chunk_work<oop>(obj, start, end );
348+ process_array_chunk_work<oop>(new_obj, 0 , checked_cast< int >(step. _index ) );
311349 }
312350}
313351
0 commit comments