1 /*
  2  * Copyright (c) 2018, 2024, 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 #include "precompiled.hpp"
 26 #include "classfile/vmSymbols.hpp"
 27 #include "gc/shared/barrierSetNMethod.hpp"
 28 #include "oops/method.inline.hpp"
 29 #include "runtime/continuation.hpp"
 30 #include "runtime/continuationEntry.inline.hpp"
 31 #include "runtime/continuationHelper.inline.hpp"
 32 #include "runtime/continuationJavaClasses.inline.hpp"
 33 #include "runtime/continuationWrapper.inline.hpp"
 34 #include "runtime/interfaceSupport.inline.hpp"
 35 #include "runtime/javaThread.inline.hpp"
 36 #include "runtime/osThread.hpp"
 37 #include "runtime/vframe.inline.hpp"
 38 #include "runtime/vframe_hp.hpp"
 39 
 40 // defined in continuationFreezeThaw.cpp
 41 extern "C" jint JNICALL CONT_isPinned0(JNIEnv* env, jobject cont_scope);
 42 
 43 JVM_ENTRY(void, CONT_pin(JNIEnv* env, jclass cls)) {
 44   if (!Continuation::pin(JavaThread::thread_from_jni_environment(env))) {
 45      THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "pin overflow");
 46   }
 47 }
 48 JVM_END
 49 
 50 JVM_ENTRY(void, CONT_unpin(JNIEnv* env, jclass cls)) {
 51   if (!Continuation::unpin(JavaThread::thread_from_jni_environment(env))) {
 52      THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "pin underflow");
 53   }
 54 }
 55 JVM_END
 56 
 57 #ifndef PRODUCT
 58 static jlong java_tid(JavaThread* thread) {
 59   return java_lang_Thread::thread_id(thread->threadObj());
 60 }
 61 #endif
 62 
 63 ContinuationEntry* Continuation::get_continuation_entry_for_continuation(JavaThread* thread, oop continuation) {
 64   if (thread == nullptr || continuation == nullptr) {
 65     return nullptr;
 66   }
 67 
 68   for (ContinuationEntry* entry = thread->last_continuation(); entry != nullptr; entry = entry->parent()) {
 69     if (continuation == entry->cont_oop(thread)) {
 70       return entry;
 71     }
 72   }
 73   return nullptr;
 74 }
 75 
 76 static bool is_on_stack(JavaThread* thread, const ContinuationEntry* entry) {
 77   if (entry == nullptr) {
 78     return false;
 79   }
 80 
 81   assert(thread->is_in_full_stack((address)entry), "");
 82   return true;
 83   // return false if called when transitioning to Java on return from freeze
 84   // return !thread->has_last_Java_frame() || thread->last_Java_sp() < cont->entry_sp();
 85 }
 86 
 87 bool Continuation::is_continuation_mounted(JavaThread* thread, oop continuation) {
 88   return is_on_stack(thread, get_continuation_entry_for_continuation(thread, continuation));
 89 }
 90 
 91 // When walking the virtual stack, this method returns true
 92 // iff the frame is a thawed continuation frame whose
 93 // caller is still frozen on the h-stack.
 94 // The continuation object can be extracted from the thread.
 95 bool Continuation::is_cont_barrier_frame(const frame& f) {
 96   assert(f.is_interpreted_frame() || f.cb() != nullptr, "");
 97   if (!Continuations::enabled()) return false;
 98   return is_return_barrier_entry(f.is_interpreted_frame() ? ContinuationHelper::InterpretedFrame::return_pc(f)
 99                                                           : ContinuationHelper::CompiledFrame::return_pc(f));
100 }
101 
102 bool Continuation::is_return_barrier_entry(const address pc) {
103   if (!Continuations::enabled()) return false;
104   return pc == StubRoutines::cont_returnBarrier();
105 }
106 
107 bool Continuation::is_continuation_enterSpecial(const frame& f) {
108   if (f.cb() == nullptr || !f.cb()->is_nmethod()) {
109     return false;
110   }
111   Method* m = f.cb()->as_nmethod()->method();
112   return (m != nullptr && m->is_continuation_enter_intrinsic());
113 }
114 
115 bool Continuation::is_continuation_entry_frame(const frame& f, const RegisterMap *map) {
116   // we can do this because the entry frame is never inlined
117   Method* m = (map != nullptr && map->in_cont() && f.is_interpreted_frame())
118                   ? map->stack_chunk()->interpreter_frame_method(f)
119                   : ContinuationHelper::Frame::frame_method(f);
120   return m != nullptr && m->intrinsic_id() == vmIntrinsics::_Continuation_enter;
121 }
122 
123 // The parameter `sp` should be the actual sp and not the unextended sp because at
124 // least on PPC64 unextended_sp < sp is possible as interpreted frames are trimmed
125 // to the actual size of the expression stack before calls. The problem there is
126 // that even unextended_sp < entry_sp < sp is possible for an interpreted frame.
127 static inline bool is_sp_in_continuation(const ContinuationEntry* entry, intptr_t* const sp) {
128   // entry_sp() returns the unextended_sp which is always greater or equal to the actual sp
129   return entry->entry_sp() > sp;
130 }
131 
132 bool Continuation::is_frame_in_continuation(const ContinuationEntry* entry, const frame& f) {
133   return is_sp_in_continuation(entry, f.sp());
134 }
135 
136 ContinuationEntry* Continuation::get_continuation_entry_for_sp(JavaThread* thread, intptr_t* const sp) {
137   assert(thread != nullptr, "");
138   ContinuationEntry* entry = thread->last_continuation();
139   while (entry != nullptr && !is_sp_in_continuation(entry, sp)) {
140     entry = entry->parent();
141   }
142   return entry;
143 }
144 
145 ContinuationEntry* Continuation::get_continuation_entry_for_entry_frame(JavaThread* thread, const frame& f) {
146   assert(is_continuation_enterSpecial(f), "");
147   ContinuationEntry* entry = (ContinuationEntry*)f.unextended_sp();
148   assert(entry == get_continuation_entry_for_sp(thread, f.sp()-2), "mismatched entry");
149   return entry;
150 }
151 
152 bool Continuation::is_frame_in_continuation(JavaThread* thread, const frame& f) {
153   return f.is_heap_frame() || (get_continuation_entry_for_sp(thread, f.sp()) != nullptr);
154 }
155 
156 static frame continuation_top_frame(const ContinuationWrapper& cont, RegisterMap* map) {
157   stackChunkOop chunk = cont.last_nonempty_chunk();
158   map->set_stack_chunk(chunk);
159   return chunk != nullptr ? chunk->top_frame(map) : frame();
160 }
161 
162 bool Continuation::has_last_Java_frame(oop continuation, frame* frame, RegisterMap* map) {
163   ContinuationWrapper cont(continuation);
164   if (!cont.is_empty()) {
165     *frame = continuation_top_frame(cont, map);
166     return true;
167   } else {
168     return false;
169   }
170 }
171 
172 frame Continuation::last_frame(oop continuation, RegisterMap *map) {
173   assert(map != nullptr, "a map must be given");
174   return continuation_top_frame(ContinuationWrapper(continuation), map);
175 }
176 
177 frame Continuation::top_frame(const frame& callee, RegisterMap* map) {
178   assert(map != nullptr, "");
179   ContinuationEntry* ce = get_continuation_entry_for_sp(map->thread(), callee.sp());
180   assert(ce != nullptr, "");
181   oop continuation = ce->cont_oop(map->thread());
182   ContinuationWrapper cont(continuation);
183   return continuation_top_frame(cont, map);
184 }
185 
186 javaVFrame* Continuation::last_java_vframe(Handle continuation, RegisterMap *map) {
187   assert(map != nullptr, "a map must be given");
188   if (!ContinuationWrapper(continuation()).is_empty()) {
189     frame f = last_frame(continuation(), map);
190     for (vframe* vf = vframe::new_vframe(&f, map, nullptr); vf; vf = vf->sender()) {
191       if (vf->is_java_frame()) {
192         return javaVFrame::cast(vf);
193       }
194     }
195   }
196   return nullptr;
197 }
198 
199 frame Continuation::continuation_parent_frame(RegisterMap* map) {
200   assert(map->in_cont(), "");
201   ContinuationWrapper cont(map);
202   assert(map->thread() != nullptr || !cont.is_mounted(), "");
203 
204   log_develop_trace(continuations)("continuation_parent_frame");
205   if (map->update_map()) {
206     // we need to register the link address for the entry frame
207     if (cont.entry() != nullptr) {
208       cont.entry()->update_register_map(map);
209     } else {
210       map->clear();
211     }
212   }
213 
214   if (!cont.is_mounted()) { // When we're walking an unmounted continuation and reached the end
215     oop parent = jdk_internal_vm_Continuation::parent(cont.continuation());
216     stackChunkOop chunk = parent != nullptr ? ContinuationWrapper(parent).last_nonempty_chunk() : nullptr;
217     if (chunk != nullptr) {
218       return chunk->top_frame(map);
219     }
220 
221     map->set_stack_chunk(nullptr);
222     return frame();
223   }
224 
225   map->set_stack_chunk(nullptr);
226 
227 #if (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64)) && !defined(ZERO)
228   frame sender(cont.entrySP(), cont.entryFP(), cont.entryPC());
229 #else
230   frame sender = frame();
231   Unimplemented();
232 #endif
233 
234   return sender;
235 }
236 
237 oop Continuation::continuation_scope(oop continuation) {
238   return continuation != nullptr ? jdk_internal_vm_Continuation::scope(continuation) : nullptr;
239 }
240 
241 bool Continuation::is_scope_bottom(oop cont_scope, const frame& f, const RegisterMap* map) {
242   if (cont_scope == nullptr || !is_continuation_entry_frame(f, map)) {
243     return false;
244   }
245 
246   oop continuation;
247   if (map->in_cont()) {
248     continuation = map->cont();
249   } else {
250     ContinuationEntry* ce = get_continuation_entry_for_sp(map->thread(), f.sp());
251     if (ce == nullptr) {
252       return false;
253     }
254     continuation = ce->cont_oop(map->thread());
255   }
256   if (continuation == nullptr) {
257     return false;
258   }
259 
260   oop sc = continuation_scope(continuation);
261   assert(sc != nullptr, "");
262   return sc == cont_scope;
263 }
264 
265 bool Continuation::is_in_usable_stack(address addr, const RegisterMap* map) {
266   ContinuationWrapper cont(map);
267   stackChunkOop chunk = cont.find_chunk_by_address(addr);
268   return chunk != nullptr ? chunk->is_usable_in_chunk(addr) : false;
269 }
270 
271 bool Continuation::pin(JavaThread* current) {
272   ContinuationEntry* ce = current->last_continuation();
273   if (ce == nullptr) {
274     return true; // no continuation mounted
275   }
276   return ce->pin();
277 }
278 
279 bool Continuation::unpin(JavaThread* current) {
280   ContinuationEntry* ce = current->last_continuation();
281   if (ce == nullptr) {
282     return true; // no continuation mounted
283   }
284   return ce->unpin();
285 }
286 
287 frame Continuation::continuation_bottom_sender(JavaThread* thread, const frame& callee, intptr_t* sender_sp) {
288   assert (thread != nullptr, "");
289   ContinuationEntry* ce = get_continuation_entry_for_sp(thread, callee.sp());
290   assert(ce != nullptr, "callee.sp(): " INTPTR_FORMAT, p2i(callee.sp()));
291 
292   log_develop_debug(continuations)("continuation_bottom_sender: [" JLONG_FORMAT "] [%d] callee: " INTPTR_FORMAT
293     " sender_sp: " INTPTR_FORMAT,
294     java_tid(thread), thread->osthread()->thread_id(), p2i(callee.sp()), p2i(sender_sp));
295 
296   frame entry = ce->to_frame();
297   if (callee.is_interpreted_frame()) {
298     entry.set_sp(sender_sp); // sp != unextended_sp
299   }
300   return entry;
301 }
302 
303 address Continuation::get_top_return_pc_post_barrier(JavaThread* thread, address pc) {
304   ContinuationEntry* ce;
305   if (thread != nullptr && is_return_barrier_entry(pc) && (ce = thread->last_continuation()) != nullptr) {
306     return ce->entry_pc();
307   }
308   return pc;
309 }
310 
311 void Continuation::set_cont_fastpath_thread_state(JavaThread* thread) {
312   assert(thread != nullptr, "");
313   bool fast = !thread->is_interp_only_mode();
314   thread->set_cont_fastpath_thread_state(fast);
315 }
316 
317 void Continuation::notify_deopt(JavaThread* thread, intptr_t* sp) {
318   ContinuationEntry* entry = thread->last_continuation();
319 
320   if (entry == nullptr) {
321     return;
322   }
323 
324   if (is_sp_in_continuation(entry, sp)) {
325     thread->push_cont_fastpath(sp);
326     return;
327   }
328 
329   ContinuationEntry* prev;
330   do {
331     prev = entry;
332     entry = entry->parent();
333   } while (entry != nullptr && !is_sp_in_continuation(entry, sp));
334 
335   if (entry == nullptr) {
336     return;
337   }
338   assert(is_sp_in_continuation(entry, sp), "");
339   if (sp > prev->parent_cont_fastpath()) {
340     prev->set_parent_cont_fastpath(sp);
341   }
342 }
343 
344 #ifndef PRODUCT
345 void Continuation::describe(FrameValues &values) {
346   JavaThread* thread = JavaThread::active();
347   if (thread != nullptr) {
348     for (ContinuationEntry* ce = thread->last_continuation(); ce != nullptr; ce = ce->parent()) {
349       intptr_t* bottom = ce->entry_sp();
350       if (bottom != nullptr) {
351         values.describe(-1, bottom, "continuation entry");
352       }
353     }
354   }
355 }
356 #endif
357 
358 #ifdef ASSERT
359 void Continuation::debug_verify_continuation(oop contOop) {
360   if (!VerifyContinuations) {
361     return;
362   }
363   assert(contOop != nullptr, "");
364   assert(oopDesc::is_oop(contOop), "");
365   ContinuationWrapper cont(contOop);
366 
367   assert(oopDesc::is_oop_or_null(cont.tail()), "");
368   assert(cont.chunk_invariant(), "");
369 
370   bool nonempty_chunk = false;
371   size_t max_size = 0;
372   int num_chunks = 0;
373   int num_frames = 0;
374   int num_interpreted_frames = 0;
375   int num_oops = 0;
376 
377   for (stackChunkOop chunk = cont.tail(); chunk != nullptr; chunk = chunk->parent()) {
378     log_develop_trace(continuations)("debug_verify_continuation chunk %d", num_chunks);
379     chunk->verify(&max_size, &num_oops, &num_frames, &num_interpreted_frames);
380     if (!chunk->is_empty()) {
381       nonempty_chunk = true;
382     }
383     num_chunks++;
384   }
385 
386   const bool is_empty = cont.is_empty();
387   assert(!nonempty_chunk || !is_empty, "");
388   assert(is_empty == (!nonempty_chunk && cont.last_frame().is_empty()), "");
389 }
390 
391 void Continuation::print(oop continuation) { print_on(tty, continuation); }
392 
393 void Continuation::print_on(outputStream* st, oop continuation) {
394   ContinuationWrapper cont(continuation);
395 
396   st->print_cr("CONTINUATION: " PTR_FORMAT " done: %d",
397     continuation->identity_hash(), jdk_internal_vm_Continuation::done(continuation));
398   st->print_cr("CHUNKS:");
399   for (stackChunkOop chunk = cont.tail(); chunk != nullptr; chunk = chunk->parent()) {
400     st->print("* ");
401     chunk->print_on(true, st);
402   }
403 }
404 #endif // ASSERT
405 
406 
407 void continuations_init() { Continuations::init(); }
408 
409 void Continuations::init() {
410   Continuation::init();
411 }
412 
413 bool Continuations::enabled() {
414   return VMContinuations;
415 }
416 
417 #define CC (char*)  /*cast a literal from (const char*)*/
418 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
419 
420 static JNINativeMethod CONT_methods[] = {
421     {CC"pin",              CC"()V",                                    FN_PTR(CONT_pin)},
422     {CC"unpin",            CC"()V",                                    FN_PTR(CONT_unpin)},
423     {CC"isPinned0",        CC"(Ljdk/internal/vm/ContinuationScope;)I", FN_PTR(CONT_isPinned0)},
424 };
425 
426 void CONT_RegisterNativeMethods(JNIEnv *env, jclass cls) {
427     JavaThread* thread = JavaThread::current();
428     ThreadToNativeFromVM trans(thread);
429     int status = env->RegisterNatives(cls, CONT_methods, sizeof(CONT_methods)/sizeof(JNINativeMethod));
430     guarantee(status == JNI_OK, "register jdk.internal.vm.Continuation natives");
431     guarantee(!env->ExceptionOccurred(), "register jdk.internal.vm.Continuation natives");
432 }