Skip to content

Commit f1de74e

Browse files
author
duke
committedFeb 13, 2024
Automatic merge of jdk:master into master
2 parents a74c613 + 5dbf137 commit f1de74e

13 files changed

+856
-48
lines changed
 

‎src/hotspot/share/prims/whitebox.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
#include "runtime/javaCalls.hpp"
8686
#include "runtime/javaThread.inline.hpp"
8787
#include "runtime/jniHandles.inline.hpp"
88+
#include "runtime/lockStack.hpp"
8889
#include "runtime/os.hpp"
8990
#include "runtime/stackFrameStream.inline.hpp"
9091
#include "runtime/synchronizer.hpp"
@@ -1847,6 +1848,14 @@ WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj))
18471848
return (jboolean) obj_oop->mark().has_monitor();
18481849
WB_END
18491850

1851+
WB_ENTRY(jint, WB_getLockStackCapacity(JNIEnv* env))
1852+
return (jint) LockStack::CAPACITY;
1853+
WB_END
1854+
1855+
WB_ENTRY(jboolean, WB_supportsRecursiveLightweightLocking(JNIEnv* env))
1856+
return (jboolean) VM_Version::supports_recursive_lightweight_locking();
1857+
WB_END
1858+
18501859
WB_ENTRY(jboolean, WB_DeflateIdleMonitors(JNIEnv* env, jobject wb))
18511860
log_info(monitorinflation)("WhiteBox initiated DeflateIdleMonitors");
18521861
return ObjectSynchronizer::request_deflate_idle_monitors_from_wb();
@@ -2829,6 +2838,8 @@ static JNINativeMethod methods[] = {
28292838
(void*)&WB_AddModuleExportsToAll },
28302839
{CC"deflateIdleMonitors", CC"()Z", (void*)&WB_DeflateIdleMonitors },
28312840
{CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated },
2841+
{CC"getLockStackCapacity", CC"()I", (void*)&WB_getLockStackCapacity },
2842+
{CC"supportsRecursiveLightweightLocking", CC"()Z", (void*)&WB_supportsRecursiveLightweightLocking },
28322843
{CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint },
28332844
{CC"forceClassLoaderStatsSafepoint", CC"()V", (void*)&WB_ForceClassLoaderStatsSafepoint },
28342845
{CC"getConstantPool0", CC"(Ljava/lang/Class;)J", (void*)&WB_GetConstantPool },

