Top


定義場所(file name)

hotspot/src/share/vm/runtime/javaCalls.cpp

名前(function name)

void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments* args, TRAPS) {

本体部(body)

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

      methodHandle method = *m;
      JavaThread* thread = (JavaThread*)THREAD;

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

      assert(thread->is_Java_thread(), "must be called by a java thread");
      assert(method.not_null(), "must have a method to call");
      assert(!SafepointSynchronize::is_at_safepoint(), "call to Java code during VM operation");
      assert(!thread->handle_area()->no_handle_mark_active(), "cannot call out to Java here");


  {- -------------------------------------------
  (1) (デバッグ用の処理) (CHECK_UNHANDLED_OOPS_ONLY 時にのみ実行) (See: UnhandledOops)
      unhandled oop をクリアする (? #TODO)
      ---------------------------------------- -}

      CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();)

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

      // Verify the arguments

      if (CheckJNICalls)  {
        args->verify(method, result->get_type(), thread);
      }
      else debug_only(args->verify(method, result->get_type(), thread));

  {- -------------------------------------------
  (1) もし呼び出し対象のメソッドが空であれば, 呼び出しても意味が無いので, ここでリターン
      ---------------------------------------- -}

      // Ignore call if method is empty
      if (method->is_empty_method()) {
        assert(result->get_type() == T_VOID, "an empty method must return a void value");
        return;
      }


  {- -------------------------------------------
  (1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
      ---------------------------------------- -}

    #ifdef ASSERT
      { klassOop holder = method->method_holder();
        // A klass might not be initialized since JavaCall's might be used during the executing of
        // the <clinit>. For example, a Thread.start might start executing on an object that is
        // not fully initialized! (bad Java programming style)
        assert(instanceKlass::cast(holder)->is_linked(), "rewritting must have taken place");
      }
    #endif


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

      assert(!thread->is_Compiler_thread(), "cannot compile from the compiler");

  {- -------------------------------------------
  (1) 呼び出し対象となっているメソッドが, 呼び出し前であってもコンパイルするべきメソッドの場合, 
      CompileBroker::compile_method() を呼んで JIT コンパイルを開始させる.
      ---------------------------------------- -}

      if (CompilationPolicy::must_be_compiled(method)) {
        CompileBroker::compile_method(method, InvocationEntryBci,
                                      CompLevel_initial_compile,
                                      methodHandle(), 0, "must_be_compiled", CHECK);
      }

  {- -------------------------------------------
  (1) メソッドのエントリポイントを取得する.

      (通常は methodOop の from_interpreted_entry フィールドのものを使用するが, 
       JVMTI の状況によっては, 実行がインタープリタのみに制限されることがある. (See: [here](no3059eFS.html) for details)
       この場合には, 代わりに interpreter_entry フィールドのものを使用する.)
      ---------------------------------------- -}

      // Since the call stub sets up like the interpreter we call the from_interpreted_entry
      // so we can go compiled via a i2c. Otherwise initial entry method will always
      // run interpreted.
      address entry_point = method->from_interpreted_entry();
      if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
        entry_point = method->interpreter_entry();
      }

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

      // Figure out if the result value is an oop or not (Note: This is a different value
      // than result_type. result_type will be T_INT of oops. (it is about size)
      BasicType result_type = runtime_type_from(result);
      bool oop_result_flag = (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY);

      // NOTE: if we move the computation of the result_val_address inside
      // the call to call_stub, the optimizer produces wrong code.
      intptr_t* result_val_address = (intptr_t*)(result->get_value_addr());

      // Find receiver
      Handle receiver = (!method->is_static()) ? args->receiver() : Handle();

  {- -------------------------------------------
  (1) もしスタック上の Yellow Page が無効にされていたら, 
      JavaThread::reguard_stack() を呼んで有効化しておく.
      ---------------------------------------- -}

      // When we reenter Java, we need to reenable the yellow zone which
      // might already be disabled when we are in VM.
      if (thread->stack_yellow_zone_disabled()) {
        thread->reguard_stack();
      }

  {- -------------------------------------------
  (1) もしこの時点でスタック状の空き領域が shadow page として不十分な量であれば, StackOverflowError.
      そうでなければ, os::bang_stack_shadow_pages() を呼んで十分な物理メモリを割り当てておく.
      ---------------------------------------- -}

      // Check that there are shadow pages available before changing thread state
      // to Java
      if (!os::stack_shadow_pages_available(THREAD, method)) {
        // Throw stack overflow exception with preinitialized exception.
        Exceptions::throw_stack_overflow_exception(THREAD, __FILE__, __LINE__, method);
        return;
      } else {
        // Touch pages checked if the OS needs them to be touched to be mapped.
        os::bang_stack_shadow_pages();
      }

  {- -------------------------------------------
  (1) StubRoutines::call_stub() が指しているコードにより, 
      指定の Java メソッドの呼び出しを行う.

      呼び出しから返ってきたら, 返値がポインタ(オブジェクトや配列)の場合には
      カレントスレッドの vm_result フィールドに入れておく.
      (これは, 以下のブロックを抜ける際に Safepoint が発生しうるため.
       どこかのフィールドに入れておかないと回収される恐れがある.)
      ---------------------------------------- -}

      // do call
      { JavaCallWrapper link(method, receiver, result, CHECK);
        { HandleMark hm(thread);  // HandleMark used by HandleMarkCleaner

          StubRoutines::call_stub()(
            (address)&link,
            // (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
            result_val_address,          // see NOTE above (compiler problem)
            result_type,
            method(),
            entry_point,
            args->parameters(),
            args->size_of_parameters(),
            CHECK
          );

          result = link.result();  // circumvent MS C++ 5.0 compiler bug (result is clobbered across call)
          // Preserve oop return value across possible gc points
          if (oop_result_flag) {
            thread->set_vm_result((oop) result->get_jobject());
          }
        }
      } // Exit JavaCallWrapper (can block - potential return oop must be preserved)

  {- -------------------------------------------
  (1) (thread が stop() や suspend() されていないかチェックするための 
       assert があったようだがコメントアウトされている.
       しかも, この assert は現実的じゃないみたいな指摘も付いている.)
      ---------------------------------------- -}

      // Check if a thread stop or suspend should be executed
      // The following assert was not realistic.  Thread.stop can set that bit at any moment.
      //assert(!thread->has_special_runtime_exit_condition(), "no async. exceptions should be installed");

  {- -------------------------------------------
  (1) 返値がポインタ(オブジェクトや配列)の場合には
      カレントスレッドの vm_result フィールドに入れておいた返値を
      カレントスレッドの jobject フィールドに入れ直す.
      (vm_result フィールドの方は NULL でクリアしておく)
      ---------------------------------------- -}

      // Restore possible oop return
      if (oop_result_flag) {
        result->set_jobject((jobject)thread->vm_result());
        thread->set_vm_result(NULL);
      }
    }

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