Skip to content

Commit

Permalink
8319773: Avoid inflating monitors when installing hash codes for LM_L…
Browse files Browse the repository at this point in the history
…IGHTWEIGHT

Reviewed-by: rkennke, dcubed, thartmann
  • Loading branch information
xmas92 committed Jan 12, 2024
1 parent e22ab10 commit 65a0672
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 47 deletions.
14 changes: 11 additions & 3 deletions src/hotspot/cpu/x86/sharedRuntime_x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "asm/macroAssembler.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/globalDefinitions.hpp"
#include "vmreg_x86.inline.hpp"
#ifdef COMPILER1
#include "c1/c1_Runtime1.hpp"
Expand Down Expand Up @@ -59,9 +60,16 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas

__ movptr(result, Address(obj_reg, oopDesc::mark_offset_in_bytes()));

// check if locked
__ testptr(result, markWord::unlocked_value);
__ jcc(Assembler::zero, slowCase);

if (LockingMode == LM_LIGHTWEIGHT) {
// check if monitor
__ testptr(result, markWord::monitor_value);
__ jcc(Assembler::notZero, slowCase);
} else {
// check if locked
__ testptr(result, markWord::unlocked_value);
__ jcc(Assembler::zero, slowCase);
}

// get hash
#ifdef _LP64
Expand Down
18 changes: 13 additions & 5 deletions src/hotspot/share/opto/library_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4572,14 +4572,22 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) {
Node* no_ctrl = nullptr;
Node* header = make_load(no_ctrl, header_addr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered);

// Test the header to see if it is unlocked.
// Test the header to see if it is safe to read w.r.t. locking.
Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place);
Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask));
Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value);
Node *chk_unlocked = _gvn.transform(new CmpXNode( lmasked_header, unlocked_val));
Node *test_unlocked = _gvn.transform(new BoolNode( chk_unlocked, BoolTest::ne));
if (LockingMode == LM_LIGHTWEIGHT) {
Node *monitor_val = _gvn.MakeConX(markWord::monitor_value);
Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val));
Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq));

generate_slow_guard(test_unlocked, slow_region);
generate_slow_guard(test_monitor, slow_region);
} else {
Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value);
Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val));
Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne));

generate_slow_guard(test_not_unlocked, slow_region);
}

