8247281: migrate ObjectMonitor::_object to OopStorage

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
This commit is contained in:
Daniel D. Daugherty 2020-09-21 22:12:07 +00:00
parent f800af978c
commit d8921ed573
37 changed files with 211 additions and 344 deletions

@ -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);

@ -48,7 +48,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
GCWorkerStart,
ExtRootScan,
ThreadRoots,
ObjectSynchronizerRoots,
CLDGRoots,
AOT_ONLY(AOTCodeRoots COMMA)
CMRefRoots,

@ -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);

@ -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,

@ -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);
@ -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);

@ -34,7 +34,6 @@ public:
// 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

@ -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);

@ -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);

@ -105,7 +105,6 @@ protected:
// 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,

@ -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:

@ -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);

@ -256,7 +256,6 @@ private:
ShenandoahConcurrentMark* _cm;
TaskTerminator* _terminator;
bool _dedup_string;
ShenandoahSharedFlag _claimed_syncroots;
public:
ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) :
@ -294,9 +293,6 @@ public:
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);
@ -304,9 +300,6 @@ public:
ShenandoahStoreValEnqueueBarrier ? &mark_cl : NULL,
do_nmethods ? &blobsCl : NULL);
Threads::threads_do(&tc);
if (ShenandoahStoreValEnqueueBarrier && _claimed_syncroots.try_set()) {
ObjectSynchronizer::oops_do(&mark_cl);
}
}
}

@ -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") \

@ -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) {
@ -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();
}
@ -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);
}
@ -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),
@ -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
@ -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),
@ -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),
@ -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
@ -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),
@ -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

