Top


定義場所(file name)

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

説明(description)

// unlock if synchronized method
//
// Unlock the receiver if this is a synchronized method.
// Unlock any Java monitors from syncronized blocks.
//
// If there are locked Java monitors
//    If throw_monitor_exception
//       throws IllegalMonitorStateException
//    Else if install_monitor_exception
//       installs IllegalMonitorStateException
//    Else
//       no error processing

名前(function name)

void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state,
                                                              bool throw_monitor_exception,
                                                              bool install_monitor_exception) {

本体部(body)

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

      Label unlocked, unlock, no_unlock;

  {- -------------------------------------------
  (1) コード生成:
      「カレントスレッド内の JavaThread::do_not_unlock_if_synchronized フィールドの値を G1_scratch に取得.
       (なお, JavaThread::do_not_unlock_if_synchronized フィールド自体は 0 に戻す)」

      (このフィールドの意味については, メソッドエントリ部の処理を参照.  (See: [here](no3059n2f.html) for details))
      ---------------------------------------- -}

      // get the value of _do_not_unlock_if_synchronized into G1_scratch
      const Address do_not_unlock_if_synchronized(G2_thread,
        JavaThread::do_not_unlock_if_synchronized_offset());
      ldbool(do_not_unlock_if_synchronized, G1_scratch);
      stbool(G0, do_not_unlock_if_synchronized); // reset the flag

  {- -------------------------------------------
  (1) コード生成:
      「呼び出したメソッドが synchronized 指定されているかどうかをチェック. 
        synchronized でない場合は, することはないので unlocked までジャンプ.

        (なお, ついでに push() で TOS に入っている返値をスタック上に待避している)」
      ---------------------------------------- -}

      // check if synchronized method
      const Address access_flags(Lmethod, methodOopDesc::access_flags_offset());
      interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
      push(state); // save tos
      ld(access_flags, G3_scratch); // Load access flags.
      btst(JVM_ACC_SYNCHRONIZED, G3_scratch);
      br(zero, false, pt, unlocked);
      delayed()->nop();

  {- -------------------------------------------
  (1) コード生成:
      「取得してあった JavaThread::do_not_unlock_if_synchronized フィールドの値を確認する.
       もし true だった場合には, 何もしなくてよいので no_unlock までジャンプ」
      ---------------------------------------- -}

      // Don't unlock anything if the _do_not_unlock_if_synchronized flag
      // is set.
      tstbool(G1_scratch);
      br(Assembler::notZero, false, pn, no_unlock);
      delayed()->nop();

  {- -------------------------------------------
  (1) (synchronized method なので, 先頭の BasicObjectLock がアンロック対象になるはず.
       ただし, モニターが変になっていないことのチェックが必要.
       より具体的には, その BasicObjectLock が monitorexit によって既に解放されていないこと, をチェックしておく.)
      ---------------------------------------- -}

      // BasicObjectLock will be first in list, since this is a synchronized method. However, need
      // to check that the object has not been unlocked by an explicit monitorexit bytecode.

      //Intel: if (throw_monitor_exception) ... else ...
      // Entry already unlocked, need to throw exception
      //...

  {- -------------------------------------------
  (1) コード生成:
      「先頭の BasicObjectLock 内の obj フィールドを確認しておく. 
        NULL でなければ (= 解放済みでなければ), unlock ラベルにジャンプしてアンロック処理を行う.

        逆に NULL の場合は (= 既に解放済みの場合は), このままフォールスルーして以下のどれかの処理を行う. 
        (なお, 以下の処理はコード生成時に引数に応じてどれかが生成される. 動的に条件判定で処理を分岐するわけではない)
        * 引数の throw_monitor_exception が true の場合
          InterpreterRuntime::throw_illegal_monitor_state_exception() を呼び出して 
          IllegalMonitorStateException を出す.
        * (throw_monitor_exception は false だが) 引数の install_monitor_exception が true の場合
          InterpreterRuntime::new_illegal_monitor_state_exception() を呼び出して 
          IllegalMonitorStateException を出す.
        * それ以外の場合
          アンロックできたことにして, unlocked ラベルにジャンプする.               」
      ---------------------------------------- -}

      // pass top-most monitor elem
      add( top_most_monitor(), O1 );

      ld_ptr(O1, BasicObjectLock::obj_offset_in_bytes(), G3_scratch);
      br_notnull(G3_scratch, false, pt, unlock);
      delayed()->nop();

      if (throw_monitor_exception) {
        // Entry already unlocked need to throw an exception
        MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
        should_not_reach_here();
      } else {
        // Monitor already unlocked during a stack unroll.
        // If requested, install an illegal_monitor_state_exception.
        // Continue with stack unrolling.
        if (install_monitor_exception) {
          MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
        }
        ba(false, unlocked);
        delayed()->nop();
      }

  {- -------------------------------------------
  (1) コード生成:
      「InterpreterMacroAssembler::unlock_object() が生成するコードで, 
        ロックの解放処理を行う」
      ---------------------------------------- -}

      bind(unlock);

      unlock_object(O1);

  {- -------------------------------------------
  (1) コード生成:
      「(ここが unlocked ラベルの位置)」
      ---------------------------------------- -}

      bind(unlocked);

  {- -------------------------------------------
  (1) (この段階では, I0 と I1 に返値が入っている可能性がある.)
      ---------------------------------------- -}

      // I0, I1: Might contain return value

  {- -------------------------------------------
  (1) (以下で, 全てのモニターがアンロックされていることを確認する.
       もしロックが取られたままのモニターがあれば, IllegalMonitorStateException)

      (制御フローは少し混み合っていて, 以下のようになっている. 何でこんな書き方になってるのか?? #TODO

       処理は (restart ラベルを経由して) entry ラベルから始まり, 
       その後 loop で全部の要素の処理が終わるまでループが繰り返される.
       ただし, ロックが取られたままの要素が見つかれば, exception にジャンプして例外送出が行われる.
       ただし, exception で例外送出が行われないケースもあり, その場合は 
       (restart ラベルを経由して) ループが再開される.)
      ---------------------------------------- -}

      // Check that all monitors are unlocked

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

      { Label loop, exception, entry, restart;

        Register Rmptr   = O0;
        Register Rtemp   = O1;
        Register Rlimit  = Lmonitors;
        const jint delta = frame::interpreter_frame_monitor_size() * wordSize;
        assert( (delta & LongAlignmentMask) == 0,
                "sizeof BasicObjectLock must be even number of doublewords");

    {- -------------------------------------------
  (1.1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
        コード生成: (デバッグ用の処理)
        ---------------------------------------- -}

        #ifdef ASSERT
        add(top_most_monitor(), Rmptr, delta);
        { Label L;
          // ensure that Rmptr starts out above (or at) Rlimit
          cmp(Rmptr, Rlimit);
          brx(Assembler::greaterEqualUnsigned, false, pn, L);
          delayed()->nop();
          stop("monitor stack has negative size");
          bind(L);
        }
        #endif

    {- -------------------------------------------
  (1.1) コード生成:
        「(ここが restart ラベルの位置)」
        ---------------------------------------- -}

        bind(restart);

    {- -------------------------------------------
  (1.1) コード生成:
        「entry ラベルにジャンプして, 確認処理を開始する」
        ---------------------------------------- -}

        ba(false, entry);
        delayed()->
        add(top_most_monitor(), Rmptr, delta);      // points to current entry, starting with bottom-most entry

    {- -------------------------------------------
  (1.1) コード生成:
        「(ここが exception ラベルの位置)
          以下のどれかの処理を行う. 
          (なお, 以下の処理はコード生成時に引数に応じてどれかが生成される. 動的に条件判定で処理を分岐するわけではない)
          * 引数の throw_monitor_exception が true の場合
            InterpreterRuntime::throw_illegal_monitor_state_exception() を呼び出して 
            IllegalMonitorStateException を出す.
          * (throw_monitor_exception は false だが) 引数の install_monitor_exception が true の場合
            InterpreterRuntime::new_illegal_monitor_state_exception() を呼び出して 
            IllegalMonitorStateException を出す.
          * それ以外の場合
            何もしない. このまま restart ラベルにジャンプして次の要素の処理に進む.」
        ---------------------------------------- -}

        // Entry is still locked, need to throw exception
        bind(exception);
        if (throw_monitor_exception) {
          MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
          should_not_reach_here();
        } else {
          // Stack unrolling. Unlock object and if requested, install illegal_monitor_exception.
          // Unlock does not block, so don't have to worry about the frame
          unlock_object(Rmptr);
          if (install_monitor_exception) {
            MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
          }
          ba(false, restart);
          delayed()->nop();
        }

    {- -------------------------------------------
  (1.1) コード生成:
        「(ここが loop ラベルの位置)
          もし obj フィールドが NULL であれば, exception ラベルにジャンプして例外送出を行う.
          そうでなければ, Rmptr をデクリメントした後, このままフォールスルー.」
        ---------------------------------------- -}

        bind(loop);
        cmp(Rtemp, G0);                             // check if current entry is used
        brx(Assembler::notEqual, false, pn, exception);
        delayed()->
        dec(Rmptr, delta);                          // otherwise advance to next entry

    {- -------------------------------------------
  (1.1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
        コード生成: (デバッグ用の処理)
        ---------------------------------------- -}

        #ifdef ASSERT
        { Label L;
          // ensure that Rmptr has not somehow stepped below Rlimit
          cmp(Rmptr, Rlimit);
          brx(Assembler::greaterEqualUnsigned, false, pn, L);
          delayed()->nop();
          stop("ran off the end of the monitor stack");
          bind(L);
        }
        #endif

    {- -------------------------------------------
  (1.1) コード生成:
        「(ここが entry ラベルの位置)
          まだ全ての BasicObjectLock を処理し終えていなければ (= RLimit に達していなければ), 
          loop にジャンプして現在の BasicObjectLock オブジェクトの処理を行う.
          逆に全ての BasicObjectLock を処理し終えたら, このままフォールスルーして終了」
        ---------------------------------------- -}

        bind(entry);
        cmp(Rmptr, Rlimit);                         // check if bottom reached
        brx(Assembler::notEqual, true, pn, loop);   // if not at bottom then check this entry
        delayed()->
        ld_ptr(Rmptr, BasicObjectLock::obj_offset_in_bytes() - delta, Rtemp);
      }

  {- -------------------------------------------
  (1) (ここまでが, 全てのモニターがアンロックされていることを確認する処理)
      ---------------------------------------- -}

  {- -------------------------------------------
  (1) コード生成:
      「(ここが no_unlock ラベルの位置)」
      ---------------------------------------- -}

      bind(no_unlock);

  {- -------------------------------------------
  (1) コード生成:
      「待避していた TOS を復帰させておく」
      ---------------------------------------- -}

      pop(state);

  {- -------------------------------------------
  (1) コード生成: (verify)
      ---------------------------------------- -}

      interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
    }

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