Skip to content

Commit

Permalink
8247281: migrate ObjectMonitor::_object to OopStorage
Browse files Browse the repository at this point in the history
Co-authored-by: Erik Österlund <erik.osterlund@oracle.com>
Co-authored-by: Daniel Daugherty <daniel.daugherty@oracle.com>
Reviewed-by: eosterlund, coleenp, dholmes, stefank, kbarrett, rkennke, sspitsyn
  • Loading branch information
3 people committed Sep 21, 2020
1 parent f800af9 commit d8921ed
Show file tree
Hide file tree
Showing 37 changed files with 211 additions and 344 deletions.
1 change: 0 additions & 1 deletion src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :

// Root scanning phases
_gc_par_phases[ThreadRoots] = new WorkerDataArray<double>("ThreadRoots", "Thread Roots (ms):", max_gc_threads);
_gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>("ObjectSynchronizerRoots", "ObjectSynchronizer Roots (ms):", max_gc_threads);
_gc_par_phases[CLDGRoots] = new WorkerDataArray<double>("CLDGRoots", "CLDG Roots (ms):", max_gc_threads);
AOT_ONLY(_gc_par_phases[AOTCodeRoots] = new WorkerDataArray<double>("AOTCodeRoots", "AOT Root Scan (ms):", max_gc_threads);)
_gc_par_phases[CMRefRoots] = new WorkerDataArray<double>("CMRefRoots", "CM RefProcessor Roots (ms):", max_gc_threads);
Expand Down
1 change: 0 additions & 1 deletion src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
GCWorkerStart,
ExtRootScan,
ThreadRoots,
ObjectSynchronizerRoots,
CLDGRoots,
AOT_ONLY(AOTCodeRoots COMMA)
CMRefRoots,
Expand Down
7 changes: 0 additions & 7 deletions src/hotspot/share/gc/g1/g1RootProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,6 @@ void G1RootProcessor::process_vm_roots(G1RootClosures* closures,
uint worker_id) {
OopClosure* strong_roots = closures->strong_oops();

{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ObjectSynchronizerRoots, worker_id);
if (_process_strong_tasks.try_claim_task(G1RP_PS_ObjectSynchronizer_oops_do)) {
ObjectSynchronizer::oops_do(strong_roots);
}
}

