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"
41
extern "C" jint JNICALL CONT_isPinned0(JNIEnv* env, jobject cont_scope);
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");
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");
58
static jlong java_tid(JavaThread* thread) {
59
return java_lang_Thread::thread_id(thread->threadObj());
63
ContinuationEntry* Continuation::get_continuation_entry_for_continuation(JavaThread* thread, oop continuation) {
64
if (thread == nullptr || continuation == nullptr) {
68
for (ContinuationEntry* entry = thread->last_continuation(); entry != nullptr; entry = entry->parent()) {
69
if (continuation == entry->cont_oop(thread)) {
76
static bool is_on_stack(JavaThread* thread, const ContinuationEntry* entry) {
77
if (entry == nullptr) {
81
assert(thread->is_in_full_stack((address)entry), "");
87
bool Continuation::is_continuation_mounted(JavaThread* thread, oop continuation) {
88
return is_on_stack(thread, get_continuation_entry_for_continuation(thread, continuation));
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));
102
bool Continuation::is_return_barrier_entry(const address pc) {
103
if (!Continuations::enabled()) return false;
104
return pc == StubRoutines::cont_returnBarrier();
107
bool Continuation::is_continuation_enterSpecial(const frame& f) {
108
if (f.cb() == nullptr || !f.cb()->is_nmethod()) {
111
Method* m = f.cb()->as_nmethod()->method();
112
return (m != nullptr && m->is_continuation_enter_intrinsic());
115
bool Continuation::is_continuation_entry_frame(const frame& f, const RegisterMap *map) {
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;
127
static inline bool is_sp_in_continuation(const ContinuationEntry* entry, intptr_t* const sp) {
129
return entry->entry_sp() > sp;
132
bool Continuation::is_frame_in_continuation(const ContinuationEntry* entry, const frame& f) {
133
return is_sp_in_continuation(entry, f.sp());
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();
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");
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);
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();
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);
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);
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);
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);
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(), "");
204
log_develop_trace(continuations)("continuation_parent_frame");
205
if (map->update_map()) {
207
if (cont.entry() != nullptr) {
208
cont.entry()->update_register_map(map);
214
if (!cont.is_mounted()) {
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);
221
map->set_stack_chunk(nullptr);
225
map->set_stack_chunk(nullptr);
227
#if (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64)) && !defined(ZERO)
228
frame sender(cont.entrySP(), cont.entryFP(), cont.entryPC());
230
frame sender = frame();
237
oop Continuation::continuation_scope(oop continuation) {
238
return continuation != nullptr ? jdk_internal_vm_Continuation::scope(continuation) : nullptr;
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)) {
247
if (map->in_cont()) {
248
continuation = map->cont();
250
ContinuationEntry* ce = get_continuation_entry_for_sp(map->thread(), f.sp());
254
continuation = ce->cont_oop(map->thread());
256
if (continuation == nullptr) {
260
oop sc = continuation_scope(continuation);
261
assert(sc != nullptr, "");
262
return sc == cont_scope;
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;
271
bool Continuation::pin(JavaThread* current) {
272
ContinuationEntry* ce = current->last_continuation();
279
bool Continuation::unpin(JavaThread* current) {
280
ContinuationEntry* ce = current->last_continuation();
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()));
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));
296
frame entry = ce->to_frame();
297
if (callee.is_interpreted_frame()) {
298
entry.set_sp(sender_sp);
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();
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);
317
void Continuation::notify_deopt(JavaThread* thread, intptr_t* sp) {
318
ContinuationEntry* entry = thread->last_continuation();
320
if (entry == nullptr) {
324
if (is_sp_in_continuation(entry, sp)) {
325
thread->push_cont_fastpath(sp);
329
ContinuationEntry* prev;
332
entry = entry->parent();
333
} while (entry != nullptr && !is_sp_in_continuation(entry, sp));
335
if (entry == nullptr) {
338
assert(is_sp_in_continuation(entry, sp), "");
339
if (sp > prev->parent_cont_fastpath()) {
340
prev->set_parent_cont_fastpath(sp);
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");
359
void Continuation::debug_verify_continuation(oop contOop) {
360
if (!VerifyContinuations) {
363
assert(contOop != nullptr, "");
364
assert(oopDesc::is_oop(contOop), "");
365
ContinuationWrapper cont(contOop);
367
assert(oopDesc::is_oop_or_null(cont.tail()), "");
368
assert(cont.chunk_invariant(), "");
370
bool nonempty_chunk = false;
374
int num_interpreted_frames = 0;
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;
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()), "");
391
void Continuation::print(oop continuation) { print_on(tty, continuation); }
393
void Continuation::print_on(outputStream* st, oop continuation) {
394
ContinuationWrapper cont(continuation);
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()) {
401
chunk->print_on(true, st);
407
void continuations_init() { Continuations::init(); }
409
void Continuations::init() {
410
Continuation::init();
413
bool Continuations::enabled() {
414
return VMContinuations;
418
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
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)},
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");