8202750: Reduce the use of get_canonical_path() in CDS

Reviewed-by: minqi, iklam
This commit is contained in:
Calvin Cheung 2021-02-18 02:51:24 +00:00
parent ea5bf45c6f
commit 5f308291a0
3 changed files with 51 additions and 45 deletions

View file

@ -4481,8 +4481,18 @@ bool os::same_files(const char* file1, const char* file2) {
return true; return true;
} }
HANDLE handle1 = create_read_only_file_handle(file1); char* native_file1 = os::strdup(file1);
HANDLE handle2 = create_read_only_file_handle(file2); native_file1 = os::native_path(native_file1);
char* native_file2 = os::strdup(file2);
native_file2 = os::native_path(native_file2);
if (strcmp(native_file1, native_file2) == 0) {
os::free(native_file1);
os::free(native_file2);
return true;
}
HANDLE handle1 = create_read_only_file_handle(native_file1);
HANDLE handle2 = create_read_only_file_handle(native_file2);
bool result = false; bool result = false;
// if we could open both paths... // if we could open both paths...
@ -4509,6 +4519,9 @@ bool os::same_files(const char* file1, const char* file2) {
::CloseHandle(handle2); ::CloseHandle(handle2);
} }
os::free(native_file1);
os::free(native_file2);
return result; return result;
} }

View file