#if INCLUDE_AOT
if (UseAOT) {
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::AOTCodeRoots, worker_id);
Expand Down
1 change: 0 additions & 1 deletion src/hotspot/share/gc/g1/g1RootProcessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ class G1RootProcessor : public StackObj {

enum G1H_process_roots_tasks {
G1RP_PS_Universe_oops_do,
G1RP_PS_ObjectSynchronizer_oops_do,
G1RP_PS_Management_oops_do,
G1RP_PS_ClassLoaderDataGraph_oops_do,
G1RP_PS_jvmti_oops_do,
Expand Down
5 changes: 0 additions & 5 deletions src/hotspot/share/gc/parallel/psParallelCompact.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2010,10 +2010,6 @@ static void mark_from_roots_work(ParallelRootType::Value root_type, uint worker_
PCMarkAndPushClosure mark_and_push_closure(cm);

switch (root_type) {
case ParallelRootType::object_synchronizer:
ObjectSynchronizer::oops_do(&mark_and_push_closure);
break;

case ParallelRootType::class_loader_data:
{
CLDToOopClosure cld_closure(&mark_and_push_closure, ClassLoaderData::_claim_strong);
Expand Down Expand Up @@ -2224,7 +2220,6 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {

// General strong roots.
Threads::oops_do(&oop_closure, NULL);
ObjectSynchronizer::oops_do(&oop_closure);
OopStorageSet::strong_oops_do(&oop_closure);
CLDToOopClosure cld_closure(&oop_closure, ClassLoaderData::_claim_strong);
ClassLoaderDataGraph::cld_do(&cld_closure);
Expand Down
1 change: 0 additions & 1 deletion src/hotspot/share/gc/parallel/psRootType.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ class ParallelRootType : public AllStatic {
// The order reflects the order these roots are to be processed,
// We do not want any holes in the enum as we enumerate these values by incrementing them.
enum Value {
object_synchronizer,
class_loader_data,
code_cache,
//"threads" are handled in parallel as a special case
Expand Down
4 changes: 0 additions & 4 deletions src/hotspot/share/gc/parallel/psScavenge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,6 @@ static void scavenge_roots_work(ParallelRootType::Value root_type, uint worker_i
PSPromoteRootsClosure roots_to_old_closure(pm);

switch (root_type) {
case ParallelRootType::object_synchronizer:
ObjectSynchronizer::oops_do(&roots_closure);
break;

case ParallelRootType::class_loader_data:
{
PSScavengeCLDClosure cld_closure(pm);
Expand Down
3 changes: 0 additions & 3 deletions src/hotspot/share/gc/shared/genCollectedHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,9 +817,6 @@ void GenCollectedHeap::process_roots(StrongRootsScope* scope,
bool is_par = scope->n_threads() > 1;
Threads::possibly_parallel_oops_do(is_par, strong_roots, roots_from_code_p);

if (_process_strong_tasks->try_claim_task(GCH_PS_ObjectSynchronizer_oops_do)) {
ObjectSynchronizer::oops_do(strong_roots);
}
#if INCLUDE_AOT
if (UseAOT && _process_strong_tasks->try_claim_task(GCH_PS_aot_oops_do)) {
AOTLoader::oops_do(strong_roots);
Expand Down
1 change: 0 additions & 1 deletion src/hotspot/share/gc/shared/genCollectedHeap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ class GenCollectedHeap : public CollectedHeap {

// The set of potentially parallel tasks in root scanning.
enum GCH_strong_roots_tasks {
GCH_PS_ObjectSynchronizer_oops_do,
GCH_PS_OopStorageSet_oops_do,
GCH_PS_ClassLoaderDataGraph_oops_do,
GCH_PS_CodeCache_oops_do,
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/gc/shared/oopStorageSet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class OopStorageSet : public AllStatic {
public:
// Must be updated when new OopStorages are introduced
static const uint strong_count = 4 JVMTI_ONLY(+ 1);
static const uint weak_count = 4 JFR_ONLY(+ 1);
static const uint weak_count = 5 JFR_ONLY(+ 1);
static const uint all_count = strong_count + weak_count;

private:
Expand Down
4 changes: 0 additions & 4 deletions src/hotspot/share/gc/shared/space.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,6 @@ inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* c
HeapWord* scan_limit = space->scan_limit();

while (cur_obj < scan_limit) {
assert(!space->scanned_block_is_obj(cur_obj) ||
oop(cur_obj)->mark_raw().is_marked() || oop(cur_obj)->mark_raw().is_unlocked() ||
oop(cur_obj)->mark_raw().has_bias_pattern(),
"these are the only valid states during a mark sweep");
if (space->scanned_block_is_obj(cur_obj) && oop(cur_obj)->is_gc_marked()) {
// prefetch beyond cur_obj
Prefetch::write(cur_obj, interval);
Expand Down
7 changes: 0 additions & 7 deletions src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ class ShenandoahFinalMarkingTask : public AbstractGangTask {
ShenandoahConcurrentMark* _cm;
TaskTerminator* _terminator;
bool _dedup_string;
ShenandoahSharedFlag _claimed_syncroots;

public:
ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :
Expand Down Expand Up @@ -294,19 +293,13 @@ class ShenandoahFinalMarkingTask : public AbstractGangTask {
ShenandoahStoreValEnqueueBarrier ? &resolve_mark_cl : NULL,
do_nmethods ? &blobsCl : NULL);
Threads::threads_do(&tc);
if (ShenandoahStoreValEnqueueBarrier && _claimed_syncroots.try_set()) {
ObjectSynchronizer::oops_do(&resolve_mark_cl);
}
} else {
ShenandoahMarkRefsClosure mark_cl(q, rp);
MarkingCodeBlobClosure blobsCl(&mark_cl, !CodeBlobToOopClosure::FixRelocations);
ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl,
ShenandoahStoreValEnqueueBarrier ? &mark_cl : NULL,
do_nmethods ? &blobsCl : NULL);
Threads::threads_do(&tc);
if (ShenandoahStoreValEnqueueBarrier && _claimed_syncroots.try_set()) {
ObjectSynchronizer::oops_do(&mark_cl);
}
}
}

Expand Down
1 change: 0 additions & 1 deletion src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class outputStream;
f(CNT_PREFIX ## CodeCacheRoots, DESC_PREFIX "Code Cache Roots") \
f(CNT_PREFIX ## VMStrongRoots, DESC_PREFIX "VM Strong Roots") \
f(CNT_PREFIX ## VMWeakRoots, DESC_PREFIX "VM Weak Roots") \
f(CNT_PREFIX ## ObjectSynchronizerRoots, DESC_PREFIX "Synchronizer Roots") \
f(CNT_PREFIX ## CLDGRoots, DESC_PREFIX "CLDG Roots") \
f(CNT_PREFIX ## JVMTIWeakRoots, DESC_PREFIX "JVMTI Weak Roots") \
f(CNT_PREFIX ## StringDedupTableRoots, DESC_PREFIX "Dedup Table Roots") \
Expand Down
40 changes: 0 additions & 40 deletions src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,6 @@
#include "memory/resourceArea.hpp"
#include "runtime/thread.hpp"

ShenandoahSerialRoot::ShenandoahSerialRoot(ShenandoahSerialRoot::OopsDo oops_do,
ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) :
_oops_do(oops_do), _phase(phase), _par_phase(par_phase) {
}

void ShenandoahSerialRoot::oops_do(OopClosure* cl, uint worker_id) {
if (_claimed.try_set()) {
ShenandoahWorkerTimingsTracker timer(_phase, _par_phase, worker_id);
_oops_do(cl);
}
}

ShenandoahSerialRoots::ShenandoahSerialRoots(ShenandoahPhaseTimings::Phase phase) :
_object_synchronizer_root(&ObjectSynchronizer::oops_do, phase, ShenandoahPhaseTimings::ObjectSynchronizerRoots) {
}

void ShenandoahSerialRoots::oops_do(OopClosure* cl, uint worker_id) {
_object_synchronizer_root.oops_do(cl, worker_id);
}

ShenandoahWeakSerialRoot::ShenandoahWeakSerialRoot(ShenandoahWeakSerialRoot::WeakOopsDo weak_oops_do,
ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) :
_weak_oops_do(weak_oops_do), _phase(phase), _par_phase(par_phase) {
Expand Down Expand Up @@ -179,7 +159,6 @@ ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase p

ShenandoahRootScanner::ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
ShenandoahRootProcessor(phase),
_serial_roots(phase),
_thread_roots(phase, n_workers > 1) {
nmethod::oops_do_marking_prologue();
}
Expand Down Expand Up @@ -207,26 +186,14 @@ void ShenandoahRootScanner::roots_do(uint worker_id, OopClosure* oops, CLDClosur
assert(clds != NULL, "Only possible with CLD closure");

ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);

ResourceMark rm;

// Process serial-claiming roots first
_serial_roots.oops_do(oops, worker_id);

// Process heavy-weight/fully parallel roots the last
_thread_roots.threads_do(&tc_cl, worker_id);
}

void ShenandoahRootScanner::strong_roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc) {
assert(ShenandoahHeap::heap()->unload_classes(), "Should be used during class unloading");
ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);

ResourceMark rm;

// Process serial-claiming roots first
_serial_roots.oops_do(oops, worker_id);

// Process heavy-weight/fully parallel roots the last
_thread_roots.threads_do(&tc_cl, worker_id);
}

Expand All @@ -235,7 +202,6 @@ ShenandoahRootEvacuator::ShenandoahRootEvacuator(uint n_workers,
bool stw_roots_processing,
bool stw_class_unloading) :
ShenandoahRootProcessor(phase),
_serial_roots(phase),
_vm_roots(phase),
_cld_roots(phase, n_workers),
_thread_roots(phase, n_workers > 1),
Expand All @@ -256,7 +222,6 @@ void ShenandoahRootEvacuator::roots_do(uint worker_id, OopClosure* oops) {
AlwaysTrueClosure always_true;

// Process serial-claiming roots first
_serial_roots.oops_do(oops, worker_id);
_serial_weak_roots.weak_oops_do(oops, worker_id);

// Process light-weight/limited parallel roots then
Expand All @@ -281,7 +246,6 @@ void ShenandoahRootEvacuator::roots_do(uint worker_id, OopClosure* oops) {

ShenandoahRootUpdater::ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
ShenandoahRootProcessor(phase),
_serial_roots(phase),
_vm_roots(phase),
_cld_roots(phase, n_workers),
_thread_roots(phase, n_workers > 1),
Expand All @@ -293,7 +257,6 @@ ShenandoahRootUpdater::ShenandoahRootUpdater(uint n_workers, ShenandoahPhaseTimi

ShenandoahRootAdjuster::ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
ShenandoahRootProcessor(phase),
_serial_roots(phase),
_vm_roots(phase),
_cld_roots(phase, n_workers),
_thread_roots(phase, n_workers > 1),
Expand All @@ -314,7 +277,6 @@ void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) {
AlwaysTrueClosure always_true;

// Process serial-claiming roots first
_serial_roots.oops_do(oops, worker_id);
_serial_weak_roots.weak_oops_do(oops, worker_id);

// Process light-weight/limited parallel roots then
Expand All @@ -330,7 +292,6 @@ void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) {

ShenandoahHeapIterationRootScanner::ShenandoahHeapIterationRootScanner() :
ShenandoahRootProcessor(ShenandoahPhaseTimings::heap_iteration_roots),
_serial_roots(ShenandoahPhaseTimings::heap_iteration_roots),
_thread_roots(ShenandoahPhaseTimings::heap_iteration_roots, false /*is par*/),
_vm_roots(ShenandoahPhaseTimings::heap_iteration_roots),
_cld_roots(ShenandoahPhaseTimings::heap_iteration_roots, 1),
Expand All @@ -351,7 +312,6 @@ ShenandoahHeapIterationRootScanner::ShenandoahHeapIterationRootScanner() :
ResourceMark rm;

// Process serial-claiming roots first
_serial_roots.oops_do(oops, 0);
_serial_weak_roots.weak_oops_do(oops, 0);

// Process light-weight/limited parallel roots then
Expand Down
13 changes: 0 additions & 13 deletions src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,6 @@ class ShenandoahSerialRoot {
void oops_do(OopClosure* cl, uint worker_id);
};

class ShenandoahSerialRoots {
private:
ShenandoahSerialRoot _object_synchronizer_root;
public:
ShenandoahSerialRoots(ShenandoahPhaseTimings::Phase phase);
void oops_do(OopClosure* cl, uint worker_id);
};

class ShenandoahWeakSerialRoot {
typedef void (*WeakOopsDo)(BoolObjectClosure*, OopClosure*);
private:
Expand Down Expand Up @@ -199,7 +191,6 @@ class ShenandoahRootProcessor : public StackObj {

class ShenandoahRootScanner : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahThreadRoots _thread_roots;

public:
Expand Down Expand Up @@ -238,7 +229,6 @@ class ShenandoahConcurrentRootScanner {
// root scanning
class ShenandoahHeapIterationRootScanner : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahVMRoots<false /*concurrent*/> _vm_roots;
ShenandoahClassLoaderDataRoots<false /*concurrent*/, true /*single threaded*/>
Expand All @@ -257,7 +247,6 @@ class ShenandoahHeapIterationRootScanner : public ShenandoahRootProcessor {
// Evacuate all roots at a safepoint
class ShenandoahRootEvacuator : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahVMRoots<false /*concurrent*/> _vm_roots;
ShenandoahClassLoaderDataRoots<false /*concurrent*/, false /*single threaded*/>
_cld_roots;
Expand All @@ -278,7 +267,6 @@ class ShenandoahRootEvacuator : public ShenandoahRootProcessor {
// Update all roots at a safepoint
class ShenandoahRootUpdater : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahVMRoots<false /*concurrent*/> _vm_roots;
ShenandoahClassLoaderDataRoots<false /*concurrent*/, false /*single threaded*/>
_cld_roots;
Expand All @@ -298,7 +286,6 @@ class ShenandoahRootUpdater : public ShenandoahRootProcessor {
// Adjuster all roots at a safepoint during full gc
class ShenandoahRootAdjuster : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahVMRoots<false /*concurrent*/> _vm_roots;
ShenandoahClassLoaderDataRoots<false /*concurrent*/, false /*single threaded*/>
_cld_roots;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAliv
CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong);

// Process serial-claiming roots first
_serial_roots.oops_do(keep_alive, worker_id);
_serial_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);

// Process light-weight/limited parallel roots then
Expand Down
3 changes: 0 additions & 3 deletions src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ void ShenandoahRootVerifier::oops_do(OopClosure* oops) {

if (verify(SerialRoots)) {
shenandoah_assert_safepoint();
ObjectSynchronizer::oops_do(oops);
}

if (verify(JNIHandleRoots)) {
Expand Down Expand Up @@ -118,7 +117,6 @@ void ShenandoahRootVerifier::roots_do(OopClosure* oops) {
ClassLoaderDataGraph::cld_do(&clds);

JNIHandles::oops_do(oops);
ObjectSynchronizer::oops_do(oops);
Universe::vm_global()->oops_do(oops);

AlwaysTrueClosure always_true;
Expand All @@ -143,7 +141,6 @@ void ShenandoahRootVerifier::strong_roots_do(OopClosure* oops) {
ClassLoaderDataGraph::roots_cld_do(&clds, NULL);

JNIHandles::oops_do(oops);
ObjectSynchronizer::oops_do(oops);
Universe::vm_global()->oops_do(oops);

// Do thread roots the last. This allows verification code to find
Expand Down
8 changes: 0 additions & 8 deletions src/hotspot/share/gc/z/zRootsIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
static const ZStatSubPhase ZSubPhasePauseRootsSetup("Pause Roots Setup");
static const ZStatSubPhase ZSubPhasePauseRoots("Pause Roots");
static const ZStatSubPhase ZSubPhasePauseRootsTeardown("Pause Roots Teardown");
static const ZStatSubPhase ZSubPhasePauseRootsObjectSynchronizer("Pause Roots ObjectSynchronizer");
static const ZStatSubPhase ZSubPhasePauseRootsJVMTIWeakExport("Pause Roots JVMTIWeakExport");
static const ZStatSubPhase ZSubPhasePauseRootsVMThread("Pause Roots VM Thread");
static const ZStatSubPhase ZSubPhasePauseRootsJavaThreads("Pause Roots Java Threads");
Expand Down Expand Up @@ -184,7 +183,6 @@ void ZJavaThreadsIterator::threads_do(ThreadClosure* cl) {
ZRootsIterator::ZRootsIterator(bool visit_jvmti_weak_export) :
_visit_jvmti_weak_export(visit_jvmti_weak_export),
_java_threads_iter(),
_object_synchronizer(this),
_jvmti_weak_export(this),
_vm_thread(this),
_java_threads(this),
Expand All @@ -211,11 +209,6 @@ ZRootsIterator::~ZRootsIterator() {
COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::update_pointers());
}

void ZRootsIterator::do_object_synchronizer(ZRootsIteratorClosure* cl) {
ZStatTimer timer(ZSubPhasePauseRootsObjectSynchronizer);
ObjectSynchronizer::oops_do(cl);
}

void ZRootsIterator::do_jvmti_weak_export(ZRootsIteratorClosure* cl) {
ZStatTimer timer(ZSubPhasePauseRootsJVMTIWeakExport);
AlwaysTrueClosure always_alive;
Expand All @@ -241,7 +234,6 @@ void ZRootsIterator::do_code_cache(ZRootsIteratorClosure* cl) {

void ZRootsIterator::oops_do(ZRootsIteratorClosure* cl) {
ZStatTimer timer(ZSubPhasePauseRoots);
_object_synchronizer.oops_do(cl);
_vm_thread.oops_do(cl);
_java_threads.oops_do(cl);
if (!ClassUnloading) {
Expand Down
Loading

1 comment on commit d8921ed

@bridgekeeper
Copy link

@bridgekeeper bridgekeeper bot commented on d8921ed Sep 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.