8229844: Remove attempt_rebias parameter from revoke_and_rebias()
Summary: Removed attempt_rebias parameter and merged fast_enter() and slow_enter() into enter()
Reviewed-by: dholmes, rehn, coleenp, dcubed
--- a/src/hotspot/cpu/aarch64/aarch64.ad Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/cpu/aarch64/aarch64.ad Tue Aug 27 20:10:06 2019 +0000
@@ -3569,7 +3569,7 @@
// 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()));
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -2607,8 +2607,8 @@
// - 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
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -1620,8 +1620,8 @@
// 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
--- a/src/hotspot/share/c1/c1_Runtime1.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -705,19 +705,11 @@
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 @@
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
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -771,12 +771,7 @@
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 @@
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);
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -394,17 +394,7 @@
}
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 @@
}
#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);
--- a/src/hotspot/share/prims/jvmtiEnvBase.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -960,7 +960,7 @@
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;
--- a/src/hotspot/share/runtime/biasedLocking.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/runtime/biasedLocking.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -157,7 +157,7 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
} 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 @@
}
-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 @@
// 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 @@
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 @@
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 @@
return _bulk_rebias;
}
- BiasedLocking::Condition status_code() const {
- return _status_code;
- }
-
uint64_t safepoint_id() const {
return _safepoint_id;
}
@@ -769,7 +727,7 @@
}
-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 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
(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 @@
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 @@
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();
--- a/src/hotspot/share/runtime/biasedLocking.hpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/runtime/biasedLocking.hpp Tue Aug 27 20:10:06 2019 +0000
@@ -168,13 +168,12 @@
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 @@
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);
+
+ static void revoke_at_safepoint(Handle obj);
- // These do not allow rebiasing; they are used by deoptimization to
- // ensure that monitors on the stack can be migrated
+ // These are used by deoptimization to ensure that monitors on the stack
+ // can be migrated
static void revoke(GrowableArray<Handle>* objs, JavaThread *biaser);
- static void revoke_at_safepoint(Handle obj);
static void revoke_at_safepoint(GrowableArray<Handle>* objs);
static void print_counters() { _counters.print(); }
--- a/src/hotspot/share/runtime/deoptimization.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/runtime/deoptimization.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -1264,7 +1264,7 @@
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 @@
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);
--- a/src/hotspot/share/runtime/sharedRuntime.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -2091,12 +2091,7 @@
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 @@
{
// 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
--- a/src/hotspot/share/runtime/synchronizer.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/runtime/synchronizer.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -257,31 +257,48 @@
}
// -----------------------------------------------------------------------------
-// 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.
+// 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::fast_enter(Handle obj, BasicLock* lock,
- bool attempt_rebias, TRAPS) {
+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() ||
@@ -331,47 +348,6 @@
}
// -----------------------------------------------------------------------------
-// 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
// complete_exit()/reenter() are used to wait on a nested lock
@@ -385,7 +361,7 @@
// 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 @@
// 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::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_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 @@
_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 @@
// 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 @@
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::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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
// 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).
--- a/src/hotspot/share/runtime/synchronizer.hpp Tue Aug 27 19:22:58 2019 +0200
+++ b/src/hotspot/share/runtime/synchronizer.hpp Tue Aug 27 20:10:06 2019 +0000
@@ -65,22 +65,9 @@
// 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.
--- a/test/hotspot/gtest/oops/test_markOop.cpp Tue Aug 27 19:22:58 2019 +0200
+++ b/test/hotspot/gtest/oops/test_markOop.cpp Tue Aug 27 20:10:06 2019 +0000
@@ -98,9 +98,10 @@
// 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");