hotspot/src/share/vm/prims/jvmtiExport.cpp
void JvmtiExport::post_method_exit(JavaThread *thread, methodOop method, frame current_frame) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
HandleMark hm(thread);
methodHandle mh(thread, method);
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("JVMTI [%s] Trg Method Exit triggered %s.%s",
JvmtiTrace::safe_get_thread_name(thread),
(mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(),
(mh() == NULL) ? "NULL" : mh()->name()->as_C_string() ));
{- -------------------------------------------
(1) 処理対象のスレッドの JvmtiThreadState を取得する.
JvmtiThreadState がまだ作られていなかったり, 作られていても interp_only_mode でなければ
(明らかにこのタイミングでのイベント通知は不要なので) ここでリターン.
---------------------------------------- -}
JvmtiThreadState *state = thread->jvmti_thread_state();
if (state == NULL || !state->is_interp_only_mode()) {
// for any thread that actually wants method exit, interp_only_mode is set
return;
}
{- -------------------------------------------
(1)
---------------------------------------- -}
// return a flag when a method terminates by throwing an exception
// i.e. if an exception is thrown and it's not caught by the current method
bool exception_exit = state->is_exception_detected() && !state->is_exception_caught();
{- -------------------------------------------
(1) 対象の JvmtiThreadState で JVMTI_EVENT_METHOD_EXIT の通知が有効になっていれば,
JvmtiThreadState オブジェクト内の全ての JvmtiEnvThreadState を辿り,
JVMTI_EVENT_METHOD_EXIT 通知が有効になっているもの全てに対してコールバックの呼び出しを行う.
(ついでに, コールバックの呼び出しを行う場合には(トレース出力)も出している)
(ただし, JVMTI_EVENT_METHOD_EXIT 通知が有効になっていても,
コールバックが設定されていない JvmtiEnvThreadState については呼び出しは行わない)
---------------------------------------- -}
if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
Handle result;
jvalue value;
value.j = 0L;
// if the method hasn't been popped because of an exception then we populate
// the return_value parameter for the callback. At this point we only have
// the address of a "raw result" and we just call into the interpreter to
// convert this into a jvalue.
if (!exception_exit) {
oop oop_result;
BasicType type = current_frame.interpreter_frame_result(&oop_result, &value);
if (type == T_OBJECT || type == T_ARRAY) {
result = Handle(thread, oop_result);
}
}
JvmtiEnvThreadStateIterator it(state);
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
if (ets->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
EVT_TRACE(JVMTI_EVENT_METHOD_EXIT, ("JVMTI [%s] Evt Method Exit sent %s.%s",
JvmtiTrace::safe_get_thread_name(thread),
(mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(),
(mh() == NULL) ? "NULL" : mh()->name()->as_C_string() ));
JvmtiEnv *env = ets->get_env();
JvmtiMethodEventMark jem(thread, mh);
if (result.not_null()) {
value.l = JNIHandles::make_local(thread, result());
}
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventMethodExit callback = env->callbacks()->MethodExit;
if (callback != NULL) {
(*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread(),
jem.jni_methodID(), exception_exit, value);
}
}
}
}
{- -------------------------------------------
(1) 対象の JvmtiThreadState で JVMTI_EVENT_FRAME_POP の通知が有効になっていれば,
JvmtiThreadState オブジェクト内の全ての JvmtiEnvThreadState を辿り,
現在のスタックフレームに NotifyFramePop が仕掛けられているもの全てに対してコールバックの呼び出しを行う.
(なお, NotifyFramePop が仕掛けられているかどうかの判定は,
JvmtiThreadState::cur_stack_depth() で現在のスタックの深さを取得し,
それを引数に JvmtiEnvThreadState::is_frame_pop() を呼ぶことで行っている)
(また, 通知済みの frame 情報は, 通知処理の後で JvmtiEnvThreadState::clear_frame_pop() によって消去している.)
---------------------------------------- -}
if (state->is_enabled(JVMTI_EVENT_FRAME_POP)) {
JvmtiEnvThreadStateIterator it(state);
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
int cur_frame_number = state->cur_stack_depth();
if (ets->is_frame_pop(cur_frame_number)) {
// we have a NotifyFramePop entry for this frame.
// now check that this env/thread wants this event
if (ets->is_enabled(JVMTI_EVENT_FRAME_POP)) {
EVT_TRACE(JVMTI_EVENT_FRAME_POP, ("JVMTI [%s] Evt Frame Pop sent %s.%s",
JvmtiTrace::safe_get_thread_name(thread),
(mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(),
(mh() == NULL) ? "NULL" : mh()->name()->as_C_string() ));
// we also need to issue a frame pop event for this frame
JvmtiEnv *env = ets->get_env();
JvmtiMethodEventMark jem(thread, mh);
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventFramePop callback = env->callbacks()->FramePop;
if (callback != NULL) {
(*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread(),
jem.jni_methodID(), exception_exit);
}
}
// remove the frame's entry
ets->clear_frame_pop(cur_frame_number);
}
}
}
{- -------------------------------------------
(1) JvmtiThreadState::decr_cur_stack_depth() を呼んで
JvmtiThreadState::_cur_stack_depth フィールドの値をデクリメントしておく.
(これは FramePop イベントのための処理. (See: [here](no2935pZs.html) for details))
---------------------------------------- -}
state->decr_cur_stack_depth();
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.