Top


定義場所(file name)

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

名前(function name)

void MacroAssembler::call_VM_base(Register oop_result,
                                  Register java_thread,
                                  Register last_java_sp,
                                  address  entry_point,
                                  int      number_of_arguments,
                                  bool     check_exceptions) {

本体部(body)

  {- -------------------------------------------
  (1) (引数でカレントスレッドの JavaThread オブジェクトを指したレジスタ(java_thread)が指定されていなければ, 
       以下のレジスタを代わりに使うことにする.
       * 64bit の場合
         r15_thread レジスタ
       * 32bit の場合
         rdi レジスタ

       なお, 32bit の場合には, MacroAssembler::get_thread() が生成するコードで
       rdi にスレッドのアドレスをロードする処理も行っておく)


       (といっても, 64bit 版の場合は明示的に r15_thread が指定されていることが多いような気がするが...
        まぁ全部調べたわけじゃないが... #TODO)
      ---------------------------------------- -}

      // determine java_thread register
      if (!java_thread->is_valid()) {
    #ifdef _LP64
        java_thread = r15_thread;
    #else
        java_thread = rdi;
        get_thread(java_thread);
    #endif // LP64
      }

  {- -------------------------------------------
  (1) (引数で last_java_sp に使うレジスタが指定されていなければ, SP を使うこととする)

      (通常は SP でも良さそうだが,
       last_java_sp を元に last_Java_pc を取得できるように調整していたりするので
       このように指定できるようになっている模様.
       See: MacroAssembler::call_VM_helper())
      ---------------------------------------- -}

      // determine last_java_sp register
      if (!last_java_sp->is_valid()) {
        last_java_sp = rsp;
      }

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

      // debugging support
      assert(number_of_arguments >= 0   , "cannot have negative number of arguments");
      LP64_ONLY(assert(java_thread == r15_thread, "unexpected register"));
    #ifdef ASSERT
      LP64_ONLY(if (UseCompressedOops) verify_heapbase("call_VM_base");)
    #endif // ASSERT

      assert(java_thread != oop_result  , "cannot use the same register for java_thread & oop_result");
      assert(java_thread != last_java_sp, "cannot use the same register for java_thread & last_java_sp");

  {- -------------------------------------------
  (1) コード生成:
      「呼び出し時の第一引数として,  
        カレントスレッドを表す JavaThread をセットする.
        (32bit の場合はスタックに積む. 64bit なら c_rarg0 レジスタにセット)」

      (せっかく MacroAssembler::pass_arg0() があるんだから使えばいいのに...)
      ---------------------------------------- -}

      // push java thread (becomes first argument of C function)

      NOT_LP64(push(java_thread); number_of_arguments++);
      LP64_ONLY(mov(c_rarg0, r15_thread));

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

      // set last Java frame before call
      assert(last_java_sp != rbp, "can't use ebp/rbp");

  {- -------------------------------------------
  (1) コード生成:
      「MacroAssembler::call_VM_leaf_base() が生成するコードにより, 
        引数で指定されたエントリポイントを呼び出す.」

      (なお, 呼び出しの前後で last_Java_sp への SP のセット/クリアも行っている. (set_last_Java_frame/reset_last_Java_frame))
      (また, 呼び出し後で引数で指定された java_thread レジスタの復帰も行っている)
      ---------------------------------------- -}

      // Only interpreter should have to set fp
      set_last_Java_frame(java_thread, last_java_sp, rbp, NULL);

      // do the call, remove parameters
      MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments);

      // restore the thread (cannot use the pushed argument since arguments
      // may be overwritten by C code generated by an optimizing compiler);
      // however can use the register value directly if it is callee saved.
      if (LP64_ONLY(true ||) java_thread == rdi || java_thread == rsi) {
        // rdi & rsi (also r15) are callee saved -> nothing to do
    #ifdef ASSERT
        guarantee(java_thread != rax, "change this code");
        push(rax);
        { Label L;
          get_thread(rax);
          cmpptr(java_thread, rax);
          jcc(Assembler::equal, L);
          stop("MacroAssembler::call_VM_base: rdi not callee saved?");
          bind(L);
        }
        pop(rax);
    #endif
      } else {
        get_thread(java_thread);
      }
      // reset last Java frame
      // Only interpreter should have to clear fp
      reset_last_Java_frame(java_thread, true, false);

  {- -------------------------------------------
  (1) コード生成: (なお, CC_INTERP が #define されている場合には生成しない)
      「InterpreterMacroAssembler::check_and_handle_popframe() や
       InterpreterMacroAssembler::check_and_handle_earlyret() が生成したコードにより, 
       JVMTI の PopFrame() や ForceEarlyReturn*() が呼ばれていないかをチェックする.
       もし呼ばれていれば, ここでそれぞれの処理ルーチンへジャンプする.」
       (See: [here](no3059hIn.html) for details)
      ---------------------------------------- -}

    #ifndef CC_INTERP
       // C++ interp handles this in the interpreter
      check_and_handle_popframe(java_thread);
      check_and_handle_earlyret(java_thread);
    #endif /* CC_INTERP */

  {- -------------------------------------------
  (1) コード生成: (ただし, 引数で例外チェックコードを生成するように
                 指定されている場合(check_exeptions が true の場合)にのみ生成する)
      「カレントスレッドの pending_exception フィールドを確認する.
        もし 0 でなければ, 例外が発生したということなので 
        StubRoutines::forward_exception_entry() が指しているコードを呼び出す.
        (0 であればこのままフォールスルー)」
       (See: [here](no3059uSt.html) for details)
      ---------------------------------------- -}

      if (check_exceptions) {
        // check for pending exceptions (java_thread is set upon return)
        cmpptr(Address(java_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
    #ifndef _LP64
        jump_cc(Assembler::notEqual,
                RuntimeAddress(StubRoutines::forward_exception_entry()));
    #else
        // This used to conditionally jump to forward_exception however it is
        // possible if we relocate that the branch will not reach. So we must jump
        // around so we can always reach

        Label ok;
        jcc(Assembler::equal, ok);
        jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
        bind(ok);
    #endif // LP64
      }

  {- -------------------------------------------
  (1) コード生成: (ただし, 引数で指定された oop_result が valid でなければ生成しない)
      「呼び出し結果(返値)をカレントスレッドの JavaThread::vm_result フィールドから取り出し, 
        引数で指定された oop_result レジスタ内に格納する.
        (ついでに, 取り出した後で JavaThread::vm_result フィールドは 0 クリアしておく)」
      ---------------------------------------- -}

      // get oop result if there is one and reset the value in the thread
      if (oop_result->is_valid()) {
        movptr(oop_result, Address(java_thread, JavaThread::vm_result_offset()));
        movptr(Address(java_thread, JavaThread::vm_result_offset()), NULL_WORD);
        verify_oop(oop_result, "broken oop in call_VM_base");
      }
    }

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