8202605: Standardize on ClassLoaderData::loader_name() throughout the VM to obtain a class loader's name
Introduced ClassLoaderData::name() and ClassLoaderData::name_and_id() for use when obtaining a class loader's name. Reviewed-by: coleenp, goetz, mchung, stuefe
This commit is contained in:
parent
731d9b1499
commit
425e1a8bb8
src
hotspot/share
classfile
classFileParser.cppclassLoaderData.cppclassLoaderData.hppclassLoaderHierarchyDCmd.cppdictionary.cppjavaClasses.cppjavaClasses.hpploaderConstraints.cppmoduleEntry.cppmodules.cppsystemDictionary.cppsystemDictionary.hpp
gc/serial
jfr/recorder/checkpoint/types
memory/metaspace
oops
java.base/share/classes/java/lang
test
hotspot/jtreg/runtime
LoaderConstraints
SharedArchiveFile
logging
jdk/jdk/jfr/event/runtime
@ -4511,7 +4511,7 @@ static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
|
||||
vmSymbols::java_lang_IllegalAccessError(),
|
||||
"class %s loaded by %s cannot access jdk/internal/reflect superclass %s",
|
||||
this_klass->external_name(),
|
||||
this_klass->class_loader_data()->loader_name(),
|
||||
this_klass->class_loader_data()->loader_name_and_id(),
|
||||
super->external_name());
|
||||
return;
|
||||
}
|
||||
|
@ -105,22 +105,41 @@ void ClassLoaderData::init_null_class_loader_data() {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
|
||||
_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 @@ ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(Handle loader) {
|
||||
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 "<bootloader>";
|
||||
} else if (_class_loader_name != NULL) {
|
||||
return _class_loader_name->as_C_string();
|
||||
} else {
|
||||
return _class_loader_klass->name()->as_C_string();
|
||||
}
|
||||
} else {
|
||||
// Handles null class loader
|
||||
return SystemDictionary::loader_name(class_loader());
|
||||
}
|
||||
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 '<loader-name>' @<id>
|
||||
// If the defining loader has no name then <qualified-class-name> @<id>
|
||||
// If built-in loader, then omit '@<id>' as there is only one instance.
|
||||
const char* ClassLoaderData::loader_name_and_id() const {
|
||||
if (_class_loader_klass == NULL) {
|
||||
return "'" BOOTSTRAP_LOADER_NAME "'";
|
||||
} else {
|
||||
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 <bootloader>
|
||||
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 @@ void ClassLoaderData::print_value_on(outputStream* out) const {
|
||||
#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 @@ void ClassLoaderDataGraph::print_dictionary_statistics(outputStream* st) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,9 @@
|
||||
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||
#endif
|
||||
|
||||
// external name (synthetic) for the primordial "bootstrap" class loader instance
|
||||
#define BOOTSTRAP_LOADER_NAME "bootstrap"
|
||||
#define BOOTSTRAP_LOADER_NAME_LEN 9
|
||||
|
||||
//
|
||||
// A class loader represents a linkset. Conceptually, a linkset identifies
|
||||
@ -258,9 +261,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
// Support for walking class loader data objects
|
||||
ClassLoaderData* _next; /// Next loader_datas created
|
||||
|
||||
// JFR support
|
||||
Klass* _class_loader_klass;
|
||||
Symbol* _class_loader_name;
|
||||
Symbol* _name;
|
||||
Symbol* _name_and_id;
|
||||
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
|
||||
|
||||
void set_next(ClassLoaderData* next) { _next = next; }
|
||||
@ -362,8 +365,6 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
|
||||
void initialize_holder(Handle holder);
|
||||
|
||||
inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); }
|
||||
|
||||
void oops_do(OopClosure* f, bool must_claim, bool clear_modified_oops = false);
|
||||
|
||||
void classes_do(KlassClosure* klass_closure);
|
||||
@ -377,7 +378,6 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
void print_value() { print_value_on(tty); }
|
||||
void print_value_on(outputStream* out) const;
|
||||
void verify();
|
||||
const char* loader_name() const;
|
||||
|
||||
OopHandle add_handle(Handle h);
|
||||
void remove_handle(OopHandle h);
|
||||
@ -400,15 +400,20 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
static ClassLoaderData* class_loader_data_or_null(oop loader);
|
||||
static ClassLoaderData* anonymous_class_loader_data(Handle loader);
|
||||
|
||||
// Returns Klass* of associated class loader, or NULL if associated loader is <bootstrap>.
|
||||
// Returns Klass* of associated class loader, or NULL if associated loader is 'bootstrap'.
|
||||
// Also works if unloading.
|
||||
Klass* class_loader_klass() const { return _class_loader_klass; }
|
||||
|
||||
// Returns Name of associated class loader.
|
||||
// Returns NULL if associated class loader is <bootstrap> or if no name has been set for
|
||||
// this loader.
|
||||
// Also works if unloading.
|
||||
Symbol* class_loader_name() const { return _class_loader_name; }
|
||||
// Returns the class loader's explict name as specified during
|
||||
// construction or the class loader's qualified class name.
|
||||
// Works during unloading.
|
||||
const char* loader_name() const;
|
||||
// Returns the explicitly specified class loader name or NULL.
|
||||
Symbol* name() const { return _name; }
|
||||
|
||||
// Obtain the class loader's _name_and_id, works during unloading.
|
||||
const char* loader_name_and_id() const;
|
||||
Symbol* name_and_id() const { return _name_and_id; }
|
||||
|
||||
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
|
||||
};
|
||||
|
@ -157,7 +157,7 @@ class LoaderTreeNode : public ResourceObj {
|
||||
|
||||
// Retrieve information.
|
||||
const Klass* const loader_klass = _cld->class_loader_klass();
|
||||
const Symbol* const loader_name = _cld->class_loader_name();
|
||||
const Symbol* const loader_name = _cld->name();
|
||||
|
||||
branchtracker.print(st);
|
||||
|
||||
|
@ -641,6 +641,6 @@ void Dictionary::verify() {
|
||||
|
||||
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());
|
||||
verify_table<DictionaryEntry>(tempst.as_string());
|
||||
}
|
||||
|
@ -3993,6 +3993,7 @@ bool java_lang_ClassLoader::offsets_computed = false;
|
||||
int java_lang_ClassLoader::_loader_data_offset = -1;
|
||||
int java_lang_ClassLoader::parallelCapable_offset = -1;
|
||||
int java_lang_ClassLoader::name_offset = -1;
|
||||
int java_lang_ClassLoader::nameAndId_offset = -1;
|
||||
int java_lang_ClassLoader::unnamedModule_offset = -1;
|
||||
|
||||
ClassLoaderData* java_lang_ClassLoader::loader_data(oop loader) {
|
||||
@ -4008,6 +4009,7 @@ ClassLoaderData* java_lang_ClassLoader::cmpxchg_loader_data(ClassLoaderData* new
|
||||
#define CLASSLOADER_FIELDS_DO(macro) \
|
||||
macro(parallelCapable_offset, k1, "parallelLockMap", concurrenthashmap_signature, false); \
|
||||
macro(name_offset, k1, vmSymbols::name_name(), string_signature, false); \
|
||||
macro(nameAndId_offset, k1, "nameAndId", string_signature, false); \
|
||||
macro(unnamedModule_offset, k1, "unnamedModule", module_signature, false); \
|
||||
macro(parent_offset, k1, "parent", classloader_signature, false)
|
||||
|
||||
@ -4033,11 +4035,24 @@ oop java_lang_ClassLoader::parent(oop loader) {
|
||||
return loader->obj_field(parent_offset);
|
||||
}
|
||||
|
||||
// Returns the name field of this class loader. If the name field has not
|
||||
// been set, null will be returned.
|
||||
oop java_lang_ClassLoader::name(oop loader) {
|
||||
assert(is_instance(loader), "loader must be oop");
|
||||
return loader->obj_field(name_offset);
|
||||
}
|
||||
|
||||
// Returns the nameAndId field of this class loader. The format is
|
||||
// as follows:
|
||||
// If the defining loader has a name explicitly set then '<loader-name>' @<id>
|
||||
// If the defining loader has no name then <qualified-class-name> @<id>
|
||||
// If built-in loader, then omit '@<id>' as there is only one instance.
|
||||
// Use ClassLoader::loader_name_id() to obtain this String as a char*.
|
||||
oop java_lang_ClassLoader::nameAndId(oop loader) {
|
||||
assert(is_instance(loader), "loader must be oop");
|
||||
return loader->obj_field(nameAndId_offset);
|
||||
}
|
||||
|
||||
bool java_lang_ClassLoader::isAncestor(oop loader, oop cl) {
|
||||
assert(is_instance(loader), "loader must be oop");
|
||||
assert(cl == NULL || is_instance(cl), "cl argument must be oop");
|
||||
@ -4111,39 +4126,28 @@ oop java_lang_ClassLoader::unnamedModule(oop loader) {
|
||||
|
||||
// Caller needs ResourceMark.
|
||||
const char* java_lang_ClassLoader::describe_external(const oop loader) {
|
||||
ClassLoaderData *cld = ClassLoaderData::class_loader_data(loader);
|
||||
const char* name = cld->loader_name_and_id();
|
||||
|
||||
// bootstrap loader
|
||||
if (loader == NULL) {
|
||||
return "<bootstrap>";
|
||||
return name;
|
||||
}
|
||||
|
||||
bool well_known_loader = SystemDictionary::is_system_class_loader(loader) ||
|
||||
SystemDictionary::is_platform_class_loader(loader);
|
||||
|
||||
const char* name = NULL;
|
||||
oop nameOop = java_lang_ClassLoader::name(loader);
|
||||
if (nameOop != NULL) {
|
||||
name = java_lang_String::as_utf8_string(nameOop);
|
||||
}
|
||||
if (name == NULL) {
|
||||
// Use placeholder for missing name to have fixed message format.
|
||||
name = "<unnamed>";
|
||||
}
|
||||
|
||||
stringStream ss;
|
||||
ss.print("\"%s\" (instance of %s", name, loader->klass()->external_name());
|
||||
ss.print("%s (instance of %s", name, loader->klass()->external_name());
|
||||
if (!well_known_loader) {
|
||||
const char* parentName = NULL;
|
||||
oop pl = java_lang_ClassLoader::parent(loader);
|
||||
ClassLoaderData *pl_cld = ClassLoaderData::class_loader_data(pl);
|
||||
const char* parentName = pl_cld->loader_name_and_id();
|
||||
if (pl != NULL) {
|
||||
oop parentNameOop = java_lang_ClassLoader::name(pl);
|
||||
if (parentNameOop != NULL) {
|
||||
parentName = java_lang_String::as_utf8_string(parentNameOop);
|
||||
}
|
||||
if (parentName == NULL) {
|
||||
parentName = "<unnamed>";
|
||||
}
|
||||
ss.print(", child of \"%s\" %s", parentName, pl->klass()->external_name());
|
||||
ss.print(", child of %s %s", parentName, pl->klass()->external_name());
|
||||
} else {
|
||||
ss.print(", child of <bootstrap>");
|
||||
// bootstrap loader
|
||||
ss.print(", child of %s", parentName);
|
||||
}
|
||||
}
|
||||
ss.print(")");
|
||||
|
@ -1272,6 +1272,7 @@ class java_lang_ClassLoader : AllStatic {
|
||||
static int parent_offset;
|
||||
static int parallelCapable_offset;
|
||||
static int name_offset;
|
||||
static int nameAndId_offset;
|
||||
static int unnamedModule_offset;
|
||||
|
||||
public:
|
||||
@ -1283,6 +1284,7 @@ class java_lang_ClassLoader : AllStatic {
|
||||
|
||||
static oop parent(oop loader);
|
||||
static oop name(oop loader);
|
||||
static oop nameAndId(oop loader);
|
||||
static bool isAncestor(oop loader, oop cl);
|
||||
|
||||
// Support for parallelCapable field
|
||||
|
@ -108,7 +108,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
|
||||
probe->name()->as_C_string());
|
||||
for (int i = 0; i < probe->num_loaders(); i++) {
|
||||
lt.print(" [%d]: %s", i,
|
||||
probe->loader_data(i)->loader_name());
|
||||
probe->loader_data(i)->loader_name_and_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -119,7 +119,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
|
||||
if (lt.is_enabled()) {
|
||||
ResourceMark rm;
|
||||
lt.print("purging loader %s from constraint for name %s",
|
||||
probe->loader_data(n)->loader_name(),
|
||||
probe->loader_data(n)->loader_name_and_id(),
|
||||
probe->name()->as_C_string()
|
||||
);
|
||||
}
|
||||
@ -135,7 +135,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
|
||||
lt.print("new loader list:");
|
||||
for (int i = 0; i < probe->num_loaders(); i++) {
|
||||
lt.print(" [%d]: %s", i,
|
||||
probe->loader_data(i)->loader_name());
|
||||
probe->loader_data(i)->loader_name_and_id());
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,8 +177,8 @@ void log_ldr_constraint_msg(Symbol* class_name, const char* reason,
|
||||
lt.print("Failed to add constraint for name: %s, loader[0]: %s,"
|
||||
" loader[1]: %s, Reason: %s",
|
||||
class_name->as_C_string(),
|
||||
SystemDictionary::loader_name(class_loader1()),
|
||||
SystemDictionary::loader_name(class_loader2()),
|
||||
ClassLoaderData::class_loader_data(class_loader1())->loader_name_and_id(),
|
||||
ClassLoaderData::class_loader_data(class_loader2())->loader_name_and_id(),
|
||||
reason);
|
||||
}
|
||||
}
|
||||
@ -247,8 +247,8 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name,
|
||||
lt.print("adding new constraint for name: %s, loader[0]: %s,"
|
||||
" loader[1]: %s",
|
||||
class_name->as_C_string(),
|
||||
SystemDictionary::loader_name(class_loader1()),
|
||||
SystemDictionary::loader_name(class_loader2())
|
||||
ClassLoaderData::class_loader_data(class_loader1())->loader_name_and_id(),
|
||||
ClassLoaderData::class_loader_data(class_loader2())->loader_name_and_id()
|
||||
);
|
||||
}
|
||||
} else if (*pp1 == *pp2) {
|
||||
@ -260,7 +260,7 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name,
|
||||
lt.print("setting class object in existing constraint for"
|
||||
" name: %s and loader %s",
|
||||
class_name->as_C_string(),
|
||||
SystemDictionary::loader_name(class_loader1())
|
||||
ClassLoaderData::class_loader_data(class_loader1())->loader_name_and_id()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -291,7 +291,7 @@ bool LoaderConstraintTable::check_or_update(InstanceKlass* k,
|
||||
lt.print("constraint check failed for name %s, loader %s: "
|
||||
"the presented class object differs from that stored",
|
||||
name->as_C_string(),
|
||||
SystemDictionary::loader_name(loader()));
|
||||
ClassLoaderData::class_loader_data(loader())->loader_name_and_id());
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
@ -302,7 +302,7 @@ bool LoaderConstraintTable::check_or_update(InstanceKlass* k,
|
||||
lt.print("updating constraint for name %s, loader %s, "
|
||||
"by setting class object",
|
||||
name->as_C_string(),
|
||||
SystemDictionary::loader_name(loader()));
|
||||
ClassLoaderData::class_loader_data(loader())->loader_name_and_id());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -353,7 +353,7 @@ void LoaderConstraintTable::extend_loader_constraint(LoaderConstraintEntry* p,
|
||||
lt.print("extending constraint for name %s by adding loader[%d]: %s %s",
|
||||
p->name()->as_C_string(),
|
||||
num,
|
||||
SystemDictionary::loader_name(loader()),
|
||||
ClassLoaderData::class_loader_data(loader())->loader_name_and_id(),
|
||||
(p->klass() == NULL ? " and setting class object" : "")
|
||||
);
|
||||
}
|
||||
@ -396,7 +396,7 @@ void LoaderConstraintTable::merge_loader_constraints(
|
||||
|
||||
for (int i = 0; i < p1->num_loaders(); i++) {
|
||||
lt.print(" [%d]: %s", i,
|
||||
p1->loader_data(i)->loader_name());
|
||||
p1->loader_data(i)->loader_name_and_id());
|
||||
}
|
||||
if (p1->klass() == NULL) {
|
||||
lt.print("... and setting class object");
|
||||
|
@ -260,7 +260,7 @@ ModuleEntry* ModuleEntry::create_unnamed_module(ClassLoaderData* cld) {
|
||||
ResourceMark rm;
|
||||
guarantee(java_lang_Module::is_instance(module),
|
||||
"The unnamed module for ClassLoader %s, is null or not an instance of java.lang.Module. The class loader has not been initialized correctly.",
|
||||
cld->loader_name());
|
||||
cld->loader_name_and_id());
|
||||
|
||||
ModuleEntry* unnamed_module = new_unnamed_module_entry(Handle(Thread::current(), module), cld);
|
||||
|
||||
@ -522,7 +522,7 @@ void ModuleEntry::print(outputStream* st) {
|
||||
p2i(this),
|
||||
name() == NULL ? UNNAMED_MODULE : name()->as_C_string(),
|
||||
p2i(module()),
|
||||
loader_data()->loader_name(),
|
||||
loader_data()->loader_name_and_id(),
|
||||
version() != NULL ? version()->as_C_string() : "NULL",
|
||||
location() != NULL ? location()->as_C_string() : "NULL",
|
||||
BOOL_TO_STR(!can_read_all_unnamed()), p2i(next()));
|
||||
|
@ -312,6 +312,10 @@ void Modules::define_module(jobject module, jboolean is_open, jstring version,
|
||||
"Class loader is an invalid delegating class loader");
|
||||
}
|
||||
Handle h_loader = Handle(THREAD, loader);
|
||||
// define_module can be called during start-up, before the class loader's ClassLoaderData
|
||||
// has been created. SystemDictionary::register_loader ensures creation, if needed.
|
||||
ClassLoaderData* loader_data = SystemDictionary::register_loader(h_loader);
|
||||
assert(loader_data != NULL, "class loader data shouldn't be null");
|
||||
|
||||
// Check that the list of packages has no duplicates and that the
|
||||
// packages are syntactically ok.
|
||||
@ -329,7 +333,7 @@ void Modules::define_module(jobject module, jboolean is_open, jstring version,
|
||||
!SystemDictionary::is_platform_class_loader(h_loader()) &&
|
||||
(strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0 &&
|
||||
(package_name[JAVAPKG_LEN] == '/' || package_name[JAVAPKG_LEN] == '\0'))) {
|
||||
const char* class_loader_name = SystemDictionary::loader_name(h_loader());
|
||||
const char* class_loader_name = loader_data->loader_name_and_id();
|
||||
size_t pkg_len = strlen(package_name);
|
||||
char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len);
|
||||
strncpy(pkg_name, package_name, pkg_len);
|
||||
@ -373,9 +377,6 @@ void Modules::define_module(jobject module, jboolean is_open, jstring version,
|
||||
}
|
||||
}
|
||||
|
||||
ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(h_loader());
|
||||
assert(loader_data != NULL, "class loader data shouldn't be null");
|
||||
|
||||
PackageEntryTable* package_table = NULL;
|
||||
PackageEntry* existing_pkg = NULL;
|
||||
{
|
||||
|
@ -3012,18 +3012,6 @@ void SystemDictionary::combine_shared_dictionaries() {
|
||||
NOT_PRODUCT(SystemDictionary::verify());
|
||||
}
|
||||
|
||||
// caller needs ResourceMark
|
||||
const char* SystemDictionary::loader_name(const oop loader) {
|
||||
return ((loader) == NULL ? "<bootloader>" :
|
||||
InstanceKlass::cast((loader)->klass())->name()->as_C_string());
|
||||
}
|
||||
|
||||
// caller needs ResourceMark
|
||||
const char* SystemDictionary::loader_name(const ClassLoaderData* loader_data) {
|
||||
return (loader_data->class_loader() == NULL ? "<bootloader>" :
|
||||
SystemDictionary::loader_name(loader_data->class_loader()));
|
||||
}
|
||||
|
||||
void SystemDictionary::initialize_oop_storage() {
|
||||
_vm_weak_oop_storage =
|
||||
new OopStorage("VM Weak Oop Handles",
|
||||
|
@ -570,10 +570,6 @@ public:
|
||||
Handle *method_type_result,
|
||||
TRAPS);
|
||||
|
||||
// Utility for printing loader "name" as part of tracing constraints
|
||||
static const char* loader_name(const oop loader);
|
||||
static const char* loader_name(const ClassLoaderData* loader_data);
|
||||
|
||||
// Record the error when the first attempt to resolve a reference from a constant
|
||||
// pool entry to a class fails.
|
||||
static void add_resolution_error(const constantPoolHandle& pool, int which, Symbol* error,
|
||||
|
@ -128,7 +128,7 @@ void CLDScanClosure::do_cld(ClassLoaderData* cld) {
|
||||
NOT_PRODUCT(ResourceMark rm);
|
||||
log_develop_trace(gc, scavenge)("CLDScanClosure::do_cld " PTR_FORMAT ", %s, dirty: %s",
|
||||
p2i(cld),
|
||||
cld->loader_name(),
|
||||
cld->loader_name_and_id(),
|
||||
cld->has_modified_oops() ? "true" : "false");
|
||||
|
||||
// If the cld has not been dirtied we know that there's
|
||||
|
@ -238,9 +238,9 @@ int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* ar
|
||||
// (primordial) boot class loader
|
||||
writer->write(cld_id); // class loader instance id
|
||||
writer->write((traceid)0); // class loader type id (absence of)
|
||||
writer->write((traceid)CREATE_SYMBOL_ID(1)); // 1 maps to synthetic name -> "boot"
|
||||
writer->write((traceid)CREATE_SYMBOL_ID(1)); // 1 maps to synthetic name -> "bootstrap"
|
||||
} else {
|
||||
Symbol* symbol_name = cld->class_loader_name();
|
||||
Symbol* symbol_name = cld->name();
|
||||
const traceid symbol_name_id = symbol_name != NULL ? artifacts->mark(symbol_name) : 0;
|
||||
writer->write(cld_id); // class loader instance id
|
||||
writer->write(TRACE_ID(class_loader_klass)); // class loader type id
|
||||
@ -441,13 +441,13 @@ int KlassSymbolWriterImpl<Predicate>::class_loader_symbols(CldPtr cld) {
|
||||
CStringEntryPtr entry = this->_artifacts->map_cstring(0);
|
||||
assert(entry != NULL, "invariant");
|
||||
assert(strncmp(entry->literal(),
|
||||
boot_class_loader_name,
|
||||
strlen(boot_class_loader_name)) == 0, "invariant");
|
||||
BOOTSTRAP_LOADER_NAME,
|
||||
BOOTSTRAP_LOADER_NAME_LEN) == 0, "invariant");
|
||||
if (_unique_predicate(entry->id())) {
|
||||
count += write__artifact__cstring__entry__(this->_writer, entry);
|
||||
}
|
||||
} else {
|
||||
const Symbol* class_loader_name = cld->class_loader_name();
|
||||
const Symbol* class_loader_name = cld->name();
|
||||
if (class_loader_name != NULL) {
|
||||
SymbolEntryPtr entry = this->_artifacts->map_symbol(class_loader_name);
|
||||
assert(entry != NULL, "invariant");
|
||||
|
@ -208,7 +208,7 @@ void JfrArtifactSet::initialize(bool class_unload) {
|
||||
assert(_symbol_id != NULL, "invariant");
|
||||
_symbol_id->initialize();
|
||||
assert(!_symbol_id->has_entries(), "invariant");
|
||||
_symbol_id->mark(boot_class_loader_name, 0); // pre-load "boot"
|
||||
_symbol_id->mark(BOOTSTRAP_LOADER_NAME, 0); // pre-load "bootstrap"
|
||||
_class_unload = class_unload;
|
||||
// resource allocation
|
||||
_klass_list = new GrowableArray<const Klass*>(initial_class_list_size, false, mtTracing);
|
||||
|
@ -295,9 +295,6 @@ class JfrSymbolId : public JfrCHeapObj {
|
||||
bool has_cstring_entries() const { return _cstring_table->has_entries(); }
|
||||
};
|
||||
|
||||
// external name (synthetic) for the primordial "boot" class loader instance
|
||||
const char* const boot_class_loader_name = "boot";
|
||||
|
||||
/**
|
||||
* When processing a set of artifacts, there will be a need
|
||||
* to track transitive dependencies originating with each artifact.
|
||||
|
@ -88,7 +88,7 @@ void PrintCLDMetaspaceInfoClosure::do_cld(ClassLoaderData* cld) {
|
||||
Klass* k = cld->class_loader_klass();
|
||||
if (k != NULL) {
|
||||
class_name = k->external_name();
|
||||
Symbol* s = cld->class_loader_name();
|
||||
Symbol* s = cld->name();
|
||||
if (s != NULL) {
|
||||
name = s->as_C_string();
|
||||
}
|
||||
|
@ -2328,8 +2328,7 @@ ModuleEntry* InstanceKlass::module() const {
|
||||
void InstanceKlass::set_package(ClassLoaderData* loader_data, TRAPS) {
|
||||
|
||||
// ensure java/ packages only loaded by boot or platform builtin loaders
|
||||
Handle class_loader(THREAD, loader_data->class_loader());
|
||||
check_prohibited_package(name(), class_loader, CHECK);
|
||||
check_prohibited_package(name(), loader_data, CHECK);
|
||||
|
||||
TempNewSymbol pkg_name = package_from_name(name(), CHECK);
|
||||
|
||||
@ -2359,7 +2358,7 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, TRAPS) {
|
||||
|
||||
// A package should have been successfully created
|
||||
assert(_package_entry != NULL, "Package entry for class %s not found, loader %s",
|
||||
name()->as_C_string(), loader_data->loader_name());
|
||||
name()->as_C_string(), loader_data->loader_name_and_id());
|
||||
}
|
||||
|
||||
if (log_is_enabled(Debug, module)) {
|
||||
@ -2368,14 +2367,14 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, TRAPS) {
|
||||
log_trace(module)("Setting package: class: %s, package: %s, loader: %s, module: %s",
|
||||
external_name(),
|
||||
pkg_name->as_C_string(),
|
||||
loader_data->loader_name(),
|
||||
loader_data->loader_name_and_id(),
|
||||
(m->is_named() ? m->name()->as_C_string() : UNNAMED_MODULE));
|
||||
}
|
||||
} else {
|
||||
ResourceMark rm;
|
||||
log_trace(module)("Setting package: class: %s, package: unnamed, loader: %s, module: %s",
|
||||
external_name(),
|
||||
(loader_data != NULL) ? loader_data->loader_name() : "NULL",
|
||||
(loader_data != NULL) ? loader_data->loader_name_and_id() : "NULL",
|
||||
UNNAMED_MODULE);
|
||||
}
|
||||
}
|
||||
@ -2471,10 +2470,10 @@ bool InstanceKlass::is_override(const methodHandle& super_method, Handle targetc
|
||||
|
||||
// Only boot and platform class loaders can define classes in "java/" packages.
|
||||
void InstanceKlass::check_prohibited_package(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
ClassLoaderData* loader_data,
|
||||
TRAPS) {
|
||||
if (!class_loader.is_null() &&
|
||||
!SystemDictionary::is_platform_class_loader(class_loader()) &&
|
||||
if (!loader_data->is_boot_class_loader_data() &&
|
||||
!loader_data->is_platform_class_loader_data() &&
|
||||
class_name != NULL) {
|
||||
ResourceMark rm(THREAD);
|
||||
char* name = class_name->as_C_string();
|
||||
@ -2482,7 +2481,7 @@ void InstanceKlass::check_prohibited_package(Symbol* class_name,
|
||||
TempNewSymbol pkg_name = InstanceKlass::package_from_name(class_name, CHECK);
|
||||
assert(pkg_name != NULL, "Error in parsing package name starting with 'java/'");
|
||||
name = pkg_name->as_C_string();
|
||||
const char* class_loader_name = SystemDictionary::loader_name(class_loader());
|
||||
const char* class_loader_name = loader_data->loader_name_and_id();
|
||||
StringUtils::replace_no_expand(name, "/", ".");
|
||||
const char* msg_text1 = "Class loader (instance of): ";
|
||||
const char* msg_text2 = " tried to load prohibited package name: ";
|
||||
|
@ -471,7 +471,7 @@ class InstanceKlass: public Klass {
|
||||
private:
|
||||
// Check prohibited package ("java/" only loadable by boot or platform loaders)
|
||||
static void check_prohibited_package(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
ClassLoaderData* loader_data,
|
||||
TRAPS);
|
||||
public:
|
||||
// tell if two classes have the same enclosing class (at package level)
|
||||
|
@ -59,6 +59,7 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import jdk.internal.loader.BuiltinClassLoader;
|
||||
import jdk.internal.perf.PerfCounter;
|
||||
import jdk.internal.loader.BootLoader;
|
||||
import jdk.internal.loader.ClassLoaders;
|
||||
@ -246,6 +247,9 @@ public abstract class ClassLoader {
|
||||
// the unnamed module for this ClassLoader
|
||||
private final Module unnamedModule;
|
||||
|
||||
// a string for exception message printing
|
||||
private final String nameAndId;
|
||||
|
||||
/**
|
||||
* Encapsulates the set of parallel capable loader types.
|
||||
*/
|
||||
@ -381,6 +385,24 @@ public abstract class ClassLoader {
|
||||
package2certs = new Hashtable<>();
|
||||
assertionLock = this;
|
||||
}
|
||||
this.nameAndId = nameAndId(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the defining loader has a name explicitly set then
|
||||
* '<loader-name>' @<id>
|
||||
* If the defining loader has no name then
|
||||
* <qualified-class-name> @<id>
|
||||
* If it's built-in loader then omit `@<id>` as there is only one instance.
|
||||
*/
|
||||
private static String nameAndId(ClassLoader ld) {
|
||||
String nid = ld.getName() != null ? "\'" + ld.getName() + "\'"
|
||||
: ld.getClass().getName();
|
||||
if (!(ld instanceof BuiltinClassLoader)) {
|
||||
String id = Integer.toHexString(System.identityHashCode(ld));
|
||||
nid = nid + " @" + id;
|
||||
}
|
||||
return nid;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,11 +75,13 @@ public class Test {
|
||||
// Then it loads the D2 variant of D from the current working directory and it's
|
||||
// superclass C. This fails as D1 is already loaded with the same superclass.
|
||||
|
||||
static String expectedErrorMessage =
|
||||
"loader constraint violation: loader \"<unnamed>\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) wants to load " +
|
||||
// Break the expectedErrorMessage into 2 pieces since the loader name will include
|
||||
// its identity hash and can not be compared against.
|
||||
static String expectedErrorMessage_part1 = "loader constraint violation: loader PreemptingClassLoader @";
|
||||
static String expectedErrorMessage_part2 = " (instance of PreemptingClassLoader, " +
|
||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) wants to load " +
|
||||
"class test.D_ambgs. A different class with the same name was previously loaded " +
|
||||
"by \"app\" (instance of jdk.internal.loader.ClassLoaders$AppClassLoader).";
|
||||
"by 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader).";
|
||||
|
||||
public static void test_access() throws Exception {
|
||||
try {
|
||||
@ -101,8 +103,9 @@ public class Test {
|
||||
throw new RuntimeException("Expected LinkageError was not thrown.");
|
||||
} catch (LinkageError jle) {
|
||||
String errorMsg = jle.getMessage();
|
||||
if (!errorMsg.equals(expectedErrorMessage)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage + "\n" +
|
||||
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
||||
!errorMsg.contains(expectedErrorMessage_part2)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
||||
"but got: " + errorMsg);
|
||||
throw new RuntimeException("Wrong error message of LinkageError.");
|
||||
} else {
|
||||
|
@ -37,23 +37,28 @@ public class Test {
|
||||
|
||||
// Check that all names have external formatting ('.' and not '/' in package names).
|
||||
// Check for parent of class loader.
|
||||
static String expectedErrorMessage1 =
|
||||
"loader \"<unnamed>\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
// Break each expectedErrorMessage into 2 parts due to the class loader name containing
|
||||
// the unique @<id> identity hash which cannot be compared against.
|
||||
static String expectedErrorMessage1_part1 = "loader PreemptingClassLoader @";
|
||||
static String expectedErrorMessage1_part2 =
|
||||
" (instance of PreemptingClassLoader, " +
|
||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"attempted duplicate class definition for test.Foo.";
|
||||
|
||||
// Check that all names have external formatting ('.' and not '/' in package names).
|
||||
// Check for name and parent of class loader.
|
||||
static String expectedErrorMessage2 =
|
||||
"loader \"DuplicateLE_Test_Loader\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
static String expectedErrorMessage2_part1 = "loader 'DuplicateLE_Test_Loader' @";
|
||||
static String expectedErrorMessage2_part2 =
|
||||
" (instance of PreemptingClassLoader, " +
|
||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"attempted duplicate class definition for test.Foo.";
|
||||
|
||||
// Check that all names have external formatting ('.' and not '/' in package names).
|
||||
// Check for name and parent of class loader. Type should be mentioned as 'interface'.
|
||||
static String expectedErrorMessage3 =
|
||||
"loader \"DuplicateLE_Test_Loader_IF\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
static String expectedErrorMessage3_part1 = "loader 'DuplicateLE_Test_Loader_IF' @";
|
||||
static String expectedErrorMessage3_part2 =
|
||||
" (instance of PreemptingClassLoader, " +
|
||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"attempted duplicate interface definition for test.J.";
|
||||
|
||||
// Test that the error message is correct when a loader constraint error is
|
||||
@ -63,7 +68,8 @@ public class Test {
|
||||
// overrides "J.m()LFoo;". But, Task's class Foo and super type J's class Foo
|
||||
// are different. So, a LinkageError exception should be thrown because the
|
||||
// loader constraint check will fail.
|
||||
public static void test(String loaderName, String expectedErrorMessage, String testType) throws Exception {
|
||||
public static void test(String loaderName, String expectedErrorMessage_part1,
|
||||
String expectedErrorMessage_part2, String testType) throws Exception {
|
||||
String[] classNames = {testType};
|
||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames, false);
|
||||
l.loadClass(testType);
|
||||
@ -72,8 +78,9 @@ public class Test {
|
||||
throw new RuntimeException("Expected LinkageError exception not thrown");
|
||||
} catch (LinkageError e) {
|
||||
String errorMsg = e.getMessage();
|
||||
if (!errorMsg.equals(expectedErrorMessage)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage + "\n" +
|
||||
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
||||
!errorMsg.contains(expectedErrorMessage_part2)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
||||
"but got: " + errorMsg);
|
||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||
}
|
||||
@ -82,9 +89,9 @@ public class Test {
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
test(null, expectedErrorMessage1, "test.Foo");
|
||||
test("DuplicateLE_Test_Loader", expectedErrorMessage2, "test.Foo");
|
||||
test("DuplicateLE_Test_Loader_IF", expectedErrorMessage3, "test.J");
|
||||
test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2, "test.Foo");
|
||||
test("DuplicateLE_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2, "test.Foo");
|
||||
test("DuplicateLE_Test_Loader_IF", expectedErrorMessage3_part1, expectedErrorMessage3_part2, "test.J");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,22 +35,28 @@
|
||||
|
||||
public class Test {
|
||||
|
||||
static String expectedErrorMessage1 =
|
||||
// Break expected error messages into 2 parts since the loader name includes its identity
|
||||
// hash which is unique and can't be compared against.
|
||||
static String expectedErrorMessage1_part1 =
|
||||
"loader constraint violation in interface itable initialization for class test.C: " +
|
||||
"when selecting method test.I.m()Ltest/Foo; " +
|
||||
"the class loader \"<unnamed>\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"for super interface test.I, and the class loader \"app\" " +
|
||||
"the class loader PreemptingClassLoader @";
|
||||
static String expectedErrorMessage1_part2 =
|
||||
" (instance of PreemptingClassLoader, " +
|
||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"for super interface test.I, and the class loader 'app' " +
|
||||
"(instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"of the selected method's type, test.J have different Class objects " +
|
||||
"for the type test.Foo used in the signature";
|
||||
|
||||
static String expectedErrorMessage2 =
|
||||
static String expectedErrorMessage2_part1 =
|
||||
"loader constraint violation in interface itable initialization for class test.C: " +
|
||||
"when selecting method test.I.m()Ltest/Foo; " +
|
||||
"the class loader \"ItableLdrCnstrnt_Test_Loader\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"for super interface test.I, and the class loader \"app\" " +
|
||||
"the class loader 'ItableLdrCnstrnt_Test_Loader' @";
|
||||
static String expectedErrorMessage2_part2 =
|
||||
" (instance of PreemptingClassLoader, " +
|
||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"for super interface test.I, and the class loader 'app' " +
|
||||
"(instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"of the selected method's type, test.J have different Class objects " +
|
||||
"for the type test.Foo used in the signature";
|
||||
@ -63,7 +69,9 @@ public class Test {
|
||||
// type super interface J. The selected method is not an overpass method nor
|
||||
// otherwise excluded from loader constraint checking. So, a LinkageError
|
||||
// exception should be thrown because the loader constraint check will fail.
|
||||
public static void test(String loaderName, String expectedErrorMessage) throws Exception {
|
||||
public static void test(String loaderName,
|
||||
String expectedErrorMessage_part1,
|
||||
String expectedErrorMessage_part2) throws Exception {
|
||||
Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
|
||||
String[] classNames = {"test.Task", "test.Foo", "test.C", "test.I"};
|
||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
|
||||
@ -73,8 +81,9 @@ public class Test {
|
||||
throw new RuntimeException("Expected LinkageError exception not thrown");
|
||||
} catch (LinkageError e) {
|
||||
String errorMsg = e.getMessage();
|
||||
if (!errorMsg.equals(expectedErrorMessage)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage + "\n" +
|
||||
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
||||
!errorMsg.contains(expectedErrorMessage_part2)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
||||
"but got: " + errorMsg);
|
||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||
}
|
||||
@ -83,7 +92,7 @@ public class Test {
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
test(null, expectedErrorMessage1);
|
||||
test("ItableLdrCnstrnt_Test_Loader", expectedErrorMessage2);
|
||||
test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2);
|
||||
test("ItableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2);
|
||||
}
|
||||
}
|
||||
|
@ -35,23 +35,29 @@
|
||||
|
||||
public class Test {
|
||||
|
||||
static String expectedErrorMessage1 =
|
||||
// Break expected error messages into 2 parts since the loader name includes its identity
|
||||
// hash which is unique and can't be compared against.
|
||||
static String expectedErrorMessage1_part1 =
|
||||
"loader constraint violation for class test.Task: " +
|
||||
"when selecting overriding method test.Task.m()Ltest/Foo; " +
|
||||
"the class loader \"<unnamed>\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"the class loader PreemptingClassLoader @";
|
||||
static String expectedErrorMessage1_part2 =
|
||||
" (instance of PreemptingClassLoader, " +
|
||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"of the selected method's type test.Task, " +
|
||||
"and the class loader \"app\" (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"and the class loader 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"for its super type test.J " +
|
||||
"have different Class objects for the type test.Foo used in the signature";
|
||||
|
||||
static String expectedErrorMessage2 =
|
||||
static String expectedErrorMessage2_part1 =
|
||||
"loader constraint violation for class test.Task: " +
|
||||
"when selecting overriding method test.Task.m()Ltest/Foo; " +
|
||||
"the class loader \"VtableLdrCnstrnt_Test_Loader\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"the class loader 'VtableLdrCnstrnt_Test_Loader' @";
|
||||
static String expectedErrorMessage2_part2 =
|
||||
" (instance of PreemptingClassLoader, " +
|
||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"of the selected method's type test.Task, " +
|
||||
"and the class loader \"app\" (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"and the class loader 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"for its super type test.J " +
|
||||
"have different Class objects for the type test.Foo used in the signature";
|
||||
|
||||
@ -62,7 +68,9 @@ public class Test {
|
||||
// overrides "J.m()LFoo;". But, Task's class Foo and super type J's class Foo
|
||||
// are different. So, a LinkageError exception should be thrown because the
|
||||
// loader constraint check will fail.
|
||||
public static void test(String loaderName, String expectedErrorMessage) throws Exception {
|
||||
public static void test(String loaderName,
|
||||
String expectedErrorMessage_part1,
|
||||
String expectedErrorMessage_part2) throws Exception {
|
||||
Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
|
||||
String[] classNames = {"test.Task", "test.Foo", "test.I"};
|
||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
|
||||
@ -72,8 +80,9 @@ public class Test {
|
||||
throw new RuntimeException("Expected LinkageError exception not thrown");
|
||||
} catch (LinkageError e) {
|
||||
String errorMsg = e.getMessage();
|
||||
if (!errorMsg.equals(expectedErrorMessage)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage + "\n" +
|
||||
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
||||
!errorMsg.contains(expectedErrorMessage_part2)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
||||
"but got: " + errorMsg);
|
||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||
}
|
||||
@ -82,8 +91,8 @@ public class Test {
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
test(null, expectedErrorMessage1);
|
||||
test("VtableLdrCnstrnt_Test_Loader", expectedErrorMessage2);
|
||||
test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2);
|
||||
test("VtableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ public class DumpSymbolAndStringTable {
|
||||
pb.command(new String[] {JDKToolFinder.getJDKTool("jcmd"), pid, "VM.systemdictionary"});
|
||||
output = CDSTestUtils.executeAndLog(pb, "jcmd-systemdictionary");
|
||||
try {
|
||||
output.shouldContain("System Dictionary for jdk/internal/loader/ClassLoaders$AppClassLoader statistics:");
|
||||
output.shouldContain("System Dictionary for 'app' class loader statistics:");
|
||||
output.shouldContain("Number of buckets");
|
||||
output.shouldContain("Number of entries");
|
||||
output.shouldContain("Maximum bucket size");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -67,12 +67,12 @@ public class LoaderConstraintsTest {
|
||||
pb = exec("-XX:+TraceLoaderConstraints");
|
||||
out = new OutputAnalyzer(pb.start());
|
||||
out.getOutput();
|
||||
out.shouldContain("[class,loader,constraints] adding new constraint for name: java/lang/Class, loader[0]: jdk/internal/loader/ClassLoaders$AppClassLoader, loader[1]: <bootloader>");
|
||||
out.shouldContain("[class,loader,constraints] adding new constraint for name: java/lang/Class, loader[0]: 'app', loader[1]: 'bootstrap'");
|
||||
|
||||
// -Xlog:class+loader+constraints=info
|
||||
pb = exec("-Xlog:class+loader+constraints=info");
|
||||
out = new OutputAnalyzer(pb.start());
|
||||
out.shouldContain("[class,loader,constraints] adding new constraint for name: java/lang/Class, loader[0]: jdk/internal/loader/ClassLoaders$AppClassLoader, loader[1]: <bootloader>");
|
||||
out.shouldContain("[class,loader,constraints] adding new constraint for name: java/lang/Class, loader[0]: 'app', loader[1]: 'bootstrap'");
|
||||
|
||||
// -XX:-TraceLoaderConstraints
|
||||
pb = exec("-XX:-TraceLoaderConstraints");
|
||||
|
@ -47,7 +47,7 @@ import jdk.test.lib.jfr.TestClassLoader;
|
||||
public final class TestClassLoadEvent {
|
||||
|
||||
private final static String TEST_CLASS_NAME = "jdk.jfr.event.runtime.TestClasses";
|
||||
private final static String BOOT_CLASS_LOADER_NAME = "boot";
|
||||
private final static String BOOT_CLASS_LOADER_NAME = "bootstrap";
|
||||
private final static String SEARCH_CLASS_NAME = "java.lang.Object";
|
||||
private final static String SEARCH_PACKAGE_NAME = "java/lang";
|
||||
private final static String SEARCH_MODULE_NAME = "java.base";
|
||||
|
Loading…
x
Reference in New Issue
Block a user