hotspot/src/share/vm/oops/instanceKlass.cpp
void instanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
{- -------------------------------------------
(1) (初期化前にリンクされていないとまずいので)
instanceKlass::link_class() を呼んで確実にリンク処理までは終わらせておく.
---------------------------------------- -}
// Make sure klass is linked (verified) before initialization
// A class could already be verified, since it has been reflected upon.
this_oop->link_class(CHECK);
{- -------------------------------------------
(1) (DTrace のフック点) (class__initialization__required)
---------------------------------------- -}
DTRACE_CLASSINIT_PROBE(required, instanceKlass::cast(this_oop()), -1);
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
bool wait = false;
{- -------------------------------------------
(1) コメントによると, 以下の処理ステップについては "JVM book page 47" を参照, とのこと.
(現行の Java 仮想マシン仕様の "5.5 Initialization" の内容だと思われる(?))
(なお, HotSpot 内では, 仕様における initialization lock ("LC") として,
初期化対象クラスのモニターを用いている (以下の処理参照))
---------------------------------------- -}
// refer to the JVM book page 47 for description of steps
{- -------------------------------------------
(1) (以下のブロック内の処理は, initialization lock ("LC") で排他した状態で行う)
(Java 仮想マシン仕様の "5.5 Initialization" における Step 1 の内容)
---------------------------------------- -}
// Step 1
{ ObjectLocker ol(this_oop, THREAD);
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
Thread *self = THREAD; // it's passed the current thread
{- -------------------------------------------
(1.1) もし他のスレッドによって初期化中であれば,
初期化が完了するまでここで待機する.
(Java 仮想マシン仕様の "5.5 Initialization" における Step 2 の内容)
(なおコメントによると,
waitUninterruptibly() の代わりに wait() で待つと
InterruptedException が出る恐れがあり,
これは link/symbol resolution では予期されていない例外なので酷いことになる, とのこと)
---------------------------------------- -}
// Step 2
// If we were to use wait() instead of waitInterruptibly() then
// we might end up throwing IE from link/symbol resolution sites
// that aren't expected to throw. This would wreak havoc. See 6320309.
while(this_oop->is_being_initialized() && !this_oop->is_reentrant_initialization(self)) {
wait = true;
ol.waitUninterruptibly(CHECK);
}
{- -------------------------------------------
(1.1) もしカレントスレッドによって初期化中であれば,
これ以上処理をする必要はないので, ここでリターン.
(Java 仮想マシン仕様の "5.5 Initialization" における Step 3 の内容)
なお, (DTrace のフック点) でもある (class__initialization__recursive)
---------------------------------------- -}
// Step 3
if (this_oop->is_being_initialized() && this_oop->is_reentrant_initialization(self)) {
DTRACE_CLASSINIT_PROBE_WAIT(recursive, instanceKlass::cast(this_oop()), -1,wait);
return;
}
{- -------------------------------------------
(1.1) もし既に初期化済みであれば,
これ以上処理をする必要はないので, ここでリターン.
(Java 仮想マシン仕様の "5.5 Initialization" における Step 4 の内容)
なお, (DTrace のフック点) でもある (class__initialization__concurrent)
---------------------------------------- -}
// Step 4
if (this_oop->is_initialized()) {
DTRACE_CLASSINIT_PROBE_WAIT(concurrent, instanceKlass::cast(this_oop()), -1,wait);
return;
}
{- -------------------------------------------
(1.1) もし対象クラスが初期化中にエラーが起こってしまった状態であれば
ここでもう一度初期化処理をしても意味はないので,
NoClassDefFoundError を出して終了.
(Java 仮想マシン仕様の "5.5 Initialization" における Step 5 の内容)
なお, (DTrace のフック点) でもある (class__initialization__erroneous)
---------------------------------------- -}
// Step 5
if (this_oop->is_in_error_state()) {
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, instanceKlass::cast(this_oop()), -1,wait);
ResourceMark rm(THREAD);
const char* desc = "Could not initialize class ";
const char* className = this_oop->external_name();
size_t msglen = strlen(desc) + strlen(className) + 1;
char* message = NEW_RESOURCE_ARRAY(char, msglen);
if (NULL == message) {
// Out of memory: can't create detailed error message
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
} else {
jio_snprintf(message, msglen, "%s%s", desc, className);
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
}
}
{- -------------------------------------------
(1.1) 以上のどれでもなければ, 対象クラスはカレントスレッドが初期化することになるので,
instanceKlass::set_init_state() 及び instanceKlass::set_init_thread() を呼んで
そのことを対象クラス内に記録しておく
(ここまでが initialization lock ("LC") で排他した処理)
(Java 仮想マシン仕様の "5.5 Initialization" における Step 6 の内容)
---------------------------------------- -}
// Step 6
this_oop->set_init_state(being_initialized);
this_oop->set_init_thread(self);
}
{- -------------------------------------------
(1) 対象がインターフェースではなくクラスの場合,
スーパークラスが初期化されてなければ,
Klass::initialize() を再帰的に呼び出してスーパークラスを初期化する.
(もし初期化でエラーが出た場合は,
instanceKlass::set_initialization_state_and_notify() を呼んで
クラスの初期化状態を initialization_error に変更し, 待機している他スレッドを起床させた後,
例外を投げ直す.
なお, (DTrace のフック点) でもある (class__initialization__super__failed))
(Java 仮想マシン仕様の "5.5 Initialization" における Step 7 の内容)
---------------------------------------- -}
// Step 7
klassOop super_klass = this_oop->super();
if (super_klass != NULL && !this_oop->is_interface() && Klass::cast(super_klass)->should_be_initialized()) {
Klass::cast(super_klass)->initialize(THREAD);
if (HAS_PENDING_EXCEPTION) {
Handle e(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
{
EXCEPTION_MARK;
this_oop->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads
CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, superclass initialization error is thrown below
}
DTRACE_CLASSINIT_PROBE_WAIT(super__failed, instanceKlass::cast(this_oop()), -1,wait);
THROW_OOP(e());
}
}
{- -------------------------------------------
(1) instanceKlass::call_class_initializer() を呼んで,
対象クラスの static 初期化子 (= <clinit>メソッド) を実行する
(Java 仮想マシン仕様の "5.5 Initialization" における Step 9 の内容)
(コメントでは Step 8 になっているので, 以前の仕様では Step 8 だった?)
なお, (DTrace のフック点) でもある (class__initialization__clinit)
また, (プロファイル情報の記録) も行っている (See: PerfClassTraceTime)
---------------------------------------- -}
// Step 8
{
assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl");
JavaThread* jt = (JavaThread*)THREAD;
DTRACE_CLASSINIT_PROBE_WAIT(clinit, instanceKlass::cast(this_oop()), -1,wait);
// Timer includes any side effects of class initialization (resolution,
// etc), but not recursive entry into call_class_initializer().
PerfClassTraceTime timer(ClassLoader::perf_class_init_time(),
ClassLoader::perf_class_init_selftime(),
ClassLoader::perf_classes_inited(),
jt->get_thread_stat()->perf_recursion_counts_addr(),
jt->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::CLASS_CLINIT);
this_oop->call_class_initializer(THREAD);
}
{- -------------------------------------------
(1) もし初期化処理が正常に終了した場合は (= 例外が出ていなければ),
instanceKlass::set_initialization_state_and_notify() を呼んで
クラスの初期化状態を fully_initialized に変更し
待機している他スレッドを起床させる.
(Java 仮想マシン仕様の "5.5 Initialization" における Step 10 の内容)
(コメントでは Step 9 になっているので, 以前の仕様では Step 9 だった?)
---------------------------------------- -}
// Step 9
if (!HAS_PENDING_EXCEPTION) {
this_oop->set_initialization_state_and_notify(fully_initialized, CHECK);
{ ResourceMark rm(THREAD);
debug_only(this_oop->vtable()->verify(tty, true);)
}
}
{- -------------------------------------------
(1) もし初期化処理で例外が出ていた場合は,
instanceKlass::set_initialization_state_and_notify() を呼んで
クラスの初期化状態を initialization_error に変更し, 待機している他スレッドを起床させた後,
例外を投げ直す.
(Java 仮想マシン仕様の "5.5 Initialization" における Step 11 及び Step 12 の内容)
(コメントでは Step 10 and 11 になっているので, 以前の仕様では Step 10 と 11 だった?)
なお, (DTrace のフック点) でもある (class__initialization__error)
---------------------------------------- -}
else {
// Step 10 and 11
Handle e(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
{
EXCEPTION_MARK;
this_oop->set_initialization_state_and_notify(initialization_error, THREAD);
CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below
}
DTRACE_CLASSINIT_PROBE_WAIT(error, instanceKlass::cast(this_oop()), -1,wait);
if (e->is_a(SystemDictionary::Error_klass())) {
THROW_OOP(e());
} else {
JavaCallArguments args(e);
THROW_ARG(vmSymbols::java_lang_ExceptionInInitializerError(),
vmSymbols::throwable_void_signature(),
&args);
}
}
{- -------------------------------------------
(1) (DTrace のフック点) (class__initialization__end)
---------------------------------------- -}
DTRACE_CLASSINIT_PROBE_WAIT(end, instanceKlass::cast(this_oop()), -1,wait);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.