PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC void markOopDesc::print_on(outputStream* st) const { if (is_marked()) { st->print(" marked(" INTPTR_FORMAT ")", value()); } else if (has_monitor()) { // have to check has_monitor() before is_locked() st->print(" monitor(" INTPTR_FORMAT ")=", value()); ObjectMonitor* mon = monitor(); if (mon == NULL) { st->print("NULL (this should never be seen!)"); } else { st->print("{count=" INTPTR_FORMAT ",waiters=" INTPTR_FORMAT ",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}", mon->count(), mon->waiters(), mon->recursions(), p2i(mon->owner())); } } else if (is_locked()) { st->print(" locked(" INTPTR_FORMAT ")->", value()); if (is_neutral()) { st->print("is_neutral"); if (has_no_hash()) { st->print(" no_hash"); } else { st->print(" hash=" INTPTR_FORMAT, hash()); } st->print(" age=%d", age()); } else if (has_bias_pattern()) { st->print("is_biased"); JavaThread* jt = biased_locker(); st->print(" biased_locker=" INTPTR_FORMAT, p2i(jt)); } else { st->print("??"); } } else { assert(is_unlocked() || has_bias_pattern(), "just checking"); st->print("mark("); if (has_bias_pattern()) st->print("biased,"); st->print("hash %#lx,", hash()); st->print("age %d)", age()); } }
jvmtiError JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject object, jvmtiMonitorUsage* info_ptr) { HandleMark hm; Handle hobj; bool at_safepoint = SafepointSynchronize::is_at_safepoint(); // Check arguments { oop mirror = JNIHandles::resolve_external_guard(object); NULL_CHECK(mirror, JVMTI_ERROR_INVALID_OBJECT); NULL_CHECK(info_ptr, JVMTI_ERROR_NULL_POINTER); hobj = Handle(mirror); } JavaThread *owning_thread = NULL; ObjectMonitor *mon = NULL; jvmtiMonitorUsage ret = { NULL, 0, 0, NULL, 0, NULL }; uint32_t debug_bits = 0; // first derive the object's owner and entry_count (if any) { // Revoke any biases before querying the mark word if (SafepointSynchronize::is_at_safepoint()) { BiasedLocking::revoke_at_safepoint(hobj); } else { BiasedLocking::revoke_and_rebias(hobj, false, calling_thread); } address owner = NULL; { markOop mark = hobj()->mark(); if (!mark->has_monitor()) { // this object has a lightweight monitor if (mark->has_locker()) { owner = (address)mark->locker(); // save the address of the Lock word } // implied else: no owner } else { // this object has a heavyweight monitor mon = mark->monitor(); // The owner field of a heavyweight monitor may be NULL for no // owner, a JavaThread * or it may still be the address of the // Lock word in a JavaThread's stack. A monitor can be inflated // by a non-owning JavaThread, but only the owning JavaThread // can change the owner field from the Lock word to the // JavaThread * and it may not have done that yet. owner = (address)mon->owner(); } } if (owner != NULL) { // This monitor is owned so we have to find the owning JavaThread. // Since owning_thread_from_monitor_owner() grabs a lock, GC can // move our object at this point. However, our owner value is safe // since it is either the Lock word on a stack or a JavaThread *. owning_thread = Threads::owning_thread_from_monitor_owner(owner, !at_safepoint); // Cannot assume (owning_thread != NULL) here because this function // may not have been called at a safepoint and the owning_thread // might not be suspended. if (owning_thread != NULL) { // The monitor's owner either has to be the current thread, at safepoint // or it has to be suspended. Any of these conditions will prevent both // contending and waiting threads from modifying the state of // the monitor. if (!at_safepoint && !JvmtiEnv::is_thread_fully_suspended(owning_thread, true, &debug_bits)) { // Don't worry! This return of JVMTI_ERROR_THREAD_NOT_SUSPENDED // will not make it back to the JVM/TI agent. The error code will // get intercepted in JvmtiEnv::GetObjectMonitorUsage() which // will retry the call via a VM_GetObjectMonitorUsage VM op. return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } HandleMark hm; Handle th(owning_thread->threadObj()); ret.owner = (jthread)jni_reference(calling_thread, th); } // implied else: no owner } if (owning_thread != NULL) { // monitor is owned // The recursions field of a monitor does not reflect recursions // as lightweight locks before inflating the monitor are not included. // We have to count the number of recursive monitor entries the hard way. // We pass a handle to survive any GCs along the way. ResourceMark rm; ret.entry_count = count_locked_objects(owning_thread, hobj); } // implied else: entry_count == 0 } jint nWant, nWait; if (mon != NULL) { // this object has a heavyweight monitor nWant = mon->contentions(); // # of threads contending for monitor nWait = mon->waiters(); // # of threads in Object.wait() ret.waiter_count = nWant + nWait; ret.notify_waiter_count = nWait; } else { // this object has a lightweight monitor ret.waiter_count = 0; ret.notify_waiter_count = 0; } // Allocate memory for heavyweight and lightweight monitor. jvmtiError err; err = allocate(ret.waiter_count * sizeof(jthread *), (unsigned char**)&ret.waiters); if (err != JVMTI_ERROR_NONE) { return err; } err = allocate(ret.notify_waiter_count * sizeof(jthread *), (unsigned char**)&ret.notify_waiters); if (err != JVMTI_ERROR_NONE) { deallocate((unsigned char*)ret.waiters); return err; } // now derive the rest of the fields if (mon != NULL) { // this object has a heavyweight monitor // Number of waiters may actually be less than the waiter count. // So NULL out memory so that unused memory will be NULL. memset(ret.waiters, 0, ret.waiter_count * sizeof(jthread *)); memset(ret.notify_waiters, 0, ret.notify_waiter_count * sizeof(jthread *)); if (ret.waiter_count > 0) { // we have contending and/or waiting threads HandleMark hm; if (nWant > 0) { // we have contending threads ResourceMark rm; // get_pending_threads returns only java thread so we do not need to // check for non java threads. GrowableArray<JavaThread*>* wantList = Threads::get_pending_threads( nWant, (address)mon, !at_safepoint); if (wantList->length() < nWant) { // robustness: the pending list has gotten smaller nWant = wantList->length(); } for (int i = 0; i < nWant; i++) { JavaThread *pending_thread = wantList->at(i); // If the monitor has no owner, then a non-suspended contending // thread could potentially change the state of the monitor by // entering it. The JVM/TI spec doesn't allow this. if (owning_thread == NULL && !at_safepoint & !JvmtiEnv::is_thread_fully_suspended(pending_thread, true, &debug_bits)) { if (ret.owner != NULL) { destroy_jni_reference(calling_thread, ret.owner); } for (int j = 0; j < i; j++) { destroy_jni_reference(calling_thread, ret.waiters[j]); } deallocate((unsigned char*)ret.waiters); deallocate((unsigned char*)ret.notify_waiters); return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } Handle th(pending_thread->threadObj()); ret.waiters[i] = (jthread)jni_reference(calling_thread, th); } } if (nWait > 0) { // we have threads in Object.wait() int offset = nWant; // add after any contending threads ObjectWaiter *waiter = mon->first_waiter(); for (int i = 0, j = 0; i < nWait; i++) { if (waiter == NULL) { // robustness: the waiting list has gotten smaller nWait = j; break; } Thread *t = mon->thread_of_waiter(waiter); if (t != NULL && t->is_Java_thread()) { JavaThread *wjava_thread = (JavaThread *)t; // If the thread was found on the ObjectWaiter list, then // it has not been notified. This thread can't change the // state of the monitor so it doesn't need to be suspended. Handle th(wjava_thread->threadObj()); ret.waiters[offset + j] = (jthread)jni_reference(calling_thread, th); ret.notify_waiters[j++] = (jthread)jni_reference(calling_thread, th); } waiter = mon->next_waiter(waiter); } } } // Adjust count. nWant and nWait count values may be less than original. ret.waiter_count = nWant + nWait; ret.notify_waiter_count = nWait; } else { // this object has a lightweight monitor and we have nothing more // to do here because the defaults are just fine. } // we don't update return parameter unless everything worked *info_ptr = ret; return JVMTI_ERROR_NONE; }