Skip to content

8354180: Clean up uses of ObjectMonitor caches #24545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/hotspot/share/runtime/basicLock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include "runtime/objectMonitor.hpp"
#include "runtime/synchronizer.hpp"

void BasicLock::print_on(outputStream* st, oop owner) {
void BasicLock::print_on(outputStream* st, oop owner) const {
st->print("monitor");
if (UseObjectMonitorTable) {
ObjectMonitor* mon = object_monitor_cache();
Expand Down
6 changes: 3 additions & 3 deletions src/hotspot/share/runtime/basicLock.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -61,12 +61,12 @@ class BasicLock {
static int displaced_header_offset_in_bytes() { return metadata_offset_in_bytes(); }

// LM_LIGHTWEIGHT
inline ObjectMonitor* object_monitor_cache();
inline ObjectMonitor* object_monitor_cache() const;
inline void clear_object_monitor_cache();
inline void set_object_monitor_cache(ObjectMonitor* mon);
static int object_monitor_cache_offset_in_bytes() { return metadata_offset_in_bytes(); }

void print_on(outputStream* st, oop owner);
void print_on(outputStream* st, oop owner) const;

// move a basic lock (used during deoptimization)
void move_to(oop obj, BasicLock* dest);
Expand Down
11 changes: 3 additions & 8 deletions src/hotspot/share/runtime/basicLock.inline.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -38,15 +38,10 @@ inline void BasicLock::set_displaced_header(markWord header) {
Atomic::store(&_metadata, header.value());
}

inline ObjectMonitor* BasicLock::object_monitor_cache() {
inline ObjectMonitor* BasicLock::object_monitor_cache() const {
assert(UseObjectMonitorTable, "must be");
#if !defined(ZERO) && (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390))
ObjectMonitor* monitor = reinterpret_cast<ObjectMonitor*>(get_metadata());
if (monitor != nullptr && monitor->is_being_async_deflated()) {
clear_object_monitor_cache();
return nullptr;
}
return monitor;
return reinterpret_cast<ObjectMonitor*>(get_metadata());
#else
// Other platforms do not make use of the cache yet,
// and are not as careful with maintaining the invariant
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/runtime/deoptimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,9 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArray<MonitorInf
// Entering may create an invalid lock stack. Inflate the lock if it
// was fast_locked to restore the valid lock stack.
if (UseObjectMonitorTable) {
// UseObjectMonitorTable expects the BasicLock cache to be either a
// valid ObjectMonitor* or nullptr. Right now it is garbage, set it
// to nullptr.
lock->clear_object_monitor_cache();
}
ObjectSynchronizer::enter_for(obj, lock, deoptee_thread);
Expand Down
50 changes: 30 additions & 20 deletions src/hotspot/share/runtime/lightweightSynchronizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,12 @@ class LightweightSynchronizer::CacheSetter : StackObj {
// Only use the cache if using the table.
if (UseObjectMonitorTable) {
if (_monitor != nullptr) {
_thread->om_set_monitor_cache(_monitor);
_lock->set_object_monitor_cache(_monitor);
// If the monitor is already in the BasicLock cache then it is most
// likely in the thread cache, do not set it again to avoid reordering.
if (_monitor != _lock->object_monitor_cache()) {
_thread->om_set_monitor_cache(_monitor);
_lock->set_object_monitor_cache(_monitor);
}
} else {
_lock->clear_object_monitor_cache();
}
Expand All @@ -533,6 +537,16 @@ class LightweightSynchronizer::CacheSetter : StackObj {

};

// Reads first from the BasicLock cache then from the OMCache in the current thread.
// C2 fast-path may have put the monitor in the cache in the BasicLock.
inline static ObjectMonitor* read_caches(JavaThread* current, BasicLock* lock, oop object) {
ObjectMonitor* monitor = lock->object_monitor_cache();
if (monitor == nullptr) {
monitor = current->om_get_from_monitor_cache(object);
}
return monitor;
}

class LightweightSynchronizer::VerifyThreadState {
bool _no_safepoint;

Expand Down Expand Up @@ -614,15 +628,14 @@ bool LightweightSynchronizer::fast_lock_spin_enter(oop obj, LockStack& lock_stac

void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
assert(LockingMode == LM_LIGHTWEIGHT, "must be");
assert(!UseObjectMonitorTable || lock->object_monitor_cache() == nullptr, "must be cleared");
JavaThread* current = JavaThread::current();
VerifyThreadState vts(locking_thread, current);

if (obj->klass()->is_value_based()) {
ObjectSynchronizer::handle_sync_on_value_based_class(obj, locking_thread);
}

CacheSetter cache_setter(locking_thread, lock);

LockStack& lock_stack = locking_thread->lock_stack();

ObjectMonitor* monitor = nullptr;
Expand All @@ -639,7 +652,7 @@ void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread*
}

assert(monitor != nullptr, "LightweightSynchronizer::enter_for must succeed");
cache_setter.set_monitor(monitor);
assert(!UseObjectMonitorTable || lock->object_monitor_cache() == nullptr, "unused. already cleared");
}

void LightweightSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) {
Expand Down Expand Up @@ -740,12 +753,9 @@ void LightweightSynchronizer::exit(oop object, BasicLock* lock, JavaThread* curr
// The monitor exists
ObjectMonitor* monitor;
if (UseObjectMonitorTable) {
monitor = lock->object_monitor_cache();
monitor = read_caches(current, lock, object);
if (monitor == nullptr) {
monitor = current->om_get_from_monitor_cache(object);
if (monitor == nullptr) {
monitor = get_monitor_from_table(current, object);
}
monitor = get_monitor_from_table(current, object);
}
} else {
monitor = ObjectSynchronizer::read_monitor(mark);
Expand Down Expand Up @@ -1018,10 +1028,7 @@ ObjectMonitor* LightweightSynchronizer::inflate_and_enter(oop object, BasicLock*
// There's no need to use the cache if we are locking
// on behalf of another thread.
if (current == locking_thread) {
monitor = lock->object_monitor_cache();
if (monitor == nullptr) {
monitor = current->om_get_from_monitor_cache(object);
}
monitor = read_caches(current, lock, object);
}

// Get or create the monitor
Expand All @@ -1043,6 +1050,9 @@ ObjectMonitor* LightweightSynchronizer::inflate_and_enter(oop object, BasicLock*
// The MonitorDeflation thread is deflating the monitor. The locking thread
// must spin until further progress has been made.

// Clear the BasicLock cache as it may contain this monitor.
lock->clear_object_monitor_cache();

const markWord mark = object->mark_acquire();

if (mark.has_monitor()) {
Expand Down Expand Up @@ -1203,12 +1213,7 @@ bool LightweightSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread*
if (mark.has_monitor()) {
ObjectMonitor* monitor;
if (UseObjectMonitorTable) {
// C2 fast-path may have put the monitor in the cache in the BasicLock.
monitor = lock->object_monitor_cache();
if (monitor == nullptr) {
// Otherwise look up the monitor in the thread's OMCache.
monitor = current->om_get_from_monitor_cache(obj);
}
monitor = read_caches(current, lock, obj);
} else {
monitor = ObjectSynchronizer::read_monitor(mark);
}
Expand All @@ -1219,6 +1224,11 @@ bool LightweightSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread*
}

if (UseObjectMonitorTable) {
// Set the monitor regardless of success.
// Either we successfully lock on the monitor, or we retry with the
// monitor in the slow path. If the monitor gets deflated, it will be
// cleared, either by the CacheSetter if we fast lock in enter or in
// inflate_and_enter when we see that the monitor is deflated.
lock->set_object_monitor_cache(monitor);
}

Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/runtime/objectMonitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2559,7 +2559,7 @@ void ObjectMonitor::print_on(outputStream* st) const {
st->print("{contentions=0x%08x,waiters=0x%08x"
",recursions=%zd,owner=" INT64_FORMAT "}",
contentions(), waiters(), recursions(),
owner());
owner_raw());
}
void ObjectMonitor::print() const { print_on(tty); }

Expand Down