提交 cbb5556e 编写于 作者: A acorn

4670071: loadClassInternal is too restrictive.

Summary: VM support for deadlock fix. Library fix in 4735126. See API proposal.
Reviewed-by: dholmes, blacklion
上级 c6c05ae8
...@@ -441,6 +441,7 @@ oop java_lang_Class::primitive_mirror(BasicType t) { ...@@ -441,6 +441,7 @@ oop java_lang_Class::primitive_mirror(BasicType t) {
bool java_lang_Class::offsets_computed = false; bool java_lang_Class::offsets_computed = false;
int java_lang_Class::classRedefinedCount_offset = -1; int java_lang_Class::classRedefinedCount_offset = -1;
int java_lang_Class::parallelCapable_offset = -1;
void java_lang_Class::compute_offsets() { void java_lang_Class::compute_offsets() {
assert(!offsets_computed, "offsets should be initialized only once"); assert(!offsets_computed, "offsets should be initialized only once");
...@@ -451,6 +452,23 @@ void java_lang_Class::compute_offsets() { ...@@ -451,6 +452,23 @@ void java_lang_Class::compute_offsets() {
// so don't go fatal. // so don't go fatal.
compute_optional_offset(classRedefinedCount_offset, compute_optional_offset(classRedefinedCount_offset,
k, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature()); k, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature());
// The field indicating parallelCapable (parallelLockMap) is only present starting in 7,
klassOop k1 = SystemDictionary::classloader_klass();
compute_optional_offset(parallelCapable_offset,
k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature());
}
// For class loader classes, parallelCapable defined
// based on non-null field
// Written to by java.lang.ClassLoader, vm only reads this field, doesn't set it
bool java_lang_Class::parallelCapable(oop class_loader) {
if (!JDK_Version::is_gte_jdk17x_version()
|| parallelCapable_offset == -1) {
// Default for backward compatibility is false
return false;
}
return (class_loader->obj_field(parallelCapable_offset) != NULL);
} }
int java_lang_Class::classRedefinedCount(oop the_class_mirror) { int java_lang_Class::classRedefinedCount(oop the_class_mirror) {
......
...@@ -141,6 +141,7 @@ class java_lang_Class : AllStatic { ...@@ -141,6 +141,7 @@ class java_lang_Class : AllStatic {
static void compute_offsets(); static void compute_offsets();
static bool offsets_computed; static bool offsets_computed;
static int classRedefinedCount_offset; static int classRedefinedCount_offset;
static int parallelCapable_offset;
public: public:
// Instance creation // Instance creation
...@@ -168,6 +169,8 @@ class java_lang_Class : AllStatic { ...@@ -168,6 +169,8 @@ class java_lang_Class : AllStatic {
// Support for classRedefinedCount field // Support for classRedefinedCount field
static int classRedefinedCount(oop the_class_mirror); static int classRedefinedCount(oop the_class_mirror);
static void set_classRedefinedCount(oop the_class_mirror, int value); static void set_classRedefinedCount(oop the_class_mirror, int value);
// Support for parallelCapable field
static bool parallelCapable(oop the_class_mirror);
// Debugging // Debugging
friend class JavaClasses; friend class JavaClasses;
friend class instanceKlass; // verification code accesses offsets friend class instanceKlass; // verification code accesses offsets
......
...@@ -89,6 +89,14 @@ bool SystemDictionary::is_internal_format(symbolHandle class_name) { ...@@ -89,6 +89,14 @@ bool SystemDictionary::is_internal_format(symbolHandle class_name) {
#endif #endif
// ----------------------------------------------------------------------------
// Parallel class loading check
bool SystemDictionary::is_parallelCapable(Handle class_loader) {
if (UnsyncloadClass || class_loader.is_null()) return true;
if (AlwaysLockClassLoader) return false;
return java_lang_Class::parallelCapable(class_loader());
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Resolving of classes // Resolving of classes
...@@ -196,7 +204,8 @@ klassOop SystemDictionary::resolve_array_class_or_null(symbolHandle class_name, ...@@ -196,7 +204,8 @@ klassOop SystemDictionary::resolve_array_class_or_null(symbolHandle class_name,
// super-class callers: // super-class callers:
// ClassFileParser - for defineClass & jvmtiRedefineClasses // ClassFileParser - for defineClass & jvmtiRedefineClasses
// load_shared_class - while loading a class from shared archive // load_shared_class - while loading a class from shared archive
// resolve_instance_class_or_fail: // resolve_instance_class_or_null:
// via: handle_parallel_super_load
// when resolving a class that has an existing placeholder with // when resolving a class that has an existing placeholder with
// a saved superclass [i.e. a defineClass is currently in progress] // a saved superclass [i.e. a defineClass is currently in progress]
// if another thread is trying to resolve the class, it must do // if another thread is trying to resolve the class, it must do
...@@ -283,12 +292,9 @@ klassOop SystemDictionary::resolve_super_or_fail(symbolHandle child_name, ...@@ -283,12 +292,9 @@ klassOop SystemDictionary::resolve_super_or_fail(symbolHandle child_name,
if (probe && probe->check_seen_thread(THREAD, PlaceholderTable::LOAD_SUPER)) { if (probe && probe->check_seen_thread(THREAD, PlaceholderTable::LOAD_SUPER)) {
throw_circularity_error = true; throw_circularity_error = true;
} }
}
// add placeholder entry even if error - callers will remove on error if (!throw_circularity_error) {
PlaceholderEntry* newprobe = placeholders()->find_and_add(p_index, p_hash, child_name, class_loader, PlaceholderTable::LOAD_SUPER, class_name, THREAD); PlaceholderEntry* newprobe = placeholders()->find_and_add(p_index, p_hash, child_name, class_loader, PlaceholderTable::LOAD_SUPER, class_name, THREAD);
if (throw_circularity_error) {
newprobe->remove_seen_thread(THREAD, PlaceholderTable::LOAD_SUPER);
}
} }
} }
if (throw_circularity_error) { if (throw_circularity_error) {
...@@ -325,7 +331,6 @@ klassOop SystemDictionary::resolve_super_or_fail(symbolHandle child_name, ...@@ -325,7 +331,6 @@ klassOop SystemDictionary::resolve_super_or_fail(symbolHandle child_name,
return superk_h(); return superk_h();
} }
void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, void SystemDictionary::validate_protection_domain(instanceKlassHandle klass,
Handle class_loader, Handle class_loader,
Handle protection_domain, Handle protection_domain,
...@@ -421,7 +426,7 @@ void SystemDictionary::double_lock_wait(Handle lockObject, TRAPS) { ...@@ -421,7 +426,7 @@ void SystemDictionary::double_lock_wait(Handle lockObject, TRAPS) {
bool calledholdinglock bool calledholdinglock
= ObjectSynchronizer::current_thread_holds_lock((JavaThread*)THREAD, lockObject); = ObjectSynchronizer::current_thread_holds_lock((JavaThread*)THREAD, lockObject);
assert(calledholdinglock,"must hold lock for notify"); assert(calledholdinglock,"must hold lock for notify");
assert(!UnsyncloadClass, "unexpected double_lock_wait"); assert((!(lockObject() == _system_loader_lock_obj) && !is_parallelCapable(lockObject)), "unexpected double_lock_wait");
ObjectSynchronizer::notifyall(lockObject, THREAD); ObjectSynchronizer::notifyall(lockObject, THREAD);
intptr_t recursions = ObjectSynchronizer::complete_exit(lockObject, THREAD); intptr_t recursions = ObjectSynchronizer::complete_exit(lockObject, THREAD);
SystemDictionary_lock->wait(); SystemDictionary_lock->wait();
...@@ -439,7 +444,7 @@ void SystemDictionary::double_lock_wait(Handle lockObject, TRAPS) { ...@@ -439,7 +444,7 @@ void SystemDictionary::double_lock_wait(Handle lockObject, TRAPS) {
// even in non-circularity situations. // even in non-circularity situations.
// Note: only one thread can define the class, but multiple can resolve // Note: only one thread can define the class, but multiple can resolve
// Note: must call resolve_super_or_fail even if null super - // Note: must call resolve_super_or_fail even if null super -
// to force placeholder entry creation for this class // to force placeholder entry creation for this class for circularity detection
// Caller must check for pending exception // Caller must check for pending exception
// Returns non-null klassOop if other thread has completed load // Returns non-null klassOop if other thread has completed load
// and we are done, // and we are done,
...@@ -477,9 +482,9 @@ instanceKlassHandle SystemDictionary::handle_parallel_super_load( ...@@ -477,9 +482,9 @@ instanceKlassHandle SystemDictionary::handle_parallel_super_load(
SystemDictionary_lock->notify_all(); SystemDictionary_lock->notify_all();
} }
// UnsyncloadClass does NOT wait for parallel superclass loads to complete // parallelCapable class loaders do NOT wait for parallel superclass loads to complete
// Bootstrap classloader does wait for parallel superclass loads // Serial class loaders and bootstrap classloader do wait for superclass loads
if (UnsyncloadClass) { if (!class_loader.is_null() && is_parallelCapable(class_loader)) {
MutexLocker mu(SystemDictionary_lock, THREAD); MutexLocker mu(SystemDictionary_lock, THREAD);
// Check if classloading completed while we were loading superclass or waiting // Check if classloading completed while we were loading superclass or waiting
klassOop check = find_class(d_index, d_hash, name, class_loader); klassOop check = find_class(d_index, d_hash, name, class_loader);
...@@ -566,10 +571,10 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam ...@@ -566,10 +571,10 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam
// This lock must be acquired here so the waiter will find // This lock must be acquired here so the waiter will find
// any successful result in the SystemDictionary and not attempt // any successful result in the SystemDictionary and not attempt
// the define // the define
// Classloaders that support parallelism, e.g. bootstrap classloader, // ParallelCapable Classloaders and the bootstrap classloader,
// or all classloaders with UnsyncloadClass do not acquire lock here // or all classloaders with UnsyncloadClass do not acquire lock here
bool DoObjectLock = true; bool DoObjectLock = true;
if (UnsyncloadClass || (class_loader.is_null())) { if (is_parallelCapable(class_loader)) {
DoObjectLock = false; DoObjectLock = false;
} }
...@@ -627,6 +632,9 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam ...@@ -627,6 +632,9 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam
// Five cases: // Five cases:
// All cases need to prevent modifying bootclasssearchpath // All cases need to prevent modifying bootclasssearchpath
// in parallel with a classload of same classname // in parallel with a classload of same classname
// Redefineclasses uses existence of the placeholder for the duration
// of the class load to prevent concurrent redefinition of not completely
// defined classes.
// case 1. traditional classloaders that rely on the classloader object lock // case 1. traditional classloaders that rely on the classloader object lock
// - no other need for LOAD_INSTANCE // - no other need for LOAD_INSTANCE
// case 2. traditional classloaders that break the classloader object lock // case 2. traditional classloaders that break the classloader object lock
...@@ -642,12 +650,13 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam ...@@ -642,12 +650,13 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam
// This classloader supports parallelism at the classloader level, // This classloader supports parallelism at the classloader level,
// but only allows a single load of a class/classloader pair. // but only allows a single load of a class/classloader pair.
// No performance benefit and no deadlock issues. // No performance benefit and no deadlock issues.
// case 5. Future: parallel user level classloaders - without objectLocker // case 5. parallelCapable user level classloaders - without objectLocker
// Allow parallel classloading of a class/classloader pair
symbolHandle nullsymbolHandle; symbolHandle nullsymbolHandle;
bool throw_circularity_error = false; bool throw_circularity_error = false;
{ {
MutexLocker mu(SystemDictionary_lock, THREAD); MutexLocker mu(SystemDictionary_lock, THREAD);
if (!UnsyncloadClass) { if (class_loader.is_null() || !is_parallelCapable(class_loader)) {
PlaceholderEntry* oldprobe = placeholders()->get_entry(p_index, p_hash, name, class_loader); PlaceholderEntry* oldprobe = placeholders()->get_entry(p_index, p_hash, name, class_loader);
if (oldprobe) { if (oldprobe) {
// only need check_seen_thread once, not on each loop // only need check_seen_thread once, not on each loop
...@@ -681,25 +690,25 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam ...@@ -681,25 +690,25 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam
} }
} }
// All cases: add LOAD_INSTANCE // All cases: add LOAD_INSTANCE
// case 3: UnsyncloadClass: allow competing threads to try // case 3: UnsyncloadClass || case 5: parallelCapable: allow competing threads to try
// LOAD_INSTANCE in parallel // LOAD_INSTANCE in parallel
// add placeholder entry even if error - callers will remove on error // add placeholder entry even if error - callers will remove on error
if (!class_has_been_loaded) { if (!throw_circularity_error && !class_has_been_loaded) {
PlaceholderEntry* newprobe = placeholders()->find_and_add(p_index, p_hash, name, class_loader, PlaceholderTable::LOAD_INSTANCE, nullsymbolHandle, THREAD); PlaceholderEntry* newprobe = placeholders()->find_and_add(p_index, p_hash, name, class_loader, PlaceholderTable::LOAD_INSTANCE, nullsymbolHandle, THREAD);
if (throw_circularity_error) {
newprobe->remove_seen_thread(THREAD, PlaceholderTable::LOAD_INSTANCE);
}
// For class loaders that do not acquire the classloader object lock, // For class loaders that do not acquire the classloader object lock,
// if they did not catch another thread holding LOAD_INSTANCE, // if they did not catch another thread holding LOAD_INSTANCE,
// need a check analogous to the acquire ObjectLocker/find_class // need a check analogous to the acquire ObjectLocker/find_class
// i.e. now that we hold the LOAD_INSTANCE token on loading this class/CL // i.e. now that we hold the LOAD_INSTANCE token on loading this class/CL
// one final check if the load has already completed // one final check if the load has already completed
// class loaders holding the ObjectLock shouldn't find the class here
klassOop check = find_class(d_index, d_hash, name, class_loader); klassOop check = find_class(d_index, d_hash, name, class_loader);
if (check != NULL) { if (check != NULL) {
// Klass is already loaded, so just return it // Klass is already loaded, so just return it
k = instanceKlassHandle(THREAD, check); k = instanceKlassHandle(THREAD, check);
class_has_been_loaded = true; class_has_been_loaded = true;
newprobe->remove_seen_thread(THREAD, PlaceholderTable::LOAD_INSTANCE); newprobe->remove_seen_thread(THREAD, PlaceholderTable::LOAD_INSTANCE);
placeholders()->find_and_remove(p_index, p_hash, name, class_loader, THREAD);
SystemDictionary_lock->notify_all();
} }
} }
} }
...@@ -714,18 +723,14 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam ...@@ -714,18 +723,14 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam
// Do actual loading // Do actual loading
k = load_instance_class(name, class_loader, THREAD); k = load_instance_class(name, class_loader, THREAD);
// In custom class loaders, the usual findClass calls // For UnsyncloadClass and AllowParallelDefineClass only:
// findLoadedClass, which directly searches the SystemDictionary, then
// defineClass. If these are not atomic with respect to other threads,
// the findLoadedClass can fail, but the defineClass can get a
// LinkageError:: duplicate class definition.
// If they got a linkageError, check if a parallel class load succeeded. // If they got a linkageError, check if a parallel class load succeeded.
// If it did, then for bytecode resolution the specification requires // If it did, then for bytecode resolution the specification requires
// that we return the same result we did for the other thread, i.e. the // that we return the same result we did for the other thread, i.e. the
// successfully loaded instanceKlass // successfully loaded instanceKlass
// Note: Class can not be unloaded as long as any classloader refs exist
// Should not get here for classloaders that support parallelism // Should not get here for classloaders that support parallelism
// with the new cleaner mechanism, e.g. bootstrap classloader // with the new cleaner mechanism
// Bootstrap goes through here to allow for an extra guarantee check
if (UnsyncloadClass || (class_loader.is_null())) { if (UnsyncloadClass || (class_loader.is_null())) {
if (k.is_null() && HAS_PENDING_EXCEPTION if (k.is_null() && HAS_PENDING_EXCEPTION
&& PENDING_EXCEPTION->is_a(SystemDictionary::linkageError_klass())) { && PENDING_EXCEPTION->is_a(SystemDictionary::linkageError_klass())) {
...@@ -955,10 +960,10 @@ klassOop SystemDictionary::parse_stream(symbolHandle class_name, ...@@ -955,10 +960,10 @@ klassOop SystemDictionary::parse_stream(symbolHandle class_name,
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
class_loader, class_loader,
protection_domain, protection_domain,
cp_patches,
parsed_name, parsed_name,
THREAD); THREAD);
// We don't redefine the class, so we just need to clean up whether there // We don't redefine the class, so we just need to clean up whether there
// was an error or not (don't want to modify any system dictionary // was an error or not (don't want to modify any system dictionary
// data structures). // data structures).
...@@ -1013,11 +1018,17 @@ klassOop SystemDictionary::resolve_from_stream(symbolHandle class_name, ...@@ -1013,11 +1018,17 @@ klassOop SystemDictionary::resolve_from_stream(symbolHandle class_name,
ClassFileStream* st, ClassFileStream* st,
TRAPS) { TRAPS) {
// Make sure we are synchronized on the class loader before we initiate // Classloaders that support parallelism, e.g. bootstrap classloader,
// loading. // or all classloaders with UnsyncloadClass do not acquire lock here
bool DoObjectLock = true;
if (is_parallelCapable(class_loader)) {
DoObjectLock = false;
}
// Make sure we are synchronized on the class loader before we proceed
Handle lockObject = compute_loader_lock_object(class_loader, THREAD); Handle lockObject = compute_loader_lock_object(class_loader, THREAD);
check_loader_lock_contention(lockObject, THREAD); check_loader_lock_contention(lockObject, THREAD);
ObjectLocker ol(lockObject, THREAD); ObjectLocker ol(lockObject, THREAD, DoObjectLock);
symbolHandle parsed_name; symbolHandle parsed_name;
...@@ -1069,7 +1080,13 @@ klassOop SystemDictionary::resolve_from_stream(symbolHandle class_name, ...@@ -1069,7 +1080,13 @@ klassOop SystemDictionary::resolve_from_stream(symbolHandle class_name,
"external class name format used internally"); "external class name format used internally");
// Add class just loaded // Add class just loaded
define_instance_class(k, THREAD); // If a class loader supports parallel classloading handle parallel define requests
// find_or_define_instance_class may return a different instanceKlass
if (is_parallelCapable(class_loader)) {
k = find_or_define_instance_class(class_name, class_loader, k, THREAD);
} else {
define_instance_class(k, THREAD);
}
} }
// If parsing the class file or define_instance_class failed, we // If parsing the class file or define_instance_class failed, we
...@@ -1299,7 +1316,7 @@ instanceKlassHandle SystemDictionary::load_instance_class(symbolHandle class_nam ...@@ -1299,7 +1316,7 @@ instanceKlassHandle SystemDictionary::load_instance_class(symbolHandle class_nam
} }
#endif // KERNEL #endif // KERNEL
// find_or_define_instance_class may return a different k // find_or_define_instance_class may return a different instanceKlass
if (!k.is_null()) { if (!k.is_null()) {
k = find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh)); k = find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh));
} }
...@@ -1316,14 +1333,24 @@ instanceKlassHandle SystemDictionary::load_instance_class(symbolHandle class_nam ...@@ -1316,14 +1333,24 @@ instanceKlassHandle SystemDictionary::load_instance_class(symbolHandle class_nam
KlassHandle spec_klass (THREAD, SystemDictionary::classloader_klass()); KlassHandle spec_klass (THREAD, SystemDictionary::classloader_klass());
// UnsyncloadClass option means don't synchronize loadClass() calls. // Call public unsynchronized loadClass(String) directly for all class loaders
// loadClassInternal() is synchronized and public loadClass(String) is not. // for parallelCapable class loaders. JDK >=7, loadClass(String, boolean) will
// This flag is for diagnostic purposes only. It is risky to call // acquire a class-name based lock rather than the class loader object lock.
// JDK < 7 already acquire the class loader lock in loadClass(String, boolean),
// so the call to loadClassInternal() was not required.
//
// UnsyncloadClass flag means both call loadClass(String) and do
// not acquire the class loader lock even for class loaders that are
// not parallelCapable. This was a risky transitional
// flag for diagnostic purposes only. It is risky to call
// custom class loaders without synchronization. // custom class loaders without synchronization.
// WARNING If a custom class loader does NOT synchronizer findClass, or callers of // WARNING If a custom class loader does NOT synchronizer findClass, or callers of
// findClass, this flag risks unexpected timing bugs in the field. // findClass, the UnsyncloadClass flag risks unexpected timing bugs in the field.
// Do NOT assume this will be supported in future releases. // Do NOT assume this will be supported in future releases.
if (!UnsyncloadClass && has_loadClassInternal()) { //
// Added MustCallLoadClassInternal in case we discover in the field
// a customer that counts on this call
if (MustCallLoadClassInternal && has_loadClassInternal()) {
JavaCalls::call_special(&result, JavaCalls::call_special(&result,
class_loader, class_loader,
spec_klass, spec_klass,
...@@ -1365,14 +1392,17 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { ...@@ -1365,14 +1392,17 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) {
Handle class_loader_h(THREAD, k->class_loader()); Handle class_loader_h(THREAD, k->class_loader());
// for bootstrap classloader don't acquire lock // for bootstrap and other parallel classloaders don't acquire lock,
if (!class_loader_h.is_null()) { // use placeholder token
// If a parallelCapable class loader calls define_instance_class instead of
// find_or_define_instance_class to get here, we have a timing
// hole with systemDictionary updates and check_constraints
if (!class_loader_h.is_null() && !is_parallelCapable(class_loader_h)) {
assert(ObjectSynchronizer::current_thread_holds_lock((JavaThread*)THREAD, assert(ObjectSynchronizer::current_thread_holds_lock((JavaThread*)THREAD,
compute_loader_lock_object(class_loader_h, THREAD)), compute_loader_lock_object(class_loader_h, THREAD)),
"define called without lock"); "define called without lock");
} }
// Check class-loading constraints. Throw exception if violation is detected. // Check class-loading constraints. Throw exception if violation is detected.
// Grabs and releases SystemDictionary_lock // Grabs and releases SystemDictionary_lock
// The check_constraints/find_class call and update_dictionary sequence // The check_constraints/find_class call and update_dictionary sequence
...@@ -1427,14 +1457,15 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) { ...@@ -1427,14 +1457,15 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) {
// Support parallel classloading // Support parallel classloading
// Initial implementation for bootstrap classloader // Initial implementation for bootstrap classloader
// For future:
// For custom class loaders that support parallel classloading, // For custom class loaders that support parallel classloading,
// in case they do not synchronize around // With AllowParallelDefine flag==true, in case they do not synchronize around
// FindLoadedClass/DefineClass calls, we check for parallel // FindLoadedClass/DefineClass, calls, we check for parallel
// loading for them, wait if a defineClass is in progress // loading for them, wait if a defineClass is in progress
// and return the initial requestor's results // and return the initial requestor's results
// With AllowParallelDefine flag==false, call through to define_instance_class
// which will throw LinkageError: duplicate class definition.
// For better performance, the class loaders should synchronize // For better performance, the class loaders should synchronize
// findClass(), i.e. FindLoadedClass/DefineClass or they // findClass(), i.e. FindLoadedClass/DefineClassIfAbsent or they
// potentially waste time reading and parsing the bytestream. // potentially waste time reading and parsing the bytestream.
// Note: VM callers should ensure consistency of k/class_name,class_loader // Note: VM callers should ensure consistency of k/class_name,class_loader
instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle class_name, Handle class_loader, instanceKlassHandle k, TRAPS) { instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle class_name, Handle class_loader, instanceKlassHandle k, TRAPS) {
...@@ -1460,26 +1491,28 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle ...@@ -1460,26 +1491,28 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle
// Acquire define token for this class/classloader // Acquire define token for this class/classloader
symbolHandle nullsymbolHandle; symbolHandle nullsymbolHandle;
probe = placeholders()->find_and_add(p_index, p_hash, class_name, class_loader, PlaceholderTable::DEFINE_CLASS, nullsymbolHandle, THREAD); probe = placeholders()->find_and_add(p_index, p_hash, class_name, class_loader, PlaceholderTable::DEFINE_CLASS, nullsymbolHandle, THREAD);
// Check if another thread defining in parallel // Wait if another thread defining in parallel
if (probe->definer() == NULL) { // All threads wait - even those that will throw duplicate class: otherwise
// Thread will define the class // caller is surprised by LinkageError: duplicate, but findLoadedClass fails
probe->set_definer(THREAD); // if other thread has not finished updating dictionary
} else { while (probe->definer() != NULL) {
// Wait for defining thread to finish and return results SystemDictionary_lock->wait();
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
if (probe->instanceKlass() != NULL) { // caught by finding an entry in the SystemDictionary
if ((UnsyncloadClass || AllowParallelDefineClass) && (probe->instanceKlass() != NULL)) {
probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS); probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS);
return(instanceKlassHandle(THREAD, probe->instanceKlass())); placeholders()->find_and_remove(p_index, p_hash, class_name, class_loader, THREAD);
} else { SystemDictionary_lock->notify_all();
// If definer had an error, try again as any new thread would
probe->set_definer(THREAD);
#ifdef ASSERT #ifdef ASSERT
klassOop check = find_class(d_index, d_hash, class_name, class_loader); klassOop check = find_class(d_index, d_hash, class_name, class_loader);
assert(check == NULL, "definer missed recording success"); assert(check != NULL, "definer missed recording success");
#endif #endif
} return(instanceKlassHandle(THREAD, probe->instanceKlass()));
} else {
// This thread will define the class (even if earlier thread tried and had an error)
probe->set_definer(THREAD);
} }
} }
...@@ -1501,6 +1534,7 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle ...@@ -1501,6 +1534,7 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle
} }
probe->set_definer(NULL); probe->set_definer(NULL);
probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS); probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS);
placeholders()->find_and_remove(p_index, p_hash, class_name, class_loader, THREAD);
SystemDictionary_lock->notify_all(); SystemDictionary_lock->notify_all();
} }
} }
...@@ -1512,7 +1546,6 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle ...@@ -1512,7 +1546,6 @@ instanceKlassHandle SystemDictionary::find_or_define_instance_class(symbolHandle
return k; return k;
} }
Handle SystemDictionary::compute_loader_lock_object(Handle class_loader, TRAPS) { Handle SystemDictionary::compute_loader_lock_object(Handle class_loader, TRAPS) {
// If class_loader is NULL we synchronize on _system_loader_lock_obj // If class_loader is NULL we synchronize on _system_loader_lock_obj
if (class_loader.is_null()) { if (class_loader.is_null()) {
...@@ -1902,11 +1935,11 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { ...@@ -1902,11 +1935,11 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
warning("Cannot find sun/jkernel/DownloadManager"); warning("Cannot find sun/jkernel/DownloadManager");
} }
#endif // KERNEL #endif // KERNEL
{ // Compute whether we should use loadClass or loadClassInternal when loading classes. { // Compute whether we should use loadClass or loadClassInternal when loading classes.
methodOop method = instanceKlass::cast(classloader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature()); methodOop method = instanceKlass::cast(classloader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature());
_has_loadClassInternal = (method != NULL); _has_loadClassInternal = (method != NULL);
} }
{ // Compute whether we should use checkPackageAccess or NOT { // Compute whether we should use checkPackageAccess or NOT
methodOop method = instanceKlass::cast(classloader_klass())->find_method(vmSymbols::checkPackageAccess_name(), vmSymbols::class_protectiondomain_signature()); methodOop method = instanceKlass::cast(classloader_klass())->find_method(vmSymbols::checkPackageAccess_name(), vmSymbols::class_protectiondomain_signature());
_has_checkPackageAccess = (method != NULL); _has_checkPackageAccess = (method != NULL);
......
...@@ -526,6 +526,7 @@ private: ...@@ -526,6 +526,7 @@ private:
static instanceKlassHandle load_instance_class(symbolHandle class_name, Handle class_loader, TRAPS); static instanceKlassHandle load_instance_class(symbolHandle class_name, Handle class_loader, TRAPS);
static Handle compute_loader_lock_object(Handle class_loader, TRAPS); static Handle compute_loader_lock_object(Handle class_loader, TRAPS);
static void check_loader_lock_contention(Handle loader_lock, TRAPS); static void check_loader_lock_contention(Handle loader_lock, TRAPS);
static bool is_parallelCapable(Handle class_loader);
static klassOop find_shared_class(symbolHandle class_name); static klassOop find_shared_class(symbolHandle class_name);
......
...@@ -362,6 +362,7 @@ ...@@ -362,6 +362,7 @@
template(class_signature, "Ljava/lang/Class;") \ template(class_signature, "Ljava/lang/Class;") \
template(string_signature, "Ljava/lang/String;") \ template(string_signature, "Ljava/lang/String;") \
template(reference_signature, "Ljava/lang/ref/Reference;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \
template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \
/* signature symbols needed by intrinsics */ \ /* signature symbols needed by intrinsics */ \
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \
\ \
...@@ -374,6 +375,9 @@ ...@@ -374,6 +375,9 @@
/* used by ClassFormatError when class name is not known yet */ \ /* used by ClassFormatError when class name is not known yet */ \
template(unknown_class_name, "<Unknown>") \ template(unknown_class_name, "<Unknown>") \
\ \
/* used to identify class loaders handling parallel class loading */ \
template(parallelCapable_name, "parallelLockMap;") \
\
/* JVM monitoring and management support */ \ /* JVM monitoring and management support */ \
template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \ template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \
template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \ template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \
......
...@@ -835,8 +835,21 @@ class CommandLineFlags { ...@@ -835,8 +835,21 @@ class CommandLineFlags {
"Prints the system dictionary at exit") \ "Prints the system dictionary at exit") \
\ \
diagnostic(bool, UnsyncloadClass, false, \ diagnostic(bool, UnsyncloadClass, false, \
"Unstable: VM calls loadClass unsynchronized. Custom classloader "\ "Unstable: VM calls loadClass unsynchronized. Custom " \
"must call VM synchronized for findClass & defineClass") \ "class loader must call VM synchronized for findClass " \
"and defineClass.") \
\
product(bool, AlwaysLockClassLoader, false, \
"Require the VM to acquire the class loader lock before calling " \
"loadClass() even for class loaders registering " \
"as parallel capable. Default false. ") \
\
product(bool, AllowParallelDefineClass, false, \
"Allow parallel defineClass requests for class loaders " \
"registering as parallel capable. Default false") \
\
product(bool, MustCallLoadClassInternal, false, \
"Call loadClassInternal() rather than loadClass().Default false") \
\ \
product_pd(bool, DontYieldALot, \ product_pd(bool, DontYieldALot, \
"Throw away obvious excess yield calls (for SOLARIS only)") \ "Throw away obvious excess yield calls (for SOLARIS only)") \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册