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