@ -712,6 +712,14 @@ void ClassLoader::add_to_exploded_build_list(Symbol* module_sym, TRAPS) {
} }
} }
jzfile* ClassLoader::open_zip_file(const char* canonical_path, char** error_msg, JavaThread* thread) {
// enable call to C land
ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread);
load_zip_library_if_needed();
return (*ZipOpen)(canonical_path, error_msg);
}
ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st, ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st,
bool throw_exception, bool throw_exception,
bool is_boot_append, bool is_boot_append,
@ -723,8 +731,8 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str
ResourceMark rm(thread); ResourceMark rm(thread);
// Regular file, should be a zip or jimage file // Regular file, should be a zip or jimage file
// Canonicalized filename // Canonicalized filename
char* canonical_path = NEW_RESOURCE_ARRAY_IN_THREAD(thread, char, JVM_MAXPATHLEN); const char* canonical_path = get_canonical_path(path, thread);
if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { if (canonical_path == NULL) {
// This matches the classic VM // This matches the classic VM
if (throw_exception) { if (throw_exception) {
THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL); THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL);
@ -738,14 +746,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str
new_entry = new ClassPathImageEntry(jimage, canonical_path); new_entry = new ClassPathImageEntry(jimage, canonical_path);
} else { } else {
char* error_msg = NULL; char* error_msg = NULL;
jzfile* zip; jzfile* zip = open_zip_file(canonical_path, &error_msg, thread);
{
// enable call to C land
ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread);
load_zip_library_if_needed();
zip = (*ZipOpen)(canonical_path, &error_msg);
}
if (zip != NULL && error_msg == NULL) { if (zip != NULL && error_msg == NULL) {
new_entry = new ClassPathZipEntry(zip, path, is_boot_append, from_class_path_attr); new_entry = new ClassPathZipEntry(zip, path, is_boot_append, from_class_path_attr);
} else { } else {
@ -784,18 +785,12 @@ ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path, bo
struct stat st; struct stat st;
if (os::stat(path, &st) == 0) { if (os::stat(path, &st) == 0) {
if ((st.st_mode & S_IFMT) == S_IFREG) { if ((st.st_mode & S_IFMT) == S_IFREG) {
char canonical_path[JVM_MAXPATHLEN];
if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) {
char* error_msg = NULL;
jzfile* zip;
{
// enable call to C land
JavaThread* thread = JavaThread::current(); JavaThread* thread = JavaThread::current();
ThreadToNativeFromVM ttn(thread); ResourceMark rm(thread);
HandleMark hm(thread); const char* canonical_path = get_canonical_path(path, thread);
load_zip_library_if_needed(); if (canonical_path != NULL) {
zip = (*ZipOpen)(canonical_path, &error_msg); char* error_msg = NULL;
} jzfile* zip = open_zip_file(canonical_path, &error_msg, thread);
if (zip != NULL && error_msg == NULL) { if (zip != NULL && error_msg == NULL) {
// create using canonical path // create using canonical path
return new ClassPathZipEntry(zip, canonical_path, is_boot_append, false); return new ClassPathZipEntry(zip, canonical_path, is_boot_append, false);
@ -1334,25 +1329,22 @@ void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream
PackageEntry* pkg_entry = ik->package(); PackageEntry* pkg_entry = ik->package();
if (FileMapInfo::get_number_of_shared_paths() > 0) { if (FileMapInfo::get_number_of_shared_paths() > 0) {
char* canonical_path_table_entry = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, JVM_MAXPATHLEN); // Save the path from the file: protocol or the module name from the jrt: protocol
// if no protocol prefix is found, path is the same as stream->source(). This path
// save the path from the file: protocol or the module name from the jrt: protocol // must be valid since the class has been successfully parsed.
// if no protocol prefix is found, path is the same as stream->source()
char* path = skip_uri_protocol(src); char* path = skip_uri_protocol(src);
char* canonical_class_src_path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, JVM_MAXPATHLEN); assert(path != NULL, "sanity");
bool success = get_canonical_path(path, canonical_class_src_path, JVM_MAXPATHLEN);
// The path is from the ClassFileStream. Since a ClassFileStream has been created successfully in functions
// such as ClassLoader::load_class(), its source path must be valid.
assert(success, "must be valid path");
for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) { for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) {
SharedClassPathEntry* ent = FileMapInfo::shared_path(i); SharedClassPathEntry* ent = FileMapInfo::shared_path(i);
success = get_canonical_path(ent->name(), canonical_path_table_entry, JVM_MAXPATHLEN);
// A shared path has been validated during its creation in ClassLoader::create_class_path_entry(), // A shared path has been validated during its creation in ClassLoader::create_class_path_entry(),
// it must be valid here. // it must be valid here.
assert(success, "must be valid path"); assert(ent->name() != NULL, "sanity");
// If the path (from the class stream source) is the same as the shared // If the path (from the class stream source) is the same as the shared
// class or module path, then we have a match. // class or module path, then we have a match.
if (strcmp(canonical_path_table_entry, canonical_class_src_path) == 0) { // src may come from the App/Platform class loaders, which would canonicalize
// the file name. We cannot use strcmp to check for equality against ent->name().
// We must use os::same_files (which is faster than canonicalizing ent->name()).
if (os::same_files(ent->name(), path)) {
// NULL pkg_entry and pkg_entry in an unnamed module implies the class // NULL pkg_entry and pkg_entry in an unnamed module implies the class
// is from the -cp or boot loader append path which consists of -Xbootclasspath/a // is from the -cp or boot loader append path which consists of -Xbootclasspath/a
// and jvmti appended entries. // and jvmti appended entries.
@ -1596,18 +1588,18 @@ void ClassLoader::classLoader_init2(TRAPS) {
} }
} }
bool ClassLoader::get_canonical_path(const char* orig, char* out, int len) { char* ClassLoader::get_canonical_path(const char* orig, Thread* thread) {
assert(orig != NULL && out != NULL && len > 0, "bad arguments"); assert(orig != NULL, "bad arguments");
JavaThread* THREAD = JavaThread::current(); // caller needs to allocate ResourceMark for the following output buffer
ResourceMark rm(THREAD); char* canonical_path = NEW_RESOURCE_ARRAY_IN_THREAD(thread, char, JVM_MAXPATHLEN);
ResourceMark rm(thread);
// os::native_path writes into orig_copy // os::native_path writes into orig_copy
char* orig_copy = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(orig)+1); char* orig_copy = NEW_RESOURCE_ARRAY_IN_THREAD(thread, char, strlen(orig)+1);
strcpy(orig_copy, orig); strcpy(orig_copy, orig);
if ((CanonicalizeEntry)(os::native_path(orig_copy), out, len) < 0) { if ((CanonicalizeEntry)(os::native_path(orig_copy), canonical_path, JVM_MAXPATHLEN) < 0) {
return false; return NULL;
} }
return true; return canonical_path;
} }
void ClassLoader::create_javabase() { void ClassLoader::create_javabase() {

View file

@ -255,6 +255,7 @@ class ClassLoader: AllStatic {
static int _libzip_loaded; // used to sync loading zip. static int _libzip_loaded; // used to sync loading zip.
static void release_load_zip_library(); static void release_load_zip_library();
static inline void load_zip_library_if_needed(); static inline void load_zip_library_if_needed();
static jzfile* open_zip_file(const char* canonical_path, char** error_msg, JavaThread* thread);
public: public:
static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st, static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st,
@ -264,7 +265,7 @@ class ClassLoader: AllStatic {
// Canonicalizes path names, so strcmp will work properly. This is mainly // Canonicalizes path names, so strcmp will work properly. This is mainly
// to avoid confusing the zip library // to avoid confusing the zip library
static bool get_canonical_path(const char* orig, char* out, int len); static char* get_canonical_path(const char* orig, Thread* thread);
static const char* file_name_for_class_name(const char* class_name, static const char* file_name_for_class_name(const char* class_name,
int class_name_len); int class_name_len);
static PackageEntry* get_package_entry(Symbol* pkg_name, ClassLoaderData* loader_data); static PackageEntry* get_package_entry(Symbol* pkg_name, ClassLoaderData* loader_data);