Skip to content

Commit ee47b5f

Browse files
committedJun 18, 2020
Fix forced preempt
1 parent 24de0d0 commit ee47b5f

File tree

4 files changed

+98
-22
lines changed

4 files changed

+98
-22
lines changed
 

‎src/hotspot/share/runtime/continuation.cpp

+89-19
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ template<int x> NOINLINE static bool verify_continuation(oop cont) { return Cont
130130
template<int x> NOINLINE static bool verify_stack_chunk(oop chunk) { return Continuation::debug_verify_stack_chunk(chunk); }
131131
#endif
132132

133+
#ifdef ASSERT
134+
extern "C" void pns2();
135+
extern "C" void pfl();
136+
#endif
137+
133138
int Continuations::_flags = 0;
134139
int ContinuationEntry::return_pc_offset = 0;
135140
nmethod* ContinuationEntry::continuation_enter = NULL;
@@ -657,7 +662,7 @@ class ContMirror {
657662
template <typename ConfigT> inline bool allocate_stacks(int size, int oops, int frames);
658663

659664
template <typename ConfigT>
660-
void make_keepalive(CompiledMethodKeepalive<ConfigT>* keepalive);
665+
void make_keepalive(Thread* thread, CompiledMethodKeepalive<ConfigT>* keepalive);
661666

662667
inline bool in_hstack(void *p) { return (_hstack != NULL && p >= _hstack && p < (_hstack + _stack_length)); }
663668

@@ -1972,7 +1977,7 @@ class CompiledMethodKeepalive {
19721977
int _nr_oops;
19731978
bool _required;
19741979

1975-
void store_keepalive(JavaThread* thread, oop* keepalive) { _keepalive = KeepaliveObjectT::make_keepalive(thread, keepalive); }
1980+
void store_keepalive(Thread* thread, oop* keepalive) { _keepalive = KeepaliveObjectT::make_keepalive(thread, keepalive); }
19761981
oop read_keepalive() { return KeepaliveObjectT::read_keepalive(_keepalive); }
19771982

19781983
public:
@@ -2199,6 +2204,11 @@ class Freeze {
21992204
int nr_bytes() const { return _size; }
22002205
int nr_frames() const { return _frames; }
22012206

2207+
Thread* cur_thread() {
2208+
assert (_preempt || _thread == Thread::current(), ""); // could be VM thread in force preempt
2209+
return mode == mode_fast ? _thread : Thread::current();
2210+
}
2211+
22022212
void verify() {
22032213
if (_cont.refStack() == NULL) {
22042214
return;
@@ -2230,19 +2240,22 @@ class Freeze {
22302240

22312241
freeze_result freeze_preempt() {
22322242
_preempt = true;
2243+
// if (!is_safe_to_preempt(_thread)) {
2244+
// return freeze_pinned_native;
2245+
// }
22332246
return freeze_no_chunk();
22342247
}
22352248

22362249
freeze_result freeze_no_chunk() {
22372250
log_develop_trace(jvmcont)("no young freeze mode: %d #" INTPTR_FORMAT, mode, _cont.hash());
22382251

22392252
assert (mode == mode_slow || !_preempt, "");
2240-
assert (_thread->thread_state() == _thread_in_vm, "");
2253+
assert (_thread->thread_state() == _thread_in_vm || _thread->thread_state() == _thread_blocked, "");
22412254

22422255
init_rest();
22432256
_cont.read_rest();
22442257

2245-
HandleMark hm(_thread);
2258+
HandleMark hm(cur_thread());
22462259

22472260
// tty->print_cr(">>> freeze mode: %d", mode);
22482261

@@ -2668,18 +2681,22 @@ class Freeze {
26682681

26692682
f.set_fp(f.real_fp()); // Instead of this, maybe in ContMirror::set_last_frame always use the real_fp? // TODO PD
26702683
if (Interpreter::contains(f.pc())) {
2671-
log_develop_trace(jvmcont)("INTERPRETER SAFEPOINT");
26722684
ContinuationHelper::update_register_map<Interpreted>(&_map, f);
26732685
// f.set_sp(f.sp() - 1); // state pushed to the stack
26742686
} else {
2675-
log_develop_trace(jvmcont)("COMPILER SAFEPOINT");
26762687
#ifdef ASSERT
26772688
if (!is_stub(f.cb())) { f.print_value_on(tty, JavaThread::current()); }
26782689
#endif
26792690
assert (is_stub(f.cb()), "must be");
26802691
assert (f.oop_map() != NULL, "must be");
2681-
ContinuationHelper::update_register_map<StubF>(&_map, f);
2682-
f.oop_map()->update_register_map(&f, (RegisterMap*)&_map); // we have callee-save registers in this case
2692+
2693+
if (Interpreter::contains(StubF::return_pc(f))) {
2694+
log_develop_trace(jvmcont)("Safepoint stub in interpreter");
2695+
f = sender<StubF>(f);
2696+
} else {
2697+
ContinuationHelper::update_register_map<StubF>(&_map, f);
2698+
f.oop_map()->update_register_map(&f, (RegisterMap*)&_map); // we have callee-save registers in this case
2699+
}
26832700
}
26842701

26852702
// Log(jvmcont) logv; LogStream st(logv.debug()); f.print_on(st);
@@ -2786,7 +2803,7 @@ class Freeze {
27862803

27872804
CompiledMethodKeepaliveT* current = _keepalive;
27882805
while (current != NULL) {
2789-
_cont.make_keepalive<ConfigT>(current);
2806+
_cont.make_keepalive<ConfigT>(cur_thread(), current);
27902807
current = current->parent();
27912808
}
27922809
}
@@ -3300,7 +3317,7 @@ static void post_JVMTI_yield(JavaThread* thread, ContMirror& cont) {
33003317
set_anchor_to_entry(thread, cont.entry()); // ensure frozen frames are invisible
33013318

33023319
// The call to JVMTI can safepoint, so we need to restore oops.
3303-
Handle conth(thread, cont.mirror());
3320+
Handle conth(Thread::current(), cont.mirror());
33043321
JvmtiExport::post_continuation_yield(JavaThread::current(), num_java_frames(cont));
33053322
cont.post_safepoint(conth);
33063323
}
@@ -3390,7 +3407,7 @@ int freeze0(JavaThread* thread, intptr_t* const sp, bool preempt) {
33903407
#endif
33913408
return freeze_epilog(thread, cont);
33923409
} else if (mode != mode_fast && UNLIKELY(preempt)) {
3393-
assert (thread->thread_state() == _thread_in_vm, "");
3410+
assert (thread->thread_state() == _thread_in_vm || thread->thread_state() == _thread_blocked, "");
33943411
freeze_result res = fr.freeze_preempt();
33953412
return freeze_epilog(thread, cont, res);
33963413
} else {
@@ -3500,10 +3517,58 @@ static freeze_result is_pinned0(JavaThread* thread, oop cont_scope, bool safepoi
35003517

35013518
typedef int (*DoYieldStub)(int scopes);
35023519

3520+
static bool is_safe_to_preempt(JavaThread* thread) {
3521+
if (!thread->has_last_Java_frame()) {
3522+
log_develop_trace(jvmcont)("is_safe_to_preempt: no last Java frame");
3523+
return false;
3524+
}
3525+
3526+
// assert (thread->thread_state() == _thread_blocked || thread == Thread::current(), "state: %s thread == Thread::current(): %d", thread->thread_state_name(), thread == Thread::current());
3527+
// if (Thread::current()->is_VM_thread() && thread->thread_state() == _thread_blocked) {
3528+
// log_develop_trace(jvmcont)("is_safe_to_preempt: thread blocked");
3529+
// return false; // if we do this, we can assume in the freeze code that the given thread is also the current thread
3530+
// }
3531+
3532+
frame f = thread->last_frame();
3533+
if (log_develop_is_enabled(Trace, jvmcont)) {
3534+
log_develop_trace(jvmcont)("is_safe_to_preempt %sSAFEPOINT", Interpreter::contains(f.pc()) ? "INTERPRETER " : "");
3535+
f.cb()->print_on(tty);
3536+
f.print_on(tty);
3537+
}
3538+
3539+
if (Interpreter::contains(f.pc())) {
3540+
InterpreterCodelet* desc = Interpreter::codelet_containing(f.pc());
3541+
if (desc != NULL) {
3542+
if (log_develop_is_enabled(Trace, jvmcont)) desc->print_on(tty);
3543+
// We allow preemption only when no bytecode (safepoint codelet) or a return byteocde
3544+
if (desc->bytecode() >= 0 && !Bytecodes::is_return(desc->bytecode())) {
3545+
log_develop_trace(jvmcont)("is_safe_to_preempt: unsafe bytecode: %s", Bytecodes::name(desc->bytecode()));
3546+
return false;
3547+
} else {
3548+
log_develop_trace(jvmcont)("is_safe_to_preempt: %s (safe)", desc->description());
3549+
// assert (Bytecodes::is_return(desc->bytecode()) || desc->description() != NULL && strncmp("safepoint", desc->description(), 9) == 0, "desc: %s", desc->description());
3550+
}
3551+
} else {
3552+
log_develop_trace(jvmcont)("is_safe_to_preempt: no codelet (safe?)");
3553+
}
3554+
} else {
3555+
// if (f.is_compiled_frame()) {
3556+
// RelocIterator iter(f.cb()->as_compiled_method(), f.pc(), f.pc()+1);
3557+
// while (iter.next()) {
3558+
// iter.print_current();
3559+
// }
3560+
// }
3561+
if (!f.cb()->is_safepoint_stub()) {
3562+
log_develop_trace(jvmcont)("is_safe_to_preempt: not safepoint stub");
3563+
return false;
3564+
}
3565+
}
3566+
return true;
3567+
}
3568+
35033569
// called in a safepoint
35043570
int Continuation::try_force_yield(JavaThread* thread, const oop cont) {
3505-
assert (thread->thread_state() == _thread_in_vm, "");
3506-
// assert (thread->thread_state() == _thread_in_vm || thread->thread_state() == _thread_blocked, "thread->thread_state(): %d", thread->thread_state());
3571+
assert (thread->thread_state() == _thread_in_vm || thread->thread_state() == _thread_blocked, "state: %s java: %d vm: %d", thread->thread_state_name(), thread->is_Java_thread(), thread->is_VM_thread());
35073572

35083573
ContinuationEntry* ce = thread->cont_entry();
35093574
oop innermost = ce->continuation();
@@ -3516,6 +3581,10 @@ int Continuation::try_force_yield(JavaThread* thread, const oop cont) {
35163581
if (thread->_cont_yield) {
35173582
return -2; // during yield
35183583
}
3584+
if (!is_safe_to_preempt(thread)) {
3585+
return freeze_pinned_native;
3586+
}
3587+
35193588
const oop scope = java_lang_Continuation::scope(cont);
35203589
if (innermost != cont) { // we have nested continuations
35213590
// make sure none of the continuations in the hierarchy are pinned
@@ -5239,8 +5308,8 @@ oop Continuation::continuation_scope(oop cont) {
52395308
///// Allocation
52405309

52415310
template <typename ConfigT>
5242-
void ContMirror::make_keepalive(CompiledMethodKeepalive<ConfigT>* keepalive) {
5243-
Handle conth(_thread, _cont);
5311+
void ContMirror::make_keepalive(Thread* thread, CompiledMethodKeepalive<ConfigT>* keepalive) {
5312+
Handle conth(thread, _cont);
52445313
int oops = keepalive->nr_oops();
52455314
if (oops == 0) {
52465315
oops = 1;
@@ -5249,7 +5318,7 @@ void ContMirror::make_keepalive(CompiledMethodKeepalive<ConfigT>* keepalive) {
52495318

52505319
uint64_t counter = SafepointSynchronize::safepoint_counter();
52515320
// check gc cycle
5252-
Handle keepaliveHandle = Handle(_thread, keepalive_obj);
5321+
Handle keepaliveHandle = Handle(thread, keepalive_obj);
52535322
keepalive->set_handle(keepaliveHandle);
52545323
// check gc cycle and maybe reload
52555324
//if (!SafepointSynchronize::is_same_safepoint(counter)) {
@@ -5560,7 +5629,7 @@ oop ContMirror::raw_allocate(Klass* klass, size_t size_in_words, size_t elements
55605629
return allocator.initialize(start);
55615630
} else {
55625631
//HandleMark hm(_thread);
5563-
Handle conth(_thread, _cont);
5632+
Handle conth(Thread::current(), _cont);
55645633
uint64_t counter = SafepointSynchronize::safepoint_counter();
55655634
oop result = allocator.allocate();
55665635
//if (!SafepointSynchronize::is_same_safepoint(counter)) {
@@ -5578,6 +5647,7 @@ oop ContMirror::allocate_stack_chunk(int stack_size) {
55785647
if (start != NULL) {
55795648
return allocator.initialize(start);
55805649
} else {
5650+
assert (_thread == Thread::current(), "");
55815651
//HandleMark hm(_thread);
55825652
Handle conth(_thread, _cont);
55835653
// uint64_t counter = SafepointSynchronize::safepoint_counter();
@@ -5726,7 +5796,7 @@ class HandleKeepalive {
57265796
public:
57275797
typedef Handle TypeT;
57285798

5729-
static Handle make_keepalive(JavaThread* thread, oop* keepalive) {
5799+
static Handle make_keepalive(Thread* thread, oop* keepalive) {
57305800
return Handle(thread, WeakHandle<vm_nmethod_keepalive_data>::from_raw(keepalive).resolve());
57315801
}
57325802

@@ -5739,7 +5809,7 @@ class NoKeepalive {
57395809
public:
57405810
typedef oop* TypeT;
57415811

5742-
static oop* make_keepalive(JavaThread* thread, oop* keepalive) {
5812+
static oop* make_keepalive(Thread* thread, oop* keepalive) {
57435813
return keepalive;
57445814
}
57455815

‎src/hotspot/share/runtime/frame.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -1295,10 +1295,16 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m
12951295
if (is_interpreted_frame()) {
12961296
Method* m = interpreter_frame_method();
12971297
int bci = interpreter_frame_bci();
1298+
InterpreterCodelet* desc = Interpreter::codelet_containing(pc());
12981299

12991300
// Label the method and current bci
13001301
values.describe(-1, info_address,
13011302
FormatBuffer<1024>("#%d method %s @ %d", frame_no, m->name_and_sig_as_C_string(), bci), 3);
1303+
if (desc != NULL) {
1304+
values.describe(-1, info_address, err_msg("- %s codelet: %s",
1305+
desc->bytecode() >= 0 ? Bytecodes::name(desc->bytecode()) : "",
1306+
desc->description() != NULL ? desc->description() : "?"), 2);
1307+
}
13021308
values.describe(-1, info_address,
13031309
err_msg("- %d locals %d max stack", m->max_locals(), m->max_stack()), 2);
13041310
values.describe(frame_no, (intptr_t*)sender_pc_addr(), Continuation::is_return_barrier_entry(*sender_pc_addr()) ? "return address (return barrier)" : "return address");

‎src/hotspot/share/runtime/thread.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2395,8 +2395,8 @@ void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
23952395
}
23962396

23972397
if (is_cont_force_yield()) {
2398-
set_cont_preempt(false);
23992398
log_develop_trace(jvmcont)("handle_special_runtime_exit_condition is_cont_force_yield: %d check_asyncs: %d", is_cont_force_yield(), check_asyncs);
2399+
set_cont_preempt(false);
24002400
if (check_asyncs) { // TODO: we should probably be even more selective than that
24012401
// we need this only for interpreted frames -- for compiled frames we install a return barrier on the safepoint stub in Continuation::try_force_yield
24022402
StubRoutines::cont_jump_from_sp_C()();

‎test/jdk/java/lang/Continuation/Preempt.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public void test1() throws Exception {
7777
do {
7878
res = cont.tryPreempt(t0);
7979
i++;
80-
} while (i < 10 && res == Continuation.PreemptStatus.TRANSIENT_FAIL_PINNED_NATIVE);
80+
} while (i < 20 && res == Continuation.PreemptStatus.TRANSIENT_FAIL_PINNED_NATIVE);
8181
assertEquals(res, Continuation.PreemptStatus.SUCCESS, "res: " + res + " i: " + i);
8282
}
8383
preemptLatch.await();
@@ -87,7 +87,7 @@ public void test1() throws Exception {
8787
do {
8888
res = cont.tryPreempt(t0);
8989
i++;
90-
} while (i < 10 && res == Continuation.PreemptStatus.TRANSIENT_FAIL_PINNED_NATIVE);
90+
} while (i < 20 && res == Continuation.PreemptStatus.TRANSIENT_FAIL_PINNED_NATIVE);
9191
assertEquals(res, Continuation.PreemptStatus.SUCCESS, "res: " + res + " i: " + i);
9292
}
9393
} catch (InterruptedException e) {

0 commit comments

Comments
 (0)
Please sign in to comment.