Top


定義場所(file name)

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

名前(function name)

IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode))

本体部(body)

  {- -------------------------------------------
  (1) (変数宣言など)
      (receiver は, 対象のメソッドのレシーバー情報)
      ---------------------------------------- -}

      // extract receiver from the outgoing argument list if necessary
      Handle receiver(thread, NULL);
      if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) {
        ResourceMark rm(thread);
        methodHandle m (thread, method(thread));
        Bytecode_invoke call(m, bci(thread));
        Symbol* signature = call.signature();
        receiver = Handle(thread,
                      thread->last_frame().interpreter_callee_receiver(signature));
        assert(Universe::heap()->is_in_reserved_or_null(receiver()),
               "sanity check");
        assert(receiver.is_null() ||
               Universe::heap()->is_in_reserved(receiver->klass()),
               "sanity check");
      }

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

      // resolve method
      CallInfo info;
      constantPoolHandle pool(thread, method(thread)->constants());

  {- -------------------------------------------
  (1) LinkResolver::resolve_invoke() を呼んで, メソッド情報の解決を行う.
      (引数で渡した CallInfo オブジェクト(以下の info)に, 解決結果がセットされて返される)
      (もしおかしなメソッドアクセスであれば, ここで例外が出る)

      (なお, 解決中にメソッドが redefine された場合は, 解決処理をやり直す.
       やり直しの解決処理も redefine と重なった場合は, 最新の情報が取れるまでやり直す.
       (現状の実装ではやり直しは最大 100 回まで. 100 回以上ぶつかるのはバグの可能性が高いとのこと))

      (なお, この処理の間は SingleStep イベントは無効にしている. (See: JvmtiHideSingleStepping))
      ---------------------------------------- -}

      {
        JvmtiHideSingleStepping jhss(thread);
        LinkResolver::resolve_invoke(info, receiver, pool,
                                     get_index_u2_cpcache(thread, bytecode), bytecode, CHECK);
        if (JvmtiExport::can_hotswap_or_post_breakpoint()) {
          int retry_count = 0;
          while (info.resolved_method()->is_old()) {
            // It is very unlikely that method is redefined more than 100 times
            // in the middle of resolve. If it is looping here more than 100 times
            // means then there could be a bug here.
            guarantee((retry_count++ < 100),
                      "Could not resolve to latest version of redefined method");
            // method is redefined in the middle of resolve so re-try.
            LinkResolver::resolve_invoke(info, receiver, pool,
                                         get_index_u2_cpcache(thread, bytecode), bytecode, CHECK);
          }
        }
      } // end JvmtiHideSingleStepping

  {- -------------------------------------------
  (1) もし, 対象スレッドが現在実行しているバイトコード箇所の 
      CPCache エントリが既に resolve 済みであれば, 
      (することはないので) ここでリターン.
      ---------------------------------------- -}

      // check if link resolution caused cpCache to be updated
      if (already_resolved(thread)) return;

  {- -------------------------------------------
  (1) 対象スレッドが現在実行しているバイトコード箇所の CPCache エントリに
      解決結果をセットする.
      なお, この処理はバイトコード種別(及び対象クラス)に応じて以下のように行う.

      * invokeinterface で, 対象クラスが java.lang.Object の場合:
        ConstantPoolCacheEntry::set_method() でセットする

        (これは Java 仮想マシン仕様のコーナーケース, とのこと.
        仕様上は invokeinterface で java.lang.Object のメソッドを呼び出すことができる, という話のことだと思われる. #TODO)

      * invokeinterface で, 対象クラスが java.lang.Object 以外の場合:
        ConstantPoolCacheEntry::set_interface_call() でセットする

      * invokeinterface 以外の場合:
        ConstantPoolCacheEntry::set_method() でセットする
      ---------------------------------------- -}

      if (bytecode == Bytecodes::_invokeinterface) {

        if (TraceItables && Verbose) {
          ResourceMark rm(thread);
          tty->print_cr("Resolving: klass: %s to method: %s", info.resolved_klass()->name()->as_C_string(), info.resolved_method()->name()->as_C_string());
        }
        if (info.resolved_method()->method_holder() ==
                                                SystemDictionary::Object_klass()) {
          // NOTE: THIS IS A FIX FOR A CORNER CASE in the JVM spec
          // (see also cpCacheOop.cpp for details)
          methodHandle rm = info.resolved_method();
          assert(rm->is_final() || info.has_vtable_index(),
                 "should have been set already");
          cache_entry(thread)->set_method(bytecode, rm, info.vtable_index());
        } else {
          // Setup itable entry
          int index = klassItable::compute_itable_index(info.resolved_method()());
          cache_entry(thread)->set_interface_call(info.resolved_method(), index);
        }
      } else {
        cache_entry(thread)->set_method(
          bytecode,
          info.resolved_method(),
          info.vtable_index());
      }
    IRT_END

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