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