8261941: Use ClassLoader for unregistered classes during -Xshare:dump
Reviewed-by: iklam, minqi
This commit is contained in:
parent
7e92abe7a4
commit
12fa7073c5
@ -29,6 +29,7 @@
|
||||
#include "cds/classListParser.hpp"
|
||||
#include "cds/lambdaFormInvokers.hpp"
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
#include "cds/unregisteredClasses.hpp"
|
||||
#include "classfile/classLoaderExt.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
@ -120,6 +121,13 @@ int ClassListParser::parse(TRAPS) {
|
||||
return 0; // THROW
|
||||
}
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
char* ex_msg = (char*)"";
|
||||
oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
|
||||
if (message != NULL) {
|
||||
ex_msg = java_lang_String::as_utf8_string(message);
|
||||
}
|
||||
log_warning(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), ex_msg);
|
||||
// We might have an invalid class name or an bad class. Warn about it
|
||||
// and keep going to the next line.
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
@ -458,7 +466,7 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
|
||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||
}
|
||||
|
||||
InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
|
||||
InstanceKlass* k = UnregisteredClasses::load_class(class_name, _source, CHECK_NULL);
|
||||
if (k->local_interfaces()->length() != _interfaces->length()) {
|
||||
print_specified_interfaces();
|
||||
print_actual_interfaces(k);
|
||||
@ -466,16 +474,14 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
|
||||
_interfaces->length(), k->local_interfaces()->length());
|
||||
}
|
||||
|
||||
bool added = SystemDictionaryShared::add_unregistered_class_for_static_archive(THREAD, k);
|
||||
assert(k->is_shared_unregistered_class(), "must be");
|
||||
|
||||
bool added = SystemDictionaryShared::add_unregistered_class(THREAD, k);
|
||||
if (!added) {
|
||||
// We allow only a single unregistered class for each unique name.
|
||||
error("Duplicated class %s", _class_name);
|
||||
}
|
||||
|
||||
// This tells JVM_FindLoadedClass to not find this class.
|
||||
k->set_shared_classpath_index(UNREGISTERED_INDEX);
|
||||
k->clear_shared_class_loader_type();
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
|
115
src/hotspot/share/cds/unregisteredClasses.cpp
Normal file
115
src/hotspot/share/cds/unregisteredClasses.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "cds/unregisteredClasses.hpp"
|
||||
#include "classfile/classFileStream.hpp"
|
||||
#include "classfile/classLoader.inline.hpp"
|
||||
#include "classfile/classLoaderExt.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "services/threadService.hpp"
|
||||
|
||||
// Load the class of the given name from the location given by path. The path is specified by
|
||||
// the "source:" in the class list file (see classListParser.cpp), and can be a directory or
|
||||
// a JAR file.
|
||||
InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, TRAPS) {
|
||||
assert(name != NULL, "invariant");
|
||||
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
|
||||
|
||||
{
|
||||
PerfClassTraceTime vmtimer(ClassLoader::perf_sys_class_lookup_time(),
|
||||
THREAD->get_thread_stat()->perf_timers_addr(),
|
||||
PerfClassTraceTime::CLASS_LOAD);
|
||||
}
|
||||
|
||||
Symbol* path_symbol = SymbolTable::new_symbol(path);
|
||||
Handle url_classloader = get_url_classloader(path_symbol, CHECK_NULL);
|
||||
Handle ext_class_name = java_lang_String::externalize_classname(name, CHECK_NULL);
|
||||
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCallArguments args(2);
|
||||
args.set_receiver(url_classloader);
|
||||
args.push_oop(ext_class_name);
|
||||
args.push_int(JNI_FALSE);
|
||||
JavaCalls::call_virtual(&result,
|
||||
vmClasses::URLClassLoader_klass(),
|
||||
vmSymbols::loadClass_name(),
|
||||
vmSymbols::string_boolean_class_signature(),
|
||||
&args,
|
||||
CHECK_NULL);
|
||||
assert(result.get_type() == T_OBJECT, "just checking");
|
||||
oop obj = result.get_oop();
|
||||
return InstanceKlass::cast(java_lang_Class::as_Klass(obj));
|
||||
}
|
||||
|
||||
class URLClassLoaderTable : public ResourceHashtable<
|
||||
Symbol*, Handle,
|
||||
137, // prime number
|
||||
ResourceObj::C_HEAP> {};
|
||||
|
||||
static URLClassLoaderTable* _url_classloader_table = NULL;
|
||||
|
||||
Handle UnregisteredClasses::create_url_classloader(Symbol* path, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
JavaValue result(T_OBJECT);
|
||||
Handle path_string = java_lang_String::create_from_str(path->as_C_string(), CHECK_NH);
|
||||
JavaCalls::call_static(&result,
|
||||
vmClasses::jdk_internal_loader_ClassLoaders_klass(),
|
||||
vmSymbols::toFileURL_name(),
|
||||
vmSymbols::toFileURL_signature(),
|
||||
path_string, CHECK_NH);
|
||||
assert(result.get_type() == T_OBJECT, "just checking");
|
||||
oop url_h = result.get_oop();
|
||||
objArrayHandle urls = oopFactory::new_objArray_handle(vmClasses::URL_klass(), 1, CHECK_NH);
|
||||
urls->obj_at_put(0, url_h);
|
||||
|
||||
Handle url_classloader = JavaCalls::construct_new_instance(
|
||||
vmClasses::URLClassLoader_klass(),
|
||||
vmSymbols::url_array_classloader_void_signature(),
|
||||
urls, Handle(), CHECK_NH);
|
||||
return url_classloader;
|
||||
}
|
||||
|
||||
Handle UnregisteredClasses::get_url_classloader(Symbol* path, TRAPS) {
|
||||
if (_url_classloader_table == NULL) {
|
||||
_url_classloader_table = new (ResourceObj::C_HEAP, mtClass)URLClassLoaderTable();
|
||||
}
|
||||
Handle* url_classloader_ptr = _url_classloader_table->get(path);
|
||||
if (url_classloader_ptr != NULL) {
|
||||
return *url_classloader_ptr;
|
||||
} else {
|
||||
Handle url_classloader = create_url_classloader(path, CHECK_NH);
|
||||
_url_classloader_table->put(path, url_classloader);
|
||||
path->increment_refcount();
|
||||
return url_classloader;
|
||||
}
|
||||
}
|
39
src/hotspot/share/cds/unregisteredClasses.hpp
Normal file
39
src/hotspot/share/cds/unregisteredClasses.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_CDS_UNREGISTEREDCLASSES_HPP
|
||||
#define SHARE_CDS_UNREGISTEREDCLASSES_HPP
|
||||
|
||||
#include "runtime/handles.hpp"
|
||||
|
||||
class UnregisteredClasses: AllStatic {
|
||||
public:
|
||||
static InstanceKlass* load_class(Symbol* h_name, const char* path, TRAPS);
|
||||
|
||||
private:
|
||||
static Handle create_url_classloader(Symbol* path, TRAPS);
|
||||
static Handle get_url_classloader(Symbol* path, TRAPS);
|
||||
};
|
||||
|
||||
#endif // SHARE_CDS_UNREGISTEREDCLASSES_HPP
|
@ -25,7 +25,6 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "cds/filemap.hpp"
|
||||
#include "classfile/classFileParser.hpp"
|
||||
#include "classfile/classFileStream.hpp"
|
||||
#include "classfile/classLoader.inline.hpp"
|
||||
#include "classfile/classLoaderExt.hpp"
|
||||
#include "classfile/classLoaderData.inline.hpp"
|
||||
@ -33,7 +32,6 @@
|
||||
#include "classfile/klassFactory.hpp"
|
||||
#include "classfile/modules.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "logging/log.hpp"
|
||||
@ -46,9 +44,7 @@
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "services/threadService.hpp"
|
||||
#include "utilities/stringUtils.hpp"
|
||||
|
||||
jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index;
|
||||
@ -250,90 +246,3 @@ void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* resu
|
||||
result->set_shared_classpath_index(classpath_index);
|
||||
result->set_shared_class_loader_type(classloader_type);
|
||||
}
|
||||
|
||||
// Load the class of the given name from the location given by path. The path is specified by
|
||||
// the "source:" in the class list file (see classListParser.cpp), and can be a directory or
|
||||
// a JAR file.
|
||||
InstanceKlass* ClassLoaderExt::load_class(Symbol* name, const char* path, TRAPS) {
|
||||
assert(name != NULL, "invariant");
|
||||
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
|
||||
ResourceMark rm(THREAD);
|
||||
const char* class_name = name->as_C_string();
|
||||
const char* file_name = file_name_for_class_name(class_name,
|
||||
name->utf8_length());
|
||||
assert(file_name != NULL, "invariant");
|
||||
|
||||
// Lookup stream for parsing .class file
|
||||
ClassFileStream* stream = NULL;
|
||||
ClassPathEntry* e = find_classpath_entry_from_cache(THREAD, path);
|
||||
if (e == NULL) {
|
||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||
}
|
||||
|
||||
{
|
||||
PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
|
||||
THREAD->get_thread_stat()->perf_timers_addr(),
|
||||
PerfClassTraceTime::CLASS_LOAD);
|
||||
stream = e->open_stream(THREAD, file_name);
|
||||
}
|
||||
|
||||
if (stream == NULL) {
|
||||
// open_stream could return NULL even when no exception has be thrown (JDK-8263632).
|
||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||
return NULL;
|
||||
}
|
||||
stream->set_verify(true);
|
||||
|
||||
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
|
||||
Handle protection_domain;
|
||||
ClassLoadInfo cl_info(protection_domain);
|
||||
InstanceKlass* k = KlassFactory::create_from_stream(stream,
|
||||
name,
|
||||
loader_data,
|
||||
cl_info,
|
||||
CHECK_NULL);
|
||||
return k;
|
||||
}
|
||||
|
||||
struct CachedClassPathEntry {
|
||||
const char* _path;
|
||||
ClassPathEntry* _entry;
|
||||
};
|
||||
|
||||
static GrowableArray<CachedClassPathEntry>* cached_path_entries = NULL;
|
||||
|
||||
ClassPathEntry* ClassLoaderExt::find_classpath_entry_from_cache(JavaThread* current, const char* path) {
|
||||
// This is called from dump time so it's single threaded and there's no need for a lock.
|
||||
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
|
||||
if (cached_path_entries == NULL) {
|
||||
cached_path_entries = new (ResourceObj::C_HEAP, mtClass) GrowableArray<CachedClassPathEntry>(20, mtClass);
|
||||
}
|
||||
CachedClassPathEntry ccpe;
|
||||
for (int i=0; i<cached_path_entries->length(); i++) {
|
||||
ccpe = cached_path_entries->at(i);
|
||||
if (strcmp(ccpe._path, path) == 0) {
|
||||
if (i != 0) {
|
||||
// Put recent entries at the beginning to speed up searches.
|
||||
cached_path_entries->remove_at(i);
|
||||
cached_path_entries->insert_before(0, ccpe);
|
||||
}
|
||||
return ccpe._entry;
|
||||
}
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (os::stat(path, &st) != 0) {
|
||||
// File or directory not found
|
||||
return NULL;
|
||||
}
|
||||
ClassPathEntry* new_entry = NULL;
|
||||
|
||||
new_entry = create_class_path_entry(current, path, &st, false, false);
|
||||
if (new_entry == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ccpe._path = strdup(path);
|
||||
ccpe._entry = new_entry;
|
||||
cached_path_entries->insert_before(0, ccpe);
|
||||
return new_entry;
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ private:
|
||||
static bool _has_non_jar_in_classpath;
|
||||
|
||||
static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size, bool clean_text);
|
||||
static ClassPathEntry* find_classpath_entry_from_cache(JavaThread* current, const char* path);
|
||||
|
||||
public:
|
||||
static void process_jar_manifest(JavaThread* current, ClassPathEntry* entry, bool check_for_duplicates);
|
||||
@ -113,7 +112,6 @@ public:
|
||||
}
|
||||
|
||||
static void record_result(const s2 classpath_index, InstanceKlass* result);
|
||||
static InstanceKlass* load_class(Symbol* h_name, const char* path, TRAPS);
|
||||
static void set_has_app_classes() {
|
||||
_has_app_classes = true;
|
||||
}
|
||||
|
@ -430,6 +430,7 @@ class UnregisteredClassesTable : public ResourceHashtable<
|
||||
|
||||
static UnregisteredClassesTable* _unregistered_classes_table = NULL;
|
||||
|
||||
// true == class was successfully added; false == a duplicated class (with the same name) already exists.
|
||||
bool SystemDictionaryShared::add_unregistered_class(Thread* current, InstanceKlass* klass) {
|
||||
// We don't allow duplicated unregistered classes with the same name.
|
||||
// We only archive the first class with that name that succeeds putting
|
||||
@ -448,18 +449,6 @@ bool SystemDictionaryShared::add_unregistered_class(Thread* current, InstanceKla
|
||||
return (klass == *v);
|
||||
}
|
||||
|
||||
// true == class was successfully added; false == a duplicated class (with the same name) already exists.
|
||||
bool SystemDictionaryShared::add_unregistered_class_for_static_archive(Thread* current, InstanceKlass* k) {
|
||||
assert(DumpSharedSpaces, "only when dumping");
|
||||
if (add_unregistered_class(current, k)) {
|
||||
MutexLocker mu_r(current, Compile_lock); // add_to_hierarchy asserts this.
|
||||
SystemDictionary::add_to_hierarchy(k);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called to lookup the super/interfaces of shared classes for
|
||||
// unregistered loaders. E.g., SharedClass in the below example
|
||||
// where "super:" (and optionally "interface:") have been specified.
|
||||
|
@ -208,7 +208,6 @@ public:
|
||||
|
||||
static bool is_builtin_loader(ClassLoaderData* loader_data);
|
||||
|
||||
static bool add_unregistered_class_for_static_archive(Thread* current, InstanceKlass* k);
|
||||
static InstanceKlass* lookup_super_for_unregistered_class(Symbol* class_name,
|
||||
Symbol* super_name, bool is_superclass);
|
||||
|
||||
|
@ -135,6 +135,7 @@
|
||||
/* support for CDS */ \
|
||||
do_klass(ByteArrayInputStream_klass, java_io_ByteArrayInputStream ) \
|
||||
do_klass(URL_klass, java_net_URL ) \
|
||||
do_klass(URLClassLoader_klass, java_net_URLClassLoader ) \
|
||||
do_klass(Jar_Manifest_klass, java_util_jar_Manifest ) \
|
||||
do_klass(jdk_internal_loader_BuiltinClassLoader_klass,jdk_internal_loader_BuiltinClassLoader ) \
|
||||
do_klass(jdk_internal_loader_ClassLoaders_klass, jdk_internal_loader_ClassLoaders ) \
|
||||
|
@ -116,6 +116,7 @@
|
||||
template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \
|
||||
template(java_security_SecureClassLoader, "java/security/SecureClassLoader") \
|
||||
template(java_net_URL, "java/net/URL") \
|
||||
template(java_net_URLClassLoader, "java/net/URLClassLoader") \
|
||||
template(java_util_jar_Manifest, "java/util/jar/Manifest") \
|
||||
template(java_io_OutputStream, "java/io/OutputStream") \
|
||||
template(java_io_Reader, "java/io/Reader") \
|
||||
@ -551,6 +552,7 @@
|
||||
template(threadgroup_runnable_void_signature, "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;)V") \
|
||||
template(threadgroup_string_void_signature, "(Ljava/lang/ThreadGroup;Ljava/lang/String;)V") \
|
||||
template(string_class_signature, "(Ljava/lang/String;)Ljava/lang/Class;") \
|
||||
template(string_boolean_class_signature, "(Ljava/lang/String;Z)Ljava/lang/Class;") \
|
||||
template(object_object_object_signature, "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \
|
||||
template(string_string_string_signature, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;") \
|
||||
template(string_string_signature, "(Ljava/lang/String;)Ljava/lang/String;") \
|
||||
@ -709,6 +711,7 @@
|
||||
template(toFileURL_name, "toFileURL") \
|
||||
template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \
|
||||
template(url_void_signature, "(Ljava/net/URL;)V") \
|
||||
template(url_array_classloader_void_signature, "([Ljava/net/URL;Ljava/lang/ClassLoader;)V") \
|
||||
\
|
||||
/*end*/
|
||||
|
||||
|
@ -349,10 +349,6 @@ class InstanceKlass: public Klass {
|
||||
// Check if the class can be shared in CDS
|
||||
bool is_shareable() const;
|
||||
|
||||
void clear_shared_class_loader_type() {
|
||||
_misc_flags &= ~shared_loader_type_bits();
|
||||
}
|
||||
|
||||
bool shared_loading_failed() const {
|
||||
return (_misc_flags & _misc_shared_loading_failed) != 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user