Skip to content
Permalink
Browse files

8228818: Shenandoah: Processing weak roots in concurrent phase when p…

…ossible

Reviewed-by: rkennke
  • Loading branch information
zhengyu123 committed Jan 9, 2020
1 parent 9ab387d commit 11738f10a7cd644fc0bec8fb0a616b47de2604af
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved.
* Copyright (c) 2017, 2020, Red Hat, Inc. All rights reserved.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
@@ -202,6 +202,7 @@ class ShenandoahNMethodUnlinkClosure : public NMethodClosure {
_heap(ShenandoahHeap::heap()) {}

virtual void do_nmethod(nmethod* nm) {
assert(_heap->is_concurrent_root_in_progress(), "Only this phase");
if (failed()) {
return;
}
@@ -222,9 +223,7 @@ class ShenandoahNMethodUnlinkClosure : public NMethodClosure {
ShenandoahReentrantLocker locker(nm_data->lock());

// Heal oops and disarm
if (_heap->is_evacuation_in_progress()) {
ShenandoahNMethod::heal_nmethod(nm);
}
ShenandoahNMethod::heal_nmethod(nm);
ShenandoahNMethod::disarm_nmethod(nm);

// Clear compiled ICs and exception caches
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved.
* Copyright (c) 2013, 2020, Red Hat, Inc. All rights reserved.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
@@ -127,10 +127,12 @@ class ShenandoahInitMarkRootsTask : public AbstractGangTask {
class ShenandoahUpdateRootsTask : public AbstractGangTask {
private:
ShenandoahRootUpdater* _root_updater;
bool _check_alive;
public:
ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater) :
ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater, bool check_alive) :
AbstractGangTask("Shenandoah update roots task"),
_root_updater(root_updater) {
_root_updater(root_updater),
_check_alive(check_alive){
}

void work(uint worker_id) {
@@ -139,8 +141,13 @@ class ShenandoahUpdateRootsTask : public AbstractGangTask {

ShenandoahHeap* heap = ShenandoahHeap::heap();
ShenandoahUpdateRefsClosure cl;
AlwaysTrueClosure always_true;
_root_updater->roots_do<AlwaysTrueClosure, ShenandoahUpdateRefsClosure>(worker_id, &always_true, &cl);
if (_check_alive) {
ShenandoahForwardedIsAliveClosure is_alive;
_root_updater->roots_do<ShenandoahForwardedIsAliveClosure, ShenandoahUpdateRefsClosure>(worker_id, &is_alive, &cl);
} else {
AlwaysTrueClosure always_true;;
_root_updater->roots_do<AlwaysTrueClosure, ShenandoahUpdateRefsClosure>(worker_id, &always_true, &cl);
}
}
};

@@ -282,14 +289,16 @@ void ShenandoahConcurrentMark::update_roots(ShenandoahPhaseTimings::Phase root_p

ShenandoahGCPhase phase(root_phase);

bool check_alive = root_phase == ShenandoahPhaseTimings::degen_gc_update_roots;

#if COMPILER2_OR_JVMCI
DerivedPointerTable::clear();
#endif

uint nworkers = _heap->workers()->active_workers();

ShenandoahRootUpdater root_updater(nworkers, root_phase);
ShenandoahUpdateRootsTask update_roots(&root_updater);
ShenandoahUpdateRootsTask update_roots(&root_updater, check_alive);
_heap->workers()->run_task(&update_roots);

#if COMPILER2_OR_JVMCI
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved.
* Copyright (c) 2013, 2020, Red Hat, Inc. All rights reserved.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
@@ -30,6 +30,7 @@
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/locationPrinter.inline.hpp"
#include "gc/shared/memAllocator.hpp"
#include "gc/shared/oopStorageSet.hpp"
#include "gc/shared/plab.hpp"

#include "gc/shenandoah/shenandoahAllocTracker.hpp"
@@ -1651,20 +1652,25 @@ class ShenandoahConcurrentRootsEvacUpdateTask : public AbstractGangTask {
ShenandoahVMRoots<true /*concurrent*/> _vm_roots;
ShenandoahWeakRoots<true /*concurrent*/> _weak_roots;
ShenandoahClassLoaderDataRoots<true /*concurrent*/, false /*single threaded*/> _cld_roots;
bool _include_weak_roots;

public:
ShenandoahConcurrentRootsEvacUpdateTask() :
AbstractGangTask("Shenandoah Evacuate/Update Concurrent Roots Task") {
ShenandoahConcurrentRootsEvacUpdateTask(bool include_weak_roots) :
AbstractGangTask("Shenandoah Evacuate/Update Concurrent Roots Task"),
_include_weak_roots(include_weak_roots) {
}

void work(uint worker_id) {
ShenandoahEvacOOMScope oom;
{
// jni_roots and weak_roots are OopStorage backed roots, concurrent iteration
// vm_roots and weak_roots are OopStorage backed roots, concurrent iteration
// may race against OopStorage::release() calls.
ShenandoahEvacUpdateOopStorageRootsClosure cl;
_vm_roots.oops_do<ShenandoahEvacUpdateOopStorageRootsClosure>(&cl);
_weak_roots.oops_do<ShenandoahEvacUpdateOopStorageRootsClosure>(&cl);

if (_include_weak_roots) {
_weak_roots.oops_do<ShenandoahEvacUpdateOopStorageRootsClosure>(&cl);
}
}

{
@@ -1675,14 +1681,121 @@ class ShenandoahConcurrentRootsEvacUpdateTask : public AbstractGangTask {
}
};

class ShenandoahEvacUpdateCleanupOopStorageRootsClosure : public BasicOopIterateClosure {
private:
ShenandoahHeap* const _heap;
ShenandoahMarkingContext* const _mark_context;
bool _evac_in_progress;
Thread* const _thread;
size_t _dead_counter;

public:
ShenandoahEvacUpdateCleanupOopStorageRootsClosure();
void do_oop(oop* p);
void do_oop(narrowOop* p);

size_t dead_counter() const;
void reset_dead_counter();
};

ShenandoahEvacUpdateCleanupOopStorageRootsClosure::ShenandoahEvacUpdateCleanupOopStorageRootsClosure() :
_heap(ShenandoahHeap::heap()),
_mark_context(ShenandoahHeap::heap()->marking_context()),
_evac_in_progress(ShenandoahHeap::heap()->is_evacuation_in_progress()),
_thread(Thread::current()),
_dead_counter(0) {
}

void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::do_oop(oop* p) {
const oop obj = RawAccess<>::oop_load(p);
if (!CompressedOops::is_null(obj)) {
if (!_mark_context->is_marked(obj)) {
shenandoah_assert_correct(p, obj);
oop old = Atomic::cmpxchg(p, obj, oop(NULL));
if (obj == old) {
_dead_counter ++;
}
assert(*p == NULL, "Must be");
} else if (_evac_in_progress && _heap->in_collection_set(obj)) {
oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
if (resolved == obj) {
resolved = _heap->evacuate_object(obj, _thread);
}
Atomic::cmpxchg(p, obj, resolved);
assert(_heap->cancelled_gc() ||
_mark_context->is_marked(resolved) && !_heap->in_collection_set(resolved),
"Sanity");
}
}
}

void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::do_oop(narrowOop* p) {
ShouldNotReachHere();
}

size_t ShenandoahEvacUpdateCleanupOopStorageRootsClosure::dead_counter() const {
return _dead_counter;
}

void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::reset_dead_counter() {
_dead_counter = 0;
}

// This task not only evacuates/updates marked weak roots, but also "NULL"
// dead weak roots.
class ShenandoahConcurrentWeakRootsEvacUpdateTask : public AbstractGangTask {
private:
ShenandoahWeakRoot<true /*concurrent*/> _jni_roots;
ShenandoahWeakRoot<true /*concurrent*/> _string_table_roots;
ShenandoahWeakRoot<true /*concurrent*/> _resolved_method_table_roots;
ShenandoahWeakRoot<true /*concurrent*/> _vm_roots;

public:
ShenandoahConcurrentWeakRootsEvacUpdateTask() :
AbstractGangTask("Shenandoah Concurrent Weak Root Task"),
_jni_roots(OopStorageSet::jni_weak(), ShenandoahPhaseTimings::JNIWeakRoots),
_string_table_roots(OopStorageSet::string_table_weak(), ShenandoahPhaseTimings::StringTableRoots),
_resolved_method_table_roots(OopStorageSet::resolved_method_table_weak(), ShenandoahPhaseTimings::ResolvedMethodTableRoots),
_vm_roots(OopStorageSet::vm_weak(), ShenandoahPhaseTimings::VMWeakRoots) {
StringTable::reset_dead_counter();
ResolvedMethodTable::reset_dead_counter();
}

~ShenandoahConcurrentWeakRootsEvacUpdateTask() {
StringTable::finish_dead_counter();
ResolvedMethodTable::finish_dead_counter();
}

void work(uint worker_id) {
ShenandoahEvacOOMScope oom;
// jni_roots and weak_roots are OopStorage backed roots, concurrent iteration
// may race against OopStorage::release() calls.
ShenandoahEvacUpdateCleanupOopStorageRootsClosure cl;
_jni_roots.oops_do(&cl, worker_id);
_vm_roots.oops_do(&cl, worker_id);

cl.reset_dead_counter();
_string_table_roots.oops_do(&cl, worker_id);
StringTable::inc_dead_counter(cl.dead_counter());

cl.reset_dead_counter();
_resolved_method_table_roots.oops_do(&cl, worker_id);
ResolvedMethodTable::inc_dead_counter(cl.dead_counter());
}
};

void ShenandoahHeap::op_roots() {
if (is_concurrent_root_in_progress()) {
if (ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()) {
// Concurrent weak root processing
ShenandoahConcurrentWeakRootsEvacUpdateTask task;
workers()->run_task(&task);

_unloader.unload();
}

if (ShenandoahConcurrentRoots::should_do_concurrent_roots()) {
ShenandoahConcurrentRootsEvacUpdateTask task;
ShenandoahConcurrentRootsEvacUpdateTask task(!ShenandoahConcurrentRoots::should_do_concurrent_class_unloading());
workers()->run_task(&task);
}
}
@@ -2076,32 +2189,34 @@ void ShenandoahHeap::stw_process_weak_roots(bool full_gc) {
ShenandoahPhaseTimings::purge_par;
// Cleanup weak roots
ShenandoahGCPhase phase(timing_phase);
phase_timings()->record_workers_start(timing_phase);
if (has_forwarded_objects()) {
if (is_traversal_mode()) {
ShenandoahForwardedIsAliveClosure is_alive;
ShenandoahTraversalUpdateRefsClosure keep_alive;
ShenandoahParallelWeakRootsCleaningTask<ShenandoahForwardedIsAliveClosure, ShenandoahTraversalUpdateRefsClosure>
cleaning_task(&is_alive, &keep_alive, num_workers);
cleaning_task(&is_alive, &keep_alive, num_workers, !ShenandoahConcurrentRoots::should_do_concurrent_class_unloading());
_workers->run_task(&cleaning_task);
} else {
ShenandoahForwardedIsAliveClosure is_alive;
ShenandoahUpdateRefsClosure keep_alive;
ShenandoahParallelWeakRootsCleaningTask<ShenandoahForwardedIsAliveClosure, ShenandoahUpdateRefsClosure>
cleaning_task(&is_alive, &keep_alive, num_workers);
cleaning_task(&is_alive, &keep_alive, num_workers, !ShenandoahConcurrentRoots::should_do_concurrent_class_unloading());
_workers->run_task(&cleaning_task);
}
} else {
ShenandoahIsAliveClosure is_alive;
#ifdef ASSERT
ShenandoahAssertNotForwardedClosure verify_cl;
ShenandoahParallelWeakRootsCleaningTask<ShenandoahIsAliveClosure, ShenandoahAssertNotForwardedClosure>
cleaning_task(&is_alive, &verify_cl, num_workers);
ShenandoahAssertNotForwardedClosure verify_cl;
ShenandoahParallelWeakRootsCleaningTask<ShenandoahIsAliveClosure, ShenandoahAssertNotForwardedClosure>
cleaning_task(&is_alive, &verify_cl, num_workers, !ShenandoahConcurrentRoots::should_do_concurrent_class_unloading());
#else
ShenandoahParallelWeakRootsCleaningTask<ShenandoahIsAliveClosure, DoNothingClosure>
cleaning_task(&is_alive, &do_nothing_cl, num_workers);
ShenandoahParallelWeakRootsCleaningTask<ShenandoahIsAliveClosure, DoNothingClosure>
cleaning_task(&is_alive, &do_nothing_cl, num_workers, !ShenandoahConcurrentRoots::should_do_concurrent_class_unloading());
#endif
_workers->run_task(&cleaning_task);
}
phase_timings()->record_workers_end(timing_phase);
}

void ShenandoahHeap::parallel_cleaning(bool full_gc) {
@@ -2348,7 +2463,7 @@ void ShenandoahHeap::op_init_updaterefs() {

if (ShenandoahVerify) {
if (!is_degenerated_gc_in_progress()) {
verifier()->verify_roots_no_forwarded_except(ShenandoahRootVerifier::ThreadRoots);
verifier()->verify_roots_in_to_space_except(ShenandoahRootVerifier::ThreadRoots);
}
verifier()->verify_before_updaterefs();
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Red Hat, Inc. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat, Inc. All rights reserved.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
@@ -28,6 +28,7 @@
#include "gc/shared/preservedMarks.inline.hpp"
#include "gc/shenandoah/shenandoahForwarding.inline.hpp"
#include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp"
#include "gc/shenandoah/shenandoahConcurrentRoots.hpp"
#include "gc/shenandoah/shenandoahCollectionSet.hpp"
#include "gc/shenandoah/shenandoahFreeSet.hpp"
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
@@ -73,6 +74,12 @@ void ShenandoahMarkCompact::do_it(GCCause::Cause gc_cause) {
Universe::verify();
}

// Degenerated GC may carry concurrent_root_in_progress flag when upgrading to
// full GC. We need to reset it before mutators resume.
if (ShenandoahConcurrentRoots::can_do_concurrent_class_unloading()) {
heap->set_concurrent_root_in_progress(false);
}

heap->set_full_gc_in_progress(true);

assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at a safepoint");
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Red Hat, Inc. All rights reserved.
* Copyright (c) 2019, 2020, Red Hat, Inc. All rights reserved.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
@@ -170,6 +170,7 @@ ShenandoahNMethod* ShenandoahNMethod::for_nmethod(nmethod* nm) {
}

void ShenandoahNMethod::heal_nmethod(nmethod* nm) {
assert(ShenandoahHeap::heap()->is_concurrent_root_in_progress(), "Only this phase");
ShenandoahNMethod* data = gc_data(nm);
assert(data != NULL, "Sanity");
assert(data->lock()->owned_by_self(), "Must hold the lock");
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Red Hat, Inc. All rights reserved.
* Copyright (c) 2019, 2020, Red Hat, Inc. All rights reserved.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
@@ -54,13 +54,15 @@ bool ShenandoahNMethod::is_unregistered() const {
}

void ShenandoahNMethod::disarm_nmethod(nmethod* nm) {
if (!ShenandoahConcurrentRoots::can_do_concurrent_class_unloading()) {
return;
}
if (!ShenandoahConcurrentRoots::can_do_concurrent_class_unloading()) {
return;
}

BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
assert(bs != NULL, "Sanity");
bs->disarm(nm);
BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
assert(bs != NULL, "Sanity");
if (bs->is_armed(nm)) {
bs->disarm(nm);
}
}

ShenandoahNMethod* ShenandoahNMethod::gc_data(nmethod* nm) {
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Red Hat, Inc. All rights reserved.
* Copyright (c) 2019, 2020, Red Hat, Inc. All rights reserved.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
@@ -35,6 +35,7 @@ void ShenandoahNormalMode::initialize_flags() const {
SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent);
if (ShenandoahConcurrentRoots::can_do_concurrent_class_unloading()) {
SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahSuspendibleWorkers);
SHENANDOAH_ERGO_DISABLE_FLAG(VerifyBeforeExit);
}

// Final configuration checks

0 comments on commit 11738f1

Please sign in to comment.
You can’t perform that action at this time.