< prev index next > src/hotspot/share/runtime/synchronizer.cpp
Print this page
}
if (mark.has_monitor()) {
ObjectMonitor* const mon = mark.monitor();
assert(mon->object() == oop(obj), "invariant");
! if (mon->owner() != current) return false; // slow-path for IMS exception
if (mon->first_waiter() != nullptr) {
// We have one or more waiters. Since this is an inflated monitor
// that we own, we can transfer one or more threads from the waitset
// to the entrylist here and now, avoiding the slow-path.
}
if (mark.has_monitor()) {
ObjectMonitor* const mon = mark.monitor();
assert(mon->object() == oop(obj), "invariant");
! if (!mon->is_owner(current)) return false; // slow-path for IMS exception
if (mon->first_waiter() != nullptr) {
// We have one or more waiters. Since this is an inflated monitor
// that we own, we can transfer one or more threads from the waitset
// to the entrylist here and now, avoiding the slow-path.
// Always go into runtime if the lock stack is full.
return false;
}
if (lock_stack.try_recursive_enter(obj)) {
// Recursive lock successful.
! current->inc_held_monitor_count();
return true;
}
}
const markWord mark = obj->mark();
// Always go into runtime if the lock stack is full.
return false;
}
if (lock_stack.try_recursive_enter(obj)) {
// Recursive lock successful.
! NOT_LOOM_MONITOR_SUPPORT(current->inc_held_monitor_count();)
return true;
}
}
const markWord mark = obj->mark();
// the ObjectMonitor busy by setting the owner below. If we detect
// that race we just bail out to the slow-path here.
if (m->object_peek() == nullptr) {
return false;
}
- JavaThread* const owner = static_cast<JavaThread*>(m->owner_raw());
// Lock contention and Transactional Lock Elision (TLE) diagnostics
// and observability
// Case: light contention possibly amenable to TLE
// Case: TLE inimical operations such as nested/recursive synchronization
! if (owner == current) {
m->_recursions++;
! current->inc_held_monitor_count();
return true;
}
if (LockingMode != LM_LIGHTWEIGHT) {
// This Java Monitor is inflated so obj's header will never be
// the ObjectMonitor busy by setting the owner below. If we detect
// that race we just bail out to the slow-path here.
if (m->object_peek() == nullptr) {
return false;
}
// Lock contention and Transactional Lock Elision (TLE) diagnostics
// and observability
// Case: light contention possibly amenable to TLE
// Case: TLE inimical operations such as nested/recursive synchronization
! if (m->is_owner(current)) {
m->_recursions++;
! NOT_LOOM_MONITOR_SUPPORT(current->inc_held_monitor_count();)
return true;
}
if (LockingMode != LM_LIGHTWEIGHT) {
// This Java Monitor is inflated so obj's header will never be
// recursive stack-locking in the displaced header in the BasicLock,
// and last are the inflated Java Monitor (ObjectMonitor) checks.
lock->set_displaced_header(markWord::unused_mark());
}
! if (owner == nullptr && m->try_set_owner_from(nullptr, current) == nullptr) {
assert(m->_recursions == 0, "invariant");
! current->inc_held_monitor_count();
return true;
}
}
// Note that we could inflate in quick_enter.
// recursive stack-locking in the displaced header in the BasicLock,
// and last are the inflated Java Monitor (ObjectMonitor) checks.
lock->set_displaced_header(markWord::unused_mark());
}
! if (!m->has_owner() && m->try_set_owner_from(nullptr, current) == nullptr) {
assert(m->_recursions == 0, "invariant");
! NOT_LOOM_MONITOR_SUPPORT(current->inc_held_monitor_count();)
return true;
}
}
// Note that we could inflate in quick_enter.
void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
// When called with locking_thread != Thread::current() some mechanism must synchronize
// the locking_thread with respect to the current thread. Currently only used when
// deoptimizing and re-locking locks. See Deoptimization::relock_objects
assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be");
+
+ NOT_LOOM_MONITOR_SUPPORT(locking_thread->inc_held_monitor_count();)
+
if (!enter_fast_impl(obj, lock, locking_thread)) {
// Inflated ObjectMonitor::enter_for is required
// An async deflation can race after the inflate_for() call and before
// enter_for() can make the ObjectMonitor busy. enter_for() returns false
}
}
void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) {
assert(current == Thread::current(), "must be");
+
+ NOT_LOOM_MONITOR_SUPPORT(current->inc_held_monitor_count();)
+
if (!enter_fast_impl(obj, lock, current)) {
// Inflated ObjectMonitor::enter is required
// An async deflation can race after the inflate() call and before
// enter() can make the ObjectMonitor busy. enter() returns false if
// 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.
bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
-
if (obj->klass()->is_value_based()) {
handle_sync_on_value_based_class(obj, locking_thread);
}
- locking_thread->inc_held_monitor_count();
-
if (!useHeavyMonitors()) {
if (LockingMode == LM_LIGHTWEIGHT) {
// Fast-locking does not use the 'lock' argument.
LockStack& lock_stack = locking_thread->lock_stack();
if (lock_stack.is_full()) {
// The least recently locked lock is chosen as it is the lock
// with the longest critical section.
log_info(monitorinflation)("LockStack capacity exceeded, inflating.");
ObjectMonitor* monitor = inflate_for(locking_thread, lock_stack.bottom(), inflate_cause_vm_internal);
! assert(monitor->owner() == Thread::current(), "must be owner=" PTR_FORMAT " current=" PTR_FORMAT " mark=" PTR_FORMAT,
p2i(monitor->owner()), p2i(Thread::current()), monitor->object()->mark_acquire().value());
assert(!lock_stack.is_full(), "must have made room here");
}
markWord mark = obj()->mark_acquire();
// The least recently locked lock is chosen as it is the lock
// with the longest critical section.
log_info(monitorinflation)("LockStack capacity exceeded, inflating.");
ObjectMonitor* monitor = inflate_for(locking_thread, lock_stack.bottom(), inflate_cause_vm_internal);
! assert(monitor->is_owner(JavaThread::current()), "must be owner=" PTR_FORMAT " current=" PTR_FORMAT " mark=" PTR_FORMAT,
p2i(monitor->owner()), p2i(Thread::current()), monitor->object()->mark_acquire().value());
assert(!lock_stack.is_full(), "must have made room here");
}
markWord mark = obj()->mark_acquire();
if (mark.is_unlocked()) {
// 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)) {
+ LOOM_MONITOR_SUPPORT_ONLY(locking_thread->inc_held_monitor_count();)
return true;
}
} else if (mark.has_locker() &&
locking_thread->is_lock_owned((address) mark.locker())) {
assert(lock != mark.locker(), "must not re-lock the same lock");
return false;
}
void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) {
! current->dec_held_monitor_count();
if (!useHeavyMonitors()) {
markWord mark = object->mark();
if (LockingMode == LM_LIGHTWEIGHT) {
// Fast-locking does not use the 'lock' argument.
return false;
}
void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) {
! NOT_LOOM_MONITOR_SUPPORT(current->dec_held_monitor_count();)
if (!useHeavyMonitors()) {
markWord mark = object->mark();
if (LockingMode == LM_LIGHTWEIGHT) {
// Fast-locking does not use the 'lock' argument.
if (mark == markWord::from_pointer(lock)) {
// If the object is stack-locked by the current thread, try to
// swing the displaced header from the BasicLock back to the mark.
assert(dhw.is_neutral(), "invariant");
if (object->cas_set_mark(dhw, mark) == mark) {
+ LOOM_MONITOR_SUPPORT_ONLY(current->dec_held_monitor_count();)
return;
}
}
}
} else if (VerifyHeavyMonitors) {
// Internal VM locks on java objects
// standard constructor, allows locking failures
ObjectLocker::ObjectLocker(Handle obj, JavaThread* thread) {
_thread = thread;
_thread->check_for_valid_safepoint_state();
+ DEBUG_ONLY(_thread->inc_obj_locker_count();)
_obj = obj;
if (_obj() != nullptr) {
ObjectSynchronizer::enter(_obj, &_lock, _thread);
}
}
ObjectLocker::~ObjectLocker() {
+ DEBUG_ONLY(_thread->dec_obj_locker_count();)
if (_obj() != nullptr) {
ObjectSynchronizer::exit(_obj(), &_lock, _thread);
}
}
markWord mark = read_stable_mark(obj);
if (LockingMode == LM_LEGACY && mark.has_locker()) {
// stack-locked so header points into owner's stack.
// owning_thread_from_monitor_owner() may also return null here:
! return Threads::owning_thread_from_monitor_owner(t_list, (address) mark.locker());
}
if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) {
// fast-locked so get owner from the object.
// owning_thread_from_object() may also return null here:
markWord mark = read_stable_mark(obj);
if (LockingMode == LM_LEGACY && mark.has_locker()) {
// stack-locked so header points into owner's stack.
// owning_thread_from_monitor_owner() may also return null here:
! return Threads::owning_thread_from_stacklock(t_list, (address) mark.locker());
}
if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) {
// fast-locked so get owner from the object.
// owning_thread_from_object() may also return null here:
// target thread is suspended or when the target thread is
// operating on itself. The current closures in use today are
// only interested in an owned ObjectMonitor and ownership
// cannot be dropped under the calling contexts so the
// ObjectMonitor cannot be async deflated.
! if (monitor->has_owner() && filter(monitor->owner_raw())) {
assert(!monitor->is_being_async_deflated(), "Owned monitors should not be deflating");
closure->do_monitor(monitor);
}
});
}
// Iterate ObjectMonitors where the owner == thread; this does NOT include
// ObjectMonitors where owner is set to a stack-lock address in thread.
void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure, JavaThread* thread) {
! auto thread_filter = [&](void* owner) { return owner == thread; };
return owned_monitors_iterate_filtered(closure, thread_filter);
}
// Iterate ObjectMonitors owned by any thread.
void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure) {
! auto all_filter = [&](void* owner) { return true; };
return owned_monitors_iterate_filtered(closure, all_filter);
}
static bool monitors_used_above_threshold(MonitorList* list) {
if (MonitorUsedDeflationThreshold == 0) { // disabled case is easy
// target thread is suspended or when the target thread is
// operating on itself. The current closures in use today are
// only interested in an owned ObjectMonitor and ownership
// cannot be dropped under the calling contexts so the
// ObjectMonitor cannot be async deflated.
! if (monitor->has_owner() && filter(monitor)) {
assert(!monitor->is_being_async_deflated(), "Owned monitors should not be deflating");
closure->do_monitor(monitor);
}
});
}
// Iterate ObjectMonitors where the owner == thread; this does NOT include
// ObjectMonitors where owner is set to a stack-lock address in thread.
void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure, JavaThread* thread) {
! auto thread_filter = [&](ObjectMonitor* monitor) { return monitor->is_owner(thread); };
return owned_monitors_iterate_filtered(closure, thread_filter);
}
// Iterate ObjectMonitors owned by any thread.
void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure) {
! auto all_filter = [&](ObjectMonitor* monitor) { return true; };
return owned_monitors_iterate_filtered(closure, all_filter);
}
static bool monitors_used_above_threshold(MonitorList* list) {
if (MonitorUsedDeflationThreshold == 0) { // disabled case is easy
(void)inflate(Thread::current(), obj, inflate_cause_vm_internal);
}
ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) {
assert(current == Thread::current(), "must be");
! if (LockingMode == LM_LIGHTWEIGHT && current->is_Java_thread()) {
- return inflate_impl(JavaThread::cast(current), obj, cause);
- }
- return inflate_impl(nullptr, obj, cause);
}
ObjectMonitor* ObjectSynchronizer::inflate_for(JavaThread* thread, oop obj, const InflateCause cause) {
assert(thread == Thread::current() || thread->is_obj_deopt_suspend(), "must be");
return inflate_impl(thread, obj, cause);
}
ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oop object, const InflateCause cause) {
! // The JavaThread* inflating_thread parameter is only used by LM_LIGHTWEIGHT and requires
! // that the inflating_thread == Thread::current() or is suspended throughout the call by
! // some other mechanism.
! // Even with LM_LIGHTWEIGHT the thread might be nullptr when called from a non
! // JavaThread. (As may still be the case from FastHashCode). However it is only
- // important for the correctness of the LM_LIGHTWEIGHT algorithm that the thread
- // is set when called from ObjectSynchronizer::enter from the owning thread,
// ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit.
EventJavaMonitorInflate event;
for (;;) {
const markWord mark = object->mark_acquire();
// The mark can be in one of the following states:
! // * inflated - Just return if using stack-locking.
! // If using fast-locking and the ObjectMonitor owner
! // is anonymous and the inflating_thread owns the
! // object lock, then we make the inflating_thread
- // the ObjectMonitor owner and remove the lock from
// the inflating_thread's lock stack.
// * fast-locked - Coerce it to inflated from fast-locked.
// * stack-locked - Coerce it to inflated from stack-locked.
// * INFLATING - Busy wait for conversion from stack-locked to
// inflated.
(void)inflate(Thread::current(), obj, inflate_cause_vm_internal);
}
ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) {
assert(current == Thread::current(), "must be");
! return inflate_impl(current->is_Java_thread() ? JavaThread::cast(current) : nullptr, obj, cause);
}
ObjectMonitor* ObjectSynchronizer::inflate_for(JavaThread* thread, oop obj, const InflateCause cause) {
assert(thread == Thread::current() || thread->is_obj_deopt_suspend(), "must be");
return inflate_impl(thread, obj, cause);
}
ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oop object, const InflateCause cause) {
! // The JavaThread* inflating_thread requires that the inflating_thread == Thread::current() or
! // is suspended throughout the call by some other mechanism.
! // The thread might be nullptr when called from a non JavaThread. (As may still be
! // the case from FastHashCode). However it is only important for correctness that the
! // thread is set when called from ObjectSynchronizer::enter from the owning thread,
// ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit.
EventJavaMonitorInflate event;
for (;;) {
const markWord mark = object->mark_acquire();
// The mark can be in one of the following states:
! // * inflated - If the ObjectMonitor owner is anonymous and the
! // inflating_thread owns the object lock, then we
! // make the inflating_thread the ObjectMonitor owner.
! // For LM_LIGHTWEIGHT we also remove the lock from
// the inflating_thread's lock stack.
// * fast-locked - Coerce it to inflated from fast-locked.
// * stack-locked - Coerce it to inflated from stack-locked.
// * INFLATING - Busy wait for conversion from stack-locked to
// inflated.
// CASE: inflated
if (mark.has_monitor()) {
ObjectMonitor* inf = mark.monitor();
markWord dmw = inf->header();
assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
! if (LockingMode == LM_LIGHTWEIGHT && inf->is_owner_anonymous() &&
! inflating_thread != nullptr && inflating_thread->lock_stack().contains(object)) {
! inf->set_owner_from_anonymous(inflating_thread);
! size_t removed = inflating_thread->lock_stack().remove(object);
! inf->set_recursions(removed - 1);
}
return inf;
}
if (LockingMode != LM_LIGHTWEIGHT) {
// CASE: inflated
if (mark.has_monitor()) {
ObjectMonitor* inf = mark.monitor();
markWord dmw = inf->header();
assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
! if (inf->is_owner_anonymous() && inflating_thread != nullptr) {
! if (LockingMode == LM_LIGHTWEIGHT) {
! if (inflating_thread->lock_stack().contains(object)) {
! inf->set_owner_from_anonymous(inflating_thread);
! size_t removed = inflating_thread->lock_stack().remove(object);
+ inf->set_recursions(removed - 1);
+ }
+ } else {
+ assert(LockingMode == LM_LEGACY, "invariant");
+ if (inflating_thread->is_lock_owned((address)inf->stack_locker())) {
+ inf->set_owner_from_BasicLock(inflating_thread);
+ // Decrement monitor count now since this monitor is okay for freezing
+ LOOM_MONITOR_SUPPORT_ONLY(inflating_thread->dec_held_monitor_count();)
+ }
+ }
}
return inf;
}
if (LockingMode != LM_LIGHTWEIGHT) {
assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
// Setup monitor fields to proper values -- prepare the monitor
m->set_header(dmw);
- // Optimization: if the mark.locker stack address is associated
- // with this thread we could simply set m->_owner = current.
// Note that a thread can inflate an object
// that it has stack-locked -- as might happen in wait() -- directly
// with CAS. That is, we can avoid the xchg-nullptr .... ST idiom.
! m->set_owner_from(nullptr, mark.locker());
// TODO-FIXME: assert BasicLock->dhw != 0.
// Must preserve store ordering. The monitor state must
// be stable at the time of publishing the monitor address.
guarantee(object->mark() == markWord::INFLATING(), "invariant");
assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
// Setup monitor fields to proper values -- prepare the monitor
m->set_header(dmw);
// Note that a thread can inflate an object
// that it has stack-locked -- as might happen in wait() -- directly
// with CAS. That is, we can avoid the xchg-nullptr .... ST idiom.
! if (inflating_thread != nullptr && inflating_thread->is_lock_owned((address)mark.locker())) {
+ m->set_owner_from(nullptr, inflating_thread);
+ // Decrement monitor count now since this monitor is okay for freezing
+ LOOM_MONITOR_SUPPORT_ONLY(inflating_thread->dec_held_monitor_count();)
+ } else {
+ // Use ANONYMOUS_OWNER to indicate that the owner is the BasicLock on the stack,
+ // and set the stack locker field in the monitor.
+ m->set_stack_locker(mark.locker());
+ m->set_owner_anonymous(); // second
+ }
// TODO-FIXME: assert BasicLock->dhw != 0.
// Must preserve store ordering. The monitor state must
// be stable at the time of publishing the monitor address.
guarantee(object->mark() == markWord::INFLATING(), "invariant");
public:
ReleaseJavaMonitorsClosure(JavaThread* thread) : _thread(thread) {}
void do_monitor(ObjectMonitor* mid) {
intx rec = mid->complete_exit(_thread);
! _thread->dec_held_monitor_count(rec + 1);
}
};
// Release all inflated monitors owned by current thread. Lightweight monitors are
// ignored. This is meant to be called during JNI thread detach which assumes
public:
ReleaseJavaMonitorsClosure(JavaThread* thread) : _thread(thread) {}
void do_monitor(ObjectMonitor* mid) {
intx rec = mid->complete_exit(_thread);
! _thread->dec_held_monitor_count(NOT_LOOM_MONITOR_SUPPORT((rec + 1)));
}
};
// Release all inflated monitors owned by current thread. Lightweight monitors are
// ignored. This is meant to be called during JNI thread detach which assumes
case inflate_cause_wait: return "Monitor Wait";
case inflate_cause_notify: return "Monitor Notify";
case inflate_cause_hash_code: return "Monitor Hash Code";
case inflate_cause_jni_enter: return "JNI Monitor Enter";
case inflate_cause_jni_exit: return "JNI Monitor Exit";
+ case inflate_cause_cont_freeze: return "Continuation Freeze";
default:
ShouldNotReachHere();
}
return "Unknown";
}
< prev index next >