‎src/hotspot/share/runtime/abstract_vm_version.hpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -187,6 +187,9 @@ class Abstract_VM_Version: AllStatic {
187187
// Does platform support stack watermark barriers for concurrent stack processing?
188188
constexpr static bool supports_stack_watermark_barrier() { return false; }
189189

190+
// Is recursive lightweight locking implemented for this platform?
191+
constexpr static bool supports_recursive_lightweight_locking() { return false; }
192+
190193
// Does platform support float16 instructions?
191194
static bool supports_float16() { return false; }
192195

‎src/hotspot/share/runtime/lockStack.cpp

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright (c) 2022, Red Hat, Inc. All rights reserved.
33
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
45
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
56
*
67
* This code is free software; you can redistribute it and/or modify it
@@ -25,20 +26,30 @@
2526

2627
#include "precompiled.hpp"
2728
#include "memory/allocation.hpp"
29+
#include "runtime/globals.hpp"
2830
#include "runtime/lockStack.inline.hpp"
2931
#include "runtime/safepoint.hpp"
3032
#include "runtime/stackWatermark.hpp"
3133
#include "runtime/stackWatermarkSet.inline.hpp"
3234
#include "runtime/thread.hpp"
3335
#include "utilities/copy.hpp"
36+
#include "utilities/debug.hpp"
37+
#include "utilities/globalDefinitions.hpp"
3438
#include "utilities/ostream.hpp"
3539

40+
#include <type_traits>
41+
3642
const int LockStack::lock_stack_offset = in_bytes(JavaThread::lock_stack_offset());
3743
const int LockStack::lock_stack_top_offset = in_bytes(JavaThread::lock_stack_top_offset());
3844
const int LockStack::lock_stack_base_offset = in_bytes(JavaThread::lock_stack_base_offset());
3945

4046
LockStack::LockStack(JavaThread* jt) :
4147
_top(lock_stack_base_offset), _base() {
48+
// Make sure the layout of the object is compatible with the emitted code's assumptions.
49+
STATIC_ASSERT(sizeof(_bad_oop_sentinel) == oopSize);
50+
STATIC_ASSERT(sizeof(_base[0]) == oopSize);
51+
STATIC_ASSERT(std::is_standard_layout<LockStack>::value);
52+
STATIC_ASSERT(offsetof(LockStack, _bad_oop_sentinel) == offsetof(LockStack, _base) - oopSize);
4253
#ifdef ASSERT
4354
for (int i = 0; i < CAPACITY; i++) {
4455
_base[i] = nullptr;
@@ -62,11 +73,21 @@ uint32_t LockStack::end_offset() {
6273
void LockStack::verify(const char* msg) const {
6374
assert(LockingMode == LM_LIGHTWEIGHT, "never use lock-stack when light weight locking is disabled");
6475
assert((_top <= end_offset()), "lockstack overflow: _top %d end_offset %d", _top, end_offset());
65-
assert((_top >= start_offset()), "lockstack underflow: _top %d end_offset %d", _top, start_offset());
76+
assert((_top >= start_offset()), "lockstack underflow: _top %d start_offset %d", _top, start_offset());
6677
if (SafepointSynchronize::is_at_safepoint() || (Thread::current()->is_Java_thread() && is_owning_thread())) {
6778
int top = to_index(_top);
6879
for (int i = 0; i < top; i++) {
6980
assert(_base[i] != nullptr, "no zapped before top");
81+
if (VM_Version::supports_recursive_lightweight_locking()) {
82+
oop o = _base[i];
83+
for (; i < top - 1; i++) {
84+
// Consecutive entries may be the same
85+
if (_base[i + 1] != o) {
86+
break;
87+
}
88+
}
89+
}
90+
7091
for (int j = i + 1; j < top; j++) {
7192
assert(_base[i] != _base[j], "entries must be unique: %s", msg);
7293
}

‎src/hotspot/share/runtime/lockStack.hpp

+31-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright (c) 2022, Red Hat, Inc. All rights reserved.
33
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
45
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
56
*
67
* This code is free software; you can redistribute it and/or modify it
@@ -35,10 +36,12 @@ class OopClosure;
3536
class outputStream;
3637

3738
class LockStack {
39+
friend class LockStackTest;
3840
friend class VMStructs;
3941
JVMCI_ONLY(friend class JVMCIVMStructs;)
40-
private:
42+
public:
4143
static const int CAPACITY = 8;
44+
private:
4245

4346
// TODO: It would be very useful if JavaThread::lock_stack_offset() and friends were constexpr,
4447
// but this is currently not the case because we're using offset_of() which is non-constexpr,
@@ -51,6 +54,9 @@ class LockStack {
5154
// We do this instead of a simple index into the array because this allows for
5255
// efficient addressing in generated code.
5356
uint32_t _top;
57+
// The _bad_oop_sentinel acts as a sentinel value to elide underflow checks in generated code.
58+
// The correct layout is statically asserted in the constructor.
59+
const uintptr_t _bad_oop_sentinel = badOopVal;
5460
oop _base[CAPACITY];
5561

5662
// Get the owning thread of this lock-stack.
@@ -75,14 +81,35 @@ class LockStack {
7581
static uint32_t start_offset();
7682
static uint32_t end_offset();
7783

78-
// Return true if we have room to push onto this lock-stack, false otherwise.
79-
inline bool can_push() const;
84+
// Returns true if the lock-stack is full. False otherwise.
85+
inline bool is_full() const;
8086

8187
// Pushes an oop on this lock-stack.
8288
inline void push(oop o);
8389

90+
// Get the oldest oop from this lock-stack.
91+
// Precondition: This lock-stack must not be empty.
92+
inline oop bottom() const;
93+
94+
// Is the lock-stack empty.
95+
inline bool is_empty() const;
96+
97+
// Check if object is recursive.
98+
// Precondition: This lock-stack must contain the oop.
99+
inline bool is_recursive(oop o) const;
100+
101+
// Try recursive enter.
102+
// Precondition: This lock-stack must not be full.
103+
inline bool try_recursive_enter(oop o);
104+
105+
// Try recursive exit.
106+
// Precondition: This lock-stack must contain the oop.
107+
inline bool try_recursive_exit(oop o);
108+
84109
// Removes an oop from an arbitrary location of this lock-stack.
85-
inline void remove(oop o);
110+
// Precondition: This lock-stack must contain the oop.
111+
// Returns the number of oops removed.
112+
inline size_t remove(oop o);
86113

87114
// Tests whether the oop is on this lock-stack.
88115
inline bool contains(oop o) const;

‎src/hotspot/share/runtime/lockStack.inline.hpp

+122-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright (c) 2022, Red Hat, Inc. All rights reserved.
33
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
45
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
56
*
67
* This code is free software; you can redistribute it and/or modify it
@@ -26,14 +27,20 @@
2627
#ifndef SHARE_RUNTIME_LOCKSTACK_INLINE_HPP
2728
#define SHARE_RUNTIME_LOCKSTACK_INLINE_HPP
2829

30+
#include "runtime/lockStack.hpp"
31+
2932
#include "memory/iterator.hpp"
3033
#include "runtime/javaThread.hpp"
31-
#include "runtime/lockStack.hpp"
3234
#include "runtime/safepoint.hpp"
3335
#include "runtime/stackWatermark.hpp"
3436
#include "runtime/stackWatermarkSet.inline.hpp"
37+
#include "utilities/align.hpp"
38+
#include "utilities/globalDefinitions.hpp"
3539

3640
inline int LockStack::to_index(uint32_t offset) {
41+
assert(is_aligned(offset, oopSize), "Bad alignment: %u", offset);
42+
assert((offset <= end_offset()), "lockstack overflow: offset %d end_offset %d", offset, end_offset());
43+
assert((offset >= start_offset()), "lockstack underflow: offset %d start_offset %d", offset, start_offset());
3744
return (offset - lock_stack_base_offset) / oopSize;
3845
}
3946

@@ -42,8 +49,8 @@ JavaThread* LockStack::get_thread() const {
4249
return reinterpret_cast<JavaThread*>(addr - lock_stack_offset);
4350
}
4451

45-
inline bool LockStack::can_push() const {
46-
return to_index(_top) < CAPACITY;
52+
inline bool LockStack::is_full() const {
53+
return to_index(_top) == CAPACITY;
4754
}
4855

4956
inline bool LockStack::is_owning_thread() const {
@@ -61,32 +68,132 @@ inline void LockStack::push(oop o) {
6168
verify("pre-push");
6269
assert(oopDesc::is_oop(o), "must be");
6370
assert(!contains(o), "entries must be unique");
64-
assert(can_push(), "must have room");
71+
assert(!is_full(), "must have room");
6572
assert(_base[to_index(_top)] == nullptr, "expect zapped entry");
6673
_base[to_index(_top)] = o;
6774
_top += oopSize;
6875
verify("post-push");
6976
}
7077

71-
inline void LockStack::remove(oop o) {
78+
inline oop LockStack::bottom() const {
79+
assert(to_index(_top) > 0, "must contain an oop");
80+
return _base[0];
81+
}
82+
83+
inline bool LockStack::is_empty() const {
84+
return to_index(_top) == 0;
85+
}
86+
87+
inline bool LockStack::is_recursive(oop o) const {
88+
if (!VM_Version::supports_recursive_lightweight_locking()) {
89+
return false;
90+
}
91+
verify("pre-is_recursive");
92+
93+
// This will succeed iff there is a consecutive run of oops on the
94+
// lock-stack with a length of at least 2.
95+
96+
assert(contains(o), "at least one entry must exist");
97+
int end = to_index(_top);
98+
// Start iterating from the top because the runtime code is more
99+
// interested in the balanced locking case when the top oop on the
100+
// lock-stack matches o. This will cause the for loop to break out
101+
// in the first loop iteration if it is non-recursive.
102+
for (int i = end - 1; i > 0; i--) {
103+
if (_base[i - 1] == o && _base[i] == o) {
104+
verify("post-is_recursive");
105+
return true;
106+
}
107+
if (_base[i] == o) {
108+
// o can only occur in one consecutive run on the lock-stack.
109+
// Only one of the two oops checked matched o, so this run
110+
// must be of length 1 and thus not be recursive. Stop the search.
111+
break;
112+
}
113+
}
114+
115+
verify("post-is_recursive");
116+
return false;
117+
}
118+
119+
inline bool LockStack::try_recursive_enter(oop o) {
120+
if (!VM_Version::supports_recursive_lightweight_locking()) {
121+
return false;
122+
}
123+
verify("pre-try_recursive_enter");
124+
125+
// This will succeed iff the top oop on the stack matches o.
126+
// When successful o will be pushed to the lock-stack creating
127+
// a consecutive run at least 2 oops that matches o on top of
128+
// the lock-stack.
129+
130+
assert(!is_full(), "precond");
131+
132+
int end = to_index(_top);
133+
if (end == 0 || _base[end - 1] != o) {
134+
// Topmost oop does not match o.
135+
verify("post-try_recursive_enter");
136+
return false;
137+
}
138+
139+
_base[end] = o;
140+
_top += oopSize;
141+
verify("post-try_recursive_enter");
142+
return true;
143+
}
144+
145+
inline bool LockStack::try_recursive_exit(oop o) {
146+
if (!VM_Version::supports_recursive_lightweight_locking()) {
147+
return false;
148+
}
149+
verify("pre-try_recursive_exit");
150+
151+
// This will succeed iff the top two oops on the stack matches o.
152+
// When successful the top oop will be popped of the lock-stack.
153+
// When unsuccessful the lock may still be recursive, in which
154+
// case the locking is unbalanced. This case is handled externally.
155+
156+
assert(contains(o), "entries must exist");
157+
158+
int end = to_index(_top);
159+
if (end <= 1 || _base[end - 1] != o || _base[end - 2] != o) {
160+
// The two topmost oops do not match o.
161+
verify("post-try_recursive_exit");
162+
return false;
163+
}
164+
165+
_top -= oopSize;
166+
DEBUG_ONLY(_base[to_index(_top)] = nullptr;)
167+
verify("post-try_recursive_exit");
168+
return true;
169+
}
170+
171+
inline size_t LockStack::remove(oop o) {
72172
verify("pre-remove");
73173
assert(contains(o), "entry must be present: " PTR_FORMAT, p2i(o));
174+
74175
int end = to_index(_top);
176+
int inserted = 0;
75177
for (int i = 0; i < end; i++) {
76-
if (_base[i] == o) {
77-
int last = end - 1;
78-
for (; i < last; i++) {
79-
_base[i] = _base[i + 1];
178+
if (_base[i] != o) {
179+
if (inserted != i) {
180+
_base[inserted] = _base[i];
80181
}
81-
_top -= oopSize;
82-
#ifdef ASSERT
83-
_base[to_index(_top)] = nullptr;
84-
#endif
85-
break;
182+
inserted++;
86183
}
87184
}
88-
assert(!contains(o), "entries must be unique: " PTR_FORMAT, p2i(o));
185+
186+
#ifdef ASSERT
187+
for (int i = inserted; i < end; i++) {
188+
_base[i] = nullptr;
189+
}
190+
#endif
191+
192+
uint32_t removed = end - inserted;
193+
_top -= removed * oopSize;
194+
assert(!contains(o), "entry must have been removed: " PTR_FORMAT, p2i(o));
89195
verify("post-remove");
196+
return removed;
90197
}
91198

92199
inline bool LockStack::contains(oop o) const {

‎src/hotspot/share/runtime/objectMonitor.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ class ObjectMonitor : public CHeapObj<mtObjectMonitor> {
295295
int contentions() const;
296296
void add_to_contentions(int value);
297297
intx recursions() const { return _recursions; }
298+
void set_recursions(size_t recursions);
298299

299300
// JVM/TI GetObjectMonitorUsage() needs this:
300301
ObjectWaiter* first_waiter() { return _WaitSet; }

‎src/hotspot/share/runtime/objectMonitor.inline.hpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -102,6 +102,12 @@ inline void ObjectMonitor::add_to_contentions(int value) {
102102
Atomic::add(&_contentions, value);
103103
}
104104

105+
inline void ObjectMonitor::set_recursions(size_t recursions) {
106+
assert(_recursions == 0, "must be");
107+
assert(has_owner(), "must be owned");
108+
_recursions = checked_cast<intx>(recursions);
109+
}
110+
105111
// Clear _owner field; current value must match old_value.
106112
inline void ObjectMonitor::release_clear_owner(void* old_value) {
107113
#ifdef ASSERT

0 commit comments

Comments
 (0)
Please sign in to comment.