/* * Copyright (c) 2003, 2022, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// marker for when the stack depth has been reset and is now unknown. // any negative number would work but small ones might obscure an // underrun error. staticconstint UNKNOWN_STACK_DEPTH = -99;
/////////////////////////////////////////////////////////////// // // class JvmtiThreadState // // Instances of JvmtiThreadState hang off of each thread. // Thread local storage for JVMTI. //
// add all the JvmtiEnvThreadState to the new JvmtiThreadState
{
JvmtiEnvIterator it; for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { if (env->is_valid()) {
add_env(env);
}
}
}
// link us into the list
{ // The thread state list manipulation code must not have safepoints. // See periodic_clean_up().
debug_only(NoSafepointVerifier nosafepoint;)
if (thread != NULL) { if (thread_oop == NULL || thread->jvmti_vthread() == NULL || thread->jvmti_vthread() == thread_oop) { // The JavaThread for carrier or mounted virtual thread case. // Set this only if thread_oop is current thread->jvmti_vthread().
thread->set_jvmti_thread_state(this);
}
thread->set_interp_only_mode(0);
}
}
// remove us from the list
{ // The thread state list manipulation code must not have safepoints. // See periodic_clean_up().
debug_only(NoSafepointVerifier nosafepoint;)
// This iteration is initialized with "_head" instead of "JvmtiThreadState::first()" // because the latter requires the JvmtiThreadState_lock. // This iteration is safe at a safepoint as well, see the NoSafepointVerifier // asserts at all list manipulation sites. for (JvmtiThreadState *state = _head; state != NULL; state = state->next()) { // For each environment thread state corresponding to an invalid environment // unlink it from the list and deallocate it.
JvmtiEnvThreadStateIterator it(state);
JvmtiEnvThreadState* previous_ets = NULL;
JvmtiEnvThreadState* ets = it.first(); while (ets != NULL) { if (ets->get_env()->is_valid()) {
previous_ets = ets;
ets = it.next(ets);
} else { // This one isn't valid, remove it from the list and deallocate it
JvmtiEnvThreadState* defunct_ets = ets;
ets = ets->next(); if (previous_ets == NULL) {
assert(state->head_env_thread_state() == defunct_ets, "sanity check");
state->set_head_env_thread_state(ets);
} else {
previous_ets->set_next(ets);
} delete defunct_ets;
}
}
}
}
// // Virtual Threads Mount State transition (VTMS transition) mechanism //
// VTMS transitions cannot be disabled while this counter is positive. volatileint JvmtiVTMSTransitionDisabler::_VTMS_transition_count = 0;
// VTMS transitions is disabled while this counter is positive volatileint JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_count = 0;
// There is an active suspender or resumer. volatilebool JvmtiVTMSTransitionDisabler::_SR_mode = false;
JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(bool is_SR) { if (!Continuations::enabled()) { return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads
} if (Thread::current_or_null() == NULL) { return; // Detached thread, can be a call from Agent_OnLoad.
}
_is_SR = is_SR;
disable_VTMS_transitions();
}
JvmtiVTMSTransitionDisabler::~JvmtiVTMSTransitionDisabler() { if (!Continuations::enabled()) { return; // JvmtiVTMSTransitionDisabler is a no-op without virtual threads
} if (Thread::current_or_null() == NULL) { return; // Detached thread, can be a call from Agent_OnLoad.
}
enable_VTMS_transitions();
}
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist.
ml.wait(10); // Wait while there is an active suspender or resumer.
} if (_is_SR) {
_SR_mode = true; while (_VTMS_transition_disable_count > 0) {
ml.wait(10); // Wait while there is any active jvmtiVTMSTransitionDisabler.
}
}
Atomic::inc(&_VTMS_transition_disable_count);
// Block while some mount/unmount transitions are in progress. // Debug version fails and prints diagnostic information. while (_VTMS_transition_count > 0) { if (ml.wait(10)) {
attempts--;
}
DEBUG_ONLY(if (attempts == 0) break;)
}
assert(!thread->is_VTMS_transition_disabler(), "VTMS_transition sanity check"); #ifdef ASSERT if (attempts > 0) {
thread->set_is_VTMS_transition_disabler(true);
} #endif
} #ifdef ASSERT if (attempts == 0) {
print_info();
fatal("stuck in JvmtiVTMSTransitionDisabler::disable_VTMS_transitions");
} #endif
}
// Avoid using MonitorLocker on performance critical path, use // two-level synchronization with lock-free operations on counters.
Atomic::inc(&_VTMS_transition_count); // Try to enter VTMS transition section optmistically.
// Do not allow suspends inside VTMS transitions. // Block while transitions are disabled or there are suspend requests.
int64_t thread_id = java_lang_Thread::thread_id(vth()); // Cannot use oops while blocked. if (_VTMS_transition_disable_count > 0 ||
thread->is_suspended() ||
JvmtiVTSuspender::is_vthread_suspended(thread_id)
) { // Slow path: undo unsuccessful optimistic counter incrementation. // It can cause an extra waiting cycle for VTMS transition disablers.
Atomic::dec(&_VTMS_transition_count);
while (true) {
ThreadBlockInVM tbivm(thread);
MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag);
// Do not allow suspends inside VTMS transitions. // Block while transitions are disabled or there are suspend requests. if (_VTMS_transition_disable_count > 0 ||
thread->is_suspended() ||
JvmtiVTSuspender::is_vthread_suspended(thread_id)
) { // Block while transitions are disabled or there are suspend requests. if (ml.wait(10)) {
attempts--;
}
DEBUG_ONLY(if (attempts == 0) break;) continue; // ~ThreadBlockInVM has handshake-based suspend point.
}
Atomic::inc(&_VTMS_transition_count); break;
}
} #ifdef ASSERT if (attempts == 0) {
log_error(jvmti)("start_VTMS_transition: thread->is_suspended: %d is_vthread_suspended: %d\n\n",
thread->is_suspended(), JvmtiVTSuspender::is_vthread_suspended(thread_id));
print_info();
fatal("stuck in JvmtiVTMSTransitionDisabler::start_VTMS_transition");
} #endif // Enter VTMS transition section.
assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check");
thread->set_is_in_VTMS_transition(true);
JvmtiThreadState* vstate = java_lang_Thread::jvmti_thread_state(vth()); if (vstate != NULL) {
vstate->set_is_in_VTMS_transition(true);
}
}
// Unblock waiting VTMS transition disablers. if (_VTMS_transition_disable_count > 0) {
MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag);
ml.notify_all();
} // In unmount case the carrier thread is attached after unmount transition. // Check and block it if there was external suspend request. int attempts = 10000; if (!is_mount && thread->is_carrier_thread_suspended()) { while (true) {
ThreadBlockInVM tbivm(thread);
MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag);
// Block while there are suspend requests. if ((!is_mount && thread->is_carrier_thread_suspended()) ||
(is_mount && JvmtiVTSuspender::is_vthread_suspended(thread_id))
) { // Block while there are suspend requests. if (ml.wait(10)) {
attempts--;
}
DEBUG_ONLY(if (attempts == 0) break;) continue;
} break;
}
} #ifdef ASSERT if (attempts == 0) {
log_error(jvmti)("finish_VTMS_transition: thread->is_suspended: %d is_vthread_suspended: %d\n\n",
thread->is_suspended(), JvmtiVTSuspender::is_vthread_suspended(thread_id));
print_info();
fatal("stuck in JvmtiVTMSTransitionDisabler::finish_VTMS_transition");
} #endif
}
JvmtiEnvThreadState *new_ets = new JvmtiEnvThreadState(this, env); // add this environment thread state to the end of the list (order is important)
{ // list deallocation (which occurs at a safepoint) cannot occur simultaneously
debug_only(NoSafepointVerifier nosafepoint;)
void JvmtiThreadState::leave_interp_only_mode() {
assert(is_interp_only_mode(), "leaving interp only when not in interp only mode"); if (_thread == NULL) { // Unmounted virtual thread updates the saved value.
--_saved_interp_only_mode;
} else {
_thread->decrement_interp_only_mode();
}
}
// Helper routine used in several places int JvmtiThreadState::count_frames() {
JavaThread* thread = get_thread_or_saved();
javaVFrame *jvf;
ResourceMark rm; if (thread == NULL) {
oop thread_obj = get_thread_oop();
jvf = JvmtiEnvBase::get_vthread_jvf(thread_obj);
} else { #ifdef ASSERT
Thread *current_thread = Thread::current(); #endif
assert(SafepointSynchronize::is_at_safepoint() ||
thread->is_handshake_safe_for(current_thread), "call by myself / at safepoint / at handshake"); if (!thread->has_last_Java_frame()) return 0; // No Java frames. // TBD: This might need to be corrected for detached carrier threads.
RegisterMap reg_map(thread,
RegisterMap::UpdateMap::skip,
RegisterMap::ProcessFrames::skip,
RegisterMap::WalkContinuation::include);
jvf = thread->last_java_vframe(®_map);
jvf = JvmtiEnvBase::check_and_skip_hidden_frames(thread, jvf);
} return (int)JvmtiEnvBase::get_frame_count(jvf);
}
void JvmtiThreadState::incr_cur_stack_depth() {
guarantee(JavaThread::current() == get_thread(), "must be current thread");
if (!is_interp_only_mode()) {
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
} if (_cur_stack_depth != UNKNOWN_STACK_DEPTH) {
++_cur_stack_depth;
}
}
void JvmtiThreadState::decr_cur_stack_depth() {
guarantee(JavaThread::current() == get_thread(), "must be current thread");
if (!is_interp_only_mode()) {
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
} if (_cur_stack_depth != UNKNOWN_STACK_DEPTH) {
--_cur_stack_depth;
assert(_cur_stack_depth >= 0, "incr/decr_cur_stack_depth mismatch");
}
}
int JvmtiThreadState::cur_stack_depth() {
Thread *current = Thread::current();
guarantee(get_thread()->is_handshake_safe_for(current), "must be current thread or direct handshake");
if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) {
_cur_stack_depth = count_frames();
} else { #ifdef ASSERT if (EnableJVMTIStackDepthAsserts) { // heavy weight assert
jint num_frames = count_frames();
assert(_cur_stack_depth == num_frames, "cur_stack_depth out of sync _cur_stack_depth: %d num_frames: %d", _cur_stack_depth, num_frames);
} #endif
} return _cur_stack_depth;
}
void JvmtiThreadState::process_pending_step_for_popframe() { // We are single stepping as the last part of the PopFrame() dance // so we have some house keeping to do.
JavaThread *thr = get_thread(); if (thr->popframe_condition() != JavaThread::popframe_inactive) { // If the popframe_condition field is not popframe_inactive, then // we missed all of the popframe_field cleanup points: // // - unpack_frames() was not called (nothing to deopt) // - remove_activation_preserving_args_entry() was not called // (did not get suspended in a call_vm() family call and did // not complete a call_vm() family call on the way here)
thr->clear_popframe_condition();
}
// clearing the flag indicates we are done with the PopFrame() dance
clr_pending_step_for_popframe();
// If exception was thrown in this frame, need to reset jvmti thread state. // Single stepping may not get enabled correctly by the agent since // exception state is passed in MethodExit event which may be sent at some // time in the future. JDWP agent ignores MethodExit events if caused by // an exception. // if (is_exception_detected()) {
clear_exception_state();
} // If step is pending for popframe then it may not be // a repeat step. The new_bci and method_id is same as current_bci // and current method_id after pop and step for recursive calls. // Force the step by clearing the last location.
JvmtiEnvThreadStateIterator it(this); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
ets->clear_current_location();
}
}
// Class: JvmtiThreadState // Function: update_for_pop_top_frame // Description: // This function removes any frame pop notification request for // the top frame and invalidates both the current stack depth and // all cached frameIDs. // // Called by: PopFrame // void JvmtiThreadState::update_for_pop_top_frame() { if (is_interp_only_mode()) { // remove any frame pop notification request for the top frame // in any environment int popframe_number = cur_stack_depth();
{
JvmtiEnvThreadStateIterator it(this); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_frame_pop(popframe_number)) {
ets->clear_frame_pop(popframe_number);
}
}
} // force stack depth to be recalculated
invalidate_cur_stack_depth();
} else {
assert(!is_enabled(JVMTI_EVENT_FRAME_POP), "Must have no framepops set");
}
}
void JvmtiThreadState::process_pending_step_for_earlyret() { // We are single stepping as the last part of the ForceEarlyReturn // dance so we have some house keeping to do.
if (is_earlyret_pending()) { // If the earlyret_state field is not earlyret_inactive, then // we missed all of the earlyret_field cleanup points: // // - remove_activation() was not called // (did not get suspended in a call_vm() family call and did // not complete a call_vm() family call on the way here) // // One legitimate way for us to miss all the cleanup points is // if we got here right after handling a compiled return. If that // is the case, then we consider our return from compiled code to // complete the ForceEarlyReturn request and we clear the condition.
clr_earlyret_pending();
set_earlyret_oop(NULL);
clr_earlyret_value();
}
// clearing the flag indicates we are done with // the ForceEarlyReturn() dance
clr_pending_step_for_earlyret();
// If exception was thrown in this frame, need to reset jvmti thread state. // Single stepping may not get enabled correctly by the agent since // exception state is passed in MethodExit event which may be sent at some // time in the future. JDWP agent ignores MethodExit events if caused by // an exception. // if (is_exception_detected()) {
clear_exception_state();
} // If step is pending for earlyret then it may not be a repeat step. // The new_bci and method_id is same as current_bci and current // method_id after earlyret and step for recursive calls. // Force the step by clearing the last location.
JvmtiEnvThreadStateIterator it(this); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
ets->clear_current_location();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.