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