Mercurial > hg > graal-compiler
view src/share/vm/prims/jvmtiThreadState.cpp @ 20357:4bfc44ba0d19
8055098: WB API should be extended to provide information about size and age of object.
Summary: Extend the WhiteBox API to provide information about the size and age of objects. Further add a mechanism to trigger a young GC.
Reviewed-by: tschatzl, sjohanss
Contributed-by: Leonid Mesnik <leonid.mesnik@oracle.com>
author | tschatzl |
---|---|
date | Thu, 21 Aug 2014 16:44:41 +0200 |
parents | da91efe96a93 |
children | 0d8d78c0329a |
line wrap: on
line source
/* * Copyright (c) 2003, 2012, 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. * */ #include "precompiled.hpp" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/gcLocker.hpp" #include "memory/resourceArea.hpp" #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiImpl.hpp" #include "prims/jvmtiThreadState.inline.hpp" #include "runtime/vframe.hpp" // 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. static const int UNKNOWN_STACK_DEPTH = -99; /////////////////////////////////////////////////////////////// // // class JvmtiThreadState // // Instances of JvmtiThreadState hang off of each thread. // Thread local storage for JVMTI. // JvmtiThreadState *JvmtiThreadState::_head = NULL; JvmtiThreadState::JvmtiThreadState(JavaThread* thread) : _thread_event_enable() { assert(JvmtiThreadState_lock->is_locked(), "sanity check"); _thread = thread; _exception_detected = false; _exception_caught = false; _debuggable = true; _hide_single_stepping = false; _hide_level = 0; _pending_step_for_popframe = false; _class_being_redefined = NULL; _class_load_kind = jvmti_class_load_kind_load; _head_env_thread_state = NULL; _dynamic_code_event_collector = NULL; _vm_object_alloc_event_collector = NULL; _the_class_for_redefinition_verification = NULL; _scratch_class_for_redefinition_verification = NULL; // JVMTI ForceEarlyReturn support _pending_step_for_earlyret = false; _earlyret_state = earlyret_inactive; _earlyret_tos = ilgl; _earlyret_value.j = 0L; _earlyret_oop = NULL; // 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(No_Safepoint_Verifier nosafepoint;) _prev = NULL; _next = _head; if (_head != NULL) { _head->_prev = this; } _head = this; } // set this as the state for the thread thread->set_jvmti_thread_state(this); } JvmtiThreadState::~JvmtiThreadState() { assert(JvmtiThreadState_lock->is_locked(), "sanity check"); // clear this as the state for the thread get_thread()->set_jvmti_thread_state(NULL); // zap our env thread states { JvmtiEnvBase::entering_dying_thread_env_iteration(); JvmtiEnvThreadStateIterator it(this); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ) { JvmtiEnvThreadState* zap = ets; ets = it.next(ets); delete zap; } JvmtiEnvBase::leaving_dying_thread_env_iteration(); } // remove us from the list { // The thread state list manipulation code must not have safepoints. // See periodic_clean_up(). debug_only(No_Safepoint_Verifier nosafepoint;) if (_prev == NULL) { assert(_head == this, "sanity check"); _head = _next; } else { assert(_head != this, "sanity check"); _prev->_next = _next; } if (_next != NULL) { _next->_prev = _prev; } _next = NULL; _prev = NULL; } } void JvmtiThreadState::periodic_clean_up() { assert(SafepointSynchronize::is_at_safepoint(), "at safepoint"); // 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 No_Safepoint_Verifier // 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; } } } } void JvmtiThreadState::add_env(JvmtiEnvBase *env) { assert(JvmtiThreadState_lock->is_locked(), "sanity check"); JvmtiEnvThreadState *new_ets = new JvmtiEnvThreadState(_thread, 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(No_Safepoint_Verifier nosafepoint;) JvmtiEnvThreadStateIterator it(this); JvmtiEnvThreadState* previous_ets = NULL; for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { previous_ets = ets; } if (previous_ets == NULL) { set_head_env_thread_state(new_ets); } else { previous_ets->set_next(new_ets); } } } void JvmtiThreadState::enter_interp_only_mode() { assert(_thread->get_interp_only_mode() == 0, "entering interp only when mode not zero"); _thread->increment_interp_only_mode(); } void JvmtiThreadState::leave_interp_only_mode() { assert(_thread->get_interp_only_mode() == 1, "leaving interp only when mode not one"); _thread->decrement_interp_only_mode(); } // Helper routine used in several places int JvmtiThreadState::count_frames() { #ifdef ASSERT uint32_t debug_bits = 0; #endif assert(SafepointSynchronize::is_at_safepoint() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), "at safepoint or must be suspended"); if (!get_thread()->has_last_Java_frame()) return 0; // no Java frames ResourceMark rm; RegisterMap reg_map(get_thread()); javaVFrame *jvf = get_thread()->last_java_vframe(®_map); int n = 0; // tty->print_cr("CSD: counting frames on %s ...", // JvmtiTrace::safe_get_thread_name(get_thread())); while (jvf != NULL) { Method* method = jvf->method(); // tty->print_cr("CSD: frame - method %s.%s - loc %d", // method->klass_name()->as_C_string(), // method->name()->as_C_string(), // jvf->bci() ); jvf = jvf->java_sender(); n++; } // tty->print_cr("CSD: frame count: %d", n); return n; } void JvmtiThreadState::invalidate_cur_stack_depth() { Thread *cur = Thread::current(); uint32_t debug_bits = 0; // The caller can be the VMThread at a safepoint, the current thread // or the target thread must be suspended. guarantee((cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()) || (JavaThread *)cur == get_thread() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), "sanity check"); _cur_stack_depth = UNKNOWN_STACK_DEPTH; } 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() { uint32_t debug_bits = 0; guarantee(JavaThread::current() == get_thread() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), "must be current thread or suspended"); if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) { _cur_stack_depth = count_frames(); } else { // heavy weight assert assert(_cur_stack_depth == count_frames(), "cur_stack_depth out of sync"); } return _cur_stack_depth; } bool JvmtiThreadState::may_be_walked() { return (get_thread()->is_being_ext_suspended() || (JavaThread::current() == get_thread())); } 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_detected(); } // 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_detected(); } // 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(); } } void JvmtiThreadState::oops_do(OopClosure* f) { f->do_oop((oop*) &_earlyret_oop); }