jdk

Форк
0
/
continuation.cpp 
432 строки · 14.6 Кб
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
}
433

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.