Top


定義場所(file name)

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

説明(description)

// Rewrites a method given the index_map information

名前(function name)

void Rewriter::scan_method(methodOop method, bool reverse) {

本体部(body)

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

      int nof_jsrs = 0;
      bool has_monitor_bytecodes = false;

  {- -------------------------------------------
  (1) 以下のブロック内で, method 引数で指定されたメソッド中の
      バイトコードの書き換え処理を行う.
      ---------------------------------------- -}

      {

    {- -------------------------------------------
  (1.1) (No_Safepoint_Verifier)(= このブロック内では Safepoint 停止は起こらないはず)
        ---------------------------------------- -}

        // We cannot tolerate a GC in this block, because we've
        // cached the bytecodes in 'code_base'. If the methodOop
        // moves, the bytecodes will also move.
        No_Safepoint_Verifier nsv;

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

        Bytecodes::Code c;

        // Bytecodes and their length
        const address code_base = method->code_base();
        const int code_length = method->code_size();

    {- -------------------------------------------
  (1.1) 以下の for ループ中で, 
        method 引数で指定されたメソッド中の全バイトコードを辿り
        書き換え対象のバイトコード命令であれば rewrite 処理を行う.
        ---------------------------------------- -}

        int bc_length;
        for (int bci = 0; bci < code_length; bci += bc_length) {

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

          address bcp = code_base + bci;
          int prefix_length = 0;
          c = (Bytecodes::Code)(*bcp);

      {- -------------------------------------------
  (1.1.1) (局所変数の初期化)
          ---------------------------------------- -}

          // Since we have the code, see if we can get the length
          // directly. Some more complicated bytecodes will report
          // a length of zero, meaning we need to make another method
          // call to calculate the length.
          bc_length = Bytecodes::length_for(c);
          if (bc_length == 0) {
            bc_length = Bytecodes::length_at(method, bcp);

            // length_at will put us at the bytecode after the one modified
            // by 'wide'. We don't currently examine any of the bytecodes
            // modified by wide, but in case we do in the future...
            if (c == Bytecodes::_wide) {
              prefix_length = 1;
              c = (Bytecodes::Code)bcp[1];
            }
          }

          assert(bc_length != 0, "impossible bytecode length");

      {- -------------------------------------------
  (1.1.1) 以下の switch 内で, 対象のバイトコード種別に応じた処理を実施.
          ---------------------------------------- -}

          switch (c) {

        {- -------------------------------------------
  (1.1.1.1) lookupswitch 命令の場合, 
            Bytecodes::_fast_linearswitch 命令, または Bytecodes::_fast_binaryswitch 命令に書き換え.
            (どちらも HotSpot 独自のバイトコード命令)

            (どちらにするかは, 飛び先候補の数に応じて決定. 
       候補数が BinarySwitchThreshold オプションの値より少なければ fast_linearswitch, 
       それ以上であれば _fast_binaryswitch にする)

            (ただし, Interpreter が C++ Interpreter である場合 (= CC_INTERP が #define されている場合) はやらない)
            ---------------------------------------- -}

            case Bytecodes::_lookupswitch   : {
    #ifndef CC_INTERP
              Bytecode_lookupswitch bc(method, bcp);
              (*bcp) = (
                bc.number_of_pairs() < BinarySwitchThreshold
                ? Bytecodes::_fast_linearswitch
                : Bytecodes::_fast_binaryswitch
              );
    #endif
              break;
            }

        {- -------------------------------------------
  (1.1.1.1) Bytecodes::_fast_linearswitch 命令や Bytecodes::_fast_binaryswitch 命令の場合,
            lookupswitch 命令に書き換え.
            (書き換えた lookupswitch 命令を元に戻す場合の処理)

            (Interpreter が C++ Interpreter である場合 (= CC_INTERP が #define されている場合) はやらない)
            ---------------------------------------- -}

            case Bytecodes::_fast_linearswitch:
            case Bytecodes::_fast_binaryswitch: {
    #ifndef CC_INTERP
              (*bcp) = Bytecodes::_lookupswitch;
    #endif
              break;
            }

        {- -------------------------------------------
  (1.1.1.1) {get|put}{static|field} 命令や invoke* 命令(invokedynamic除く) の場合, 
            Rewriter::rewrite_member_reference() を呼んで
            バイトコード命令中の Constant Pool index が埋まっている 2byte を 
            Constant Pool Cache の index に置き換える.

            (なお, reverse 引数が true の場合には, 逆に元に戻す処理が行われる)
            ---------------------------------------- -}

            case Bytecodes::_getstatic      : // fall through
            case Bytecodes::_putstatic      : // fall through
            case Bytecodes::_getfield       : // fall through
            case Bytecodes::_putfield       : // fall through
            case Bytecodes::_invokevirtual  : // fall through
            case Bytecodes::_invokespecial  : // fall through
            case Bytecodes::_invokestatic   :
            case Bytecodes::_invokeinterface:
              rewrite_member_reference(bcp, prefix_length+1, reverse);
              break;

        {- -------------------------------------------
  (1.1.1.1) invokedynamic 命令の場合, 
            Rewriter::rewrite_invokedynamic() を呼んで
            バイトコード命令中の Constant Pool index が埋まっている 4byte を 
            Constant Pool Cache の index に置き換える.

            (なお, invokedynamic に関しては 
             Constant Pool の index と Constant Pool Cache の index が 1対1対応ではなく,
             CP の 1つの index に対して CPC の複数の index が対応する.
             invokedynamic が 2byte ではなく 4byte の operand を取るのは, 
             このような実装を考慮してのことらしい
             (もちろん他の JVM 実装では他の用途で使うかもしれないが))
            ---------------------------------------- -}

            case Bytecodes::_invokedynamic:
              rewrite_invokedynamic(bcp, prefix_length+1, reverse);
              break;

        {- -------------------------------------------
  (1.1.1.1) ldc 命令や ldc_w 命令の場合, 
            Rewriter::maybe_rewrite_ldc() を呼んで
            バイトコード命令の書き換えを行う

            (この関数では, 
            ロード対象が method handle もしくは method type の場合には
            Bytecodes::_fast_aldc 命令や Bytecodes::_fast_aldc_w 命令に置き換える
            (どちらも HotSpot 独自のバイトコード命令).
            ロード対象がそれ以外の定数の場合は, 何もしない)

            (なお, reverse 引数が true の場合には, 逆に元に戻す処理が行われる)
            ---------------------------------------- -}

            case Bytecodes::_ldc:
            case Bytecodes::_fast_aldc:
              maybe_rewrite_ldc(bcp, prefix_length+1, false, reverse);
              break;
            case Bytecodes::_ldc_w:
            case Bytecodes::_fast_aldc_w:
              maybe_rewrite_ldc(bcp, prefix_length+1, true, reverse);
              break;

        {- -------------------------------------------
  (1.1.1.1) jsr 命令, jsr_w 命令, monitorenter 命令, monitorexit 命令があった場合は, 
            そのことを局所変数に記録しておく.
            (この関数内の後の処理で参照)

            (ところで, 現状の使われ方を見る限り nof_jsrs も boolean でいい気がするが...)
            ---------------------------------------- -}

            case Bytecodes::_jsr            : // fall through
            case Bytecodes::_jsr_w          : nof_jsrs++;                   break;
            case Bytecodes::_monitorenter   : // fall through
            case Bytecodes::_monitorexit    : has_monitor_bytecodes = true; break;
          }
        }
      }

  {- -------------------------------------------
  (1) monitorenter 命令や monitorexit 命令があった場合は, 
      このメソッドのフラグに JVM_ACC_HAS_MONITOR_BYTECODES ビットを立てておく.

      (この情報は, JIT コンパイラが最適化の可否を判断する際などに用いられる模様 #TODO)
      ---------------------------------------- -}

      // Update access flags
      if (has_monitor_bytecodes) {
        method->set_has_monitor_bytecodes();
      }

  {- -------------------------------------------
  (1) jsr 命令や jsr_w 命令があった場合は, 
      このメソッドのフラグに JVM_ACC_HAS_JSRS ビットを立てておく.

      (この情報は, 後で飛び先を再配置する際の目安として参照される (See: Rewriter::relocate_and_link()))
      (また, この情報は JIT コンパイラが最適化の可否を判断する際などにも用いられる模様 #TODO)
      ---------------------------------------- -}

      // The present of a jsr bytecode implies that the method might potentially
      // have to be rewritten, so we run the oopMapGenerator on the method
      if (nof_jsrs > 0) {
        method->set_has_jsrs();
        // Second pass will revisit this method.
        assert(method->has_jsrs(), "didn't we just set this?");
      }
    }

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