< prev index next >
src/hotspot/share/runtime/biasedLocking.cpp
Print this page
*** 155,165 ****
}
// 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) {
assert(SafepointSynchronize::is_at_safepoint(), "must be done at safepoint");
assert(Thread::current()->is_VM_thread(), "must be VMThread");
markWord mark = obj->mark();
if (!mark.has_bias_pattern()) {
--- 155,165 ----
}
// 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).
! 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");
markWord mark = obj->mark();
if (!mark.has_bias_pattern()) {
*** 171,227 ****
" because it's no longer biased)",
p2i((void *)obj), mark.value(),
obj->klass()->external_name(),
(intptr_t) requesting_thread);
}
! return NOT_BIASED;
}
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
if (!is_bulk) {
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,
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,
p2i((void *)obj),
mark.value(),
obj->klass()->external_name(),
obj->klass()->prototype_header().value(),
- (allow_rebias ? 1 : 0),
(intptr_t) requesting_thread);
}
JavaThread* biased_thread = mark.biased_locker();
if (biased_thread == NULL) {
// 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);
! }
// 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;
}
// Handle case where the thread toward which the object was biased has exited
bool thread_is_alive = false;
if (requesting_thread == biased_thread) {
--- 171,223 ----
" because it's no longer biased)",
p2i((void *)obj), mark.value(),
obj->klass()->external_name(),
(intptr_t) requesting_thread);
}
! return;
}
uint age = mark.age();
markWord unbiased_prototype = markWord::prototype().set_age(age);
// Log at "info" level if not bulk, else "trace" level
if (!is_bulk) {
ResourceMark rm;
log_info(biasedlocking)("Revoking bias of object " INTPTR_FORMAT ", mark "
INTPTR_FORMAT ", type %s, prototype header " INTPTR_FORMAT
! ", requesting thread " INTPTR_FORMAT,
p2i((void *)obj),
mark.value(),
obj->klass()->external_name(),
obj->klass()->prototype_header().value(),
(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
! " , requesting thread " INTPTR_FORMAT,
p2i((void *)obj),
mark.value(),
obj->klass()->external_name(),
obj->klass()->prototype_header().value(),
(intptr_t) requesting_thread);
}
JavaThread* biased_thread = mark.biased_locker();
if (biased_thread == NULL) {
// 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.
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;
}
// Handle case where the thread toward which the object was biased has exited
bool thread_is_alive = false;
if (requesting_thread == biased_thread) {
*** 229,252 ****
} else {
ThreadsListHandle tlh;
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);
- }
// Log at "info" level if not bulk, else "trace" level
if (!is_bulk) {
log_info(biasedlocking)(" Revoked bias of object biased toward dead thread ("
PTR_FORMAT ")", p2i(biased_thread));
} else {
log_trace(biasedlocking)(" Revoked bias of object biased toward dead thread ("
PTR_FORMAT ")", p2i(biased_thread));
}
! return BIAS_REVOKED;
}
// Log at "info" level if not bulk, else "trace" level
if (!is_bulk) {
log_info(biasedlocking)(" Revoked bias of object biased toward live thread ("
--- 225,244 ----
} else {
ThreadsListHandle tlh;
thread_is_alive = tlh.includes(biased_thread);
}
if (!thread_is_alive) {
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 ("
PTR_FORMAT ")", p2i(biased_thread));
} else {
log_trace(biasedlocking)(" Revoked bias of object biased toward dead thread ("
PTR_FORMAT ")", p2i(biased_thread));
}
! return;
}
// Log at "info" level if not bulk, else "trace" level
if (!is_bulk) {
log_info(biasedlocking)(" Revoked bias of object biased toward live thread ("
*** 299,322 ****
if (!is_bulk) {
log_info(biasedlocking)(" Revoked bias of currently-unlocked object");
} 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);
}
- }
// If requested, return information on which thread held the bias
if (biased_locker != NULL) {
*biased_locker = biased_thread;
}
-
- return BIAS_REVOKED;
}
enum HeuristicsResult {
HR_NOT_BIASED = 1,
--- 291,308 ----
*** 377,390 ****
return HR_SINGLE_REVOKE;
}
! BiasedLocking::Condition BiasedLocking::bulk_revoke_or_rebias_at_safepoint(oop o,
! bool bulk_rebias,
! bool attempt_rebias_of_object,
! JavaThread* requesting_thread) {
assert(SafepointSynchronize::is_at_safepoint(), "must be done at safepoint");
assert(Thread::current()->is_VM_thread(), "must be VMThread");
log_info(biasedlocking)("* Beginning bulk revocation (kind == %s) because of object "
INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s",
--- 363,373 ----
return HR_SINGLE_REVOKE;
}
! 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");
log_info(biasedlocking)("* Beginning bulk revocation (kind == %s) because of object "
INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s",
*** 435,445 ****
}
}
// 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);
} else {
if (log_is_enabled(Info, biasedlocking)) {
ResourceMark rm;
log_info(biasedlocking)("* Disabling biased locking for type %s", klass->external_name());
}
--- 418,428 ----
}
}
// 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, true, requesting_thread, NULL);
} else {
if (log_is_enabled(Info, biasedlocking)) {
ResourceMark rm;
log_info(biasedlocking)("* Disabling biased locking for type %s", klass->external_name());
}
*** 457,496 ****
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
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);
}
}
}
// 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);
}
} // 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;
}
static void clean_up_cached_monitor_info(JavaThread* thread = NULL) {
if (thread != NULL) {
--- 440,463 ----
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
oop owner = mon_info->owner();
markWord mark = owner->mark();
if ((owner->klass() == k_o) && mark.has_bias_pattern()) {
! 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, true, requesting_thread, NULL);
}
} // ThreadsListHandle is destroyed here.
log_info(biasedlocking)("* Ending bulk revocation");
! assert(!o->mark().has_bias_pattern(), "bug in bulk bias revocation");
}
static void clean_up_cached_monitor_info(JavaThread* thread = NULL) {
if (thread != NULL) {
*** 507,547 ****
class VM_BulkRevokeBias : public VM_Operation {
private:
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)
: _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);
_safepoint_id = SafepointSynchronize::safepoint_id();
clean_up_cached_monitor_info();
}
bool is_bulk_rebias() const {
return _bulk_rebias;
}
- BiasedLocking::Condition status_code() const {
- return _status_code;
- }
-
uint64_t safepoint_id() const {
return _safepoint_id;
}
};
--- 474,505 ----
class VM_BulkRevokeBias : public VM_Operation {
private:
Handle* _obj;
JavaThread* _requesting_thread;
bool _bulk_rebias;
uint64_t _safepoint_id;
public:
VM_BulkRevokeBias(Handle* obj, JavaThread* requesting_thread,
! bool bulk_rebias)
: _obj(obj)
, _requesting_thread(requesting_thread)
, _bulk_rebias(bulk_rebias)
, _safepoint_id(0) {}
virtual VMOp_Type type() const { return VMOp_BulkRevokeBias; }
virtual void doit() {
! BiasedLocking::bulk_revoke_at_safepoint((*_obj)(), _bulk_rebias, _requesting_thread);
_safepoint_id = SafepointSynchronize::safepoint_id();
clean_up_cached_monitor_info();
}
bool is_bulk_rebias() const {
return _bulk_rebias;
}
uint64_t safepoint_id() const {
return _safepoint_id;
}
};
*** 767,800 ****
assert(!obj->mark().has_bias_pattern(), "must not be biased");
}
! BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {
assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");
while (true) {
// We can revoke the biases of anonymously-biased objects
// efficiently enough that we should not cause these revocations to
// 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) {
// 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
// compare-and-exchange an unbiased header into the mark word of
// the object, meaning that no other thread has raced to acquire
// the bias of the object.
markWord biased_value = mark;
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;
}
mark = res_mark; // Refresh mark with the latest value.
! } else if (mark.has_bias_pattern()) {
Klass* k = obj->klass();
markWord prototype_header = k->prototype_header();
if (!prototype_header.has_bias_pattern()) {
// This object has a stale bias from before the bulk revocation
// for this data type occurred. It's pointless to update the
--- 725,763 ----
assert(!obj->mark().has_bias_pattern(), "must not be biased");
}
! void BiasedLocking::revoke(Handle obj, TRAPS) {
assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");
while (true) {
// We can revoke the biases of anonymously-biased objects
// efficiently enough that we should not cause these revocations to
// update the heuristics because doing so may cause unwanted bulk
// revocations (which are expensive) to occur.
markWord mark = obj->mark();
!
! 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
// compare-and-exchange an unbiased header into the mark word of
// the object, meaning that no other thread has raced to acquire
// the bias of the object.
markWord biased_value = mark;
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;
}
mark = res_mark; // Refresh mark with the latest value.
! } else {
Klass* k = obj->klass();
markWord prototype_header = k->prototype_header();
if (!prototype_header.has_bias_pattern()) {
// This object has a stale bias from before the bulk revocation
// for this data type occurred. It's pointless to update the
*** 802,844 ****
// CAS. If we fail this race, the object's bias has been revoked
// by another thread so we simply return and let the caller deal
// 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;
} 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
// 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;
! }
}
mark = res_mark; // Refresh mark with the latest value.
}
}
HeuristicsResult heuristics = update_heuristics(obj());
if (heuristics == HR_NOT_BIASED) {
! return NOT_BIASED;
} else if (heuristics == HR_SINGLE_REVOKE) {
JavaThread *blt = mark.biased_locker();
assert(blt != NULL, "invariant");
if (blt == THREAD) {
// A thread is trying to revoke the bias of an object biased
--- 765,796 ----
// CAS. If we fail this race, the object's bias has been revoked
// by another thread so we simply return and let the caller deal
// 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;
} else if (prototype_header.bias_epoch() != mark.bias_epoch()) {
// The epoch of this biasing has expired indicating that 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;
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.
}
}
HeuristicsResult heuristics = update_heuristics(obj());
if (heuristics == HR_NOT_BIASED) {
! return;
} else if (heuristics == HR_SINGLE_REVOKE) {
JavaThread *blt = mark.biased_locker();
assert(blt != NULL, "invariant");
if (blt == THREAD) {
// A thread is trying to revoke the bias of an object biased
*** 853,881 ****
blt->set_cached_monitor_info(NULL);
assert(!obj->mark().has_bias_pattern(), "invariant");
if (event.should_commit()) {
post_self_revocation_event(&event, obj->klass());
}
! return BIAS_REVOKED;
} else {
BiasedLocking::Condition cond = single_revoke_with_handshake(obj, (JavaThread*)THREAD, blt);
if (cond != NOT_REVOKED) {
! return cond;
}
}
} else {
assert((heuristics == HR_BULK_REVOKE) ||
(heuristics == HR_BULK_REBIAS), "?");
EventBiasedLockClassRevocation event;
VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*)THREAD,
! (heuristics == HR_BULK_REBIAS),
! attempt_rebias);
VMThread::execute(&bulk_revoke);
if (event.should_commit()) {
post_class_revocation_event(&event, obj->klass(), &bulk_revoke);
}
! return bulk_revoke.status_code();
}
}
}
// All objects in objs should be locked by biaser
--- 805,832 ----
blt->set_cached_monitor_info(NULL);
assert(!obj->mark().has_bias_pattern(), "invariant");
if (event.should_commit()) {
post_self_revocation_event(&event, obj->klass());
}
! return;
} else {
BiasedLocking::Condition cond = single_revoke_with_handshake(obj, (JavaThread*)THREAD, blt);
if (cond != NOT_REVOKED) {
! return;
}
}
} else {
assert((heuristics == HR_BULK_REVOKE) ||
(heuristics == HR_BULK_REBIAS), "?");
EventBiasedLockClassRevocation event;
VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*)THREAD,
! (heuristics == HR_BULK_REBIAS));
VMThread::execute(&bulk_revoke);
if (event.should_commit()) {
post_class_revocation_event(&event, obj->klass(), &bulk_revoke);
}
! return;
}
}
}
// All objects in objs should be locked by biaser
*** 899,915 ****
assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");
oop obj = 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);
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);
clean_up_cached_monitor_info();
}
}
--- 850,866 ----
assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");
oop obj = h_obj();
HeuristicsResult heuristics = update_heuristics(obj);
if (heuristics == HR_SINGLE_REVOKE) {
JavaThread* biased_locker = NULL;
! 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_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), NULL);
clean_up_cached_monitor_info();
}
}
*** 918,931 ****
int len = objs->length();
for (int i = 0; i < len; i++) {
oop obj = (objs->at(i))();
HeuristicsResult heuristics = update_heuristics(obj);
if (heuristics == HR_SINGLE_REVOKE) {
! single_revoke_at_safepoint(obj, false, 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);
}
}
clean_up_cached_monitor_info();
}
--- 869,882 ----
int len = objs->length();
for (int i = 0; i < len; i++) {
oop obj = (objs->at(i))();
HeuristicsResult heuristics = update_heuristics(obj);
if (heuristics == HR_SINGLE_REVOKE) {
! single_revoke_at_safepoint(obj, false, NULL, NULL);
} else if ((heuristics == HR_BULK_REBIAS) ||
(heuristics == HR_BULK_REVOKE)) {
! bulk_revoke_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), NULL);
}
}
clean_up_cached_monitor_info();
}
< prev index next >