< prev index next > src/hotspot/share/classfile/systemDictionary.cpp
Print this page
#include "memory/metaspaceClosure.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/access.inline.hpp"
+ #include "oops/fieldStreams.inline.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/method.inline.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.hpp"
#include "oops/oopHandle.hpp"
#include "oops/oopHandle.inline.hpp"
#include "oops/symbol.hpp"
#include "oops/typeArrayKlass.hpp"
+ #include "oops/inlineKlass.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
+ #include "runtime/os.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/synchronizer.hpp"
#include "services/classLoadingService.hpp"
#include "services/diagnosticCommand.hpp"
// Helper function
inline ClassLoaderData* class_loader_data(Handle class_loader) {
return ClassLoaderData::class_loader_data(class_loader());
}
ClassLoaderData* SystemDictionary::register_loader(Handle class_loader, bool create_mirror_cld) {
if (create_mirror_cld) {
// Add a new class loader data to the graph.
return ClassLoaderDataGraph::add(class_loader, true);
} else {
! return (class_loader() == nullptr) ? ClassLoaderData::the_null_class_loader_data() :
! ClassLoaderDataGraph::find_or_create(class_loader);
}
}
void SystemDictionary::set_system_loader(ClassLoaderData *cld) {
assert(_java_system_loader.is_empty(), "already set!");
// Helper function
inline ClassLoaderData* class_loader_data(Handle class_loader) {
return ClassLoaderData::class_loader_data(class_loader());
}
+ static void add_wrapper_class(JavaThread* current, ClassLoaderData* cld, Symbol* classname) {
+ InstanceKlass* ik = SystemDictionary::find_instance_klass(current, classname, Handle(current, nullptr));
+ assert(ik != nullptr, "Must exist");
+ SystemDictionary::add_to_initiating_loader(current, ik, cld);
+ }
+
+ static void add_wrapper_classes(ClassLoaderData* cld) {
+ MonitorLocker mu1(SystemDictionary_lock);
+ JavaThread* current = JavaThread::current();
+ add_wrapper_class(current, cld, vmSymbols::java_lang_Boolean());
+ add_wrapper_class(current, cld, vmSymbols::java_lang_Byte());
+ add_wrapper_class(current, cld, vmSymbols::java_lang_Character());
+ add_wrapper_class(current, cld, vmSymbols::java_lang_Short());
+ add_wrapper_class(current, cld, vmSymbols::java_lang_Integer());
+ add_wrapper_class(current, cld, vmSymbols::java_lang_Long());
+ add_wrapper_class(current, cld, vmSymbols::java_lang_Float());
+ add_wrapper_class(current, cld, vmSymbols::java_lang_Double());
+ }
+
ClassLoaderData* SystemDictionary::register_loader(Handle class_loader, bool create_mirror_cld) {
if (create_mirror_cld) {
// Add a new class loader data to the graph.
return ClassLoaderDataGraph::add(class_loader, true);
} else {
! if (class_loader() == nullptr) {
! return ClassLoaderData::the_null_class_loader_data();
+ } else {
+ ClassLoaderData* cld = ClassLoaderDataGraph::find_or_create(class_loader);
+ add_wrapper_classes(cld);
+ return cld;
+ }
}
}
void SystemDictionary::set_system_loader(ClassLoaderData *cld) {
assert(_java_system_loader.is_empty(), "already set!");
return resolve_array_class_or_null(class_name, class_loader, THREAD);
} else {
assert(class_name != nullptr && !Signature::is_array(class_name), "must be");
if (Signature::has_envelope(class_name)) {
ResourceMark rm(THREAD);
! // Ignore wrapping L and ;.
TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1,
class_name->utf8_length() - 2);
return resolve_instance_class_or_null(name, class_loader, THREAD);
} else {
return resolve_instance_class_or_null(class_name, class_loader, THREAD);
return resolve_array_class_or_null(class_name, class_loader, THREAD);
} else {
assert(class_name != nullptr && !Signature::is_array(class_name), "must be");
if (Signature::has_envelope(class_name)) {
ResourceMark rm(THREAD);
! // Ignore wrapping L and ; (and Q and ; for value types).
TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1,
class_name->utf8_length() - 2);
return resolve_instance_class_or_null(name, class_loader, THREAD);
} else {
return resolve_instance_class_or_null(class_name, class_loader, THREAD);
// Check if a shared class can be loaded by the specific classloader.
bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
InstanceKlass* ik,
PackageEntry* pkg_entry,
Handle class_loader) {
! assert(!ModuleEntryTable::javabase_moduleEntry()->is_patched(),
- "Cannot use sharing if java.base is patched");
// (1) Check if we are loading into the same loader as in dump time.
if (ik->is_shared_boot_class()) {
if (class_loader() != nullptr) {
// Check if a shared class can be loaded by the specific classloader.
bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
InstanceKlass* ik,
PackageEntry* pkg_entry,
Handle class_loader) {
! assert(!CDSConfig::module_patching_disables_cds(), "Cannot use CDS");
// (1) Check if we are loading into the same loader as in dump time.
if (ik->is_shared_boot_class()) {
if (class_loader() != nullptr) {
if (was_archived_from_named_module) {
if (should_be_in_named_module) {
// Is the module loaded from the same location as during dump time?
visible = mod_entry->shared_path_index() == scp_index;
if (visible) {
! assert(!mod_entry->is_patched(), "cannot load archived classes for patched module");
}
} else {
// During dump time, this class was in a named module, but at run time, this class should be
// in an unnamed module.
visible = false;
if (was_archived_from_named_module) {
if (should_be_in_named_module) {
// Is the module loaded from the same location as during dump time?
visible = mod_entry->shared_path_index() == scp_index;
if (visible) {
! assert(!CDSConfig::module_patching_disables_cds(), "Cannot use CDS");
}
} else {
// During dump time, this class was in a named module, but at run time, this class should be
// in an unnamed module.
visible = false;
}
return true;
}
+ // Pre-load class referred to in non-static null-free instance field. These fields trigger MANDATORY loading.
+ // Some pre-loading does not fail fatally
+ bool SystemDictionary::preload_from_null_free_field(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS) {
+ TempNewSymbol name = Signature::strip_envelope(sig);
+ log_info(class, preload)("Preloading class %s during loading of shared class %s. "
+ "Cause: a null-free non-static field is declared with this type",
+ name->as_C_string(), ik->name()->as_C_string());
+ InstanceKlass* real_k = SystemDictionary::resolve_with_circularity_detection_or_fail(ik->name(), name,
+ class_loader, false, CHECK_false);
+ if (HAS_PENDING_EXCEPTION) {
+ log_warning(class, preload)("Preloading of class %s during loading of class %s "
+ "(cause: null-free non-static field) failed: %s",
+ name->as_C_string(), ik->name()->as_C_string(),
+ PENDING_EXCEPTION->klass()->name()->as_C_string());
+ return false; // Exception is still pending
+ }
+
+ InstanceKlass* k = ik->get_inline_type_field_klass_or_null(field_index);
+ if (real_k != k) {
+ // oops, the app has substituted a different version of k! Does not fail fatally
+ log_warning(class, preload)("Preloading of class %s during loading of shared class %s "
+ "(cause: null-free non-static field) failed : "
+ "app substituted a different version of %s",
+ name->as_C_string(), ik->name()->as_C_string(),
+ name->as_C_string());
+ return false;
+ }
+ log_info(class, preload)("Preloading of class %s during loading of shared class %s "
+ "(cause: null-free non-static field) succeeded",
+ name->as_C_string(), ik->name()->as_C_string());
+
+ assert(real_k != nullptr, "Sanity check");
+ InstanceKlass::check_can_be_annotated_with_NullRestricted(real_k, ik->name(), CHECK_false);
+
+ return true;
+ }
+
+ // Tries to pre-load classes referred to in non-static nullable instance fields if they are found in the
+ // loadable descriptors attribute. If loading fails, we can fail silently.
+ void SystemDictionary::try_preload_from_loadable_descriptors(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS) {
+ TempNewSymbol name = Signature::strip_envelope(sig);
+ if (name != ik->name() && ik->is_class_in_loadable_descriptors_attribute(sig)) {
+ log_info(class, preload)("Preloading class %s during loading of shared class %s. "
+ "Cause: field type in LoadableDescriptors attribute",
+ name->as_C_string(), ik->name()->as_C_string());
+ InstanceKlass* real_k = SystemDictionary::resolve_with_circularity_detection_or_fail(ik->name(), name,
+ class_loader, false, THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ }
+
+ InstanceKlass* k = ik->get_inline_type_field_klass_or_null(field_index);
+ if (real_k != k) {
+ // oops, the app has substituted a different version of k!
+ log_warning(class, preload)("Preloading of class %s during loading of shared class %s "
+ "(cause: field type in LoadableDescriptors attribute) failed : "
+ "app substituted a different version of %s",
+ name->as_C_string(), ik->name()->as_C_string(),
+ k->name()->as_C_string());
+ return;
+ } else if (real_k != nullptr) {
+ log_info(class, preload)("Preloading of class %s during loading of shared class %s "
+ "(cause: field type in LoadableDescriptors attribute) succeeded",
+ name->as_C_string(), ik->name()->as_C_string());
+ }
+ }
+ }
+
+
InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
Handle class_loader,
Handle protection_domain,
const ClassFileStream *cfs,
PackageEntry* pkg_entry,
if (!check) {
ik->set_shared_loading_failed();
return nullptr;
}
+ if (ik->has_inline_type_fields()) {
+ for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
+ if (fs.access_flags().is_static()) continue;
+
+ Symbol* sig = fs.signature();
+ int field_index = fs.index();
+
+ if (fs.is_null_free_inline_type()) {
+ // A false return means that the class didn't load for other reasons than an exception.
+ bool check = preload_from_null_free_field(ik, class_loader, sig, field_index, CHECK_NULL);
+ if (!check) {
+ ik->set_shared_loading_failed();
+ return nullptr;
+ }
+ } else if (Signature::has_envelope(sig)) {
+ // Pending exceptions are cleared so we can fail silently
+ try_preload_from_loadable_descriptors(ik, class_loader, sig, field_index, CHECK_NULL);
+ }
+ }
+ }
+
InstanceKlass* new_ik = nullptr;
// CFLH check is skipped for VM hidden classes (see KlassFactory::create_from_stream).
// It will be skipped for shared VM hidden lambda proxy classes.
if (!ik->is_hidden()) {
new_ik = KlassFactory::check_shared_class_file_load_hook(
// restore_unshareable_info which calls ik->set_package()
ik->restore_unshareable_info(loader_data, protection_domain, pkg_entry, CHECK_NULL);
}
load_shared_class_misc(ik, loader_data);
+
return ik;
}
void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData* loader_data) {
ik->print_class_load_logging(loader_data, nullptr, nullptr);
dictionary->add_klass(current, name, k);
}
mu1.notify_all();
}
- #if INCLUDE_CDS
// Indicate that loader_data has initiated the loading of class k, which
// has already been defined by a parent loader.
! // This API should be used only by AOTLinkedClassBulkLoader
void SystemDictionary::add_to_initiating_loader(JavaThread* current,
InstanceKlass* k,
ClassLoaderData* loader_data) {
- assert(CDSConfig::is_using_aot_linked_classes(), "must be");
assert_locked_or_safepoint(SystemDictionary_lock);
Symbol* name = k->name();
Dictionary* dictionary = loader_data->dictionary();
assert(k->is_loaded(), "must be");
assert(k->class_loader_data() != loader_data, "only for classes defined by a parent loader");
! assert(dictionary->find_class(current, name) == nullptr, "sanity");
! dictionary->add_klass(current, name, k);
}
- #endif
// Try to find a class name using the loader constraints. The
// loader constraints might know about a class that isn't fully loaded
// yet and these will be ignored.
Klass* SystemDictionary::find_constrained_instance_or_array_klass(
dictionary->add_klass(current, name, k);
}
mu1.notify_all();
}
// Indicate that loader_data has initiated the loading of class k, which
// has already been defined by a parent loader.
! // This API is used by AOTLinkedClassBulkLoader and to register boxing
+ // classes from java.lang in all class loaders to enable more value
+ // classes optimizations
void SystemDictionary::add_to_initiating_loader(JavaThread* current,
InstanceKlass* k,
ClassLoaderData* loader_data) {
assert_locked_or_safepoint(SystemDictionary_lock);
Symbol* name = k->name();
Dictionary* dictionary = loader_data->dictionary();
assert(k->is_loaded(), "must be");
assert(k->class_loader_data() != loader_data, "only for classes defined by a parent loader");
! if (dictionary->find_class(current, name) == nullptr) {
! dictionary->add_klass(current, name, k);
+ }
}
// Try to find a class name using the loader constraints. The
// loader constraints might know about a class that isn't fully loaded
// yet and these will be ignored.
Klass* SystemDictionary::find_constrained_instance_or_array_klass(
< prev index next >