diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index a6cdebea7b8..6f9c00f27da 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -3569,7 +3569,7 @@ encode %{ // Store a non-null value into the box to avoid looking like a re-entrant // lock. The fast-path monitor unlock code checks for // markWord::monitor_value so use markWord::unused_mark which has the - // relevant bit set, and also matches ObjectSynchronizer::slow_enter. + // relevant bit set, and also matches ObjectSynchronizer::enter. __ mov(tmp, (address)markWord::unused_mark().value()); __ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp index 5f3194bc390..ec0f7f71d88 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp @@ -2607,8 +2607,8 @@ void MacroAssembler::biased_locking_exit (Address mark_addr, Register temp_reg, // - Successful Stack-lock: box->dhw == mark. // box->dhw must contain the displaced mark word value // - Failure -- icc.ZFlag == 0 and box->dhw is undefined. -// The slow-path fast_enter() and slow_enter() operators -// are responsible for setting box->dhw = NonZero (typically markWord::unused_mark()). +// The slow-path enter() is responsible for setting +// box->dhw = NonZero (typically markWord::unused_mark()). // - Biased: box->dhw is undefined // // SPARC refworkload performance - specifically jetstream and scimark - are diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 30180e719fa..51f0c9df4da 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1620,8 +1620,8 @@ void MacroAssembler::rtm_inflated_locking(Register objReg, Register boxReg, Regi // See also: cmpFastLock and cmpFastUnlock. // // What follows is a specialized inline transliteration of the code -// in slow_enter() and slow_exit(). If we're concerned about I$ bloat -// another option would be to emit TrySlowEnter and TrySlowExit methods +// in enter() and exit(). If we're concerned about I$ bloat another +// option would be to emit TrySlowEnter and TrySlowExit methods // at startup-time. These methods would accept arguments as // (rax,=Obj, rbx=Self, rcx=box, rdx=Scratch) and return success-failure // indications in the icc.ZFlag. Fast_Lock and Fast_Unlock would simply diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 3476fc5b381..df080d77cdc 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -705,19 +705,11 @@ JRT_ENTRY_NO_ASYNC(void, Runtime1::monitorenter(JavaThread* thread, oopDesc* obj Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); } Handle h_obj(thread, obj); - if (UseBiasedLocking) { - // Retry fast entry if bias is revoked to avoid unnecessary inflation - ObjectSynchronizer::fast_enter(h_obj, lock->lock(), true, CHECK); - } else { - if (UseFastLocking) { - // When using fast locking, the compiled code has already tried the fast case - assert(obj == lock->obj(), "must match"); - ObjectSynchronizer::slow_enter(h_obj, lock->lock(), THREAD); - } else { - lock->set_obj(obj); - ObjectSynchronizer::fast_enter(h_obj, lock->lock(), false, THREAD); - } + if (!UseFastLocking) { + lock->set_obj(obj); } + assert(obj == lock->obj(), "must match"); + ObjectSynchronizer::enter(h_obj, lock->lock(), THREAD); JRT_END @@ -730,12 +722,7 @@ JRT_LEAF(void, Runtime1::monitorexit(JavaThread* thread, BasicObjectLock* lock)) oop obj = lock->obj(); assert(oopDesc::is_oop(obj), "must be NULL or an object"); - if (UseFastLocking) { - // When using fast locking, the compiled code has already tried the fast case - ObjectSynchronizer::slow_exit(obj, lock->lock(), THREAD); - } else { - ObjectSynchronizer::fast_exit(obj, lock->lock(), THREAD); - } + ObjectSynchronizer::exit(obj, lock->lock(), THREAD); JRT_END // Cf. OptoRuntime::deoptimize_caller_frame diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 4e95301f00e..6dc142f5c89 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -771,12 +771,7 @@ JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, Ba Handle h_obj(thread, elem->obj()); assert(Universe::heap()->is_in_reserved_or_null(h_obj()), "must be NULL or an object"); - if (UseBiasedLocking) { - // Retry fast entry if bias is revoked to avoid unnecessary inflation - ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK); - } else { - ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK); - } + ObjectSynchronizer::enter(h_obj, elem->lock(), CHECK); assert(Universe::heap()->is_in_reserved_or_null(elem->obj()), "must be NULL or an object"); #ifdef ASSERT @@ -796,7 +791,7 @@ JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorexit(JavaThread* thread, Bas if (elem == NULL || h_obj()->is_unlocked()) { THROW(vmSymbols::java_lang_IllegalMonitorStateException()); } - ObjectSynchronizer::slow_exit(h_obj(), elem->lock(), thread); + ObjectSynchronizer::exit(h_obj(), elem->lock(), thread); // Free entry. This must be done here, since a pending exception might be installed on // exit. If it is not cleared, the exception handling code will try to unlock the monitor again. elem->set_obj(NULL); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 67b2e995b45..12c00e84a17 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -394,17 +394,7 @@ JRT_ENTRY_NO_ASYNC(void, JVMCIRuntime::monitorenter(JavaThread* thread, oopDesc* } Handle h_obj(thread, obj); assert(oopDesc::is_oop(h_obj()), "must be NULL or an object"); - if (UseBiasedLocking) { - // Retry fast entry if bias is revoked to avoid unnecessary inflation - ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); - } else { - if (JVMCIUseFastLocking) { - // When using fast locking, the compiled code has already tried the fast case - ObjectSynchronizer::slow_enter(h_obj, lock, THREAD); - } else { - ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD); - } - } + ObjectSynchronizer::enter(h_obj, lock, THREAD); TRACE_jvmci_3("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), p2i(obj)); JRT_END @@ -426,12 +416,7 @@ JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* thread, oopDesc* obj, Basic } #endif - if (JVMCIUseFastLocking) { - // When using fast locking, the compiled code has already tried the fast case - ObjectSynchronizer::slow_exit(obj, lock, THREAD); - } else { - ObjectSynchronizer::fast_exit(obj, lock, THREAD); - } + ObjectSynchronizer::exit(obj, lock, THREAD); IF_TRACE_jvmci_3 { char type[O_BUFLEN]; obj->klass()->name()->as_C_string(type, O_BUFLEN); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 7cd21e9e5fe..b29113d2c52 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -960,7 +960,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec if (at_safepoint) { BiasedLocking::revoke_at_safepoint(hobj); } else { - BiasedLocking::revoke_and_rebias(hobj, false, calling_thread); + BiasedLocking::revoke(hobj, calling_thread); } address owner = NULL; diff --git a/src/hotspot/share/runtime/biasedLocking.cpp b/src/hotspot/share/runtime/biasedLocking.cpp index 663e127ba95..7931ec345ae 100644 --- a/src/hotspot/share/runtime/biasedLocking.cpp +++ b/src/hotspot/share/runtime/biasedLocking.cpp @@ -157,7 +157,7 @@ static GrowableArray* get_or_compute_monitor_info(JavaThread* thre // After the call, *biased_locker will be set to obj->mark()->biased_locker() if biased_locker != NULL, // AND it is a living thread. Otherwise it will not be updated, (i.e. the caller is responsible for initialization). -BiasedLocking::Condition BiasedLocking::single_revoke_at_safepoint(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread, JavaThread** biased_locker) { +void BiasedLocking::single_revoke_at_safepoint(oop obj, bool is_bulk, JavaThread* requesting_thread, JavaThread** biased_locker) { assert(SafepointSynchronize::is_at_safepoint(), "must be done at safepoint"); assert(Thread::current()->is_VM_thread(), "must be VMThread"); @@ -173,11 +173,10 @@ BiasedLocking::Condition BiasedLocking::single_revoke_at_safepoint(oop obj, bool obj->klass()->external_name(), (intptr_t) requesting_thread); } - return NOT_BIASED; + return; } uint age = mark.age(); - markWord biased_prototype = markWord::biased_locking_prototype().set_age(age); markWord unbiased_prototype = markWord::prototype().set_age(age); // Log at "info" level if not bulk, else "trace" level @@ -185,23 +184,21 @@ BiasedLocking::Condition BiasedLocking::single_revoke_at_safepoint(oop obj, bool ResourceMark rm; log_info(biasedlocking)("Revoking bias of object " INTPTR_FORMAT ", mark " INTPTR_FORMAT ", type %s, prototype header " INTPTR_FORMAT - ", allow rebias %d, requesting thread " INTPTR_FORMAT, + ", requesting thread " INTPTR_FORMAT, p2i((void *)obj), mark.value(), obj->klass()->external_name(), obj->klass()->prototype_header().value(), - (allow_rebias ? 1 : 0), (intptr_t) requesting_thread); } else { ResourceMark rm; log_trace(biasedlocking)("Revoking bias of object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s , prototype header " INTPTR_FORMAT - " , allow rebias %d , requesting thread " INTPTR_FORMAT, + " , requesting thread " INTPTR_FORMAT, p2i((void *)obj), mark.value(), obj->klass()->external_name(), obj->klass()->prototype_header().value(), - (allow_rebias ? 1 : 0), (intptr_t) requesting_thread); } @@ -210,16 +207,15 @@ BiasedLocking::Condition BiasedLocking::single_revoke_at_safepoint(oop obj, bool // Object is anonymously biased. We can get here if, for // example, we revoke the bias due to an identity hash code // being computed for an object. - if (!allow_rebias) { - obj->set_mark(unbiased_prototype); - } + obj->set_mark(unbiased_prototype); + // Log at "info" level if not bulk, else "trace" level if (!is_bulk) { log_info(biasedlocking)(" Revoked bias of anonymously-biased object"); } else { log_trace(biasedlocking)(" Revoked bias of anonymously-biased object"); } - return BIAS_REVOKED; + return; } // Handle case where the thread toward which the object was biased has exited @@ -231,11 +227,7 @@ BiasedLocking::Condition BiasedLocking::single_revoke_at_safepoint(oop obj, bool thread_is_alive = tlh.includes(biased_thread); } if (!thread_is_alive) { - if (allow_rebias) { - obj->set_mark(biased_prototype); - } else { - obj->set_mark(unbiased_prototype); - } + obj->set_mark(unbiased_prototype); // Log at "info" level if not bulk, else "trace" level if (!is_bulk) { log_info(biasedlocking)(" Revoked bias of object biased toward dead thread (" @@ -244,7 +236,7 @@ BiasedLocking::Condition BiasedLocking::single_revoke_at_safepoint(oop obj, bool log_trace(biasedlocking)(" Revoked bias of object biased toward dead thread (" PTR_FORMAT ")", p2i(biased_thread)); } - return BIAS_REVOKED; + return; } // Log at "info" level if not bulk, else "trace" level @@ -301,20 +293,14 @@ BiasedLocking::Condition BiasedLocking::single_revoke_at_safepoint(oop obj, bool } else { log_trace(biasedlocking)(" Revoked bias of currently-unlocked object"); } - if (allow_rebias) { - obj->set_mark(biased_prototype); - } else { - // Store the unlocked value into the object's header. - obj->set_mark(unbiased_prototype); - } + // Store the unlocked value into the object's header. + obj->set_mark(unbiased_prototype); } // If requested, return information on which thread held the bias if (biased_locker != NULL) { *biased_locker = biased_thread; } - - return BIAS_REVOKED; } @@ -379,10 +365,7 @@ static HeuristicsResult update_heuristics(oop o) { } -BiasedLocking::Condition BiasedLocking::bulk_revoke_or_rebias_at_safepoint(oop o, - bool bulk_rebias, - bool attempt_rebias_of_object, - JavaThread* requesting_thread) { +void BiasedLocking::bulk_revoke_at_safepoint(oop o, bool bulk_rebias, JavaThread* requesting_thread) { assert(SafepointSynchronize::is_at_safepoint(), "must be done at safepoint"); assert(Thread::current()->is_VM_thread(), "must be VMThread"); @@ -437,7 +420,7 @@ BiasedLocking::Condition BiasedLocking::bulk_revoke_or_rebias_at_safepoint(oop o // At this point we're done. All we have to do is potentially // adjust the header of the given object to revoke its bias. - single_revoke_at_safepoint(o, attempt_rebias_of_object && klass->prototype_header().has_bias_pattern(), true, requesting_thread, NULL); + single_revoke_at_safepoint(o, true, requesting_thread, NULL); } else { if (log_is_enabled(Info, biasedlocking)) { ResourceMark rm; @@ -459,36 +442,20 @@ BiasedLocking::Condition BiasedLocking::bulk_revoke_or_rebias_at_safepoint(oop o oop owner = mon_info->owner(); markWord mark = owner->mark(); if ((owner->klass() == k_o) && mark.has_bias_pattern()) { - single_revoke_at_safepoint(owner, false, true, requesting_thread, NULL); + single_revoke_at_safepoint(owner, true, requesting_thread, NULL); } } } // Must force the bias of the passed object to be forcibly revoked // as well to ensure guarantees to callers - single_revoke_at_safepoint(o, false, true, requesting_thread, NULL); + single_revoke_at_safepoint(o, true, requesting_thread, NULL); } } // ThreadsListHandle is destroyed here. log_info(biasedlocking)("* Ending bulk revocation"); - BiasedLocking::Condition status_code = BIAS_REVOKED; - - if (attempt_rebias_of_object && - o->mark().has_bias_pattern() && - klass->prototype_header().has_bias_pattern()) { - markWord new_mark = markWord::encode(requesting_thread, o->mark().age(), - klass->prototype_header().bias_epoch()); - o->set_mark(new_mark); - status_code = BIAS_REVOKED_AND_REBIASED; - log_info(biasedlocking)(" Rebiased object toward thread " INTPTR_FORMAT, (intptr_t) requesting_thread); - } - - assert(!o->mark().has_bias_pattern() || - (attempt_rebias_of_object && (o->mark().biased_locker() == requesting_thread)), - "bug in bulk bias revocation"); - - return status_code; + assert(!o->mark().has_bias_pattern(), "bug in bulk bias revocation"); } @@ -509,25 +476,20 @@ class VM_BulkRevokeBias : public VM_Operation { Handle* _obj; JavaThread* _requesting_thread; bool _bulk_rebias; - bool _attempt_rebias_of_object; - BiasedLocking::Condition _status_code; uint64_t _safepoint_id; public: VM_BulkRevokeBias(Handle* obj, JavaThread* requesting_thread, - bool bulk_rebias, - bool attempt_rebias_of_object) + bool bulk_rebias) : _obj(obj) , _requesting_thread(requesting_thread) , _bulk_rebias(bulk_rebias) - , _attempt_rebias_of_object(attempt_rebias_of_object) - , _status_code(BiasedLocking::NOT_BIASED) , _safepoint_id(0) {} virtual VMOp_Type type() const { return VMOp_BulkRevokeBias; } virtual void doit() { - _status_code = BiasedLocking::bulk_revoke_or_rebias_at_safepoint((*_obj)(), _bulk_rebias, _attempt_rebias_of_object, _requesting_thread); + BiasedLocking::bulk_revoke_at_safepoint((*_obj)(), _bulk_rebias, _requesting_thread); _safepoint_id = SafepointSynchronize::safepoint_id(); clean_up_cached_monitor_info(); } @@ -536,10 +498,6 @@ class VM_BulkRevokeBias : public VM_Operation { return _bulk_rebias; } - BiasedLocking::Condition status_code() const { - return _status_code; - } - uint64_t safepoint_id() const { return _safepoint_id; } @@ -769,7 +727,7 @@ void BiasedLocking::walk_stack_and_revoke(oop obj, JavaThread* biased_locker) { } -BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { +void BiasedLocking::revoke(Handle obj, TRAPS) { assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); while (true) { @@ -778,7 +736,12 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem // update the heuristics because doing so may cause unwanted bulk // revocations (which are expensive) to occur. markWord mark = obj->mark(); - if (mark.is_biased_anonymously() && !attempt_rebias) { + + if (!mark.has_bias_pattern()) { + return; + } + + if (mark.is_biased_anonymously()) { // We are probably trying to revoke the bias of this object due to // an identity hash code computation. Try to revoke the bias // without a safepoint. This is possible if we can successfully @@ -789,10 +752,10 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem markWord unbiased_prototype = markWord::prototype().set_age(mark.age()); markWord res_mark = obj->cas_set_mark(unbiased_prototype, mark); if (res_mark == biased_value) { - return BIAS_REVOKED; + return; } mark = res_mark; // Refresh mark with the latest value. - } else if (mark.has_bias_pattern()) { + } else { Klass* k = obj->klass(); markWord prototype_header = k->prototype_header(); if (!prototype_header.has_bias_pattern()) { @@ -804,31 +767,20 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem // with it. obj->cas_set_mark(prototype_header.set_age(mark.age()), mark); assert(!obj->mark().has_bias_pattern(), "even if we raced, should still be revoked"); - return BIAS_REVOKED; + return; } else if (prototype_header.bias_epoch() != mark.bias_epoch()) { // The epoch of this biasing has expired indicating that the - // object is effectively unbiased. Depending on whether we need - // to rebias or revoke the bias of this object we can do it - // efficiently enough with a CAS that we shouldn't update the + // object is effectively unbiased. We can revoke the bias of this + // object efficiently enough with a CAS that we shouldn't update the // heuristics. This is normally done in the assembly code but we // can reach this point due to various points in the runtime // needing to revoke biases. markWord res_mark; - if (attempt_rebias) { - assert(THREAD->is_Java_thread(), ""); - markWord biased_value = mark; - markWord rebiased_prototype = markWord::encode((JavaThread*) THREAD, mark.age(), prototype_header.bias_epoch()); - res_mark = obj->cas_set_mark(rebiased_prototype, mark); - if (res_mark == biased_value) { - return BIAS_REVOKED_AND_REBIASED; - } - } else { - markWord biased_value = mark; - markWord unbiased_prototype = markWord::prototype().set_age(mark.age()); - res_mark = obj->cas_set_mark(unbiased_prototype, mark); - if (res_mark == biased_value) { - return BIAS_REVOKED; - } + markWord biased_value = mark; + markWord unbiased_prototype = markWord::prototype().set_age(mark.age()); + res_mark = obj->cas_set_mark(unbiased_prototype, mark); + if (res_mark == biased_value) { + return; } mark = res_mark; // Refresh mark with the latest value. } @@ -836,7 +788,7 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem HeuristicsResult heuristics = update_heuristics(obj()); if (heuristics == HR_NOT_BIASED) { - return NOT_BIASED; + return; } else if (heuristics == HR_SINGLE_REVOKE) { JavaThread *blt = mark.biased_locker(); assert(blt != NULL, "invariant"); @@ -855,11 +807,11 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem if (event.should_commit()) { post_self_revocation_event(&event, obj->klass()); } - return BIAS_REVOKED; + return; } else { BiasedLocking::Condition cond = single_revoke_with_handshake(obj, (JavaThread*)THREAD, blt); if (cond != NOT_REVOKED) { - return cond; + return; } } } else { @@ -867,13 +819,12 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem (heuristics == HR_BULK_REBIAS), "?"); EventBiasedLockClassRevocation event; VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*)THREAD, - (heuristics == HR_BULK_REBIAS), - attempt_rebias); + (heuristics == HR_BULK_REBIAS)); VMThread::execute(&bulk_revoke); if (event.should_commit()) { post_class_revocation_event(&event, obj->klass(), &bulk_revoke); } - return bulk_revoke.status_code(); + return; } } } @@ -901,13 +852,13 @@ void BiasedLocking::revoke_at_safepoint(Handle h_obj) { HeuristicsResult heuristics = update_heuristics(obj); if (heuristics == HR_SINGLE_REVOKE) { JavaThread* biased_locker = NULL; - single_revoke_at_safepoint(obj, false, false, NULL, &biased_locker); + single_revoke_at_safepoint(obj, false, NULL, &biased_locker); if (biased_locker) { clean_up_cached_monitor_info(biased_locker); } } else if ((heuristics == HR_BULK_REBIAS) || (heuristics == HR_BULK_REVOKE)) { - bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL); + bulk_revoke_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), NULL); clean_up_cached_monitor_info(); } } @@ -920,10 +871,10 @@ void BiasedLocking::revoke_at_safepoint(GrowableArray* objs) { oop obj = (objs->at(i))(); HeuristicsResult heuristics = update_heuristics(obj); if (heuristics == HR_SINGLE_REVOKE) { - single_revoke_at_safepoint(obj, false, false, NULL, NULL); + single_revoke_at_safepoint(obj, false, NULL, NULL); } else if ((heuristics == HR_BULK_REBIAS) || (heuristics == HR_BULK_REVOKE)) { - bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL); + bulk_revoke_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), NULL); } } clean_up_cached_monitor_info(); diff --git a/src/hotspot/share/runtime/biasedLocking.hpp b/src/hotspot/share/runtime/biasedLocking.hpp index 05e11a77765..6b3139179c8 100644 --- a/src/hotspot/share/runtime/biasedLocking.hpp +++ b/src/hotspot/share/runtime/biasedLocking.hpp @@ -168,13 +168,12 @@ friend class RevokeOneBias; enum Condition { NOT_BIASED = 1, BIAS_REVOKED = 2, - BIAS_REVOKED_AND_REBIASED = 3, - NOT_REVOKED = 4 + NOT_REVOKED = 3 }; private: - static Condition single_revoke_at_safepoint(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requester, JavaThread** biaser); - static Condition bulk_revoke_or_rebias_at_safepoint(oop o, bool bulk_rebias, bool attempt_rebias, JavaThread* requester); + static void single_revoke_at_safepoint(oop obj, bool is_bulk, JavaThread* requester, JavaThread** biaser); + static void bulk_revoke_at_safepoint(oop o, bool bulk_rebias, JavaThread* requester); static Condition single_revoke_with_handshake(Handle obj, JavaThread *requester, JavaThread *biaser); static void walk_stack_and_revoke(oop obj, JavaThread* biased_locker); @@ -189,12 +188,13 @@ friend class RevokeOneBias; static bool enabled(); // This should be called by JavaThreads to revoke the bias of an object - static Condition revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS); + static void revoke(Handle obj, TRAPS); - // These do not allow rebiasing; they are used by deoptimization to - // ensure that monitors on the stack can be migrated - static void revoke(GrowableArray* objs, JavaThread *biaser); static void revoke_at_safepoint(Handle obj); + + // These are used by deoptimization to ensure that monitors on the stack + // can be migrated + static void revoke(GrowableArray* objs, JavaThread *biaser); static void revoke_at_safepoint(GrowableArray* objs); static void print_counters() { _counters.print(); } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 0e2c94ea375..6d6a7ccad04 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1264,7 +1264,7 @@ void Deoptimization::relock_objects(GrowableArray* monitors, JavaT obj->set_mark(unbiased_prototype); } BasicLock* lock = mon_info->lock(); - ObjectSynchronizer::slow_enter(obj, lock, thread); + ObjectSynchronizer::enter(obj, lock, thread); assert(mon_info->owner()->is_locked(), "object must be locked now"); } } @@ -1374,7 +1374,7 @@ void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* for (int j = 0; j < monitors->number_of_monitors(); j++) { BasicObjectLock* src = monitors->at(j); if (src->obj() != NULL) { - ObjectSynchronizer::fast_exit(src->obj(), src->lock(), thread); + ObjectSynchronizer::exit(src->obj(), src->lock(), thread); } } array->element(i)->free_monitors(thread); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 39fd96d8ac8..3afaa06e8ef 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2091,12 +2091,7 @@ JRT_BLOCK_ENTRY(void, SharedRuntime::complete_monitor_locking_C(oopDesc* _obj, B Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); } Handle h_obj(THREAD, obj); - if (UseBiasedLocking) { - // Retry fast entry if bias is revoked to avoid unnecessary inflation - ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); - } else { - ObjectSynchronizer::slow_enter(h_obj, lock, CHECK); - } + ObjectSynchronizer::enter(h_obj, lock, CHECK); assert(!HAS_PENDING_EXCEPTION, "Should have no exception here"); JRT_BLOCK_END JRT_END @@ -2127,7 +2122,7 @@ JRT_LEAF(void, SharedRuntime::complete_monitor_unlocking_C(oopDesc* _obj, BasicL { // Exit must be non-blocking, and therefore no exceptions can be thrown. EXCEPTION_MARK; - ObjectSynchronizer::slow_exit(obj, lock, THREAD); + ObjectSynchronizer::exit(obj, lock, THREAD); } #ifdef MIGHT_HAVE_PENDING diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index acac02ea63a..afe48981629 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -257,31 +257,48 @@ bool ObjectSynchronizer::quick_enter(oop obj, Thread * Self, } // ----------------------------------------------------------------------------- -// Fast Monitor Enter/Exit -// This the fast monitor enter. The interpreter and compiler use -// some assembly copies of this code. Make sure update those code -// if the following function is changed. The implementation is -// extremely sensitive to race condition. Be careful. - -void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, - bool attempt_rebias, TRAPS) { +// Monitor Enter/Exit +// The interpreter and compiler assembly code tries to lock using the fast path +// of this algorithm. Make sure to update that code if the following function is +// changed. The implementation is extremely sensitive to race condition. Be careful. + +void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, TRAPS) { if (UseBiasedLocking) { if (!SafepointSynchronize::is_at_safepoint()) { - BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD); - if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) { - return; - } + BiasedLocking::revoke(obj, THREAD); } else { - assert(!attempt_rebias, "can not rebias toward VM thread"); BiasedLocking::revoke_at_safepoint(obj); } - assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } - slow_enter(obj, lock, THREAD); + markWord mark = obj->mark(); + assert(!mark.has_bias_pattern(), "should not see bias pattern here"); + + if (mark.is_neutral()) { + // Anticipate successful CAS -- the ST of the displaced mark must + // be visible <= the ST performed by the CAS. + lock->set_displaced_header(mark); + if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) { + return; + } + // Fall through to inflate() ... + } else if (mark.has_locker() && + THREAD->is_lock_owned((address)mark.locker())) { + assert(lock != mark.locker(), "must not re-lock the same lock"); + assert(lock != (BasicLock*)obj->mark().value(), "don't relock with same BasicLock"); + lock->set_displaced_header(markWord::from_pointer(NULL)); + return; + } + + // The object header will never be displaced to this lock, + // so it does not matter what the value is, except that it + // must be non-zero to avoid looking like a re-entrant lock, + // and must not look locked either. + lock->set_displaced_header(markWord::unused_mark()); + inflate(THREAD, obj(), inflate_cause_monitor_enter)->enter(THREAD); } -void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) { +void ObjectSynchronizer::exit(oop object, BasicLock* lock, TRAPS) { markWord mark = object->mark(); // We cannot check for Biased Locking if we are racing an inflation. assert(mark == markWord::INFLATING() || @@ -330,47 +347,6 @@ void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) { inflate(THREAD, object, inflate_cause_vm_internal)->exit(true, THREAD); } -// ----------------------------------------------------------------------------- -// Interpreter/Compiler Slow Case -// This routine is used to handle interpreter/compiler slow case -// We don't need to use fast path here, because it must have been -// failed in the interpreter/compiler code. -void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) { - markWord mark = obj->mark(); - assert(!mark.has_bias_pattern(), "should not see bias pattern here"); - - if (mark.is_neutral()) { - // Anticipate successful CAS -- the ST of the displaced mark must - // be visible <= the ST performed by the CAS. - lock->set_displaced_header(mark); - if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) { - return; - } - // Fall through to inflate() ... - } else if (mark.has_locker() && - THREAD->is_lock_owned((address)mark.locker())) { - assert(lock != mark.locker(), "must not re-lock the same lock"); - assert(lock != (BasicLock*)obj->mark().value(), "don't relock with same BasicLock"); - lock->set_displaced_header(markWord::from_pointer(NULL)); - return; - } - - // The object header will never be displaced to this lock, - // so it does not matter what the value is, except that it - // must be non-zero to avoid looking like a re-entrant lock, - // and must not look locked either. - lock->set_displaced_header(markWord::unused_mark()); - inflate(THREAD, obj(), inflate_cause_monitor_enter)->enter(THREAD); -} - -// This routine is used to handle interpreter/compiler slow case -// We don't need to use fast path here, because it must have -// failed in the interpreter/compiler code. Simply use the heavy -// weight monitor should be ok, unless someone find otherwise. -void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) { - fast_exit(object, lock, THREAD); -} - // ----------------------------------------------------------------------------- // Class Loader support to workaround deadlocks on the class loader lock objects // Also used by GC @@ -385,7 +361,7 @@ void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) { // NOTE: must use heavy weight monitor to handle complete_exit/reenter() intptr_t ObjectSynchronizer::complete_exit(Handle obj, TRAPS) { if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); + BiasedLocking::revoke(obj, THREAD); assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } @@ -397,7 +373,7 @@ intptr_t ObjectSynchronizer::complete_exit(Handle obj, TRAPS) { // NOTE: must use heavy weight monitor to handle complete_exit/reenter() void ObjectSynchronizer::reenter(Handle obj, intptr_t recursion, TRAPS) { if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); + BiasedLocking::revoke(obj, THREAD); assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } @@ -411,7 +387,7 @@ void ObjectSynchronizer::reenter(Handle obj, intptr_t recursion, TRAPS) { void ObjectSynchronizer::jni_enter(Handle obj, TRAPS) { // the current locking is from JNI instead of Java code if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); + BiasedLocking::revoke(obj, THREAD); assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } THREAD->set_current_pending_monitor_is_from_java(false); @@ -423,7 +399,7 @@ void ObjectSynchronizer::jni_enter(Handle obj, TRAPS) { void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) { if (UseBiasedLocking) { Handle h_obj(THREAD, obj); - BiasedLocking::revoke_and_rebias(h_obj, false, THREAD); + BiasedLocking::revoke(h_obj, THREAD); obj = h_obj(); } assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); @@ -447,13 +423,13 @@ ObjectLocker::ObjectLocker(Handle obj, Thread* thread, bool doLock) { _obj = obj; if (_dolock) { - ObjectSynchronizer::fast_enter(_obj, &_lock, false, _thread); + ObjectSynchronizer::enter(_obj, &_lock, _thread); } } ObjectLocker::~ObjectLocker() { if (_dolock) { - ObjectSynchronizer::fast_exit(_obj(), &_lock, _thread); + ObjectSynchronizer::exit(_obj(), &_lock, _thread); } } @@ -463,7 +439,7 @@ ObjectLocker::~ObjectLocker() { // NOTE: must use heavy weight monitor to handle wait() int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); + BiasedLocking::revoke(obj, THREAD); assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } if (millis < 0) { @@ -483,7 +459,7 @@ int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) { if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); + BiasedLocking::revoke(obj, THREAD); assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } if (millis < 0) { @@ -494,7 +470,7 @@ void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) { void ObjectSynchronizer::notify(Handle obj, TRAPS) { if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); + BiasedLocking::revoke(obj, THREAD); assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } @@ -508,7 +484,7 @@ void ObjectSynchronizer::notify(Handle obj, TRAPS) { // NOTE: see comment of notify() void ObjectSynchronizer::notifyall(Handle obj, TRAPS) { if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); + BiasedLocking::revoke(obj, THREAD); assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } @@ -695,7 +671,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread * Self, oop obj) { assert(Universe::verify_in_progress() || !SafepointSynchronize::is_at_safepoint(), "biases should not be seen by VM thread here"); - BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current()); + BiasedLocking::revoke(hobj, JavaThread::current()); obj = hobj(); assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now"); } @@ -794,7 +770,7 @@ intptr_t ObjectSynchronizer::identity_hash_value_for(Handle obj) { bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* thread, Handle h_obj) { if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(h_obj, false, thread); + BiasedLocking::revoke(h_obj, thread); assert(!h_obj->mark().has_bias_pattern(), "biases should be revoked by now"); } @@ -833,7 +809,7 @@ ObjectSynchronizer::LockOwnership ObjectSynchronizer::query_lock_ownership if (UseBiasedLocking && h_obj()->mark().has_bias_pattern()) { // CASE: biased - BiasedLocking::revoke_and_rebias(h_obj, false, self); + BiasedLocking::revoke(h_obj, self); assert(!h_obj->mark().has_bias_pattern(), "biases should be revoked by now"); } @@ -869,7 +845,7 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob if (SafepointSynchronize::is_at_safepoint()) { BiasedLocking::revoke_at_safepoint(h_obj); } else { - BiasedLocking::revoke_and_rebias(h_obj, false, JavaThread::current()); + BiasedLocking::revoke(h_obj, JavaThread::current()); } assert(!h_obj->mark().has_bias_pattern(), "biases should be revoked by now"); } @@ -1463,8 +1439,7 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread * Self, // CAS inflates the object *and* confers ownership to the inflating thread. // In the current implementation we use a 2-step mechanism where we CAS() // to inflate and then CAS() again to try to swing _owner from NULL to Self. - // An inflateTry() method that we could call from fast_enter() and slow_enter() - // would be useful. + // An inflateTry() method that we could call from enter() would be useful. // Catch if the object's header is not neutral (not locked and // not marked is what we care about here). diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index bb3910d3a0b..cb047891107 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -65,22 +65,9 @@ class ObjectSynchronizer : AllStatic { // exit must be implemented non-blocking, since the compiler cannot easily handle // deoptimization at monitor exit. Hence, it does not take a Handle argument. - // This is full version of monitor enter and exit. I choose not - // to use enter() and exit() in order to make sure user be ware - // of the performance and semantics difference. They are normally - // used by ObjectLocker etc. The interpreter and compiler use - // assembly copies of these routines. Please keep them synchronized. - // - // attempt_rebias flag is used by UseBiasedLocking implementation - static void fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, - TRAPS); - static void fast_exit(oop obj, BasicLock* lock, Thread* THREAD); - - // WARNING: They are ONLY used to handle the slow cases. They should - // only be used when the fast cases failed. Use of these functions - // without previous fast case check may cause fatal error. - static void slow_enter(Handle obj, BasicLock* lock, TRAPS); - static void slow_exit(oop obj, BasicLock* lock, Thread* THREAD); + // This is the "slow path" version of monitor enter and exit. + static void enter(Handle obj, BasicLock* lock, TRAPS); + static void exit(oop obj, BasicLock* lock, Thread* THREAD); // Used only to handle jni locks or other unmatched monitor enter/exit // Internally they will use heavy weight monitor. diff --git a/test/hotspot/gtest/oops/test_markOop.cpp b/test/hotspot/gtest/oops/test_markOop.cpp index 89f3571b09c..29f9c8f8c4d 100644 --- a/test/hotspot/gtest/oops/test_markOop.cpp +++ b/test/hotspot/gtest/oops/test_markOop.cpp @@ -98,9 +98,10 @@ TEST_VM(markWord, printing) { // Lock using biased locking. BasicObjectLock lock; lock.set_obj(obj); - markWord mark = obj->mark().incr_bias_epoch(); - obj->set_mark(mark); - ObjectSynchronizer::fast_enter(h_obj, lock.lock(), true, THREAD); + markWord prototype_header = obj->klass()->prototype_header(); + markWord mark = obj->mark(); + markWord biased_mark = markWord::encode((JavaThread*) THREAD, mark.age(), prototype_header.bias_epoch()); + obj->set_mark(biased_mark); // Look for the biased_locker in markWord, not prototype_header. #ifdef _LP64 assert_not_test_pattern(h_obj, "mark(is_biased biased_locker=0x0000000000000000");