--- old/src/hotspot/share/classfile/classLoaderData.cpp 2018-06-15 15:14:48.392922735 -0400 +++ new/src/hotspot/share/classfile/classLoaderData.cpp 2018-06-15 15:14:47.001584229 -0400 @@ -105,22 +105,41 @@ } } -// JFR and logging support so that the name and klass are available after the -// class_loader oop is no longer alive, during unloading. +// Obtain and set the class loader's name within the ClassLoaderData so +// it will be available for error messages, logging, JFR, etc. The name +// and klass are available after the class_loader oop is no longer alive, +// during unloading. void ClassLoaderData::initialize_name_and_klass(Handle class_loader) { + Thread* THREAD = Thread::current(); + ResourceMark rm(THREAD); _class_loader_klass = class_loader->klass(); - oop class_loader_name = java_lang_ClassLoader::name(class_loader()); - if (class_loader_name != NULL) { - Thread* THREAD = Thread::current(); - ResourceMark rm(THREAD); - const char* class_loader_instance_name = - java_lang_String::as_utf8_string(class_loader_name); - if (class_loader_instance_name != NULL && class_loader_instance_name[0] != '\0') { + // Obtain the class loader's name. If the class loader's name was not + // explicitly set during construction, the CLD's _name field will be null. + oop cl_name = java_lang_ClassLoader::name(class_loader()); + if (cl_name != NULL) { + const char* cl_instance_name = java_lang_String::as_utf8_string(cl_name); + + if (cl_instance_name != NULL && cl_instance_name[0] != '\0') { // Can't throw InternalError and SymbolTable doesn't throw OOM anymore. - _class_loader_name = SymbolTable::new_symbol(class_loader_instance_name, CATCH); + _name = SymbolTable::new_symbol(cl_instance_name, CATCH); } } + + // Obtain the class loader's name and identity hash. If the class loader's + // name was not explicitly set during construction, the class loader's name and id + // will be set to the qualified class name of the class loader along with its + // identity hash. + // If for some reason the ClassLoader's constructor has not been run, instead of + // leaving the _name_and_id field null, fall back to the external qualified class + // name. Thus CLD's _name_and_id field should never have a null value. + oop cl_name_and_id = java_lang_ClassLoader::nameAndId(class_loader()); + const char* cl_instance_name_and_id = + (cl_name_and_id == NULL) ? _class_loader_klass->external_name() : + java_lang_String::as_utf8_string(cl_name_and_id); + assert(cl_instance_name_and_id != NULL && cl_instance_name_and_id[0] != '\0', "class loader has no name and id"); + // Can't throw InternalError and SymbolTable doesn't throw OOM anymore. + _name_and_id = SymbolTable::new_symbol(cl_instance_name_and_id, CATCH); } ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) : @@ -134,7 +153,7 @@ _claimed(0), _modified_oops(true), _accumulated_modified_oops(false), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), _next(NULL), - _class_loader_klass(NULL), _class_loader_name(NULL), + _class_loader_klass(NULL), _name(NULL), _name_and_id(NULL), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, Monitor::_safepoint_check_never)) { @@ -911,29 +930,40 @@ return ClassLoaderDataGraph::add(loader, true); } +// Caller needs ResourceMark +// If the class loader's _name has not been explicitly set, the class loader's +// qualified class name is returned. const char* ClassLoaderData::loader_name() const { - if (is_unloading()) { - if (_class_loader_klass == NULL) { - return ""; - } else if (_class_loader_name != NULL) { - return _class_loader_name->as_C_string(); - } else { - return _class_loader_klass->name()->as_C_string(); - } + if (_class_loader_klass == NULL) { + return BOOTSTRAP_LOADER_NAME; + } else if (_name != NULL) { + return _name->as_C_string(); + } else { + return _class_loader_klass->external_name(); + } +} + +// Caller needs ResourceMark +// Format of the _name_and_id is as follows: +// If the defining loader has a name explicitly set then '' @ +// If the defining loader has no name then @ +// If built-in loader, then omit '@' as there is only one instance. +const char* ClassLoaderData::loader_name_and_id() const { + if (_class_loader_klass == NULL) { + return "'" BOOTSTRAP_LOADER_NAME "'"; } else { - // Handles null class loader - return SystemDictionary::loader_name(class_loader()); + assert(_name_and_id != NULL, "encountered a class loader null name and id"); + return _name_and_id->as_C_string(); } } - void ClassLoaderData::print_value_on(outputStream* out) const { if (!is_unloading() && class_loader() != NULL) { out->print("loader data: " INTPTR_FORMAT " for instance ", p2i(this)); - class_loader()->print_value_on(out); // includes loader_name() and address of class loader instance + class_loader()->print_value_on(out); // includes loader_name_and_id() and address of class loader instance } else { - // loader data: 0xsomeaddr of - out->print("loader data: " INTPTR_FORMAT " of %s", p2i(this), loader_name()); + // loader data: 0xsomeaddr of 'bootstrap' + out->print("loader data: " INTPTR_FORMAT " of %s", p2i(this), loader_name_and_id()); } if (is_anonymous()) { out->print(" anonymous"); @@ -943,7 +973,7 @@ #ifndef PRODUCT void ClassLoaderData::print_on(outputStream* out) const { out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: %s {", - p2i(this), p2i(_class_loader.ptr_raw()), loader_name()); + p2i(this), p2i(_class_loader.ptr_raw()), loader_name_and_id()); if (is_anonymous()) out->print(" anonymous"); if (claimed()) out->print(" claimed"); if (is_unloading()) out->print(" unloading"); @@ -1237,7 +1267,7 @@ FOR_ALL_DICTIONARY(cld) { ResourceMark rm; stringStream tempst; - tempst.print("System Dictionary for %s", cld->loader_name()); + tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id()); cld->dictionary()->print_table_statistics(st, tempst.as_string()); } }