--- old/src/share/vm/runtime/vframe.cpp Fri Jul 3 16:39:56 2015 +++ new/src/share/vm/runtime/vframe.cpp Fri Jul 3 16:39:55 2015 @@ -160,17 +160,29 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { ResourceMark rm; - // If this is the first frame, and java.lang.Object.wait(...) then print out the receiver. + // If this is the first frame and it is java.lang.Object.wait(...) + // then print out the receiver. Locals are not always available, + // e.g., compiled native frames have no scope so there are no locals. if (frame_count == 0) { if (method()->name() == vmSymbols::wait_name() && method()->method_holder()->name() == vmSymbols::java_lang_Object()) { + const char *wait_state = "waiting on"; // assume we are waiting + // It would be nice to distinguish between "waiting on" and + // "waited on". Currently, "waiting on" here with a + // java.lang.Thread.State == "WAITING (on object monitor)" + // earlier in the output means that the monitor has not yet been + // notified and java.lang.Thread.State == "BLOCKED (on object + // monitor)" earlier in the output means that the monitor has + // been notified and the thread is blocked on reentry. StackValueCollection* locs = locals(); if (!locs->is_empty()) { StackValue* sv = locs->at(0); if (sv->type() == T_OBJECT) { Handle o = locs->at(0)->get_obj(); - print_locked_object_class_name(st, o, "waiting on"); + print_locked_object_class_name(st, o, wait_state); } + } else { + st->print_cr("\t- %s ", wait_state); } } else if (thread()->current_park_blocker() != NULL) { oop obj = thread()->current_park_blocker(); @@ -180,7 +192,8 @@ } - // Print out all monitors that we have locked or are trying to lock + // Print out all monitors that we have locked, are trying to lock + // or are trying to relock after a wait(). GrowableArray* mons = monitors(); if (!mons->is_empty()) { bool found_first_monitor = false; @@ -202,14 +215,14 @@ if (monitor->owner() != NULL) { // the monitor is associated with an object, i.e., it is locked - // First, assume we have the monitor locked. If we haven't found an - // owned monitor before and this is the first frame, then we need to - // see if we have completed the lock or we are blocked trying to - // acquire it - we can only be blocked if the monitor is inflated - markOop mark = NULL; const char *lock_state = "locked"; // assume we have the monitor locked if (!found_first_monitor && frame_count == 0) { + // If this is the first frame and we haven't found an owned + // monitor before, then we need to see if we have completed + // the lock or if we are blocked trying to acquire it. Only + // an inflated monitor that is first on the monitor list in + // the first frame can block us on a monitor enter. mark = monitor->owner()->mark(); if (mark->has_monitor() && ( // we have marked ourself as pending on this monitor @@ -219,13 +232,33 @@ )) { lock_state = "waiting to lock"; } else { - mark = NULL; // Disable printing below + // We own the monitor which is not as interesting so + // disable the extra printing below. + mark = NULL; } + } else if (frame_count != 0) { + // This is not the first frame so we either own this monitor + // or we owned the monitor before and called wait(). Because + // wait() could have been called on any monitor in a lower + // numbered frame on the stack, we have to check all the + // monitors on the list for this frame. + mark = monitor->owner()->mark(); + if (mark->has_monitor() && + ( // we have marked ourself as pending on this monitor + mark->monitor() == thread()->current_pending_monitor() || + // we are not the owner of this monitor + !mark->monitor()->is_entered(thread()) + )) { + lock_state = "waiting to relock"; + } else { + // We own the monitor which is not as interesting so + // disable the extra printing below. + mark = NULL; + } } print_locked_object_class_name(st, monitor->owner(), lock_state); - if (Verbose && mark != NULL) { - // match with format above, replacing "-" with " ". - st->print("\t lockbits="); + if (VerboseStackTrace && mark != NULL) { + st->print("\t- lockbits="); mark->print_on(st); st->cr(); }