Top


定義場所(file name)

hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp

名前(function name)

void TemplateTable::putfield_or_static(int byte_no, bool is_static) {

本体部(body)

  {- -------------------------------------------
  (1) (assert) (See: TemplateTable::transition())
      ---------------------------------------- -}

      transition(vtos, vtos);

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

      Register Rcache = G3_scratch;
      Register index  = G4_scratch;
      Register Rclass = Rcache;
      Register Roffset= G4_scratch;
      Register Rflags = G1_scratch;
      ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset();

  {- -------------------------------------------
  (1) TemplateTable::resolve_cache_and_index() を呼んで, 以下のようなコードを生成.
      「現在箇所のバイトコード(bcp)に対応する CPCache エントリのアドレスを Rcache に取得する.
      もし対応する CPCache エントリがまだ生成されていなければ, その生成も行う.」
      ---------------------------------------- -}

      resolve_cache_and_index(byte_no, noreg, Rcache, index, sizeof(u2));

  {- -------------------------------------------
  (1) コード生成: (JVMTI のフック点)
      ---------------------------------------- -}

      jvmti_post_field_mod(Rcache, index, is_static);

  {- -------------------------------------------
  (1) TemplateTable::load_field_cp_cache_entry() を呼んで, 以下のようなコードを生成.
      「取得した CPCache エントリの中から, 実際のオフセット情報を Roffset に取得.
      また, 取得した CPCache エントリの中から, フラグ情報を Rflags に取得.」
      ---------------------------------------- -}

      load_field_cp_cache_entry(Rclass, Rcache, index, Roffset, Rflags, is_static);

  {- -------------------------------------------
  (1) (変数宣言など)
      (メモリバリアの必要がある環境かどうかを示す)
      ---------------------------------------- -}

      Assembler::Membar_mask_bits read_bits =
        Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore);
      Assembler::Membar_mask_bits write_bits = Assembler::StoreLoad;

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

      Label notVolatile, checkVolatile, exit;

  {- -------------------------------------------
  (1) もしメモリバリアの必要がある環境であれば, 
      ここに「volatile 情報を Lscratch に取得する」というコードを生成しておく (この情報は後で使用する).
      (ちなみに, このコードによると, 
      volatile 情報は, CPCache エントリの ConstantPoolCacheEntry::volatileField ビットの箇所に入っている模様)

      さらに, メモリバリアが必要な環境の中でも read で必要な場合には, 
      ここに volatile field だった場合のメモリバリア処理も入れておく.
      以下のようなコードを生成.
      「volatile かどうかのチェック(tst(Lscratch))を行い, 
       もし volatile であれば, volatile_barrier() が生成したメモリバリアコードを実行する.
       volatile でなければ何もしない (notVolatile までジャンプする)」
      ---------------------------------------- -}

      if (__ membar_has_effect(read_bits) || __ membar_has_effect(write_bits)) {
        __ set((1 << ConstantPoolCacheEntry::volatileField), Lscratch);
        __ and3(Rflags, Lscratch, Lscratch);

        if (__ membar_has_effect(read_bits)) {
          __ tst(Lscratch);
          __ br(Assembler::zero, false, Assembler::pt, notVolatile);
          __ delayed()->nop();
          volatile_barrier(read_bits);
          __ bind(notVolatile);
        }
      }

  {- -------------------------------------------
  (1) CPCache のエントリから型情報を取り出す.
      ---------------------------------------- -}

      __ srl(Rflags, ConstantPoolCacheEntry::tosBits, Rflags);
      // Make sure we don't need to mask Rflags for tosBits after the above shift
      ConstantPoolCacheEntry::verify_tosBits();

  {- -------------------------------------------
  (1) 以下, 型情報に応じた処理を行う.
      なお, putstatic の場合と putfield の場合では, 
      atos と itos についてはチェックの順序が異なる.
      (それぞれ, よく使われる方を先にチェックしている模様.
       atos,itos 以外のものに付いては順番は同じ.)

      (1) atos と itos についてチェック.
          * putstatic の場合は, 
            まず atos かどうかをチェック.
            次に itos かどうかをチェック.
          * putfield の場合は, 
            まず itos かどうかをチェック.
            次に atos かどうかをチェック.
      (1) 次に btos かどうかをチェック.
      (1) 次に ltos かどうかをチェック.
      (1) 次に ctos かどうかをチェック.
      (1) 次に stos かどうかをチェック.
      (1) 次に ftos かどうかをチェック.
      (1) 以上のどれでもなければ dtos.

      なお, それぞれの場合で高速版への rewrite 処理を行っている (See: [here](no7882vBO.html) for details)
      そのため, ここのコードはそれぞれの箇所で最初の一回だけ実行される.
      (なぜ static は最適化しない?? static は使われる比率が小さいから効果が低い?? #TODO)
      ---------------------------------------- -}

      // compute field type
      Label notInt, notShort, notChar, notObj, notByte, notLong, notFloat;

      if (is_static) {

    {- -------------------------------------------
  (1.1) (ここが putstatic の場合の atos チェック)
        ---------------------------------------- -}

        // putstatic with object type most likely, check that first
        __ cmp(Rflags, atos );
        __ br(Assembler::notEqual, false, Assembler::pt, notObj);
        __ delayed() ->cmp(Rflags, itos );

    {- -------------------------------------------
  (1.1) (ここが putstatic の場合の atos の場合の処理)
        ---------------------------------------- -}

        // atos
        __ pop_ptr();
        __ verify_oop(Otos_i);

        do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false);

        __ ba(false, checkVolatile);
        __ delayed()->tst(Lscratch);

    {- -------------------------------------------
  (1.1) (ここが putstatic の場合の itos チェック)
        ---------------------------------------- -}

        __ bind(notObj);

        // cmp(Rflags, itos );
        __ br(Assembler::notEqual, false, Assembler::pt, notInt);
        __ delayed() ->cmp(Rflags, btos );

    {- -------------------------------------------
  (1.1) (ここが putstatic の場合の itos の場合の処理)
        ---------------------------------------- -}

        // itos
        __ pop_i();
        __ st(Otos_i, Rclass, Roffset);
        __ ba(false, checkVolatile);
        __ delayed()->tst(Lscratch);

        __ bind(notInt);

      } else {

    {- -------------------------------------------
  (1.1) (ここが putfield の場合の itos チェック)
        ---------------------------------------- -}

        // putfield with int type most likely, check that first
        __ cmp(Rflags, itos );
        __ br(Assembler::notEqual, false, Assembler::pt, notInt);
        __ delayed() ->cmp(Rflags, atos );

    {- -------------------------------------------
  (1.1) (ここが putfield の場合の itos の場合の処理)
        ---------------------------------------- -}

        // itos
        __ pop_i();
        pop_and_check_object(Rclass);
        __ st(Otos_i, Rclass, Roffset);
        patch_bytecode(Bytecodes::_fast_iputfield, G3_scratch, G4_scratch);
        __ ba(false, checkVolatile);
        __ delayed()->tst(Lscratch);

    {- -------------------------------------------
  (1.1) (ここが putfield の場合の atos チェック)
        ---------------------------------------- -}

        __ bind(notInt);
        // cmp(Rflags, atos );
        __ br(Assembler::notEqual, false, Assembler::pt, notObj);
        __ delayed() ->cmp(Rflags, btos );

    {- -------------------------------------------
  (1.1) (ここが putfield の場合の atos の場合の処理)
        ---------------------------------------- -}

        // atos
        __ pop_ptr();
        pop_and_check_object(Rclass);
        __ verify_oop(Otos_i);

        do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false);

        patch_bytecode(Bytecodes::_fast_aputfield, G3_scratch, G4_scratch);
        __ ba(false, checkVolatile);
        __ delayed()->tst(Lscratch);

        __ bind(notObj);
      }

    {- -------------------------------------------
  (1.1) (ここが btos チェック)
        ---------------------------------------- -}

      // cmp(Rflags, btos );
      __ br(Assembler::notEqual, false, Assembler::pt, notByte);
      __ delayed() ->cmp(Rflags, ltos );

    {- -------------------------------------------
  (1.1) (ここが btos の場合の処理)
        ---------------------------------------- -}

      // btos
      __ pop_i();
      if (!is_static) pop_and_check_object(Rclass);
      __ stb(Otos_i, Rclass, Roffset);
      if (!is_static) {
        patch_bytecode(Bytecodes::_fast_bputfield, G3_scratch, G4_scratch);
      }
      __ ba(false, checkVolatile);
      __ delayed()->tst(Lscratch);

    {- -------------------------------------------
  (1.1) (ここが ltos チェック)
        ---------------------------------------- -}

      __ bind(notByte);

      // cmp(Rflags, ltos );
      __ br(Assembler::notEqual, false, Assembler::pt, notLong);
      __ delayed() ->cmp(Rflags, ctos );

    {- -------------------------------------------
  (1.1) (ここが ltos の場合の処理)
        ---------------------------------------- -}

      // ltos
      __ pop_l();
      if (!is_static) pop_and_check_object(Rclass);
      __ st_long(Otos_l, Rclass, Roffset);
      if (!is_static) {
        patch_bytecode(Bytecodes::_fast_lputfield, G3_scratch, G4_scratch);
      }
      __ ba(false, checkVolatile);
      __ delayed()->tst(Lscratch);

    {- -------------------------------------------
  (1.1) (ここが ctos チェック)
        ---------------------------------------- -}

      __ bind(notLong);

      // cmp(Rflags, ctos );
      __ br(Assembler::notEqual, false, Assembler::pt, notChar);
      __ delayed() ->cmp(Rflags, stos );

    {- -------------------------------------------
  (1.1) (ここが ctos の場合の処理)
        ---------------------------------------- -}

      // ctos (char)
      __ pop_i();
      if (!is_static) pop_and_check_object(Rclass);
      __ sth(Otos_i, Rclass, Roffset);
      if (!is_static) {
        patch_bytecode(Bytecodes::_fast_cputfield, G3_scratch, G4_scratch);
      }
      __ ba(false, checkVolatile);
      __ delayed()->tst(Lscratch);

    {- -------------------------------------------
  (1.1) (ここが stos チェック)
        ---------------------------------------- -}

      __ bind(notChar);
      // cmp(Rflags, stos );
      __ br(Assembler::notEqual, false, Assembler::pt, notShort);
      __ delayed() ->cmp(Rflags, ftos );

    {- -------------------------------------------
  (1.1) (ここが stos の場合の処理)
        ---------------------------------------- -}

      // stos (char)
      __ pop_i();
      if (!is_static) pop_and_check_object(Rclass);
      __ sth(Otos_i, Rclass, Roffset);
      if (!is_static) {
        patch_bytecode(Bytecodes::_fast_sputfield, G3_scratch, G4_scratch);
      }
      __ ba(false, checkVolatile);
      __ delayed()->tst(Lscratch);

    {- -------------------------------------------
  (1.1) (ここが ftos チェック)
        ---------------------------------------- -}

      __ bind(notShort);
      // cmp(Rflags, ftos );
      __ br(Assembler::notZero, false, Assembler::pt, notFloat);
      __ delayed()->nop();

    {- -------------------------------------------
  (1.1) (ここが ftos の場合の処理)
        ---------------------------------------- -}

      // ftos
      __ pop_f();
      if (!is_static) pop_and_check_object(Rclass);
      __ stf(FloatRegisterImpl::S, Ftos_f, Rclass, Roffset);
      if (!is_static) {
        patch_bytecode(Bytecodes::_fast_fputfield, G3_scratch, G4_scratch);
      }
      __ ba(false, checkVolatile);
      __ delayed()->tst(Lscratch);

    {- -------------------------------------------
  (1.1) (以上のどれでもなければ dtos)
        ---------------------------------------- -}

      __ bind(notFloat);

    {- -------------------------------------------
  (1.1) (ここが dtos の場合の処理)
        ---------------------------------------- -}

      // dtos
      __ pop_d();
      if (!is_static) pop_and_check_object(Rclass);
      __ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset);
      if (!is_static) {
        patch_bytecode(Bytecodes::_fast_dputfield, G3_scratch, G4_scratch);
      }

  {- -------------------------------------------
  (1) ここで, volatile field だった場合のメモリバリア処理を行う (メモリバリアが必要な環境の場合, かつ write 後のバリアが必要な場合).

      (なお, 以下のコメントにある通り, 
      それぞれのケースの遅延スロットで volatile かどうかのチェック(tst(Lscratch))を行っている.
      具体的には, ConstantPoolCacheEntry::volatileField のチェックをしている.
      そのため, この段階では volatile チェックは終わっている.)

      以下のようなコードを生成.
      「チェック結果に基づき, もし volatile であれば, volatile_barrier() が生成したメモリバリアコードを実行する.
      volatile でなければ何もしない (exit までジャンプする)」
      ---------------------------------------- -}

      __ bind(checkVolatile);
      __ tst(Lscratch);

      if (__ membar_has_effect(write_bits)) {
        // __ tst(Lscratch); in delay slot
        __ br(Assembler::zero, false, Assembler::pt, exit);
        __ delayed()->nop();
        volatile_barrier(Assembler::StoreLoad);
        __ bind(exit);
      }
    }

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