Top


定義場所(file name)

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

名前(function name)

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {

本体部(body)

  {- -------------------------------------------
  (1) (extern 宣言)
      ---------------------------------------- -}

      extern void JDK_Version_init();

  {- -------------------------------------------
  (1) JNI のバージョンがサポート範囲かどうか確認.
      ---------------------------------------- -}

      // Check version
      if (!is_supported_jni_version(args->version)) return JNI_EVERSION;

  {- -------------------------------------------
  (1) ostream_init() により, output stream module を gc log のために初期化する.
      ---------------------------------------- -}

      // Initialize the output stream module
      ostream_init();

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

      // Process java launcher properties.
      Arguments::process_sun_java_launcher_properties(args);

  {- -------------------------------------------
  (1) os::init() により, OS モジュール (乱数生成機, 現在のPID, 高精度タイマー, etc) を初期化する
      ---------------------------------------- -}

      // Initialize the os module before using TLS
      os::init();

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

      // Initialize system properties.
      Arguments::init_system_properties();

  {- -------------------------------------------
  (1) JDK_Version_init() により, JDK_Version クラスを初期化する (See: JDK_Version).
      ---------------------------------------- -}

      // So that JDK version can be used as a discrimintor when parsing arguments
      JDK_Version_init();

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

      // Update/Initialize System properties after JDK version number is known
      Arguments::init_version_specific_system_properties();

  {- -------------------------------------------
  (1) Arguments::parse() により, コマンドライン引数などを処理する.
      ---------------------------------------- -}

      // Parse arguments
      jint parse_result = Arguments::parse(args);
      if (parse_result != JNI_OK) return parse_result;

  {- -------------------------------------------
  (1) PauseAtStartup オプションが指定されていれば, pause file が削除されるまで待つ
      ---------------------------------------- -}

      if (PauseAtStartup) {
        os::pause();
      }

  {- -------------------------------------------
  (1) (DTrace のフック点)
      ---------------------------------------- -}

      HS_DTRACE_PROBE(hotspot, vm__init__begin);

  {- -------------------------------------------
  (1) (トレース出力用の処理)

      TraceVmCreationTime のインスタンスを作成し, Threads::create_vm() にかかった時間の計測を開始する
      (See: TraceVmCreationTime)
      ---------------------------------------- -}

      // Record VM creation timing statistics
      TraceVmCreationTime create_vm_timer;
      create_vm_timer.start();

  {- -------------------------------------------
  (1) (トレース出力)
      ---------------------------------------- -}

      // Timing (must come after argument parsing)
      TraceTime timer("Create VM", TraceStartupTime);

  {- -------------------------------------------
  (1) os::init_2() により, コマンドライン引数に基づいて OS モジュールをさらに生成&初期化する.

      (e.g. synchronization, stack, memory, safepoint pages, etc).

      (また, その他のライブラリ(libzip, libjava, etc) をロードしたり, 
      シグナルハンドラを初期化したりもする)
      ---------------------------------------- -}

      // Initialize the os module after parsing the args
      jint os_init_2_result = os::init_2();
      if (os_init_2_result != JNI_OK) return os_init_2_result;

  {- -------------------------------------------
  (1) ostream_init_log() で, output stream logger を初期化する.

      必要な agent libraries (hprof, jdi) も初期化してスタートさせる
      ---------------------------------------- -}

      // Initialize output stream logging
      ostream_init_log();

  {- -------------------------------------------
  (1) -Xrun オプションを agentlib, agentpath 形式に変換する
      ---------------------------------------- -}

      // Convert -Xrun to -agentlib: if there is no JVM_OnLoad
      // Must be before create_vm_init_agents()
      if (Arguments::init_libraries_at_startup()) {
        convert_vm_init_libraries_to_agents();
      }

  {- -------------------------------------------
  (1) Threads::create_vm_init_agents() で,
      JVMTI エージェントをロードし, それぞれの Agent_OnLoad() 関数を呼び出す.

      (なお, JVMTI の phase の変更も行う.
       Threads::create_vm_init_agents() の中だけが JVMTI_PHASE_ONLOAD であり, 
       Threads::create_vm_init_agents() の終了後には JVMTI_PHASE_PRIMORDIAL になる.
       (See: Threads::create_vm_init_agents()))
      ---------------------------------------- -}

      // Launch -agentlib/-agentpath and converted -Xrun agents
      if (Arguments::init_agents_at_startup()) {
        create_vm_init_agents();
      }

  {- -------------------------------------------
  (1) ThreadLocalStorage::init() で, スレッドの状態や TLS などを初期化する.
      ---------------------------------------- -}

      // Initialize Threads state
      _thread_list = NULL;
      _number_of_threads = 0;
      _number_of_non_daemon_threads = 0;

      // Initialize TLS
      ThreadLocalStorage::init();

  {- -------------------------------------------
  (1) vm_init_globals() で, 大域データを初期化する
      ---------------------------------------- -}

      // Initialize global data structures and create system classes in heap
      vm_init_globals();

  {- -------------------------------------------
  (1) この段階でスレッドが作れるようになる.
      メインスレッドを表す JavaThread が作られ, 現在実行中のネイティブスレッドに対応付けられる.
      (ただし, このスレッドは the known list of the Threads には追加されない ?? #TODO)

      ちなみに, ここが "point of no return"
      (set_as_starting_thread() の途中で失敗したらやり直せない)
      ---------------------------------------- -}

      // Attach the main thread to this os thread
      JavaThread* main_thread = new JavaThread();
      main_thread->set_thread_state(_thread_in_vm);
      // must do this before set_active_handles and initialize_thread_local_storage
      // Note: on solaris initialize_thread_local_storage() will (indirectly)
      // change the stack size recorded here to one based on the java thread
      // stacksize. This adjusted size is what is used to figure the placement
      // of the guard pages.
      main_thread->record_stack_base_and_size();
      main_thread->initialize_thread_local_storage();

      main_thread->set_active_handles(JNIHandleBlock::allocate_block());

      if (!main_thread->set_as_starting_thread()) {
        vm_shutdown_during_initialization(
          "Failed necessary internal allocation. Out of swap space");
        delete main_thread;
        *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
        return JNI_ENOMEM;
      }

  {- -------------------------------------------
  (1) メインスレッドの stack guard page を作成する.
      (os::create_main_thread() の後で作らないと Linux でクラッシュするとのこと)
      ---------------------------------------- -}

      // Enable guard page *after* os::create_main_thread(), otherwise it would
      // crash Linux VM, see notes in os_linux.cpp.
      main_thread->create_stack_guard_pages();

  {- -------------------------------------------
  (1) ObjectMonitor::Initialize() で, Java レベルの同期排他機構の初期化を行う.
      ---------------------------------------- -}

      // Initialize Java-Level synchronization subsystem
      ObjectMonitor::Initialize() ;

  {- -------------------------------------------
  (1) init_globals() で, 残りの大域モジュールを初期化する.

      (e.g. BootClassLoader, CodeCache, Interpreter, Compiler, JNI, SystemDictionary, Universe, etc)

      ちなみに, ここも "point of no return"
      (init_globals() の途中で失敗したらやり直せない)
      ---------------------------------------- -}

      // Initialize global modules
      jint status = init_globals();
      if (status != JNI_OK) {
        delete main_thread;
        *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
        return status;
      }

  {- -------------------------------------------
  (1) メインスレッドを表す JavaThread 内のプラットフォーム依存なフィールドの初期化を行う
      ---------------------------------------- -}

      // Should be done after the heap is fully created
      main_thread->cache_global_variables();

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

      HandleMark hm;

  {- -------------------------------------------
  (1) main スレッドが list (the known list of the Threads??) に追加される.
      (Thread_Lock(??) を最初にロックするのはこの時らしい ?? #TODO)
      ---------------------------------------- -}

      { MutexLocker mu(Threads_lock);
        Threads::add(main_thread);
      }

  {- -------------------------------------------
  (1) ここまでで JavaThread が動き出した状態になったので, 
      JvmtiExport::transition_pending_onload_raw_monitors() を呼んで
      JvmtiPendingMonitors 内に溜まっている JvmtiRawMonitor を現在のスレッドへと移し替える.
      (See: JvmtiPendingMonitors)
      ---------------------------------------- -}

      // Any JVMTI raw monitors entered in onload will transition into
      // real raw monitor. VM is setup enough here for raw monitor enter.
      JvmtiExport::transition_pending_onload_raw_monitors();

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

      (Verify 系のオプションが指定されていれば, Universe::verify() で Universe のチェックを行う)
      ---------------------------------------- -}

      if (VerifyBeforeGC &&
          Universe::heap()->total_collections() >= VerifyGCStartAt) {
        Universe::heap()->prepare_for_verify();
        Universe::verify();   // make sure we're starting with a clean slate
      }

  {- -------------------------------------------
  (1) VMThread::create() で, VMThread を生成する.

      (生成後, Notify_lock を使って同期を取り, 
       VMThread が ready 状態になるまで待ってから次に進む.
       (See: VMThread::run()))
      ---------------------------------------- -}

      // Create the VMThread
      { TraceTime timer("Start VMThread", TraceStartupTime);
        VMThread::create();
        Thread* vmthread = VMThread::vm_thread();

        if (!os::create_thread(vmthread, os::vm_thread))
          vm_exit_during_initialization("Cannot create VM thread. Out of system resources.");

        // Wait for the VM thread to become ready, and VMThread::run to initialize
        // Monitors can have spurious returns, must always check another state flag
        {
          MutexLocker ml(Notify_lock);
          os::start_thread(vmthread);
          while (vmthread->active_handles() == NULL) {
            Notify_lock->wait();
          }
        }
      }

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

      assert (Universe::is_fully_initialized(), "not initialized");
      EXCEPTION_MARK;

  {- -------------------------------------------
  (1) DumpSharedSpaces オプションが指定されている場合には, ここでヒープをダンプして終了.
      ---------------------------------------- -}

      // At this point, the Universe is initialized, but we have not executed
      // any byte code.  Now is a good time (the only time) to dump out the
      // internal state of the JVM for sharing.

      if (DumpSharedSpaces) {
        Universe::heap()->preload_and_dump(CHECK_0);
        ShouldNotReachHere();
      }

  {- -------------------------------------------
  (1) (JVMTI の phase の変更)
      (ここからが JVMTI_PHASE_START)
      ---------------------------------------- -}

      // Always call even when there are not JVMTI environments yet, since environments
      // may be attached late and JVMTI must track phases of VM execution
      JvmtiExport::enter_start_phase();

  {- -------------------------------------------
  (1) (JVMTI のフック点) (See: VMStart イベント)
      (なお, ここで java.lang.instrument の premain() が呼び出されたりする)
      ---------------------------------------- -}

      // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.
      JvmtiExport::post_vm_start();

  {- -------------------------------------------
  (1) initialize_class() を用いて, 種々の Java クラスがロードされ初期化される.

      (e.g. java.lang.String, java.lang.System, java.lang.ThreadGroup, java.lang.Thread, java.lang.reflect.Method, java.lang.ref.Finalizer, java.lang.Class, and the rest of the System)
      ---------------------------------------- -}

      {
        TraceTime timer("Initialize java.lang classes", TraceStartupTime);

        if (EagerXrunInit && Arguments::init_libraries_at_startup()) {
          create_vm_init_libraries();
        }

        if (InitializeJavaLangString) {
          initialize_class(vmSymbols::java_lang_String(), CHECK_0);
        } else {
          warning("java.lang.String not initialized");
        }

    {- -------------------------------------------
  (1.1) AggressiveOpts オプションが指定されている場合は, ... #TODO
        ---------------------------------------- -}

        if (AggressiveOpts) {
          {
            // Forcibly initialize java/util/HashMap and mutate the private
            // static final "frontCacheEnabled" field before we start creating instances
    #ifdef ASSERT
            klassOop tmp_k = SystemDictionary::find(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);
            assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet");
    #endif
            klassOop k_o = SystemDictionary::resolve_or_null(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);
            KlassHandle k = KlassHandle(THREAD, k_o);
            guarantee(k.not_null(), "Must find java/util/HashMap");
            instanceKlassHandle ik = instanceKlassHandle(THREAD, k());
            ik->initialize(CHECK_0);
            fieldDescriptor fd;
            // Possible we might not find this field; if so, don't break
            if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) {
              k()->java_mirror()->bool_field_put(fd.offset(), true);
            }
          }

          if (UseStringCache) {
            // Forcibly initialize java/lang/StringValue and mutate the private
            // static final "stringCacheEnabled" field before we start creating instances
            klassOop k_o = SystemDictionary::resolve_or_null(vmSymbols::java_lang_StringValue(), Handle(), Handle(), CHECK_0);
            // Possible that StringValue isn't present: if so, silently don't break
            if (k_o != NULL) {
              KlassHandle k = KlassHandle(THREAD, k_o);
              instanceKlassHandle ik = instanceKlassHandle(THREAD, k());
              ik->initialize(CHECK_0);
              fieldDescriptor fd;
              // Possible we might not find this field: if so, silently don't break
              if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) {
                k()->java_mirror()->bool_field_put(fd.offset(), true);
              }
            }
          }
        }

        // Initialize java_lang.System (needed before creating the thread)
        if (InitializeJavaLangSystem) {
          initialize_class(vmSymbols::java_lang_System(), CHECK_0);
          initialize_class(vmSymbols::java_lang_ThreadGroup(), CHECK_0);
          Handle thread_group = create_initial_thread_group(CHECK_0);
          Universe::set_main_thread_group(thread_group());
          initialize_class(vmSymbols::java_lang_Thread(), CHECK_0);
          oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0);
          main_thread->set_threadObj(thread_object);
          // Set thread status to running since main thread has
          // been started and running.
          java_lang_Thread::set_thread_status(thread_object,
                                              java_lang_Thread::RUNNABLE);

          // The VM preresolve methods to these classes. Make sure that get initialized
          initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK_0);
          initialize_class(vmSymbols::java_lang_ref_Finalizer(),  CHECK_0);
          // The VM creates & returns objects of this class. Make sure it's initialized.
          initialize_class(vmSymbols::java_lang_Class(), CHECK_0);
          call_initializeSystemClass(CHECK_0);
        } else {
          warning("java.lang.System not initialized");
        }

        // an instance of OutOfMemory exception has been allocated earlier
        if (InitializeJavaLangExceptionsErrors) {
          initialize_class(vmSymbols::java_lang_OutOfMemoryError(), CHECK_0);
          initialize_class(vmSymbols::java_lang_NullPointerException(), CHECK_0);
          initialize_class(vmSymbols::java_lang_ClassCastException(), CHECK_0);
          initialize_class(vmSymbols::java_lang_ArrayStoreException(), CHECK_0);
          initialize_class(vmSymbols::java_lang_ArithmeticException(), CHECK_0);
          initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK_0);
          initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK_0);
        } else {
          warning("java.lang.OutOfMemoryError has not been initialized");
          warning("java.lang.NullPointerException has not been initialized");
          warning("java.lang.ClassCastException has not been initialized");
          warning("java.lang.ArrayStoreException has not been initialized");
          warning("java.lang.ArithmeticException has not been initialized");
          warning("java.lang.StackOverflowError has not been initialized");
        }
      }

      // See        : bugid 4211085.
      // Background : the static initializer of java.lang.Compiler tries to read
      //              property"java.compiler" and read & write property "java.vm.info".
      //              When a security manager is installed through the command line
      //              option "-Djava.security.manager", the above properties are not
      //              readable and the static initializer for java.lang.Compiler fails
      //              resulting in a NoClassDefFoundError.  This can happen in any
      //              user code which calls methods in java.lang.Compiler.
      // Hack :       the hack is to pre-load and initialize this class, so that only
      //              system domains are on the stack when the properties are read.
      //              Currently even the AWT code has calls to methods in java.lang.Compiler.
      //              On the classic VM, java.lang.Compiler is loaded very early to load the JIT.
      // Future Fix : the best fix is to grant everyone permissions to read "java.compiler" and
      //              read and write"java.vm.info" in the default policy file. See bugid 4211383
      //              Once that is done, we should remove this hack.
      initialize_class(vmSymbols::java_lang_Compiler(), CHECK_0);

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

      // More hackery - the static initializer of java.lang.Compiler adds the string "nojit" to
      // the java.vm.info property if no jit gets loaded through java.lang.Compiler (the hotspot
      // compiler does not get loaded through java.lang.Compiler).  "java -version" with the
      // hotspot vm says "nojit" all the time which is confusing.  So, we reset it here.
      // This should also be taken out as soon as 4211383 gets fixed.
      reset_vm_info_property(CHECK_0);

  {- -------------------------------------------
  (1) JNIEnv (JNI Function Table) 内の Get<Primitive>Field 関数を高速版に置き換える.
      (See: [here](nooEDMFr0n.html) for details)
      ---------------------------------------- -}

      quicken_jni_functions();

  {- -------------------------------------------
  (1) 基本的な初期化が終わったので, set_init_completed() で _init_completed 変数を true にする
      (ConcurrentGCThread 等がこの変数の値を見ており, 初期化が完了するまで処理を開始しないようにしている.
       See: is_init_completed())
      ---------------------------------------- -}

      // Set flag that basic initialization has completed. Used by exceptions and various
      // debug stuff, that does not work until all basic classes have been initialized.
      set_init_completed();

  {- -------------------------------------------
  (1) (DTrace のフック点)
      ---------------------------------------- -}

      HS_DTRACE_PROBE(hotspot, vm__init__end);

  {- -------------------------------------------
  (1) VM の起動処理が終わった時間を記録する.
      ---------------------------------------- -}

      // record VM initialization completion time
      Management::record_vm_init_completed();

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

      // Compute system loader. Note that this has to occur after set_init_completed, since
      // valid exceptions may be thrown in the process.
      // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and
      // set_init_completed has just been called, causing exceptions not to be shortcut
      // anymore. We call vm_exit_during_initialization directly instead.
      SystemDictionary::compute_java_system_loader(THREAD);
      if (HAS_PENDING_EXCEPTION) {
        vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
      }

  {- -------------------------------------------
  (1) GC アルゴリズムとして CMS か G1GC が指定されている場合には, 
      ここで SurrogateLockerThread を生成しておく.
      ---------------------------------------- -}

    #ifndef SERIALGC
      // Support for ConcurrentMarkSweep. This should be cleaned up
      // and better encapsulated. The ugly nested if test would go away
      // once things are properly refactored. XXX YSR
      if (UseConcMarkSweepGC || UseG1GC) {
        if (UseConcMarkSweepGC) {
          ConcurrentMarkSweepThread::makeSurrogateLockerThread(THREAD);
        } else {
          ConcurrentMarkThread::makeSurrogateLockerThread(THREAD);
        }
        if (HAS_PENDING_EXCEPTION) {
          vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
        }
      }
    #endif // SERIALGC

  {- -------------------------------------------
  (1) (JVMTI の phase の変更)
      (ここからが JVMTI_PHASE_LIVE)
      ---------------------------------------- -}

      // Always call even when there are not JVMTI environments yet, since environments
      // may be attached late and JVMTI must track phases of VM execution
      JvmtiExport::enter_live_phase();

  {- -------------------------------------------
  (1) シグナル処理を行うためのスレッド("Signal Dispatcher" スレッド)を立ち上げる.
      (これは VMInit イベントを送出する前に行う必要があるとのこと)
      ---------------------------------------- -}

      // Signal Dispatcher needs to be started before VMInit event is posted
      os::signal_init();

  {- -------------------------------------------
  (1) 以下の2つの条件がどちらも成り立つなら, 
      AttachListener::init() で AttachListener を初期化する (See: AttachListener)

      * AttachListener 機能が有効
        (= DisableAttachMechanism オプションが指定されていない)
      * AttachListener を HotSpot の起動時に初期化することになっている
        (= StartAttachListener オプションが指定されている, もしくは
           AttachListener::init_at_startup() が true を返す)
      ---------------------------------------- -}

      // Start Attach Listener if +StartAttachListener or it can't be started lazily
      if (!DisableAttachMechanism) {
        if (StartAttachListener || AttachListener::init_at_startup()) {
          AttachListener::init();
        }
      }

  {- -------------------------------------------
  (1) Threads::create_vm_init_libraries() で,
      -Xrun オプションで指定された JVMTI エージェントをロードし, それぞれの JVM_OnLoad() 関数を呼び出す.
      ---------------------------------------- -}

      // Launch -Xrun agents
      // Must be done in the JVMTI live phase so that for backward compatibility the JDWP
      // back-end can launch with -Xdebug -Xrunjdwp.
      if (!EagerXrunInit && Arguments::init_libraries_at_startup()) {
        create_vm_init_libraries();
      }

  {- -------------------------------------------
  (1) (JVMTI のフック点) (See: VMInit イベント)
      ---------------------------------------- -}

      // Notify JVMTI agents that VM initialization is complete - nop if no agents.
      JvmtiExport::post_vm_initialized();

  {- -------------------------------------------
  (1) ChunkPoolCleaner オブジェクトを生成し, 実行を開始させる.
      (See: ChunkPoolCleaner)
      ---------------------------------------- -}

      Chunk::start_chunk_pool_cleaner_task();

  {- -------------------------------------------
  (1) CompileBroker を初期化する
      (See: CompileBroker)
      ---------------------------------------- -}

      // initialize compiler(s)
      CompileBroker::compilation_init();

  {- -------------------------------------------
  (1) Management::initialize() を呼んで serviceability 機能関係の初期化を行う 

      (ServiceThread の起動, JMX Management Server の起動, etc)
      (See: )
      (See: [here](novYWKneN9.html) for details)

      もしこの初期化処理でエラーが起きたら, vm_exit() で異常終了.
      ---------------------------------------- -}

      Management::initialize(THREAD);
      if (HAS_PENDING_EXCEPTION) {
        // management agent fails to start possibly due to
        // configuration problem and is responsible for printing
        // stack trace if appropriate. Simply exit VM.
        vm_exit(1);
      }

  {- -------------------------------------------
  (1) コマンドラインオプションでの指定に基づき, 必要があれば簡易的なプロファイラを生成する.
      (See: FlatProfiler)
      (See: AllocationProfiler)
      (See: MemProfiler)
      (See: StatSampler)
      ---------------------------------------- -}

      if (Arguments::has_profile())       FlatProfiler::engage(main_thread, true);
      if (Arguments::has_alloc_profile()) AllocationProfiler::engage();
      if (MemProfiling)                   MemProfiler::engage();
      StatSampler::engage();

  {- -------------------------------------------
  (1) CheckJNICalls オプションが指定されていれば, JniPeriodicChecker オブジェクトを生成しておく.
      (See: JniPeriodicChecker)
      ---------------------------------------- -}

      if (CheckJNICalls)                  JniPeriodicChecker::engage();

  {- -------------------------------------------
  (1) biased locking 処理を有効にする
      ---------------------------------------- -}

      BiasedLocking::init();

  {- -------------------------------------------
  (1) もし sun.misc.PostVMInitHook クラスがあれば, sun.misc.PostVMInitHook.run() メソッドを呼び出しておく.

      (sun.misc.PostVMInitHook クラスは OpenJDK では見当たらない (Oracle JDK の rt.jar 内には存在している).
       まぁクラスがなければ call_postVMInitHook() が何もせずに返ってくるだけだが...
       See: sun.misc.PostVMInitHook)
      ---------------------------------------- -}

      if (JDK_Version::current().post_vm_init_hook_enabled()) {
        call_postVMInitHook(THREAD);
        // The Java side of PostVMInitHook.run must deal with all
        // exceptions and provide means of diagnosis.
        if (HAS_PENDING_EXCEPTION) {
          CLEAR_PENDING_EXCEPTION;
        }
      }

  {- -------------------------------------------
  (1) もし PeriodicTask があれば, WatcherThread::start() で WatcherThread を生成する (See: WatcherThread).
      ---------------------------------------- -}

      // Start up the WatcherThread if there are any periodic tasks
      // NOTE:  All PeriodicTasks should be registered by now. If they
      //   aren't, late joiners might appear to start slowly (we might
      //   take a while to process their first tick).
      if (PeriodicTask::num_tasks() > 0) {
        WatcherThread::start();
      }

  {- -------------------------------------------
  (1) OS モジュールに関する最後の初期化処理を実行する.

      (といっても, 現状ではこの関数はどのプラットフォーム上でも何もしないようだが...)
      ---------------------------------------- -}

      // Give os specific code one last chance to start
      os::init_3();

  {- -------------------------------------------
  (1) TraceVmCreationTime::end() を呼び出して Threads::create_vm() にかかった時間の計測を終了する.
      ---------------------------------------- -}

      create_vm_timer.end();

  {- -------------------------------------------
  (1) リターン.
      ---------------------------------------- -}

      return JNI_OK;
    }

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