1 /*
  2  * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #ifndef SHARE_VM_RUNTIME_CONTINUATIONWRAPPER_INLINE_HPP
 26 #define SHARE_VM_RUNTIME_CONTINUATIONWRAPPER_INLINE_HPP
 27 
 28 // There is no continuationWrapper.hpp file
 29 
 30 #include "classfile/javaClasses.inline.hpp"
 31 #include "oops/oop.inline.hpp"
 32 #include "memory/allocation.hpp"
 33 #include "oops/oopsHierarchy.hpp"
 34 #include "oops/stackChunkOop.hpp"
 35 #include "runtime/continuationEntry.inline.hpp"
 36 #include "runtime/continuationJavaClasses.inline.hpp"
 37 #include "runtime/javaThread.hpp"
 38 
 39 /////////////////////////////////////////////////////////////////////
 40 
 41 // Intermediary to the jdk.internal.vm.Continuation objects and ContinuationEntry
 42 // This object is created when we begin a operation for a continuation, and is destroyed when the operation completes.
 43 // Contents are read from the Java object at the entry points of this module, and written at exit or calls into Java
 44 // It also serves as a custom NoSafepointVerifier
 45 class ContinuationWrapper : public StackObj {
 46 private:
 47   JavaThread* const  _thread;   // Thread being frozen/thawed
 48   ContinuationEntry* _entry;
 49   // These oops are managed by SafepointOp
 50   oop                _continuation;  // jdk.internal.vm.Continuation instance
 51   stackChunkOop      _tail;
 52   bool               _done;
 53 
 54   ContinuationWrapper(const ContinuationWrapper& cont); // no copy constructor
 55 
 56 private:
 57   DEBUG_ONLY(Thread* _current_thread;)
 58   friend class SafepointOp;
 59 
 60   void disallow_safepoint() {
 61     #ifdef ASSERT
 62       assert(!_done, "");
 63       assert(_continuation != nullptr, "");
 64       _current_thread = Thread::current();
 65       if (_current_thread->is_Java_thread()) {
 66         JavaThread::cast(_current_thread)->inc_no_safepoint_count();
 67       }
 68     #endif
 69   }
 70 
 71   void allow_safepoint() {
 72     #ifdef ASSERT
 73       // we could have already allowed safepoints in done
 74       if (!_done && _current_thread->is_Java_thread()) {
 75         JavaThread::cast(_current_thread)->dec_no_safepoint_count();
 76       }
 77     #endif
 78   }
 79 
 80   ContinuationWrapper(JavaThread* thread, ContinuationEntry* entry, oop continuation);
 81 
 82 public:
 83   void done() {
 84     allow_safepoint(); // must be done first
 85     _done = true;
 86     *reinterpret_cast<intptr_t*>(&_continuation) = badHeapOopVal;
 87     *reinterpret_cast<intptr_t*>(&_tail) = badHeapOopVal;
 88   }
 89 
 90   class SafepointOp : public StackObj {
 91     ContinuationWrapper& _cont;
 92     Handle _conth;
 93   public:
 94     SafepointOp(Thread* current, ContinuationWrapper& cont)
 95       : _cont(cont), _conth(current, cont._continuation) {
 96       _cont.allow_safepoint();
 97     }
 98     inline ~SafepointOp() { // reload oops
 99       _cont._continuation = _conth();
100       _cont._tail = jdk_internal_vm_Continuation::tail(_cont._continuation);
101       _cont.disallow_safepoint();
102     }
103   };
104 
105 public:
106   ~ContinuationWrapper() { allow_safepoint(); }
107 
108   ContinuationWrapper(JavaThread* thread, oop continuation);
109   ContinuationWrapper(oop continuation);
110   ContinuationWrapper(const RegisterMap* map);
111 
112   JavaThread* thread() const         { return _thread; }
113   oop continuation()                 { return _continuation; }
114   stackChunkOop tail() const         { return _tail; }
115   void set_tail(stackChunkOop chunk) { _tail = chunk; }
116 
117   inline bool is_preempted();
118   inline void set_preempted(bool value);
119   inline void read();
120   inline void write();
121 
122   NOT_PRODUCT(intptr_t hash();)
123 
124   ContinuationEntry* entry() const { return _entry; }
125   bool is_mounted()   const { return _entry != nullptr; }
126   intptr_t* entrySP() const { return _entry->entry_sp(); }
127   intptr_t* entryFP() const { return _entry->entry_fp(); }
128   address   entryPC() const { return _entry->entry_pc(); }
129   int argsize()       const { assert(_entry->argsize() >= 0, ""); return _entry->argsize(); }
130   int entry_frame_extension() const {
131     // the entry frame is extended if the bottom frame has stack arguments
132     assert(_entry->argsize() >= 0, "");
133     return _entry->argsize() == 0 ? _entry->argsize() : _entry->argsize() + frame::metadata_words_at_top;
134   }
135   void set_argsize(int value) { _entry->set_argsize(value); }
136 
137   bool is_empty() const { return last_nonempty_chunk() == nullptr; }
138   const frame last_frame();
139 
140   inline stackChunkOop last_nonempty_chunk() const;
141   stackChunkOop find_chunk_by_address(void* p) const;
142 
143 #ifdef ASSERT
144   bool is_entry_frame(const frame& f);
145   bool chunk_invariant() const;
146 #endif
147 };
148 
149 inline ContinuationWrapper::ContinuationWrapper(JavaThread* thread, ContinuationEntry* entry, oop continuation)
150   : _thread(thread), _entry(entry), _continuation(continuation), _done(false) {
151   assert(oopDesc::is_oop(_continuation),
152          "Invalid continuation object: " INTPTR_FORMAT, p2i((void*)_continuation));
153   disallow_safepoint();
154   read();
155 }
156 
157 inline ContinuationWrapper::ContinuationWrapper(JavaThread* thread, oop continuation)
158   : ContinuationWrapper(thread, thread->last_continuation(), continuation) {}
159 
160 inline ContinuationWrapper::ContinuationWrapper(oop continuation)
161   : ContinuationWrapper(nullptr, nullptr, continuation) {}
162 
163 inline bool ContinuationWrapper::is_preempted() {
164   return jdk_internal_vm_Continuation::is_preempted(_continuation);
165 }
166 
167 inline void ContinuationWrapper::set_preempted(bool value) {
168   jdk_internal_vm_Continuation::set_preempted(_continuation, value);
169 }
170 
171 inline void ContinuationWrapper::read() {
172   _tail  = jdk_internal_vm_Continuation::tail(_continuation);
173 }
174 
175 inline void ContinuationWrapper::write() {
176   assert(oopDesc::is_oop(_continuation), "bad oop");
177   assert(oopDesc::is_oop_or_null(_tail), "bad oop");
178   jdk_internal_vm_Continuation::set_tail(_continuation, _tail);
179 }
180 
181 inline stackChunkOop ContinuationWrapper::last_nonempty_chunk() const {
182   assert(chunk_invariant(), "");
183   stackChunkOop chunk = _tail;
184   if (chunk != nullptr && chunk->is_empty()) {
185     chunk = chunk->parent();
186   }
187   assert(chunk == nullptr || !chunk->is_empty(), "");
188   return chunk;
189 }
190 
191 #endif // SHARE_VM_RUNTIME_CONTINUATIONWRAPPER_INLINE_HPP