Top


定義場所(file name)

hotspot/src/share/vm/prims/jvmtiExport.cpp

名前(function name)

void JvmtiExport::post_method_exit(JavaThread *thread, methodOop method, frame current_frame) {

本体部(body)

  {- -------------------------------------------
  (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.