1 /*
2 * Copyright (c) 2022, Red Hat, Inc. All rights reserved.
3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 *
7 * This code is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 only, as
9 * published by the Free Software Foundation.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 */
26
27 #ifndef SHARE_RUNTIME_LOCKSTACK_INLINE_HPP
28 #define SHARE_RUNTIME_LOCKSTACK_INLINE_HPP
29
30 #include "runtime/lockStack.hpp"
31
32 #include "memory/iterator.hpp"
33 #include "runtime/safepoint.hpp"
34 #include "runtime/stackWatermark.hpp"
35 #include "runtime/stackWatermarkSet.inline.hpp"
36 #include "runtime/thread.hpp"
37 #include "runtime/vm_version.hpp"
38 #include "utilities/align.hpp"
39 #include "utilities/globalDefinitions.hpp"
40
41 inline int LockStack::to_index(uint32_t offset) {
42 assert(is_aligned(offset, oopSize), "Bad alignment: %u", offset);
43 assert((offset <= end_offset()), "lockstack overflow: offset %d end_offset %d", offset, end_offset());
44 assert((offset >= start_offset()), "lockstack underflow: offset %d start_offset %d", offset, start_offset());
45 return (offset - lock_stack_base_offset) / oopSize;
46 }
47
48 JavaThread* LockStack::get_thread() const {
49 char* addr = reinterpret_cast<char*>(const_cast<LockStack*>(this));
50 return reinterpret_cast<JavaThread*>(addr - lock_stack_offset);
51 }
52
53 inline bool LockStack::is_full() const {
54 return to_index(_top) == CAPACITY;
55 }
56
57 inline bool LockStack::is_owning_thread() const {
58 Thread* current = Thread::current();
59 if (current->is_Java_thread()) {
60 JavaThread* thread = current->as_Java_thread();
61 bool is_owning = &thread->lock_stack() == this;
62 assert(is_owning == (get_thread() == thread), "is_owning sanity");
63 return is_owning;
64 }
65 return false;
66 }
67
68 inline void LockStack::push(oop o) {
69 verify("pre-push");
70 assert(oopDesc::is_oop(o), "must be");
71 assert(!contains(o), "entries must be unique");
72 assert(!is_full(), "must have room");
73 assert(_base[to_index(_top)] == NULL, "expect zapped entry");
74 _base[to_index(_top)] = o;
75 _top += oopSize;
76 verify("post-push");
77 }
78
79 inline oop LockStack::bottom() const {
80 assert(to_index(_top) > 0, "must contain an oop");
81 return _base[0];
82 }
83
84 inline bool LockStack::is_empty() const {
85 return to_index(_top) == 0;
86 }
87
88 inline bool LockStack::is_recursive(oop o) const {
89 if (!VM_Version::supports_recursive_lightweight_locking()) {
90 return false;
91 }
92 verify("pre-is_recursive");
93
94 // This will succeed iff there is a consecutive run of oops on the
95 // lock-stack with a length of at least 2.
96
97 assert(contains(o), "at least one entry must exist");
98 int end = to_index(_top);
99 // Start iterating from the top because the runtime code is more
100 // interested in the balanced locking case when the top oop on the
101 // lock-stack matches o. This will cause the for loop to break out
102 // in the first loop iteration if it is non-recursive.
103 for (int i = end - 1; i > 0; i--) {
104 if (_base[i - 1] == o && _base[i] == o) {
105 verify("post-is_recursive");
106 return true;
107 }
108 if (_base[i] == o) {
109 // o can only occur in one consecutive run on the lock-stack.
110 // Only one of the two oops checked matched o, so this run
111 // must be of length 1 and thus not be recursive. Stop the search.
112 break;
113 }
114 }
115
116 verify("post-is_recursive");
117 return false;
118 }
119
120 inline bool LockStack::try_recursive_enter(oop o) {
121 if (!VM_Version::supports_recursive_lightweight_locking()) {
122 return false;
123 }
124 verify("pre-try_recursive_enter");
125
126 // This will succeed iff the top oop on the stack matches o.
127 // When successful o will be pushed to the lock-stack creating
128 // a consecutive run at least 2 oops that matches o on top of
129 // the lock-stack.
130
131 assert(!is_full(), "precond");
132
133 int end = to_index(_top);
134 if (end == 0 || _base[end - 1] != o) {
135 // Topmost oop does not match o.
136 verify("post-try_recursive_enter");
137 return false;
138 }
139
140 _base[end] = o;
141 _top += oopSize;
142 verify("post-try_recursive_enter");
143 return true;
144 }
145
146 inline bool LockStack::try_recursive_exit(oop o) {
147 if (!VM_Version::supports_recursive_lightweight_locking()) {
148 return false;
149 }
150 verify("pre-try_recursive_exit");
151
152 // This will succeed iff the top two oops on the stack matches o.
153 // When successful the top oop will be popped of the lock-stack.
154 // When unsuccessful the lock may still be recursive, in which
155 // case the locking is unbalanced. This case is handled externally.
156
157 assert(contains(o), "entries must exist");
158
159 int end = to_index(_top);
160 if (end <= 1 || _base[end - 1] != o || _base[end - 2] != o) {
161 // The two topmost oops do not match o.
162 verify("post-try_recursive_exit");
163 return false;
164 }
165
166 _top -= oopSize;
167 DEBUG_ONLY(_base[to_index(_top)] = nullptr;)
168 verify("post-try_recursive_exit");
169 return true;
170 }
171
172 inline size_t LockStack::remove(oop o) {
173 verify("pre-remove");
174 assert(contains(o), "entry must be present: " PTR_FORMAT, p2i(o));
175
176 int end = to_index(_top);
177 int inserted = 0;
178 for (int i = 0; i < end; i++) {
179 if (_base[i] != o) {
180 if (inserted != i) {
181 _base[inserted] = _base[i];
182 }
183 inserted++;
184 }
185 }
186
187 #ifdef ASSERT
188 for (int i = inserted; i < end; i++) {
189 _base[i] = nullptr;
190 }
191 #endif
192
193 uint32_t removed = end - inserted;
194 _top -= removed * oopSize;
195 assert(!contains(o), "entry must have been removed: " PTR_FORMAT, p2i(o));
196 verify("post-remove");
197 return removed;
198 }
199
200 inline bool LockStack::contains(oop o) const {
201 verify("pre-contains");
202
203 // Can't poke around in thread oops without having started stack watermark processing.
204 assert(StackWatermarkSet::processing_started(get_thread()), "Processing must have started!");
205
206 int end = to_index(_top);
207 for (int i = end - 1; i >= 0; i--) {
208 if (_base[i] == o) {
209 verify("post-contains");
210 return true;
211 }
212 }
213 verify("post-contains");
214 return false;
215 }
216
217 inline void LockStack::oops_do(OopClosure* cl) {
218 verify("pre-oops-do");
219 int end = to_index(_top);
220 for (int i = 0; i < end; i++) {
221 cl->do_oop(&_base[i]);
222 }
223 verify("post-oops-do");
224 }
225
226 #endif // SHARE_RUNTIME_LOCKSTACK_INLINE_HPP