2424#include " precompiled.hpp"
2525#include " classfile/classLoaderData.hpp"
2626#include " classfile/classLoaderDataGraph.hpp"
27+ #include " classfile/javaClasses.inline.hpp"
2728#include " code/nmethod.hpp"
2829#include " gc/shared/gc_globals.hpp"
30+ #include " gc/shared/stringdedup/stringDedup.hpp"
2931#include " gc/shared/suspendibleThreadSet.hpp"
3032#include " gc/z/zAbort.inline.hpp"
3133#include " gc/z/zBarrier.inline.hpp"
3234#include " gc/z/zHeap.inline.hpp"
3335#include " gc/z/zLock.inline.hpp"
3436#include " gc/z/zMark.inline.hpp"
3537#include " gc/z/zMarkCache.inline.hpp"
38+ #include " gc/z/zMarkContext.inline.hpp"
3639#include " gc/z/zMarkStack.inline.hpp"
3740#include " gc/z/zMarkTerminate.inline.hpp"
3841#include " gc/z/zNMethod.hpp"
@@ -279,7 +282,27 @@ void ZMark::follow_object(oop obj, bool finalizable) {
279282 }
280283}
281284
282- void ZMark::mark_and_follow (ZMarkCache* cache, ZMarkStackEntry entry) {
285+ static void try_deduplicate (ZMarkContext* context, oop obj) {
286+ if (!StringDedup::is_enabled ()) {
287+ // Not enabled
288+ return ;
289+ }
290+
291+ if (!java_lang_String::is_instance_inlined (obj)) {
292+ // Not a String object
293+ return ;
294+ }
295+
296+ if (java_lang_String::test_and_set_deduplication_requested (obj)) {
297+ // Already requested deduplication
298+ return ;
299+ }
300+
301+ // Request deduplication
302+ context->string_dedup_requests ()->add (obj);
303+ }
304+
305+ void ZMark::mark_and_follow (ZMarkContext* context, ZMarkStackEntry entry) {
283306 // Decode flags
284307 const bool finalizable = entry.finalizable ();
285308 const bool partial_array = entry.partial_array ();
@@ -311,26 +334,32 @@ void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
311334 // and alignment paddings can never be reclaimed.
312335 const size_t size = ZUtils::object_size (addr);
313336 const size_t aligned_size = align_up (size, page->object_alignment ());
314- cache->inc_live (page, aligned_size);
337+ context-> cache () ->inc_live (page, aligned_size);
315338 }
316339
317340 // Follow
318341 if (follow) {
319342 if (is_array (addr)) {
320343 follow_array_object (objArrayOop (ZOop::from_address (addr)), finalizable);
321344 } else {
322- follow_object (ZOop::from_address (addr), finalizable);
345+ const oop obj = ZOop::from_address (addr);
346+ follow_object (obj, finalizable);
347+
348+ // Try deduplicate
349+ try_deduplicate (context, obj);
323350 }
324351 }
325352}
326353
327354template <typename T>
328- bool ZMark::drain (ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, ZMarkCache* cache, T* timeout) {
355+ bool ZMark::drain (ZMarkContext* context, T* timeout) {
356+ ZMarkStripe* const stripe = context->stripe ();
357+ ZMarkThreadLocalStacks* const stacks = context->stacks ();
329358 ZMarkStackEntry entry;
330359
331360 // Drain stripe stacks
332361 while (stacks->pop (&_allocator, &_stripes, stripe, entry)) {
333- mark_and_follow (cache , entry);
362+ mark_and_follow (context , entry);
334363
335364 // Check timeout
336365 if (timeout->has_expired ()) {
@@ -343,7 +372,10 @@ bool ZMark::drain(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, ZMarkCach
343372 return !timeout->has_expired ();
344373}
345374
346- bool ZMark::try_steal_local (ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
375+ bool ZMark::try_steal_local (ZMarkContext* context) {
376+ ZMarkStripe* const stripe = context->stripe ();
377+ ZMarkThreadLocalStacks* const stacks = context->stacks ();
378+
347379 // Try to steal a local stack from another stripe
348380 for (ZMarkStripe* victim_stripe = _stripes.stripe_next (stripe);
349381 victim_stripe != stripe;
@@ -360,7 +392,10 @@ bool ZMark::try_steal_local(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks)
360392 return false ;
361393}
362394
363- bool ZMark::try_steal_global (ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
395+ bool ZMark::try_steal_global (ZMarkContext* context) {
396+ ZMarkStripe* const stripe = context->stripe ();
397+ ZMarkThreadLocalStacks* const stacks = context->stacks ();
398+
364399 // Try to steal a stack from another stripe
365400 for (ZMarkStripe* victim_stripe = _stripes.stripe_next (stripe);
366401 victim_stripe != stripe;
@@ -377,8 +412,8 @@ bool ZMark::try_steal_global(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks
377412 return false ;
378413}
379414
380- bool ZMark::try_steal (ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks ) {
381- return try_steal_local (stripe, stacks ) || try_steal_global (stripe, stacks );
415+ bool ZMark::try_steal (ZMarkContext* context ) {
416+ return try_steal_local (context ) || try_steal_global (context );
382417}
383418
384419void ZMark::idle () const {
@@ -496,17 +531,17 @@ class ZMarkNoTimeout : public StackObj {
496531 }
497532};
498533
499- void ZMark::work_without_timeout (ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks ) {
534+ void ZMark::work_without_timeout (ZMarkContext* context ) {
500535 ZStatTimer timer (ZSubPhaseConcurrentMark);
501536 ZMarkNoTimeout no_timeout;
502537
503538 for (;;) {
504- if (!drain (stripe, stacks, cache , &no_timeout)) {
539+ if (!drain (context , &no_timeout)) {
505540 // Abort
506541 break ;
507542 }
508543
509- if (try_steal (stripe, stacks )) {
544+ if (try_steal (context )) {
510545 // Stole work
511546 continue ;
512547 }
@@ -561,17 +596,17 @@ class ZMarkTimeout : public StackObj {
561596 }
562597};
563598
564- void ZMark::work_with_timeout (ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks , uint64_t timeout_in_micros) {
599+ void ZMark::work_with_timeout (ZMarkContext* context , uint64_t timeout_in_micros) {
565600 ZStatTimer timer (ZSubPhaseMarkTryComplete);
566601 ZMarkTimeout timeout (timeout_in_micros);
567602
568603 for (;;) {
569- if (!drain (stripe, stacks, cache , &timeout)) {
604+ if (!drain (context , &timeout)) {
570605 // Timed out
571606 break ;
572607 }
573608
574- if (try_steal (stripe, stacks )) {
609+ if (try_steal (context )) {
575610 // Stole work
576611 continue ;
577612 }
@@ -582,14 +617,14 @@ void ZMark::work_with_timeout(ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThrea
582617}
583618
584619void ZMark::work (uint64_t timeout_in_micros) {
585- ZMarkCache cache (_stripes.nstripes ());
586620 ZMarkStripe* const stripe = _stripes.stripe_for_worker (_nworkers, ZThread::worker_id ());
587621 ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks (Thread::current ());
622+ ZMarkContext context (_stripes.nstripes (), stripe, stacks);
588623
589624 if (timeout_in_micros == 0 ) {
590- work_without_timeout (&cache, stripe, stacks );
625+ work_without_timeout (&context );
591626 } else {
592- work_with_timeout (&cache, stripe, stacks , timeout_in_micros);
627+ work_with_timeout (&context , timeout_in_micros);
593628 }
594629
595630 // Flush and publish stacks
0 commit comments