// Get the hash value and check to see that it has been properly assigned.
// We depend on hash_mask being at most 32 bits and avoid the use of
Expand Down
61 changes: 26 additions & 35 deletions src/hotspot/share/runtime/synchronizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,16 +519,18 @@ void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current)
LockStack& lock_stack = current->lock_stack();
if (lock_stack.can_push()) {
markWord mark = obj()->mark_acquire();
if (mark.is_neutral()) {
assert(!lock_stack.contains(obj()), "thread must not already hold the lock");
while (mark.is_neutral()) {
// Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications.
// Try to swing into 'fast-locked' state.
markWord locked_mark = mark.set_fast_locked();
markWord old_mark = obj()->cas_set_mark(locked_mark, mark);
assert(!lock_stack.contains(obj()), "thread must not already hold the lock");
const markWord locked_mark = mark.set_fast_locked();
const markWord old_mark = obj()->cas_set_mark(locked_mark, mark);
if (old_mark == mark) {
// Successfully fast-locked, push object to lock-stack and return.
lock_stack.push(obj());
return;
}
mark = old_mark;
}
}
// All other paths fall-through to inflate-enter.
Expand Down Expand Up @@ -578,23 +580,15 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current)
markWord mark = object->mark();
if (LockingMode == LM_LIGHTWEIGHT) {
// Fast-locking does not use the 'lock' argument.
if (mark.is_fast_locked()) {
markWord unlocked_mark = mark.set_unlocked();
markWord old_mark = object->cas_set_mark(unlocked_mark, mark);
if (old_mark != mark) {
// Another thread won the CAS, it must have inflated the monitor.
// It can only have installed an anonymously locked monitor at this point.
// Fetch that monitor, set owner correctly to this thread, and
// exit it (allowing waiting threads to enter).
assert(old_mark.has_monitor(), "must have monitor");
ObjectMonitor* monitor = old_mark.monitor();
assert(monitor->is_owner_anonymous(), "must be anonymous owner");
monitor->set_owner_from_anonymous(current);
monitor->exit(current);
while (mark.is_fast_locked()) {
// Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications.
const markWord unlocked_mark = mark.set_unlocked();
const markWord old_mark = object->cas_set_mark(unlocked_mark, mark);
if (old_mark == mark) {
current->lock_stack().remove(object);
return;
}
LockStack& lock_stack = current->lock_stack();
lock_stack.remove(object);
return;
mark = old_mark;
}
} else if (LockingMode == LM_LEGACY) {
markWord dhw = lock->displaced_header();
Expand Down Expand Up @@ -908,13 +902,6 @@ static inline intptr_t get_next_hash(Thread* current, oop obj) {
return value;
}

// Can be called from non JavaThreads (e.g., VMThread) for FastHashCode
// calculations as part of JVM/TI tagging.
static bool is_lock_owned(Thread* thread, oop obj) {
assert(LockingMode == LM_LIGHTWEIGHT, "only call this with new lightweight locking enabled");
return thread->is_Java_thread() ? JavaThread::cast(thread)->lock_stack().contains(obj) : false;
}

intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {

while (true) {
Expand All @@ -926,7 +913,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
assert(LockingMode == LM_MONITOR, "+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)");
guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked");
}
if (mark.is_neutral()) { // if this is a normal header
if (mark.is_neutral() || (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked())) {
hash = mark.hash();
if (hash != 0) { // if it has a hash, just return it
return hash;
Expand All @@ -938,6 +925,10 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
if (test == mark) { // if the hash was installed, return it
return hash;
}
if (LockingMode == LM_LIGHTWEIGHT) {
// CAS failed, retry
continue;
}
// Failed to install the hash. It could be that another thread
// installed the hash just before our attempt or inflation has
// occurred or... so we fall thru to inflate the monitor for
Expand Down Expand Up @@ -969,13 +960,6 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
}
// Fall thru so we only have one place that installs the hash in
// the ObjectMonitor.
} else if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked() && is_lock_owned(current, obj)) {
// This is a fast-lock owned by the calling thread so use the
// markWord from the object.
hash = mark.hash();
if (hash != 0) { // if it has a hash, just return it
return hash;
}
} else if (LockingMode == LM_LEGACY && mark.has_locker() && current->is_lock_owned((address)mark.locker())) {
// This is a stack-lock owned by the calling thread so fetch the
// displaced markWord from the BasicLock on the stack.
Expand Down Expand Up @@ -1305,6 +1289,13 @@ void ObjectSynchronizer::inflate_helper(oop obj) {
(void)inflate(Thread::current(), obj, inflate_cause_vm_internal);
}

// Can be called from non JavaThreads (e.g., VMThread) for FastHashCode
// calculations as part of JVM/TI tagging.
static bool is_lock_owned(Thread* thread, oop obj) {
assert(LockingMode == LM_LIGHTWEIGHT, "only call this with new lightweight locking enabled");
return thread->is_Java_thread() ? JavaThread::cast(thread)->lock_stack().contains(obj) : false;
}

ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop object,
const InflateCause cause) {
EventJavaMonitorInflate event;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,11 @@ public static class InflateMonitorsTest {
static WhiteBox wb = WhiteBox.getWhiteBox();
public static Object obj;

public static void main(String args[]) {
public static void main(String args[]) throws Exception {
obj = new Object();
synchronized (obj) {
// HotSpot implementation detail: asking for the hash code
// when the object is locked causes monitor inflation.
if (obj.hashCode() == 0xBAD) System.out.println("!");
// The current implementation of notify-wait requires inflation.
obj.wait(1);
Asserts.assertEQ(wb.isMonitorInflated(obj), true,
"Monitor should be inflated.");
}
Expand Down

5 comments on commit 65a0672

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rkennke
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/backport lilliput-jdk21u

@openjdk
Copy link

@openjdk openjdk bot commented on 65a0672 Mar 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rkennke the backport was successfully created on the branch backport-rkennke-65a06727 in my personal fork of openjdk/lilliput-jdk21u. To create a pull request with this backport targeting openjdk/lilliput-jdk21u:lilliput, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit 65a06727 from the openjdk/jdk repository.

The commit being backported was authored by Axel Boldt-Christmas on 12 Jan 2024 and was reviewed by Roman Kennke, Daniel D. Daugherty and Tobias Hartmann.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/lilliput-jdk21u:

$ git fetch https://github.com/openjdk-bots/lilliput-jdk21u.git backport-rkennke-65a06727:backport-rkennke-65a06727
$ git checkout backport-rkennke-65a06727
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/lilliput-jdk21u.git backport-rkennke-65a06727

@TheRealMDoerr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/backport jdk21u-dev

@openjdk
Copy link

@openjdk openjdk bot commented on 65a0672 May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheRealMDoerr the backport was successfully created on the branch backport-TheRealMDoerr-65a06727 in my personal fork of openjdk/jdk21u-dev. To create a pull request with this backport targeting openjdk/jdk21u-dev:master, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit 65a06727 from the openjdk/jdk repository.

The commit being backported was authored by Axel Boldt-Christmas on 12 Jan 2024 and was reviewed by Roman Kennke, Daniel D. Daugherty and Tobias Hartmann.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk21u-dev:

$ git fetch https://github.com/openjdk-bots/jdk21u-dev.git backport-TheRealMDoerr-65a06727:backport-TheRealMDoerr-65a06727
$ git checkout backport-TheRealMDoerr-65a06727
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/jdk21u-dev.git backport-TheRealMDoerr-65a06727

Please sign in to comment.