diff -r c604234be658 -r 04857e2cd509 src/hotspot/share/runtime/synchronizer.cpp --- a/src/hotspot/share/runtime/synchronizer.cpp Wed Apr 24 15:37:55 2019 +0200 +++ b/src/hotspot/share/runtime/synchronizer.cpp Wed Apr 24 10:20:25 2019 -0400 @@ -735,7 +735,7 @@ } else if (mark->has_monitor()) { monitor = mark->monitor(); temp = monitor->header(); - assert(temp->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i((address)temp)); + assert(temp->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(temp)); hash = temp->hash(); if (hash != 0) { return hash; @@ -743,39 +743,38 @@ // Skip to the following code to reduce code size } else if (Self->is_lock_owned((address)mark->locker())) { temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned - assert(temp->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i((address)temp)); + assert(temp->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(temp)); hash = temp->hash(); // by current thread, check if the displaced if (hash != 0) { // header contains hash code return hash; } // WARNING: - // The displaced header is strictly immutable. - // It can NOT be changed in ANY cases. So we have - // to inflate the header into heavyweight monitor - // even the current thread owns the lock. The reason - // is the BasicLock (stack slot) will be asynchronously - // read by other threads during the inflate() function. - // Any change to stack may not propagate to other threads - // correctly. + // The displaced header in the BasicLock on a thread's stack + // is strictly immutable. It CANNOT be changed in ANY cases. + // So we have to inflate the stack lock into an ObjectMonitor + // even if the current thread owns the lock. The BasicLock on + // a thread's stack can be asynchronously read by other threads + // during an inflate() call so any change to that stack memory + // may not propagate to other threads correctly. } // Inflate the monitor to set hash code monitor = inflate(Self, obj, inflate_cause_hash_code); // Load displaced header and check it has hash code mark = monitor->header(); - assert(mark->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i((address)mark)); + assert(mark->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(mark)); hash = mark->hash(); if (hash == 0) { hash = get_next_hash(Self, obj); temp = mark->copy_set_hash(hash); // merge hash code into header - assert(temp->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i((address)temp)); + assert(temp->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(temp)); test = Atomic::cmpxchg(temp, monitor->header_addr(), mark); if (test != mark) { - // The only update to the header in the monitor (outside GC) - // is install the hash code. If someone add new usage of - // displaced header, please update this code + // The only update to the ObjectMonitor's header/dmw field + // is to merge in the hash code. If someone adds a new usage + // of the header/dmw field, please update this code. hash = test->hash(); - assert(test->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i((address)test)); + assert(test->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(test)); assert(hash != 0, "Trivial unexpected object/monitor header usage."); } } @@ -1334,7 +1333,7 @@ if (mark->has_monitor()) { ObjectMonitor * inf = mark->monitor(); markOop dmw = inf->header(); - assert(dmw->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i((address)dmw)); + assert(dmw->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(dmw)); assert(oopDesc::equals((oop) inf->object(), object), "invariant"); assert(ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid"); return inf; @@ -1398,7 +1397,7 @@ // Consider what happens when a thread unlocks a stack-locked object. // It attempts to use CAS to swing the displaced header value from the // on-stack basiclock back into the object header. Recall also that the - // header value (hashcode, etc) can reside in (a) the object header, or + // header value (hash code, etc) can reside in (a) the object header, or // (b) a displaced header associated with the stack-lock, or (c) a displaced // header in an objectMonitor. The inflate() routine must copy the header // value from the basiclock on the owner's stack to the objectMonitor, all @@ -1419,7 +1418,9 @@ // object is in the mark. Furthermore the owner can't complete // an unlock on the object, either. markOop dmw = mark->displaced_mark_helper(); - assert(dmw->is_neutral(), "invariant"); + // Catch if the object's header is not neutral (not locked and + // not marked is what we care about here). + assert(dmw->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(dmw)); // Setup monitor fields to proper values -- prepare the monitor m->set_header(dmw); @@ -1463,7 +1464,9 @@ // An inflateTry() method that we could call from fast_enter() and slow_enter() // would be useful. - assert(mark->is_neutral(), "invariant"); + // Catch if the object's header is not neutral (not locked and + // not marked is what we care about here). + assert(mark->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(mark)); ObjectMonitor * m = omAlloc(Self); // prepare m for installation - set monitor to initial state m->Recycle(); @@ -1503,7 +1506,7 @@ } -// We create a list of in-use monitors for each thread. +// We maintain a list of in-use monitors for each thread. // // deflate_thread_local_monitors() scans a single thread's in-use list, while // deflate_idle_monitors() scans only a global list of in-use monitors which @@ -1512,7 +1515,7 @@ // These operations are called at all safepoints, immediately after mutators // are stopped, but before any objects have moved. Collectively they traverse // the population of in-use monitors, deflating where possible. The scavenged -// monitors are returned to the monitor free list. +// monitors are returned to the global monitor free list. // // Beware that we scavenge at *every* stop-the-world point. Having a large // number of monitors in-use could negatively impact performance. We also want @@ -1521,7 +1524,7 @@ // // Perversely, the heap size -- and thus the STW safepoint rate -- // typically drives the scavenge rate. Large heaps can mean infrequent GC, -// which in turn can mean large(r) numbers of objectmonitors in circulation. +// which in turn can mean large(r) numbers of ObjectMonitors in circulation. // This is an unfortunate aspect of this design. // Deflate a single monitor if not in-use @@ -1531,9 +1534,15 @@ ObjectMonitor** freeTailp) { bool deflated; // Normal case ... The monitor is associated with obj. - guarantee(obj->mark() == markOopDesc::encode(mid), "invariant"); - guarantee(mid == obj->mark()->monitor(), "invariant"); - guarantee(mid->header()->is_neutral(), "invariant"); + const markOop mark = obj->mark(); + guarantee(mark == markOopDesc::encode(mid), "should match: mark=" + INTPTR_FORMAT ", encoded mid=" INTPTR_FORMAT, p2i(mark), + p2i(markOopDesc::encode(mid))); + // Make sure that mark->monitor() and markOopDesc::encode() agree: + guarantee(mark->monitor() == mid, "should match: monitor()=" INTPTR_FORMAT + ", mid=" INTPTR_FORMAT, p2i(mark->monitor()), p2i(mid)); + const markOop dmw = mid->header(); + guarantee(dmw->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(dmw)); if (mid->is_busy()) { deflated = false; @@ -1544,16 +1553,17 @@ if (log_is_enabled(Trace, monitorinflation)) { ResourceMark rm; log_trace(monitorinflation)("deflate_monitor: " - "object=" INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", type='%s'", - p2i(obj), p2i(obj->mark()), - obj->klass()->external_name()); + "object=" INTPTR_FORMAT ", mark=" + INTPTR_FORMAT ", type='%s'", p2i(obj), + p2i(mark), obj->klass()->external_name()); } // Restore the header back to obj - obj->release_set_mark(mid->header()); + obj->release_set_mark(dmw); mid->clear(); - assert(mid->object() == NULL, "invariant"); + assert(mid->object() == NULL, "invariant: object=" INTPTR_FORMAT, + p2i(mid->object())); // Move the object to the working free list defined by freeHeadp, freeTailp if (*freeHeadp == NULL) *freeHeadp = mid; @@ -2022,13 +2032,12 @@ 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((address)obj), - p2i((address)mark)); + INTPTR_FORMAT, p2i(jt), p2i(n), p2i(obj), p2i(mark)); } 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((address)obj), p2i((address)mark)); + p2i(obj), p2i(mark)); } *error_cnt_p = *error_cnt_p + 1; } @@ -2039,14 +2048,12 @@ ": 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((address)obj), p2i((address)mark), - p2i((address)obj_mon)); + p2i(n), p2i(obj), p2i(mark), 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((address)obj), - p2i((address)mark), p2i((address)obj_mon)); + INTPTR_FORMAT, p2i(n), p2i(obj), p2i(mark), p2i(obj_mon)); } *error_cnt_p = *error_cnt_p + 1; } @@ -2105,7 +2112,7 @@ if (gOmInUseCount > 0) { out->print_cr("In-use global monitor info:"); - out->print_cr("(B -> is_busy, H -> has hashcode, L -> lock status)"); + out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)"); out->print_cr("%18s %s %18s %18s", "monitor", "BHL", "object", "object type"); out->print_cr("================== === ================== =================="); @@ -2124,7 +2131,7 @@ } out->print_cr("In-use per-thread monitor info:"); - out->print_cr("(B -> is_busy, H -> has hashcode, L -> lock status)"); + out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)"); out->print_cr("%18s %18s %s %18s %18s", "jt", "monitor", "BHL", "object", "object type"); out->print_cr("================== ================== === ================== ==================");