1 /*
  2  * Copyright (c) 2022, Red Hat, Inc. All rights reserved.
  3  * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #ifndef SHARE_RUNTIME_LOCKSTACK_INLINE_HPP
 27 #define SHARE_RUNTIME_LOCKSTACK_INLINE_HPP
 28 
 29 #include "memory/iterator.hpp"
 30 #include "runtime/lockStack.hpp"
 31 #include "runtime/safepoint.hpp"
 32 #include "runtime/stackWatermark.hpp"
 33 #include "runtime/stackWatermarkSet.inline.hpp"
 34 #include "runtime/thread.hpp"
 35 
 36 inline int LockStack::to_index(uint32_t offset) {
 37   return (offset - lock_stack_base_offset) / oopSize;
 38 }
 39 
 40 JavaThread* LockStack::get_thread() const {
 41   char* addr = reinterpret_cast<char*>(const_cast<LockStack*>(this));
 42   return reinterpret_cast<JavaThread*>(addr - lock_stack_offset);
 43 }
 44 
 45 inline bool LockStack::can_push() const {
 46   return to_index(_top) < CAPACITY;
 47 }
 48 
 49 inline bool LockStack::is_owning_thread() const {
 50   JavaThread* thread = JavaThread::current();
 51   bool is_owning = &thread->lock_stack() == this;
 52   assert(is_owning == (get_thread() == thread), "is_owning sanity");
 53   return is_owning;
 54 }
 55 
 56 inline void LockStack::push(oop o) {
 57   verify("pre-push");
 58   assert(oopDesc::is_oop(o), "must be");
 59   assert(!contains(o), "entries must be unique");
 60   assert(can_push(), "must have room");
 61   assert(_base[to_index(_top)] == NULL, "expect zapped entry");
 62   _base[to_index(_top)] = o;
 63   _top += oopSize;
 64   verify("post-push");
 65 }
 66 
 67 inline oop LockStack::pop() {
 68   verify("pre-pop");
 69   assert(to_index(_top) > 0, "underflow, probably unbalanced push/pop");
 70   _top -= oopSize;
 71   oop o = _base[to_index(_top)];
 72 #ifdef ASSERT
 73   _base[to_index(_top)] = NULL;
 74 #endif
 75   assert(!contains(o), "entries must be unique: " PTR_FORMAT, p2i(o));
 76   verify("post-pop");
 77   return o;
 78 }
 79 
 80 inline void LockStack::remove(oop o) {
 81   verify("pre-remove");
 82   assert(contains(o), "entry must be present: " PTR_FORMAT, p2i(o));
 83   int end = to_index(_top);
 84   for (int i = 0; i < end; i++) {
 85     if (_base[i] == o) {
 86       int last = end - 1;
 87       for (; i < last; i++) {
 88         _base[i] = _base[i + 1];
 89       }
 90       _top -= oopSize;
 91 #ifdef ASSERT
 92       _base[to_index(_top)] = NULL;
 93 #endif
 94       break;
 95     }
 96   }
 97   assert(!contains(o), "entries must be unique: " PTR_FORMAT, p2i(o));
 98   verify("post-remove");
 99 }
100 
101 inline bool LockStack::contains(oop o) const {
102   verify("pre-contains");
103   if (!SafepointSynchronize::is_at_safepoint() && !is_owning_thread()) {
104     // When a foreign thread inspects this thread's lock-stack, it may see
105     // bad references here when a concurrent collector has not gotten
106     // to processing the lock-stack, yet. Call StackWaterMark::start_processing()
107     // to ensure that all references are valid.
108     StackWatermark* watermark = StackWatermarkSet::get(get_thread(), StackWatermarkKind::gc);
109     if (watermark != NULL) {
110       watermark->start_processing();
111     }
112   }
113   int end = to_index(_top);
114   for (int i = end - 1; i >= 0; i--) {
115     if (_base[i] == o) {
116       verify("post-contains");
117       return true;
118     }
119   }
120   verify("post-contains");
121   return false;
122 }
123 
124 inline void LockStack::oops_do(OopClosure* cl) {
125   verify("pre-oops-do");
126   int end = to_index(_top);
127   for (int i = 0; i < end; i++) {
128     cl->do_oop(&_base[i]);
129   }
130   verify("post-oops-do");
131 }
132 
133 #endif // SHARE_RUNTIME_LOCKSTACK_INLINE_HPP