@ -49,14 +49,6 @@ public:
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:
@ -199,7 +191,6 @@ public:
class ShenandoahRootScanner : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahThreadRoots _thread_roots;
public:
@ -238,7 +229,6 @@ public:
// root scanning
class ShenandoahHeapIterationRootScanner : public ShenandoahRootProcessor {
private:
ShenandoahSerialRoots _serial_roots;
ShenandoahThreadRoots _thread_roots;
ShenandoahVMRoots<false /*concurrent*/> _vm_roots;
ShenandoahClassLoaderDataRoots<false /*concurrent*/, true /*single threaded*/>
@ -257,7 +247,6 @@ public:
// 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;
@ -278,7 +267,6 @@ public:
// 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;
@ -298,7 +286,6 @@ public:
// 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;

@ -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

@ -74,7 +74,6 @@ void ShenandoahRootVerifier::oops_do(OopClosure* oops) {
if (verify(SerialRoots)) {
shenandoah_assert_safepoint();
ObjectSynchronizer::oops_do(oops);
}
if (verify(JNIHandleRoots)) {
@ -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;
@ -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

@ -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");
@ -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),
@ -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;
@ -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) {

@ -110,13 +110,11 @@ private:
const bool _visit_jvmti_weak_export;
ZJavaThreadsIterator _java_threads_iter;
void do_object_synchronizer(ZRootsIteratorClosure* cl);
void do_jvmti_weak_export(ZRootsIteratorClosure* cl);
void do_vm_thread(ZRootsIteratorClosure* cl);
void do_java_threads(ZRootsIteratorClosure* cl);
void do_code_cache(ZRootsIteratorClosure* cl);
ZSerialOopsDo<ZRootsIterator, &ZRootsIterator::do_object_synchronizer> _object_synchronizer;
ZSerialOopsDo<ZRootsIterator, &ZRootsIterator::do_jvmti_weak_export> _jvmti_weak_export;
ZSerialOopsDo<ZRootsIterator, &ZRootsIterator::do_vm_thread> _vm_thread;
ZParallelOopsDo<ZRootsIterator, &ZRootsIterator::do_java_threads> _java_threads;

@ -71,7 +71,6 @@ void RootSetClosure<Delegate>::process() {
ClassLoaderDataGraph::always_strong_cld_do(&cldt_closure);
// We don't follow code blob oops, because they have misaligned oops.
Threads::oops_do(this, NULL);
ObjectSynchronizer::oops_do(this);
OopStorageSet::strong_oops_do(this);
AOTLoader::oops_do(this);
}

@ -95,7 +95,6 @@ class ReferenceToRootClosure : public StackObj {
bool _complete;
bool do_cldg_roots();
bool do_object_synchronizer_roots();
bool do_oop_storage_roots();
bool do_string_table_roots();
bool do_aot_loader_roots();
@ -129,13 +128,6 @@ bool ReferenceToRootClosure::do_cldg_roots() {
return rlc.complete();
}
bool ReferenceToRootClosure::do_object_synchronizer_roots() {
assert(!complete(), "invariant");
ReferenceLocateClosure rlc(_callback, OldObjectRoot::_object_synchronizer, OldObjectRoot::_type_undetermined, NULL);
ObjectSynchronizer::oops_do(&rlc);
return rlc.complete();
}
bool ReferenceToRootClosure::do_oop_storage_roots() {
int i = 0;
for (OopStorageSet::Iterator it = OopStorageSet::strong_iterator(); !it.is_end(); ++it, ++i) {
@ -171,11 +163,6 @@ bool ReferenceToRootClosure::do_roots() {
return true;
}
if (do_object_synchronizer_roots()) {
_complete = true;
return true;
}
if (do_oop_storage_roots()) {
_complete = true;
return true;

@ -54,8 +54,6 @@ const char* OldObjectRoot::system_description(System system) {
return "Universe";
case _threads:
return "Threads";
case _object_synchronizer:
return "Object Monitor";
case _class_loader_data:
return "Class Loader Data";
case _code_cache:

@ -36,7 +36,6 @@ class OldObjectRoot : public AllStatic {
_threads,
_strong_oop_storage_set_first,
_strong_oop_storage_set_last = _strong_oop_storage_set_first + OopStorageSet::strong_count - 1,
_object_synchronizer,
_class_loader_data,
_code_cache,
_aot,

@ -31,8 +31,11 @@
#include "utilities/ostream.hpp"
WeakHandle::WeakHandle(OopStorage* storage, Handle obj) :
WeakHandle(storage, obj()) {}
WeakHandle::WeakHandle(OopStorage* storage, oop obj) :
_obj(storage->allocate()) {
assert(obj() != NULL, "no need to create weak null oop");
assert(obj != NULL, "no need to create weak null oop");
if (_obj == NULL) {
vm_exit_out_of_memory(sizeof(oop*), OOM_MALLOC_ERROR,
@ -40,7 +43,7 @@ WeakHandle::WeakHandle(OopStorage* storage, Handle obj) :
storage->name());
}
NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(_obj, obj());
NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(_obj, obj);
}
void WeakHandle::release(OopStorage* storage) const {

@ -48,6 +48,7 @@ class WeakHandle {
public:
WeakHandle() : _obj(NULL) {} // needed for init
WeakHandle(OopStorage* storage, Handle obj);
WeakHandle(OopStorage* storage, oop obj);
inline oop resolve() const;
inline oop peek() const;

@ -1751,7 +1751,6 @@ static jvmtiHeapRootKind toJvmtiHeapRootKind(jvmtiHeapReferenceKind kind) {
switch (kind) {
case JVMTI_HEAP_REFERENCE_JNI_GLOBAL: return JVMTI_HEAP_ROOT_JNI_GLOBAL;
case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: return JVMTI_HEAP_ROOT_SYSTEM_CLASS;
case JVMTI_HEAP_REFERENCE_MONITOR: return JVMTI_HEAP_ROOT_MONITOR;
case JVMTI_HEAP_REFERENCE_STACK_LOCAL: return JVMTI_HEAP_ROOT_STACK_LOCAL;
case JVMTI_HEAP_REFERENCE_JNI_LOCAL: return JVMTI_HEAP_ROOT_JNI_LOCAL;
case JVMTI_HEAP_REFERENCE_THREAD: return JVMTI_HEAP_ROOT_THREAD;
@ -3017,13 +3016,6 @@ inline bool VM_HeapWalkOperation::collect_simple_roots() {
return false;
}
// Inflated monitors
blk.set_kind(JVMTI_HEAP_REFERENCE_MONITOR);
ObjectSynchronizer::oops_do(&blk);
if (blk.stopped()) {
return false;
}
// threads are now handled in collect_stack_roots()
// Other kinds of roots maintained by HotSpot

@ -24,6 +24,8 @@
#include "precompiled.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc/shared/oopStorage.hpp"
#include "gc/shared/oopStorageSet.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrThreadId.hpp"
#include "logging/log.hpp"
@ -114,6 +116,8 @@ static int Knob_PreSpin = 10; // 20-100 likely better
DEBUG_ONLY(static volatile bool InitDone = false;)
OopStorage* ObjectMonitor::_oop_storage = NULL;
// -----------------------------------------------------------------------------
// Theory of operations -- Monitors lists, thread residency, etc:
//
@ -237,6 +241,53 @@ void ObjectMonitor::operator delete[] (void *p) {
operator delete(p);
}
// Check that object() and set_object() are called from the right context:
static void check_object_context() {
#ifdef ASSERT
Thread* self = Thread::current();
if (self->is_Java_thread()) {
// Mostly called from JavaThreads so sanity check the thread state.
JavaThread* jt = self->as_Java_thread();
switch (jt->thread_state()) {
case _thread_in_vm: // the usual case
case _thread_in_Java: // during deopt
break;
default:
fatal("called from an unsafe thread state");
}
assert(jt->is_active_Java_thread(), "must be active JavaThread");
} else {
// However, ThreadService::get_current_contended_monitor()
// can call here via the VMThread so sanity check it.
assert(self->is_VM_thread(), "must be");
}
#endif // ASSERT
}
oop ObjectMonitor::object() const {
check_object_context();
if (_object.is_null()) {
return NULL;
}
return _object.resolve();
}
oop ObjectMonitor::object_peek() const {
if (_object.is_null()) {
return NULL;
}
return _object.peek();
}
void ObjectMonitor::set_object(oop obj) {
check_object_context();
if (_object.is_null()) {
_object = WeakHandle(_oop_storage, obj);
} else {
_object.replace(obj);
}
}
// -----------------------------------------------------------------------------
// Enter support
@ -446,10 +497,10 @@ void ObjectMonitor::install_displaced_markword_in_object(const oop obj) {
OrderAccess::loadload();
}
const oop l_object = object();
const oop l_object = object_peek();
if (l_object == NULL) {
// ObjectMonitor's object ref has already been cleared by async
// deflation so we're done here.
// deflation or GC so we're done here.
return;
}
assert(l_object == obj, "object=" INTPTR_FORMAT " must equal obj="
@ -703,7 +754,6 @@ void ObjectMonitor::EnterI(TRAPS) {
// In addition, Self.TState is stable.
assert(_owner == Self, "invariant");
assert(object() != NULL, "invariant");
UnlinkAfterAcquire(Self, &node);
if (_succ == Self) _succ = NULL;
@ -2055,6 +2105,8 @@ void ObjectMonitor::Initialize() {
#undef NEWPERFVARIABLE
}
_oop_storage = OopStorageSet::create_weak("ObjectSynchronizer Weak");
DEBUG_ONLY(InitDone = true;)
}
@ -2103,7 +2155,7 @@ void ObjectMonitor::print() const { print_on(tty); }
void ObjectMonitor::print_debug_style_on(outputStream* st) const {
st->print_cr("(ObjectMonitor*) " INTPTR_FORMAT " = {", p2i(this));
st->print_cr(" _header = " INTPTR_FORMAT, header().value());
st->print_cr(" _object = " INTPTR_FORMAT, p2i(object()));
st->print_cr(" _object = " INTPTR_FORMAT, p2i(object_peek()));
st->print(" _allocation_state = ");
if (is_free()) {
st->print("Free");

@ -28,6 +28,7 @@
#include "memory/allocation.hpp"
#include "memory/padded.hpp"
#include "oops/markWord.hpp"
#include "oops/weakHandle.hpp"
#include "runtime/os.hpp"
#include "runtime/park.hpp"
#include "runtime/perfData.hpp"
@ -132,14 +133,17 @@ class ObjectMonitor {
friend class VMStructs;
JVMCI_ONLY(friend class JVMCIVMStructs;)
static OopStorage* _oop_storage;
// The sync code expects the header field to be at offset zero (0).
// Enforced by the assert() in header_addr().
volatile markWord _header; // displaced object header word - mark
void* volatile _object; // backward object pointer - strong root
WeakHandle _object; // backward object pointer
typedef enum {
Free = 0, // Free must be 0 for monitor to be free after memset(..,0,..).
New,
Old
Old,
ChainMarker
} AllocationState;
AllocationState _allocation_state;
// Separate _header and _owner on different cache lines since both can
@ -148,7 +152,7 @@ class ObjectMonitor {
// change until deflation so _object and _allocation_state are good
// choices to share the cache line with _header.
DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(volatile markWord) +
sizeof(void* volatile) + sizeof(AllocationState));
sizeof(WeakHandle) + sizeof(AllocationState));
// Used by async deflation as a marker in the _owner field:
#define DEFLATER_MARKER reinterpret_cast<void*>(-1)
void* volatile _owner; // pointer to owning thread OR BasicLock
@ -329,6 +333,7 @@ class ObjectMonitor {
public:
oop object() const;
oop object_peek() const;
oop* object_addr();
void set_object(oop obj);
void release_set_allocation_state(AllocationState s);
@ -338,6 +343,7 @@ class ObjectMonitor {
bool is_free() const;
bool is_old() const;
bool is_new() const;
bool is_chainmarker() const;
// Returns true if the specified thread owns the ObjectMonitor. Otherwise
// returns false and throws IllegalMonitorStateException (IMSE).

@ -92,24 +92,15 @@ inline void ObjectMonitor::clear_common() {
assert(contentions() <= 0, "must not be positive: contentions=%d", contentions());
assert(_waiters == 0, "must be 0: waiters=%d", _waiters);
assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions);
assert(object() != NULL, "must be non-NULL");
set_allocation_state(Free);
set_object(NULL);
}
inline oop ObjectMonitor::object() const {
return (oop)_object;
}
inline oop* ObjectMonitor::object_addr() {
return (oop*)&_object;
}
inline void ObjectMonitor::set_object(oop obj) {
_object = (void*)obj;
}
// Return number of threads contending for this monitor.
inline jint ObjectMonitor::contentions() const {
return Atomic::load(&_contentions);
@ -223,6 +214,10 @@ inline bool ObjectMonitor::is_new() const {
return _allocation_state == New;
}
inline bool ObjectMonitor::is_chainmarker() const {
return _allocation_state == ChainMarker;
}
// The _next_om field can be concurrently read and modified so we
// use Atomic operations to disable compiler optimizations that
// might try to elide loading and/or storing this field.

@ -159,8 +159,6 @@ struct ObjectMonitorListGlobals {
};
static ObjectMonitorListGlobals om_list_globals;
#define CHAINMARKER (cast_to_oop<intptr_t>(-1))
// =====================> Spin-lock functions
@ -510,10 +508,10 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread* self,
if (mark.has_monitor()) {
ObjectMonitor* const m = mark.monitor();
// An async deflation can race us before we manage to make the
// ObjectMonitor busy by setting the owner below. If we detect
// An async deflation or GC can race us before we manage to make
// the ObjectMonitor busy by setting the owner below. If we detect
// that race we just bail out to the slow-path here.
if (m->object() == NULL) {
if (m->object_peek() == NULL) {
return false;
}
Thread* const owner = (Thread *) m->_owner;
@ -1314,10 +1312,10 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob
void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) {
PaddedObjectMonitor* block = Atomic::load(&g_block_list);
while (block != NULL) {
assert(block->object() == CHAINMARKER, "must be a block header");
assert(block->is_chainmarker(), "must be a block header");
for (int i = _BLOCKSIZE - 1; i > 0; i--) {
ObjectMonitor* mid = (ObjectMonitor *)(block + i);
if (mid->object() != NULL) {
if (mid->object_peek() != NULL) {
// Only process with closure if the object is set.
// monitors_iterate() is only called at a safepoint or when the
@ -1402,34 +1400,6 @@ jlong ObjectSynchronizer::time_since_last_async_deflation_ms() {
return (os::javaTimeNanos() - last_async_deflation_time_ns()) / (NANOUNITS / MILLIUNITS);
}
void ObjectSynchronizer::oops_do(OopClosure* f) {
// We only scan the global used list here (for moribund threads), and
// the thread-local monitors in Thread::oops_do().
global_used_oops_do(f);
}
void ObjectSynchronizer::global_used_oops_do(OopClosure* f) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
// Acquire semantics not needed since we're at a safepoint.
list_oops_do(Atomic::load(&om_list_globals._in_use_list), f);
}
void ObjectSynchronizer::thread_local_used_oops_do(Thread* thread, OopClosure* f) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
list_oops_do(thread->om_in_use_list, f);
}
void ObjectSynchronizer::list_oops_do(ObjectMonitor* list, OopClosure* f) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
// The oops_do() phase does not overlap with monitor deflation
// so no need to lock ObjectMonitors for the list traversal.
for (ObjectMonitor* mid = list; mid != NULL; mid = unmarked_next(mid)) {
if (mid->object() != NULL) {
f->do_oop(mid->object_addr());
}
}
}
// -----------------------------------------------------------------------------
// ObjectMonitor Lifecycle
@ -1467,7 +1437,7 @@ ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
// on the shared global list.
m = take_from_start_of_om_free_list(self);
if (m != NULL) {
guarantee(m->object() == NULL, "invariant");
guarantee(m->object_peek() == NULL, "invariant");
m->set_allocation_state(ObjectMonitor::New);
prepend_to_om_in_use_list(self, m);
return m;
@ -1488,7 +1458,7 @@ ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
if (take == NULL) {
break; // No more are available.
}
guarantee(take->object() == NULL, "invariant");
guarantee(take->object_peek() == NULL, "invariant");
// We allowed 3 field values to linger during async deflation.
// Clear or restore them as appropriate.
take->set_header(markWord::zero());
@ -1550,7 +1520,7 @@ ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
temp[_BLOCKSIZE - 1].set_next_om((ObjectMonitor*)NULL);
// Element [0] is reserved for global list linkage
temp[0].set_object(CHAINMARKER);
temp[0].set_allocation_state(ObjectMonitor::ChainMarker);
// Consider carving out this thread's current request from the
// block in hand. This avoids some lock traffic and redundant
@ -1575,7 +1545,7 @@ ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) {
void ObjectSynchronizer::om_release(Thread* self, ObjectMonitor* m,
bool from_per_thread_alloc) {
guarantee(m->header().value() == 0, "invariant");
guarantee(m->object() == NULL, "invariant");
guarantee(m->object_peek() == NULL, "invariant");
NoSafepointVerifier nsv;
if ((m->is_busy() | m->_recursions) != 0) {
@ -1686,10 +1656,7 @@ void ObjectSynchronizer::om_release(Thread* self, ObjectMonitor* m,
//
// We currently call om_flush() from Threads::remove() before the
// thread has been excised from the thread list and is no longer a
// mutator. In particular, this ensures that the thread's in-use
// monitors are scanned by a GC safepoint, either via Thread::oops_do()
// (before om_flush() is called) or via ObjectSynchronizer::oops_do()
// (after om_flush() is called).
// mutator.
//
// deflate_global_idle_monitors_using_JT() and
// deflate_per_thread_idle_monitors_using_JT() (in another thread) can
@ -1733,13 +1700,24 @@ void ObjectSynchronizer::om_flush(Thread* self) {
cur_om = unmarked_next(in_use_tail);
continue;
}
if (cur_om->object() == NULL) {
// cur_om was deflated and the object ref was cleared while it
if (cur_om->object_peek() == NULL) {
// Two reasons for object() to be NULL here:
// 1) cur_om was deflated and the object ref was cleared while it
// was locked. We happened to see it just after it was unlocked
// (and added to the free list). Refetch the possibly changed
// next field and try again.
cur_om = unmarked_next(in_use_tail);
continue;
// (and added to the free list).
// 2) The object has been GC'ed so the association with object is
// already broken, but we don't want to do the deflation work now.
// Refetch the possibly changed next field:
ObjectMonitor* in_use_next = unmarked_next(in_use_tail);
if (cur_om != in_use_next) {
// The NULL is because of async deflation so try again:
cur_om = in_use_next;
continue;
}
// Implied else: The NULL is because of GC, but we leave the
// node on the in-use list to be deflated after it has been
// moved to the global in-use list.
}
in_use_tail = cur_om;
in_use_count++;
@ -1785,7 +1763,7 @@ void ObjectSynchronizer::om_flush(Thread* self) {
}
free_tail = s;
free_count++;
guarantee(s->object() == NULL, "invariant");
guarantee(s->object_peek() == NULL, "invariant");
if (s->is_busy()) {
stringStream ss;
fatal("must be !is_busy: %s", s->is_busy_to_string(&ss));
@ -2101,38 +2079,47 @@ bool ObjectSynchronizer::deflate_monitor_using_JT(ObjectMonitor* mid,
return false;
}
// Set a NULL owner to DEFLATER_MARKER to force any contending thread
// through the slow path. This is just the first part of the async
// deflation dance.
if (mid->try_set_owner_from(NULL, DEFLATER_MARKER) != NULL) {
// The owner field is no longer NULL so we lost the race since the
// ObjectMonitor is now busy.
return false;
}
const oop obj = mid->object_peek();
if (mid->contentions() > 0 || mid->_waiters != 0) {
// Another thread has raced to enter the ObjectMonitor after
// mid->is_busy() above or has already entered and waited on
// it which makes it busy so no deflation. Restore owner to
// NULL if it is still DEFLATER_MARKER.
if (mid->try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) {
// Deferred decrement for the JT EnterI() that cancelled the async deflation.
mid->add_to_contentions(-1);
if (obj == NULL) {
// If the object died, we can recycle the monitor without racing with
// Java threads. The GC already broke the association with the object.
mid->set_owner_from(NULL, DEFLATER_MARKER);
mid->_contentions = -max_jint;
} else {
// Set a NULL owner to DEFLATER_MARKER to force any contending thread
// through the slow path. This is just the first part of the async
// deflation dance.
if (mid->try_set_owner_from(NULL, DEFLATER_MARKER) != NULL) {
// The owner field is no longer NULL so we lost the race since the
// ObjectMonitor is now busy.
return false;
}
return false;
}
// Make a zero contentions field negative to force any contending threads
// to retry. This is the second part of the async deflation dance.
if (Atomic::cmpxchg(&mid->_contentions, (jint)0, -max_jint) != 0) {
// Contentions was no longer 0 so we lost the race since the
// ObjectMonitor is now busy. Restore owner to NULL if it is
// still DEFLATER_MARKER:
if (mid->try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) {
// Deferred decrement for the JT EnterI() that cancelled the async deflation.
mid->add_to_contentions(-1);
if (mid->contentions() > 0 || mid->_waiters != 0) {
// Another thread has raced to enter the ObjectMonitor after
// mid->is_busy() above or has already entered and waited on
// it which makes it busy so no deflation. Restore owner to
// NULL if it is still DEFLATER_MARKER.
if (mid->try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) {
// Deferred decrement for the JT EnterI() that cancelled the async deflation.
mid->add_to_contentions(-1);
}
return false;
}
// Make a zero contentions field negative to force any contending threads
// to retry. This is the second part of the async deflation dance.
if (Atomic::cmpxchg(&mid->_contentions, (jint)0, -max_jint) != 0) {
// Contentions was no longer 0 so we lost the race since the
// ObjectMonitor is now busy. Restore owner to NULL if it is
// still DEFLATER_MARKER:
if (mid->try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) {
// Deferred decrement for the JT EnterI() that cancelled the async deflation.
mid->add_to_contentions(-1);
}
return false;
}
return false;
}
// Sanity checks for the races:
@ -2146,22 +2133,23 @@ bool ObjectSynchronizer::deflate_monitor_using_JT(ObjectMonitor* mid,
"must be no entering threads: EntryList=" INTPTR_FORMAT,
p2i(mid->_EntryList));
const oop obj = mid->object();
if (log_is_enabled(Trace, monitorinflation)) {
ResourceMark rm;
log_trace(monitorinflation)("deflate_monitor_using_JT: "
"object=" INTPTR_FORMAT ", mark="
INTPTR_FORMAT ", type='%s'",
p2i(obj), obj->mark().value(),
obj->klass()->external_name());
}
if (obj != NULL) {
if (log_is_enabled(Trace, monitorinflation)) {
ResourceMark rm;
log_trace(monitorinflation)("deflate_monitor_using_JT: "
"object=" INTPTR_FORMAT ", mark="
INTPTR_FORMAT ", type='%s'",
p2i(obj), obj->mark().value(),
obj->klass()->external_name());
}
// Install the old mark word if nobody else has already done it.
mid->install_displaced_markword_in_object(obj);
// Install the old mark word if nobody else has already done it.
mid->install_displaced_markword_in_object(obj);
}
mid->clear_common();
assert(mid->object() == NULL, "must be NULL: object=" INTPTR_FORMAT,
p2i(mid->object()));
assert(mid->object_peek() == NULL, "must be NULL: object=" INTPTR_FORMAT,
p2i(mid->object_peek()));
assert(mid->is_free(), "must be free: allocation_state=%d",
(int)mid->allocation_state());
@ -2256,10 +2244,9 @@ int ObjectSynchronizer::deflate_monitor_list_using_JT(ObjectMonitor** list_p,
next_next = unmarked_next(next);
}
// Only try to deflate if there is an associated Java object and if
// mid is old (is not newly allocated and is not newly freed).
if (mid->object() != NULL && mid->is_old() &&
deflate_monitor_using_JT(mid, free_head_p, free_tail_p)) {
// Only try to deflate if mid is old (is not newly allocated and
// is not newly freed).
if (mid->is_old() && deflate_monitor_using_JT(mid, free_head_p, free_tail_p)) {
// Deflation succeeded and already updated free_head_p and
// free_tail_p as needed. Finish the move to the local free list
// by unlinking mid from the global or per-thread in-use list.
@ -2290,9 +2277,8 @@ int ObjectSynchronizer::deflate_monitor_list_using_JT(ObjectMonitor** list_p,
mid = next; // mid keeps non-NULL next's locked state
next = next_next;
} else {
// mid is considered in-use if it does not have an associated
// Java object or mid is not old or deflation did not succeed.
// A mid->is_new() node can be seen here when it is freshly
// mid is considered in-use if mid is not old or deflation did not
// succeed. A mid->is_new() node can be seen here when it is freshly
// returned by om_alloc() (and skips the deflation code path).
// A mid->is_old() node can be seen here when deflation failed.
// A mid->is_free() node can be seen here when a fresh node from
@ -2717,16 +2703,16 @@ void ObjectSynchronizer::chk_free_entry(JavaThread* jt, ObjectMonitor* n,
*error_cnt_p = *error_cnt_p + 1;
}
}
if (n->object() != NULL) {
if (n->object_peek() != NULL) {
if (jt != NULL) {
out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
": free per-thread monitor must have NULL _object "
"field: _object=" INTPTR_FORMAT, p2i(jt), p2i(n),
p2i(n->object()));
p2i(n->object_peek()));
} else {
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor "
"must have NULL _object field: _object=" INTPTR_FORMAT,
p2i(n), p2i(n->object()));
p2i(n), p2i(n->object_peek()));
}
*error_cnt_p = *error_cnt_p + 1;
}
@ -2856,48 +2842,39 @@ void ObjectSynchronizer::chk_in_use_entry(JavaThread* jt, ObjectMonitor* n,
}
*error_cnt_p = *error_cnt_p + 1;
}
if (n->object() == NULL) {
if (jt != NULL) {
out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
": in-use per-thread monitor must have non-NULL _object "
"field.", p2i(jt), p2i(n));
} else {
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global monitor "
"must have non-NULL _object field.", p2i(n));
const oop obj = n->object_peek();
if (obj != NULL) {
const markWord mark = obj->mark();
if (!mark.has_monitor()) {
if (jt != NULL) {
out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
": in-use per-thread monitor's object does not think "
"it has a monitor: obj=" INTPTR_FORMAT ", mark="
INTPTR_FORMAT, p2i(jt), p2i(n), p2i(obj), mark.value());
} else {
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global "
"monitor's object does not think it has a monitor: obj="
INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n),
p2i(obj), mark.value());
}
*error_cnt_p = *error_cnt_p + 1;
}
*error_cnt_p = *error_cnt_p + 1;
}
const oop obj = n->object();
const markWord mark = obj->mark();
if (!mark.has_monitor()) {
if (jt != NULL) {
out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
": in-use per-thread monitor's object does not think "
"it has a monitor: obj=" INTPTR_FORMAT ", mark="
INTPTR_FORMAT, p2i(jt), p2i(n), p2i(obj), mark.value());
} else {
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global "
"monitor's object does not think it has a monitor: obj="
INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n),
p2i(obj), mark.value());
ObjectMonitor* const obj_mon = mark.monitor();
if (n != obj_mon) {
if (jt != NULL) {
out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
": in-use per-thread monitor's object does not refer "
"to the same monitor: obj=" INTPTR_FORMAT ", mark="
INTPTR_FORMAT ", obj_mon=" INTPTR_FORMAT, p2i(jt),
p2i(n), p2i(obj), mark.value(), p2i(obj_mon));
} else {
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global "
"monitor's object does not refer to the same monitor: obj="
INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon="
INTPTR_FORMAT, p2i(n), p2i(obj), mark.value(), p2i(obj_mon));
}
*error_cnt_p = *error_cnt_p + 1;
}
*error_cnt_p = *error_cnt_p + 1;
}
ObjectMonitor* const obj_mon = mark.monitor();
if (n != obj_mon) {
if (jt != NULL) {
out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
": in-use per-thread monitor's object does not refer "
"to the same monitor: obj=" INTPTR_FORMAT ", mark="
INTPTR_FORMAT ", obj_mon=" INTPTR_FORMAT, p2i(jt),
p2i(n), p2i(obj), mark.value(), p2i(obj_mon));
} else {
out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global "
"monitor's object does not refer to the same monitor: obj="
INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon="
INTPTR_FORMAT, p2i(n), p2i(obj), mark.value(), p2i(obj_mon));
}
*error_cnt_p = *error_cnt_p + 1;
}
}
@ -2977,12 +2954,12 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream * out) {
if ((cur = get_list_head_locked(&om_list_globals._in_use_list)) != NULL) {
// Marked the global in-use list head so process the list.
while (true) {
const oop obj = cur->object();
const oop obj = cur->object_peek();
const markWord mark = cur->header();
ResourceMark rm;
out->print(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(cur),
cur->is_busy() != 0, mark.hash() != 0, cur->owner() != NULL,
p2i(obj), obj->klass()->external_name());
p2i(obj), obj == NULL ? "" : obj->klass()->external_name());
if (cur->is_busy() != 0) {
out->print(" (%s)", cur->is_busy_to_string(&ss));
ss.reset();
@ -3007,13 +2984,13 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream * out) {
if ((cur = get_list_head_locked(&jt->om_in_use_list)) != NULL) {
// Marked the global in-use list head so process the list.
while (true) {
const oop obj = cur->object();
const oop obj = cur->object_peek();
const markWord mark = cur->header();
ResourceMark rm;
out->print(INTPTR_FORMAT " " INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT
" %s", p2i(jt), p2i(cur), cur->is_busy() != 0,
mark.hash() != 0, cur->owner() != NULL, p2i(obj),
obj->klass()->external_name());
obj == NULL ? "" : obj->klass()->external_name());
if (cur->is_busy() != 0) {
out->print(" (%s)", cur->is_busy_to_string(&ss));
ss.reset();
@ -3069,7 +3046,7 @@ int ObjectSynchronizer::log_monitor_list_counts(outputStream * out) {
int ObjectSynchronizer::verify_objmon_isinpool(ObjectMonitor *monitor) {
PaddedObjectMonitor* block = Atomic::load(&g_block_list);
while (block != NULL) {
assert(block->object() == CHAINMARKER, "must be a block header");
assert(block->is_chainmarker(), "must be a block header");
if (monitor > &block[0] && monitor < &block[_BLOCKSIZE]) {
address mon = (address)monitor;
address blk = (address)block;

@ -150,9 +150,6 @@ class ObjectSynchronizer : AllStatic {
static bool request_deflate_idle_monitors(); // for whitebox test support and VM exit logging
static void set_is_async_deflation_requested(bool new_value) { _is_async_deflation_requested = new_value; }
static jlong time_since_last_async_deflation_ms();
static void oops_do(OopClosure* f);
// Process oops in thread local used monitors
static void thread_local_used_oops_do(Thread* thread, OopClosure* f);
// debugging
static void audit_and_print_stats(bool on_exit);
@ -190,11 +187,6 @@ class ObjectSynchronizer : AllStatic {
// Function to prepend new blocks to the appropriate lists:
static void prepend_block_to_lists(PaddedObjectMonitor* new_blk);
// Process oops in all global used monitors (i.e. moribund thread's monitors)
static void global_used_oops_do(OopClosure* f);
// Process oops in monitors on the given list
static void list_oops_do(ObjectMonitor* list, OopClosure* f);
// Support for SynchronizerTest access to GVars fields:
static u_char* get_gvars_addr();
static u_char* get_gvars_hc_sequence_addr();

@ -889,10 +889,6 @@ void Thread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
// Do oop for ThreadShadow
f->do_oop((oop*)&_pending_exception);
handle_area()->oops_do(f);
// We scan thread local monitor lists here, and the remaining global
// monitors in ObjectSynchronizer::oops_do().
ObjectSynchronizer::thread_local_used_oops_do(this, f);
}
void Thread::metadata_handles_do(void f(Metadata*)) {
@ -2217,11 +2213,6 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
thread_name = os::strdup(get_thread_name());
}
// We must flush any deferred card marks and other various GC barrier
// related buffers (e.g. G1 SATB buffer and G1 dirty card queue buffer)
// before removing a thread from the list of active threads.
BarrierSet::barrier_set()->on_thread_detach(this);
log_info(os, thread)("JavaThread %s (tid: " UINTX_FORMAT ").",
exit_type == JavaThread::normal_exit ? "exiting" : "detaching",
os::current_thread_id());
@ -2269,8 +2260,6 @@ void JavaThread::cleanup_failed_attach_current_thread(bool is_daemon) {
tlab().retire();
}
BarrierSet::barrier_set()->on_thread_detach(this);
Threads::remove(this, is_daemon);
this->smr_delete();
}
@ -4598,6 +4587,13 @@ void Threads::remove(JavaThread* p, bool is_daemon) {
// Reclaim the ObjectMonitors from the om_in_use_list and om_free_list of the moribund thread.
ObjectSynchronizer::om_flush(p);
// We must flush any deferred card marks and other various GC barrier
// related buffers (e.g. G1 SATB buffer and G1 dirty card queue buffer)
// before removing a thread from the list of active threads.
// This must be done after ObjectSynchronizer::om_flush(), as GC barriers
// are used in om_flush().
BarrierSet::barrier_set()->on_thread_detach(p);
// Extra scope needed for Thread_lock, so we can check
// that we do not remove thread without safepoint code notice
{ MonitorLocker ml(Threads_lock);

@ -1379,27 +1379,6 @@ void JNIGlobalsDumper::do_oop(oop* obj_p) {
}
};
// Support class used to generate HPROF_GC_ROOT_MONITOR_USED records
class MonitorUsedDumper : public OopClosure {
private:
DumpWriter* _writer;
DumpWriter* writer() const { return _writer; }
public:
MonitorUsedDumper(DumpWriter* writer) {
_writer = writer;
}
void do_oop(oop* obj_p) {
u4 size = 1 + sizeof(address);
writer()->start_sub_record(HPROF_GC_ROOT_MONITOR_USED, size);
writer()->write_objectID(*obj_p);
writer()->end_sub_record();
}
void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
};
// Support class used to generate HPROF_GC_ROOT_STICKY_CLASS records
class StickyClassDumper : public KlassClosure {
@ -1852,10 +1831,6 @@ void VM_HeapDumper::work(uint worker_id) {
// HPROF_GC_ROOT_THREAD_OBJ + frames + jni locals
do_threads();
// HPROF_GC_ROOT_MONITOR_USED
MonitorUsedDumper mon_dumper(writer());
ObjectSynchronizer::oops_do(&mon_dumper);
// HPROF_GC_ROOT_JNI_GLOBAL
JNIGlobalsDumper jni_dumper(writer());
JNIHandles::oops_do(&jni_dumper);

@ -92,7 +92,11 @@ public class ObjectMonitor extends VMObject {
public long recursions() { return recursionsField.getValue(addr); }
public OopHandle object() {
return addr.getOopHandleAt(objectFieldOffset);
Address objAddr = addr.getAddressAt(objectFieldOffset);
if (objAddr == null) {
return null;
}
return objAddr.getOopHandleAt(0);
}
public int contentions() {

@ -121,7 +121,6 @@ public class TestGCLogMessages {
new LogMessageWithLevel("LAB Undo Waste", Level.DEBUG),
// Ext Root Scan
new LogMessageWithLevel("Thread Roots", Level.TRACE),
new LogMessageWithLevel("ObjectSynchronizer Roots", Level.TRACE),
new LogMessageWithLevel("CLDG Roots", Level.TRACE),
new LogMessageWithLevel("CM RefProcessor Roots", Level.TRACE),
new LogMessageWithLevel("JNI Global Roots", Level.TRACE),

@ -203,10 +203,6 @@ public class TestHumongousClassLoader {
gc.provoke();
boolean did_deflation = WB.deflateIdleMonitors();
Asserts.assertEQ(did_deflation, true,
"deflateIdleMonitors() should have worked.");
// Test checks
Asserts.assertEquals(WB.isClassAlive(HUMONGOUS_CLASSLOADER_NAME), false,
String.format("Classloader class %s is loaded after we forget all references to it",

@ -91,7 +91,6 @@ public class TestG1ParallelPhases {
Set<String> allPhases = of(
"ExtRootScan",
"ThreadRoots",
"ObjectSynchronizerRoots",
"VM Global",
"JNI Global",
"Thread OopStorage",