Top


定義場所(file name)

hotspot/src/share/vm/interpreter/interpreterRuntime.cpp

説明(description)

// exception_handler_for_exception(...) returns the continuation address,
// the exception oop (via TLS) and sets the bci/bcp for the continuation.
// The exception oop is returned to make sure it is preserved over GC (it
// is only on the stack if the exception was thrown explicitly via athrow).
// During this operation, the expression stack contains the values for the
// bci where the exception happened. If the exception was propagated back
// from a call, the expression stack contains the values for the bci at the
// invoke w/o arguments (i.e., as if one were inside the call).

名前(function name)

IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThread* thread, oopDesc* exception))

本体部(body)

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

      Handle             h_exception(thread, exception);
      methodHandle       h_method   (thread, method(thread));
      constantPoolHandle h_constants(thread, h_method->constants());
      typeArrayHandle    h_extable  (thread, h_method->exception_table());
      bool               should_repeat;
      int                handler_bci;
      int                current_bci = bci(thread);

  {- -------------------------------------------
  (1) #TODO
      ---------------------------------------- -}

      // Need to do this check first since when _do_not_unlock_if_synchronized
      // is set, we don't want to trigger any classloading which may make calls
      // into java, or surprisingly find a matching exception handler for bci 0
      // since at this moment the method hasn't been "officially" entered yet.
      if (thread->do_not_unlock_if_synchronized()) {
        ResourceMark rm;
        assert(current_bci == 0,  "bci isn't zero for do_not_unlock_if_synchronized");
        thread->set_vm_result(exception);
    #ifdef CC_INTERP
        return (address) -1;
    #else
        return Interpreter::remove_activation_entry();
    #endif
      }

  {- -------------------------------------------
  (1) (以下の do ループ内で, 対応する例外ハンドラを探す.
       なおループになっているのは, 例外ハンドラを探す間で再帰的に例外が発生した場合に, 
       新しい例外の方を優先するため (後述))
      ---------------------------------------- -}

      do {
        should_repeat = false;

    {- -------------------------------------------
  (1.1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
        ---------------------------------------- -}

        // assertions
    #ifdef ASSERT
        assert(h_exception.not_null(), "NULL exceptions should be handled by athrow");
        assert(h_exception->is_oop(), "just checking");
        // Check that exception is a subclass of Throwable, otherwise we have a VerifyError
        if (!(h_exception->is_a(SystemDictionary::Throwable_klass()))) {
          if (ExitVMOnVerifyError) vm_exit(-1);
          ShouldNotReachHere();
        }
    #endif

    {- -------------------------------------------
  (1.1) (トレース出力)
        ---------------------------------------- -}

        // tracing
        if (TraceExceptions) {
          ttyLocker ttyl;
          ResourceMark rm(thread);
          tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", h_exception->print_value_string(), (address)h_exception());
          tty->print_cr(" thrown in interpreter method <%s>", h_method->print_value_string());
          tty->print_cr(" at bci %d for thread " INTPTR_FORMAT, current_bci, thread);
        }
    // Don't go paging in something which won't be used.
    //     else if (h_extable->length() == 0) {
    //       // disabled for now - interpreter is not using shortcut yet
    //       // (shortcut is not to call runtime if we have no exception handlers)
    //       // warning("performance bug: should not call runtime if method has no exception handlers");
    //     }

    {- -------------------------------------------
  (1.1) (デバッグ用の処理)
        ---------------------------------------- -}

        // for AbortVMOnException flag
        NOT_PRODUCT(Exceptions::debug_check_abort(h_exception));

    {- -------------------------------------------
  (1.1) methodOopDesc::fast_exception_handler_bci_for() を呼んで, 
        対応する例外ハンドラのエントリポイント(を表す BCI) を取得する 
        (もしこのメソッド内に対応するハンドラがなければ, -1 が返される).

        なお, methodOopDesc::fast_exception_handler_bci_for() 内で
        コンスタントプールからクラス情報を取得する際に例外が発生する可能性がある.
        この場合, 新たに発生した例外の方を優先して, もう一度ループの先頭からやり直す.
        (この挙動は JavaVM 仕様のどこに書いてある?? #TODO)
        ---------------------------------------- -}

        // exception handler lookup
        KlassHandle h_klass(THREAD, h_exception->klass());
        handler_bci = h_method->fast_exception_handler_bci_for(h_klass, current_bci, THREAD);
        if (HAS_PENDING_EXCEPTION) {
          // We threw an exception while trying to find the exception handler.
          // Transfer the new exception to the exception handle which will
          // be set into thread local storage, and do another lookup for an
          // exception handler for this exception, this time starting at the
          // BCI of the exception handler which caused the exception to be
          // thrown (bug 4307310).
          h_exception = Handle(THREAD, PENDING_EXCEPTION);
          CLEAR_PENDING_EXCEPTION;
          if (handler_bci >= 0) {
            current_bci = handler_bci;
            should_repeat = true;
          }
        }
      } while (should_repeat == true);

  {- -------------------------------------------
  (1) (JVMTI のフック点)
      ---------------------------------------- -}

      // notify JVMTI of an exception throw; JVMTI will detect if this is a first
      // time throw or a stack unwinding throw and accordingly notify the debugger
      if (JvmtiExport::can_post_on_exceptions()) {
        JvmtiExport::post_exception_throw(thread, h_method(), bcp(thread), h_exception());
      }

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

    #ifdef CC_INTERP
      address continuation = (address)(intptr_t) handler_bci;
    #else
      address continuation = NULL;
    #endif
      address handler_pc = NULL;

  {- -------------------------------------------
  (1) 以下の2つの条件に応じて, リターンする値を決める.
        * このメソッド内に対応するハンドラがあったかどうか (= handler_bci が -1 かどうか)
        * Stack Overflow 間近でスタックに空きがない状況かどうか (= JavaThread::reguard_stack() が false を返かどうか)

      * ハンドラが見当たらなかった場合, またはスタックに空きがない場合
        Interpreter::remove_activation_entry() を返すことにする.
        (なお, このケースではついでに
         対応する methodOop の interpreter_throwout_count() も増加させている.
         これは JIT コンパイラが使用する模様.)

      * それ以外の場合
        例外ハンドラのエントリポイントの BCI に対応するテンプレートを返すことにする.
        (ここで, Interpreter::dispatch_table から対応するテンプレートを取得しておく)
      ---------------------------------------- -}

      if (handler_bci < 0 || !thread->reguard_stack((address) &continuation)) {
        // Forward exception to callee (leaving bci/bcp untouched) because (a) no
        // handler in this method, or (b) after a stack overflow there is not yet
        // enough stack space available to reprotect the stack.
    #ifndef CC_INTERP
        continuation = Interpreter::remove_activation_entry();
    #endif
        // Count this for compilation purposes
        h_method->interpreter_throwout_increment();
      } else {
        // handler in this method => change bci/bcp to handler bci/bcp and continue there
        handler_pc = h_method->code_base() + handler_bci;
    #ifndef CC_INTERP
        set_bcp_and_mdp(handler_pc, thread);
        continuation = Interpreter::dispatch_table(vtos)[*handler_pc];
    #endif
      }

  {- -------------------------------------------
  (1) (JVMTI のフック点)
      ---------------------------------------- -}

      // notify debugger of an exception catch
      // (this is good for exceptions caught in native methods as well)
      if (JvmtiExport::can_post_on_exceptions()) {
        JvmtiExport::notice_unwind_due_to_exception(thread, h_method(), handler_pc, h_exception(), (handler_pc != NULL));
      }

  {- -------------------------------------------
  (1) 引数で指定されたスレッドの vm_result フィールドに例外オブジェクトを格納しておく.
      ---------------------------------------- -}

      thread->set_vm_result(h_exception());

  {- -------------------------------------------
  (1) リターン
      ---------------------------------------- -}

      return continuation;
    IRT_END

This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.