mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-01 11:40:33 +00:00
8373367: interp-only mechanism fails to work for carrier threads in a corner case
Reviewed-by: amenkov, lmesnik
This commit is contained in:
parent
6daca7ef99
commit
dc06fede2a
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2491,7 +2491,7 @@ SetOrClearFramePopClosure::do_thread(Thread *target) {
|
||||
_result = JVMTI_ERROR_NO_MORE_FRAMES;
|
||||
return;
|
||||
}
|
||||
assert(_state->get_thread_or_saved() == java_thread, "Must be");
|
||||
assert(_state->get_thread() == java_thread, "Must be");
|
||||
|
||||
RegisterMap reg_map(java_thread,
|
||||
RegisterMap::UpdateMap::include,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -151,11 +151,6 @@ bool JvmtiEnvThreadState::is_virtual() {
|
||||
return _state->is_virtual();
|
||||
}
|
||||
|
||||
// Use _thread_saved if cthread is detached from JavaThread (_thread == nullptr).
|
||||
JavaThread* JvmtiEnvThreadState::get_thread_or_saved() {
|
||||
return _state->get_thread_or_saved();
|
||||
}
|
||||
|
||||
JavaThread* JvmtiEnvThreadState::get_thread() {
|
||||
return _state->get_thread();
|
||||
}
|
||||
@ -344,7 +339,7 @@ void JvmtiEnvThreadState::reset_current_location(jvmtiEvent event_type, bool ena
|
||||
if (enabled) {
|
||||
// If enabling breakpoint, no need to reset.
|
||||
// Can't do anything if empty stack.
|
||||
JavaThread* thread = get_thread_or_saved();
|
||||
JavaThread* thread = get_thread();
|
||||
|
||||
if (event_type == JVMTI_EVENT_SINGLE_STEP &&
|
||||
((thread == nullptr && is_virtual()) || thread->has_last_Java_frame())) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -170,8 +170,6 @@ public:
|
||||
|
||||
inline JvmtiThreadState* jvmti_thread_state() { return _state; }
|
||||
|
||||
// use _thread_saved if cthread is detached from JavaThread
|
||||
JavaThread *get_thread_or_saved();
|
||||
JavaThread *get_thread();
|
||||
inline JvmtiEnv *get_env() { return _env; }
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -217,6 +217,10 @@ class EnterInterpOnlyModeClosure : public HandshakeClosure {
|
||||
|
||||
assert(state != nullptr, "sanity check");
|
||||
assert(state->get_thread() == jt, "handshake unsafe conditions");
|
||||
assert(jt->jvmti_thread_state() == state, "sanity check");
|
||||
assert(!jt->is_interp_only_mode(), "sanity check");
|
||||
assert(!state->is_interp_only_mode(), "sanity check");
|
||||
|
||||
if (!state->is_pending_interp_only_mode()) {
|
||||
_completed = true;
|
||||
return; // The pending flag has been already cleared, so bail out.
|
||||
@ -361,7 +365,8 @@ void VM_ChangeSingleStep::doit() {
|
||||
|
||||
void JvmtiEventControllerPrivate::enter_interp_only_mode(JvmtiThreadState *state) {
|
||||
EC_TRACE(("[%s] # Entering interpreter only mode",
|
||||
JvmtiTrace::safe_get_thread_name(state->get_thread_or_saved())));
|
||||
JvmtiTrace::safe_get_thread_name(state->get_thread())));
|
||||
|
||||
JavaThread *target = state->get_thread();
|
||||
Thread *current = Thread::current();
|
||||
|
||||
@ -371,8 +376,13 @@ void JvmtiEventControllerPrivate::enter_interp_only_mode(JvmtiThreadState *state
|
||||
}
|
||||
// This flag will be cleared in EnterInterpOnlyModeClosure handshake.
|
||||
state->set_pending_interp_only_mode(true);
|
||||
if (target == nullptr) { // an unmounted virtual thread
|
||||
return; // EnterInterpOnlyModeClosure will be executed right after mount.
|
||||
|
||||
// There are two cases when entering interp_only_mode is postponed:
|
||||
// 1. Unmounted virtual thread - EnterInterpOnlyModeClosure::do_thread will be executed at mount;
|
||||
// 2. Carrier thread with mounted virtual thread - EnterInterpOnlyModeClosure::do_thread will be executed at unmount.
|
||||
if (target == nullptr || // an unmounted virtual thread
|
||||
JvmtiEnvBase::is_thread_carrying_vthread(target, state->get_thread_oop())) { // a vthread carrying thread
|
||||
return; // EnterInterpOnlyModeClosure will be executed right after mount or unmount.
|
||||
}
|
||||
EnterInterpOnlyModeClosure hs(state);
|
||||
if (target->is_handshake_safe_for(current)) {
|
||||
@ -388,7 +398,8 @@ void JvmtiEventControllerPrivate::enter_interp_only_mode(JvmtiThreadState *state
|
||||
void
|
||||
JvmtiEventControllerPrivate::leave_interp_only_mode(JvmtiThreadState *state) {
|
||||
EC_TRACE(("[%s] # Leaving interpreter only mode",
|
||||
JvmtiTrace::safe_get_thread_name(state->get_thread_or_saved())));
|
||||
JvmtiTrace::safe_get_thread_name(state->get_thread())));
|
||||
|
||||
if (state->is_pending_interp_only_mode()) {
|
||||
state->set_pending_interp_only_mode(false); // Just clear the pending flag.
|
||||
assert(!state->is_interp_only_mode(), "sanity check");
|
||||
@ -409,7 +420,7 @@ JvmtiEventControllerPrivate::trace_changed(JvmtiThreadState *state, jlong now_en
|
||||
if (changed & bit) {
|
||||
// it changed, print it
|
||||
log_trace(jvmti)("[%s] # %s event %s",
|
||||
JvmtiTrace::safe_get_thread_name(state->get_thread_or_saved()),
|
||||
JvmtiTrace::safe_get_thread_name(state->get_thread()),
|
||||
(now_enabled & bit)? "Enabling" : "Disabling", JvmtiTrace::event_name((jvmtiEvent)ei));
|
||||
}
|
||||
}
|
||||
@ -932,7 +943,7 @@ JvmtiEventControllerPrivate::set_user_enabled(JvmtiEnvBase *env, JavaThread *thr
|
||||
void
|
||||
JvmtiEventControllerPrivate::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
|
||||
EC_TRACE(("[%s] # set frame pop - frame=%d",
|
||||
JvmtiTrace::safe_get_thread_name(ets->get_thread_or_saved()),
|
||||
JvmtiTrace::safe_get_thread_name(ets->get_thread()),
|
||||
fpop.frame_number() ));
|
||||
|
||||
ets->get_frame_pops()->set(fpop);
|
||||
@ -943,7 +954,7 @@ JvmtiEventControllerPrivate::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFrameP
|
||||
void
|
||||
JvmtiEventControllerPrivate::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
|
||||
EC_TRACE(("[%s] # clear frame pop - frame=%d",
|
||||
JvmtiTrace::safe_get_thread_name(ets->get_thread_or_saved()),
|
||||
JvmtiTrace::safe_get_thread_name(ets->get_thread()),
|
||||
fpop.frame_number() ));
|
||||
|
||||
ets->get_frame_pops()->clear(fpop);
|
||||
@ -953,7 +964,7 @@ JvmtiEventControllerPrivate::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFram
|
||||
void
|
||||
JvmtiEventControllerPrivate::clear_all_frame_pops(JvmtiEnvThreadState *ets) {
|
||||
EC_TRACE(("[%s] # clear all frame pops",
|
||||
JvmtiTrace::safe_get_thread_name(ets->get_thread_or_saved())
|
||||
JvmtiTrace::safe_get_thread_name(ets->get_thread())
|
||||
));
|
||||
|
||||
ets->get_frame_pops()->clear_all();
|
||||
@ -965,7 +976,7 @@ JvmtiEventControllerPrivate::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiF
|
||||
int cleared_cnt = ets->get_frame_pops()->clear_to(fpop);
|
||||
|
||||
EC_TRACE(("[%s] # clear to frame pop - frame=%d, count=%d",
|
||||
JvmtiTrace::safe_get_thread_name(ets->get_thread_or_saved()),
|
||||
JvmtiTrace::safe_get_thread_name(ets->get_thread()),
|
||||
fpop.frame_number(),
|
||||
cleared_cnt ));
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -57,7 +57,6 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread, oop thread_oop)
|
||||
: _thread_event_enable() {
|
||||
assert(JvmtiThreadState_lock->is_locked(), "sanity check");
|
||||
_thread = thread;
|
||||
_thread_saved = nullptr;
|
||||
_exception_state = ES_CLEARED;
|
||||
_hide_single_stepping = false;
|
||||
_pending_interp_only_mode = false;
|
||||
@ -118,11 +117,11 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread, oop thread_oop)
|
||||
|
||||
if (thread != nullptr) {
|
||||
if (thread_oop == nullptr || thread->jvmti_vthread() == nullptr || thread->jvmti_vthread() == thread_oop) {
|
||||
// The JavaThread for carrier or mounted virtual thread case.
|
||||
// The JavaThread for an active carrier or a mounted virtual thread case.
|
||||
// Set this only if thread_oop is current thread->jvmti_vthread().
|
||||
thread->set_jvmti_thread_state(this);
|
||||
assert(!thread->is_interp_only_mode(), "sanity check");
|
||||
}
|
||||
thread->set_interp_only_mode(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +134,10 @@ JvmtiThreadState::~JvmtiThreadState() {
|
||||
}
|
||||
|
||||
// clear this as the state for the thread
|
||||
assert(get_thread() != nullptr, "sanity check");
|
||||
assert(get_thread()->jvmti_thread_state() == this, "sanity check");
|
||||
get_thread()->set_jvmti_thread_state(nullptr);
|
||||
get_thread()->set_interp_only_mode(false);
|
||||
|
||||
// zap our env thread states
|
||||
{
|
||||
@ -323,6 +325,9 @@ void JvmtiThreadState::enter_interp_only_mode() {
|
||||
assert(_thread != nullptr, "sanity check");
|
||||
assert(JvmtiThreadState_lock->is_locked(), "sanity check");
|
||||
assert(!is_interp_only_mode(), "entering interp only when in interp only mode");
|
||||
assert(_thread->jvmti_vthread() == nullptr || _thread->jvmti_vthread() == get_thread_oop(), "sanity check");
|
||||
assert(_thread->jvmti_thread_state() == this, "sanity check");
|
||||
_saved_interp_only_mode = true;
|
||||
_thread->set_interp_only_mode(true);
|
||||
invalidate_cur_stack_depth();
|
||||
}
|
||||
@ -330,10 +335,9 @@ void JvmtiThreadState::enter_interp_only_mode() {
|
||||
void JvmtiThreadState::leave_interp_only_mode() {
|
||||
assert(JvmtiThreadState_lock->is_locked(), "sanity check");
|
||||
assert(is_interp_only_mode(), "leaving interp only when not in interp only mode");
|
||||
if (_thread == nullptr) {
|
||||
// Unmounted virtual thread updates the saved value.
|
||||
_saved_interp_only_mode = false;
|
||||
} else {
|
||||
_saved_interp_only_mode = false;
|
||||
if (_thread != nullptr && _thread->jvmti_thread_state() == this) {
|
||||
assert(_thread->jvmti_vthread() == nullptr || _thread->jvmti_vthread() == get_thread_oop(), "sanity check");
|
||||
_thread->set_interp_only_mode(false);
|
||||
}
|
||||
}
|
||||
@ -341,7 +345,7 @@ void JvmtiThreadState::leave_interp_only_mode() {
|
||||
|
||||
// Helper routine used in several places
|
||||
int JvmtiThreadState::count_frames() {
|
||||
JavaThread* thread = get_thread_or_saved();
|
||||
JavaThread* thread = get_thread();
|
||||
javaVFrame *jvf;
|
||||
ResourceMark rm;
|
||||
if (thread == nullptr) {
|
||||
@ -578,11 +582,8 @@ void JvmtiThreadState::update_thread_oop_during_vm_start() {
|
||||
}
|
||||
}
|
||||
|
||||
// For virtual threads only.
|
||||
void JvmtiThreadState::set_thread(JavaThread* thread) {
|
||||
_thread_saved = nullptr; // Common case.
|
||||
if (!_is_virtual && thread == nullptr) {
|
||||
// Save JavaThread* if carrier thread is being detached.
|
||||
_thread_saved = _thread;
|
||||
}
|
||||
assert(is_virtual(), "sanity check");
|
||||
_thread = thread;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -123,8 +123,11 @@ class JvmtiVTSuspender : AllStatic {
|
||||
class JvmtiThreadState : public CHeapObj<mtInternal> {
|
||||
private:
|
||||
friend class JvmtiEnv;
|
||||
// The _thread field is a link to the JavaThread associated with JvmtiThreadState.
|
||||
// A platform (including carrier) thread should always have a stable link to its JavaThread.
|
||||
// The _thread field of a virtual thread should point to the JavaThread when
|
||||
// virtual thread is mounted. It should be set to null when it is unmounted.
|
||||
JavaThread *_thread;
|
||||
JavaThread *_thread_saved;
|
||||
OopHandle _thread_oop_h;
|
||||
// Jvmti Events that cannot be posted in their current context.
|
||||
JvmtiDeferredEventQueue* _jvmti_event_queue;
|
||||
@ -219,7 +222,7 @@ class JvmtiThreadState : public CHeapObj<mtInternal> {
|
||||
|
||||
// Used by the interpreter for fullspeed debugging support
|
||||
bool is_interp_only_mode() {
|
||||
return _thread == nullptr ? _saved_interp_only_mode : _thread->is_interp_only_mode();
|
||||
return _saved_interp_only_mode;
|
||||
}
|
||||
void enter_interp_only_mode();
|
||||
void leave_interp_only_mode();
|
||||
@ -248,8 +251,10 @@ class JvmtiThreadState : public CHeapObj<mtInternal> {
|
||||
|
||||
int count_frames();
|
||||
|
||||
inline JavaThread *get_thread() { return _thread; }
|
||||
inline JavaThread *get_thread_or_saved(); // return _thread_saved if _thread is null
|
||||
inline JavaThread *get_thread() {
|
||||
assert(is_virtual() || _thread != nullptr, "sanity check");
|
||||
return _thread;
|
||||
}
|
||||
|
||||
// Needed for virtual threads as they can migrate to different JavaThread's.
|
||||
// Also used for carrier threads to clear/restore _thread.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -130,22 +130,21 @@ inline JvmtiThreadState* JvmtiThreadState::state_for(JavaThread *thread, Handle
|
||||
return state;
|
||||
}
|
||||
|
||||
inline JavaThread* JvmtiThreadState::get_thread_or_saved() {
|
||||
// Use _thread_saved if cthread is detached from JavaThread (_thread == null).
|
||||
return (_thread == nullptr && !is_virtual()) ? _thread_saved : _thread;
|
||||
}
|
||||
|
||||
inline void JvmtiThreadState::set_should_post_on_exceptions(bool val) {
|
||||
get_thread_or_saved()->set_should_post_on_exceptions_flag(val ? JNI_TRUE : JNI_FALSE);
|
||||
get_thread()->set_should_post_on_exceptions_flag(val ? JNI_TRUE : JNI_FALSE);
|
||||
}
|
||||
|
||||
inline void JvmtiThreadState::unbind_from(JvmtiThreadState* state, JavaThread* thread) {
|
||||
if (state == nullptr) {
|
||||
assert(!thread->is_interp_only_mode(), "sanity check");
|
||||
return;
|
||||
}
|
||||
// Save thread's interp_only_mode.
|
||||
state->_saved_interp_only_mode = thread->is_interp_only_mode();
|
||||
state->set_thread(nullptr); // Make sure stale _thread value is never used.
|
||||
assert(thread->jvmti_thread_state() == state, "sanity check");
|
||||
assert(state->get_thread() == thread, "sanity check");
|
||||
assert(thread->is_interp_only_mode() == state->_saved_interp_only_mode, "sanity check");
|
||||
if (state->is_virtual()) { // clean _thread link for virtual threads only
|
||||
state->set_thread(nullptr); // make sure stale _thread value is never used
|
||||
}
|
||||
}
|
||||
|
||||
inline void JvmtiThreadState::bind_to(JvmtiThreadState* state, JavaThread* thread) {
|
||||
@ -158,7 +157,7 @@ inline void JvmtiThreadState::bind_to(JvmtiThreadState* state, JavaThread* threa
|
||||
// Bind JavaThread to JvmtiThreadState.
|
||||
thread->set_jvmti_thread_state(state);
|
||||
|
||||
if (state != nullptr) {
|
||||
if (state != nullptr && state->is_virtual()) {
|
||||
// Bind to JavaThread.
|
||||
state->set_thread(thread);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user