Top


定義場所(file name)

hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp

説明(description)

// Call an accessor method (assuming it is resolved, otherwise drop
// into vanilla (slow path) entry

名前(function name)

address InterpreterGenerator::generate_accessor_entry(void) {

本体部(body)

  {- -------------------------------------------
  (1) (生成したコードが実行される時点では, レジスタには以下の値が入っているはず)
      ---------------------------------------- -}

      // rbx: methodOop

      // r13: senderSP must preserver for slow path, set SP to it on fast path

  {- -------------------------------------------
  (1) (ここからが生成するコードの始まり)
      ---------------------------------------- -}

      address entry_point = __ pc();

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

      Label xreturn_path;

  {- -------------------------------------------
  (1) (UseFastAccessorMethods オプションが指定されている場合には, 
      以下のコードを生成し, そのエントリポイントのアドレスをリターンする.

      そうでない場合には, InterpreterGenerator::generate_normal_entry() で
      通常パスのコードを生成し, そのエントリポイントのアドレスをリターンする.)
      ---------------------------------------- -}

      // do fastpath for resolved accessor methods
      if (UseFastAccessorMethods) {

    {- -------------------------------------------
  (1.1) (この関数は, 以下のような典型的なアクセサメソッドの処理を高速化するためのもの.
          _aload_0, _(i|a)getfield, _(i|a)return

         なお, この高速版のコードが使えるのは 
         getfield が resolve 済みで有り, 第一引数(this)が NULL ではない場合.
         このため, これらの条件を最初にチェックしている)
        ---------------------------------------- -}

        // Code: _aload_0, _(i|a)getfield, _(i|a)return or any rewrites
        //       thereof; parameter size = 1
        // Note: We can only use this code if the getfield has been resolved
        //       and if we don't have a null-pointer exception => check for
        //       these conditions first and use slow path if necessary.

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

        Label slow_path;

    {- -------------------------------------------
  (1.1) コード生成:
        「Safepoint 処理中かどうかをチェックする (= SafepointSynchronize::address_of_state を確認).
          もし Safepoint 停止の要求が出ていれば, slow_path ラベルにジャンプして停止処理を行う.」
        ---------------------------------------- -}

        // If we need a safepoint check, generate full interpreter entry.
        __ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
                 SafepointSynchronize::_not_synchronized);

        __ jcc(Assembler::notEqual, slow_path);

    {- -------------------------------------------
  (1.1) コード生成:
        「第一引数(this)が NULL かどうかを確認する.
          もし NULL だった場合は, slow_path ラベルにジャンプして通常処理にフォールバック.」
        ---------------------------------------- -}

        // rbx: method
        __ movptr(rax, Address(rsp, wordSize));

        // check if local 0 != NULL and read field
        __ testptr(rax, rax);
        __ jcc(Assembler::zero, slow_path);

    {- -------------------------------------------
  (1.1) コード生成:
        「アクセス対象のフィールドが resolve 済みかどうかをチェックする.
          まだ resolve されてなかった場合は, slow_path ラベルにジャンプして通常処理にフォールバック.」
        ---------------------------------------- -}

        __ movptr(rdi, Address(rbx, methodOopDesc::constants_offset()));
        // read first instruction word and extract bytecode @ 1 and index @ 2
        __ movptr(rdx, Address(rbx, methodOopDesc::const_offset()));
        __ movl(rdx, Address(rdx, constMethodOopDesc::codes_offset()));
        // Shift codes right to get the index on the right.
        // The bytecode fetched looks like <index><0xb4><0x2a>
        __ shrl(rdx, 2 * BitsPerByte);
        __ shll(rdx, exact_log2(in_words(ConstantPoolCacheEntry::size())));
        __ movptr(rdi, Address(rdi, constantPoolOopDesc::cache_offset_in_bytes()));

        // rax: local 0
        // rbx: method
        // rdx: constant pool cache index
        // rdi: constant pool cache

        // check if getfield has been resolved and read constant pool cache entry
        // check the validity of the cache entry by testing whether _indices field
        // contains Bytecode::_getfield in b1 byte.
        assert(in_words(ConstantPoolCacheEntry::size()) == 4,
               "adjust shift below");
        __ movl(rcx,
                Address(rdi,
                        rdx,
                        Address::times_8,
                        constantPoolCacheOopDesc::base_offset() +
                        ConstantPoolCacheEntry::indices_offset()));
        __ shrl(rcx, 2 * BitsPerByte);
        __ andl(rcx, 0xFF);
        __ cmpl(rcx, Bytecodes::_getfield);
        __ jcc(Assembler::notEqual, slow_path);

    {- -------------------------------------------
  (1.1) コード生成:
        「対応する CPCache entry から, アクセス対象であるフィールドの型とオフセットを取得」
        ---------------------------------------- -}

        // Note: constant pool entry is not valid before bytecode is resolved
        __ movptr(rcx,
                  Address(rdi,
                          rdx,
                          Address::times_8,
                          constantPoolCacheOopDesc::base_offset() +
                          ConstantPoolCacheEntry::f2_offset()));
        // edx: flags
        __ movl(rdx,
                Address(rdi,
                        rdx,
                        Address::times_8,
                        constantPoolCacheOopDesc::base_offset() +
                        ConstantPoolCacheEntry::flags_offset()));

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

        Label notObj, notInt, notByte, notShort;
        const Address field_address(rax, rcx, Address::times_1);

    {- -------------------------------------------
  (1.1) コード生成:
        「取得した型に応じて適切なロード命令を実行し, フィールドの値を取得する
          (ロード命令のオフセットとして, 上で取得したオフセット値を使用)」

         なお, 型は次の順序で調べている.
           atos, itos, btos, stos, ctos, 
        ---------------------------------------- -}

        // Need to differentiate between igetfield, agetfield, bgetfield etc.
        // because they are different sizes.
        // Use the type from the constant pool cache
        __ shrl(rdx, ConstantPoolCacheEntry::tosBits);
        // Make sure we don't need to mask edx for tosBits after the above shift
        ConstantPoolCacheEntry::verify_tosBits();

        __ cmpl(rdx, atos);
        __ jcc(Assembler::notEqual, notObj);
        // atos
        __ load_heap_oop(rax, field_address);
        __ jmp(xreturn_path);

        __ bind(notObj);
        __ cmpl(rdx, itos);
        __ jcc(Assembler::notEqual, notInt);
        // itos
        __ movl(rax, field_address);
        __ jmp(xreturn_path);

        __ bind(notInt);
        __ cmpl(rdx, btos);
        __ jcc(Assembler::notEqual, notByte);
        // btos
        __ load_signed_byte(rax, field_address);
        __ jmp(xreturn_path);

        __ bind(notByte);
        __ cmpl(rdx, stos);
        __ jcc(Assembler::notEqual, notShort);
        // stos
        __ load_signed_short(rax, field_address);
        __ jmp(xreturn_path);

        __ bind(notShort);
    #ifdef ASSERT
        Label okay;
        __ cmpl(rdx, ctos);
        __ jcc(Assembler::equal, okay);
        __ stop("what type is this?");
        __ bind(okay);
    #endif
        // ctos
        __ load_unsigned_short(rax, field_address);

        __ bind(xreturn_path);

    {- -------------------------------------------
  (1.1) コード生成:
        「SP を r13 の値に復帰させた後, リターン」
        ---------------------------------------- -}

        // _ireturn/_areturn
        __ pop(rdi);
        __ mov(rsp, r13);
        __ jmp(rdi);
        __ ret(0);

    {- -------------------------------------------
  (1.1) コード生成:
        「高速処理が不可能な状況であれば, 
         InterpreterGenerator::generate_normal_entry() が生成する通常パスにフォールバック」
        ---------------------------------------- -}

        // generate a vanilla interpreter entry as the slow path
        __ bind(slow_path);
        (void) generate_normal_entry(false);

    {- -------------------------------------------
  (1.1) コード生成: (以下は UseFastAccessorMethods オプションが指定されていない場合用)
        「InterpreterGenerator::generate_normal_entry() が生成する通常パスにフォールバックするだけ」
        ---------------------------------------- -}

      } else {
        (void) generate_normal_entry(false);
      }

  {- -------------------------------------------
  (1) 以上で生成したコードの先頭アドレスをリターン.
      ---------------------------------------- -}

      return entry_point;
    }

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