hotspot/src/share/vm/classfile/systemDictionary.cpp
// Support parallel classloading
// All parallel class loaders, including bootstrap classloader
// lock a placeholder entry for this class/class_loader pair
// to allow parallel defines of different classes for this class loader
// With AllowParallelDefine flag==true, in case they do not synchronize around
// FindLoadedClass/DefineClass, calls, we check for parallel
// loading for them, wait if a defineClass is in progress
// and return the initial requestor's results
// This flag does not apply to the bootstrap classloader.
// With AllowParallelDefine flag==false, call through to define_instance_class
// which will throw LinkageError: duplicate class definition.
// False is the requested default.
// For better performance, the class loaders should synchronize
// findClass(), i.e. FindLoadedClass/DefineClassIfAbsent or they
// potentially waste time reading and parsing the bytestream.
// Note: VM callers should ensure consistency of k/class_name,class_loader
instanceKlassHandle SystemDictionary::find_or_define_instance_class(Symbol* class_name, Handle class_loader, instanceKlassHandle k, TRAPS) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
Symbol* name_h = k->name(); // passed in class_name may be null
unsigned int d_hash = dictionary()->compute_hash(name_h, class_loader);
int d_index = dictionary()->hash_to_index(d_hash);
// Hold SD lock around find_class and placeholder creation for DEFINE_CLASS
unsigned int p_hash = placeholders()->compute_hash(name_h, class_loader);
int p_index = placeholders()->hash_to_index(p_hash);
PlaceholderEntry* probe;
{- -------------------------------------------
(1) 処理対象のクラスが
「既にロードされているかどうか」および「現在他のスレッドがロード中かどうか」を調べる.
* 既にロード済みであれば, ここでリターン.
* 現在他のスレッドがロード中であれば, それが終わるまで以下のブロック内で待機.
(待機処理は, SystemDictionary_lock に対して Monitor::wait() を呼ぶことで行う)
* 上記のどちらでもなければ, 対象のクラスの処理スレッドとして自分自身を登録.
(なお, この処理は SystemDictionary_lock を取得して排他した状態で行う)
(See: Placeholder)
---------------------------------------- -}
{
MutexLocker mu(SystemDictionary_lock, THREAD);
{- -------------------------------------------
(1.1) 既にロード済みであれば, ここでリターン.
---------------------------------------- -}
// First check if class already defined
if (UnsyncloadClass || (is_parallelDefine(class_loader))) {
klassOop check = find_class(d_index, d_hash, name_h, class_loader);
if (check != NULL) {
return(instanceKlassHandle(THREAD, check));
}
}
{- -------------------------------------------
(1.1) 処理対象のクラスに関する PlaceholderEntry を取得.
---------------------------------------- -}
// Acquire define token for this class/classloader
probe = placeholders()->find_and_add(p_index, p_hash, name_h, class_loader, PlaceholderTable::DEFINE_CLASS, NULL, THREAD);
{- -------------------------------------------
(1.1) 現在他のスレッドがロード中であれば, それが終わるまで以下のブロック内で待機し, リターン.
(待機処理は, SystemDictionary_lock に対して Monitor::wait() を呼ぶことで行う)
---------------------------------------- -}
// Wait if another thread defining in parallel
// All threads wait - even those that will throw duplicate class: otherwise
// caller is surprised by LinkageError: duplicate, but findLoadedClass fails
// if other thread has not finished updating dictionary
while (probe->definer() != NULL) {
SystemDictionary_lock->wait();
}
// Only special cases allow parallel defines and can use other thread's results
// Other cases fall through, and may run into duplicate defines
// caught by finding an entry in the SystemDictionary
if ((UnsyncloadClass || is_parallelDefine(class_loader)) && (probe->instanceKlass() != NULL)) {
probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS);
placeholders()->find_and_remove(p_index, p_hash, name_h, class_loader, THREAD);
SystemDictionary_lock->notify_all();
#ifdef ASSERT
klassOop check = find_class(d_index, d_hash, name_h, class_loader);
assert(check != NULL, "definer missed recording success");
#endif
return(instanceKlassHandle(THREAD, probe->instanceKlass()));
{- -------------------------------------------
(1.1) 上記のどちらでもなければ, 対象のクラスの処理スレッドとして自分自身を登録.
---------------------------------------- -}
} else {
// This thread will define the class (even if earlier thread tried and had an error)
probe->set_definer(THREAD);
}
}
{- -------------------------------------------
(1) SystemDictionary::define_instance_class() を呼んで, SystemDictionary への登録を行う.
---------------------------------------- -}
define_instance_class(k, THREAD);
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Handle linkage_exception = Handle(); // null handle
{- -------------------------------------------
(1) 対応する PlaceholderEntry を片付けて排他を解除し,
待っているスレッドを notify_all() で起床させておく.
(なお, 例外が発生していた場合は,
(ロックを握っている間は投げられないので)
ここでは linkage_exception 局所変数に入れるだけにし, 後で投げる)
(ところで, assert(probe != NULL) があるのに, if でのチェックもあるのは...?? #TODO)
---------------------------------------- -}
// definer must notify any waiting threads
{
MutexLocker mu(SystemDictionary_lock, THREAD);
PlaceholderEntry* probe = placeholders()->get_entry(p_index, p_hash, name_h, class_loader);
assert(probe != NULL, "DEFINE_CLASS placeholder lost?");
if (probe != NULL) {
if (HAS_PENDING_EXCEPTION) {
linkage_exception = Handle(THREAD,PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
} else {
probe->set_instanceKlass(k());
}
probe->set_definer(NULL);
probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS);
placeholders()->find_and_remove(p_index, p_hash, name_h, class_loader, THREAD);
SystemDictionary_lock->notify_all();
}
}
{- -------------------------------------------
(1) 例外が発生していた場合は, ここで投げ直す.
---------------------------------------- -}
// Can't throw exception while holding lock due to rank ordering
if (linkage_exception() != NULL) {
THROW_OOP_(linkage_exception(), nh); // throws exception and returns
}
{- -------------------------------------------
(1) 結果をリターン
---------------------------------------- -}
return k;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.