自分用メモ。Ubuntu bionicでビルドできた最小バージョンのjdk-12-ga (jdk-12+33)を読んでいる。
関連リソース
- OpenJDK の設計と実装に関する備忘録
- Java 起動(Launcher)の仕組み
-
JJUG CCC 2013 Fall「JVMコードリーディング入門-JVMのOS抽象化レイヤーについて-」
-
HotSpotのディレクトリ構造 -
src/
はsrc/hotspot/
に移った?
-
HotSpotのディレクトリ構造 -
- HotSpot Runtime Overview
- 徹底解剖「G1GC」実装編
- OpenJDKのビルドやデバッグ
- Hotspot VMの基本構造を理解する
- DEMYSTIFYING THE JVM: JVM VARIANTS, CPPINTERPRETER AND TEMPLATEINTERPRETER
- Hotspot JVMの圧縮OOP
ディレクトリ構造
- src/
- hotspot/
- cpu: x86 など
- os: linux など
- os_cpu: linux_x86 など
- share/
- adlc: C2 JITのプラットフォーム依存コード生成 ADLC
- asm: アセンブラのアーキテクチャ非依存部
- c1: C1 JITコンパイラ
- ci: (JIT) Compiler Interface
- classfile: クラスファイルの実装
- code: CodeCache領域
- compiler: JIT管理用スレッド
- gc: G1GC, Parallel GC, ZGC など
- interpreter: C++インタプリタ, テンプレートインタプリタ
- libadt: ALDCが使うデータ構造
- memory: ヒープ管理
- oops: オブジェクトの管理ポインタ (Ordinary Object Pointer)
- opto: C2 JITコンパイラ
- prims: JNIのAPIなど
- runtime: JVMスレッド作成など
- java.base/
- share/
- classes/
* java.lang: Object, String, Integerなど
* java.util: List, Map, Setなど - native/
* launcher/main.c: javaコマンドのエントリポイント
* libjli/java.c: javaコマンドの実際の実装
- classes/
- share/
- jdk.internal.vm.compiler: Graal
- hotspot/
インタプリタが起動されるまで
1. javaコマンド
-
main()
: src/java.base/share/native/launcher/main.c- libjliの
JLI_*
なAPIが呼び出され、コマンドライン引数処理の準備がされる - 最後に
JLI_Launch
を呼んで終わり (ここが本体)
- libjliの
2. Java Launcher Infrastructure: libjli
-
JLI_Launch()
: src/java.base/share/native/libjli/java.c- LoadJavaVM(): libjvm.so をダイナミックロードするらしい
- JVMInit(): これは src/java.base/unix/native/libjli/java_md_solinux.c にある
- ContinueInNewThread()
- ContinueInNewThread0(JavaMain, ...): これも share ではなく unix
- pthread_create で JavaMain() が呼び出される
- pthread_join で JavaMain() の終了を待つ
- ContinueInNewThread0(JavaMain, ...): これも share ではなく unix
- ContinueInNewThread()
-
JavaMain()
: src/java.base/share/native/libjli/java.c- InitializeJVM()
- JNI_CreateJavaVM(): ここまでlibjli内
- JNI_CreateJavaVM_inner(): src/hotspot/share/prims/jni.cpp
- Threads::create_vm(): src/hotspot/share/runtime/thread.cpp
* 14くらい新たにスレッドが作られる。ここで何回かSEGV
- Threads::create_vm(): src/hotspot/share/runtime/thread.cpp
- JNI_CreateJavaVM_inner(): src/hotspot/share/prims/jni.cpp
- JNI_CreateJavaVM(): ここまでlibjli内
- LoadMainClass(): Main-Class を取得する
- GetStaticMethodID(): そのmainClassからstaticなmainメソッドを探索、methodIDを取得
- CallStaticVoidMethod() を呼ぶ
- InitializeJVM()
3. Java Virtual Machine: libjvm
以下はC++インタプリタでのフロー。templateインタプリタだとStubGenerator::call_stub
のところから動的生成コードになる。
-
jni_CallStaticVoidMethod()
: src/hotspot/share/prims/jni.cpp- jni_invoke_static()
- Method::resolve_jmethod_id(): methodIDから
methodHandle method
が取り出される - JavaCalls::call(): src/hotspot/share/runtime/javaCalls.cpp
- JavaCalls::call_helper()
- StubGenerator::call_stub(): src/hotspot/cpu/zero/stubGenerator_zero.cpp
- CppInterpreter::invoke_method(): src/hotspot/share/interpreter/cppInterpreter.cpp
- ZeroEntry::invoke(): src/hotspot/cpu/zero/entry_zero.hpp
- CppInterpreter::normal_entry(): src/hotspot/cpu/zero/cppInterpreter_zero.cpp
- CppInterpreter::main_loop()
- BytecodeInterpreter::run(): hotspot/share/interpreter/bytecodeInterpreter.cpp
- CppInterpreter::main_loop()
- CppInterpreter::normal_entry(): src/hotspot/cpu/zero/cppInterpreter_zero.cpp
- ZeroEntry::invoke(): src/hotspot/cpu/zero/entry_zero.hpp
- CppInterpreter::invoke_method(): src/hotspot/share/interpreter/cppInterpreter.cpp
- StubGenerator::call_stub(): src/hotspot/cpu/zero/stubGenerator_zero.cpp
- JavaCalls::call_helper()
- Method::resolve_jmethod_id(): methodIDから
- jni_invoke_static()