Top


定義場所(file name)

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

説明(description)

// remove activation
//
// Unlock the receiver if this is a synchronized method.
// Unlock any Java monitors from syncronized blocks.
// Remove the activation from the stack.
//
// 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::remove_activation(
        TosState state,
        Register ret_addr,
        bool throw_monitor_exception,
        bool install_monitor_exception,
        bool notify_jvmdi) {

本体部(body)

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      // Note: Registers rdx xmm0 may be in use for the
      // result check if synchronized method

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

      Label unlocked, unlock, no_unlock;

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

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

      // get the value of _do_not_unlock_if_synchronized into rdx
      const Address do_not_unlock_if_synchronized(r15_thread,
        in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
      movbool(rdx, do_not_unlock_if_synchronized);
      movbool(do_not_unlock_if_synchronized, false); // reset the flag

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

     // get method access flags
      movptr(rbx, Address(rbp, frame::interpreter_frame_method_offset * wordSize));
      movl(rcx, Address(rbx, methodOopDesc::access_flags_offset()));
      testl(rcx, JVM_ACC_SYNCHRONIZED);
      jcc(Assembler::zero, unlocked);

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

      // Don't unlock anything if the _do_not_unlock_if_synchronized flag
      // is set.
      testbool(rdx);
      jcc(Assembler::notZero, no_unlock);

  {- -------------------------------------------
  (1) (以下で, 実際のロック解放処理を行う)
      ---------------------------------------- -}

      // unlock monitor

  {- -------------------------------------------
  (1) コード生成:
      「TOS に入っている返値をスタック上に待避しておく」
      ---------------------------------------- -}

      push(state); // save result

  {- -------------------------------------------
  (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.

  {- -------------------------------------------
  (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 ラベルにジャンプする.               」
      ---------------------------------------- -}

      const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset *
                            wordSize - (int) sizeof(BasicObjectLock));
      // We use c_rarg1 so that if we go slow path it will be the correct
      // register for unlock_object to pass to VM directly
      lea(c_rarg1, monitor); // address of first monitor

      movptr(rax, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()));
      testptr(rax, rax);
      jcc(Assembler::notZero, unlock);

      pop(state);
      if (throw_monitor_exception) {
        // Entry already unlocked, need to throw exception
        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) {
          call_VM(noreg, CAST_FROM_FN_PTR(address,
                         InterpreterRuntime::new_illegal_monitor_state_exception));
        }
        jmp(unlocked);
      }

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

      bind(unlock);
      unlock_object(c_rarg1);

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

      pop(state);

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

      // Check that for block-structured locking (i.e., that all locked
      // objects has been unlocked)
      bind(unlocked);

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

      // rax: Might contain return value

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

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

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

      // Check that all monitors are unlocked
      {
        Label loop, exception, entry, restart;
        const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
        const Address monitor_block_top(
            rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
        const Address monitor_block_bot(
            rbp, frame::interpreter_frame_initial_sp_offset * wordSize);

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

        bind(restart);

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

        // We use c_rarg1 so that if we go slow path it will be the correct
        // register for unlock_object to pass to VM directly
        movptr(c_rarg1, monitor_block_top); // points to current entry, starting
                                      // with top-most entry
        lea(rbx, monitor_block_bot);  // points to word before bottom of
                                      // monitor block
        jmp(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 already locked, need to throw exception
        bind(exception);

        if (throw_monitor_exception) {
          // Throw 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 install illegal_monitor_exception.
          // Unlock does not block, so don't have to worry about the frame.
          // We don't have to preserve c_rarg1 since we are going to throw an exception.

          push(state);
          unlock_object(c_rarg1);
          pop(state);

          if (install_monitor_exception) {
            call_VM(noreg, CAST_FROM_FN_PTR(address,
                                            InterpreterRuntime::
                                            new_illegal_monitor_state_exception));
          }

          jmp(restart);
        }

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

        bind(loop);
        // check if current entry is used
        cmpptr(Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL);
        jcc(Assembler::notEqual, exception);

        addptr(c_rarg1, entry_size); // otherwise advance to next entry

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

        bind(entry);
        cmpptr(c_rarg1, rbx); // check if bottom reached
        jcc(Assembler::notEqual, loop); // if not at bottom then check this entry
      }

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

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

      bind(no_unlock);

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

      // jvmti support
      if (notify_jvmdi) {
        notify_method_exit(state, NotifyJVMTI);    // preserve TOSCA
      } else {
        notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA
      }

  {- -------------------------------------------
  (1) コード生成:
      「スタックフレーム上に待避しておいた SP の値を取得する」
      ---------------------------------------- -}

      // remove activation
      // get sender sp
      movptr(rbx,
             Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize));

  {- -------------------------------------------
  (1) コード生成:
      「スタックフレームを破棄し, リターンアドレスを取得した後, 
       SP を待避しておいた値に復帰させる」
      ---------------------------------------- -}

      leave();                           // remove frame anchor
      pop(ret_addr);                     // get return address
      mov(rsp, rbx);                     // set sp to sender sp
    }

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