From 2d886b2de3f0c46f4fb8c00f7b952e9db38c505b Mon Sep 17 00:00:00 2001 From: iklam Date: Mon, 13 Oct 2014 16:09:57 -0700 Subject: [PATCH] 8061651: Interface to the Lookup Index Cache to improve URLClassPath search time Summary: Implemented the interface in sun.misc.URLClassPath and corresponding JVM_XXX APIs Reviewed-by: mchung, acorn, jiangli, dholmes --- make/bsd/makefiles/mapfile-vers-debug | 3 ++ make/bsd/makefiles/mapfile-vers-product | 3 ++ make/linux/makefiles/mapfile-vers-debug | 3 ++ make/linux/makefiles/mapfile-vers-product | 3 ++ make/solaris/makefiles/mapfile-vers | 3 ++ src/share/vm/classfile/classLoader.cpp | 10 ++++- src/share/vm/classfile/classLoader.hpp | 8 +++- src/share/vm/classfile/classLoaderExt.hpp | 9 +++++ src/share/vm/classfile/systemDictionary.hpp | 2 + src/share/vm/classfile/vmSymbols.hpp | 1 + src/share/vm/memory/metadataFactory.hpp | 6 +++ src/share/vm/memory/metaspaceShared.cpp | 8 ++++ src/share/vm/memory/metaspaceShared.hpp | 6 +-- src/share/vm/prims/jvm.cpp | 39 +++++++++++++++++++ src/share/vm/prims/jvm.h | 25 ++++++++++++ src/share/vm/prims/whitebox.cpp | 27 +++++++++++++ .../whitebox/sun/hotspot/WhiteBox.java | 6 +++ 17 files changed, 155 insertions(+), 7 deletions(-) diff --git a/make/bsd/makefiles/mapfile-vers-debug b/make/bsd/makefiles/mapfile-vers-debug index 44991d202..a94bf88dd 100644 --- a/make/bsd/makefiles/mapfile-vers-debug +++ b/make/bsd/makefiles/mapfile-vers-debug @@ -187,6 +187,9 @@ _JVM_IsSupportedJNIVersion _JVM_IsThreadAlive _JVM_IsVMGeneratedMethodIx + _JVM_KnownToNotExist + _JVM_GetResourceLookupCacheURLs + _JVM_GetResourceLookupCache _JVM_LatestUserDefinedLoader _JVM_Listen _JVM_LoadClass0 diff --git a/make/bsd/makefiles/mapfile-vers-product b/make/bsd/makefiles/mapfile-vers-product index ed15428ab..6be804272 100644 --- a/make/bsd/makefiles/mapfile-vers-product +++ b/make/bsd/makefiles/mapfile-vers-product @@ -187,6 +187,9 @@ _JVM_IsSupportedJNIVersion _JVM_IsThreadAlive _JVM_IsVMGeneratedMethodIx + _JVM_KnownToNotExist + _JVM_GetResourceLookupCacheURLs + _JVM_GetResourceLookupCache _JVM_LatestUserDefinedLoader _JVM_Listen _JVM_LoadClass0 diff --git a/make/linux/makefiles/mapfile-vers-debug b/make/linux/makefiles/mapfile-vers-debug index d20eb1eec..2da4b7d9a 100644 --- a/make/linux/makefiles/mapfile-vers-debug +++ b/make/linux/makefiles/mapfile-vers-debug @@ -217,6 +217,9 @@ SUNWprivate_1.1 { JVM_RegisterSignal; JVM_ReleaseUTF; JVM_ResolveClass; + JVM_KnownToNotExist; + JVM_GetResourceLookupCacheURLs; + JVM_GetResourceLookupCache; JVM_ResumeThread; JVM_Send; JVM_SendTo; diff --git a/make/linux/makefiles/mapfile-vers-product b/make/linux/makefiles/mapfile-vers-product index 976ea1bd9..4ec3d5bf8 100644 --- a/make/linux/makefiles/mapfile-vers-product +++ b/make/linux/makefiles/mapfile-vers-product @@ -217,6 +217,9 @@ SUNWprivate_1.1 { JVM_RegisterSignal; JVM_ReleaseUTF; JVM_ResolveClass; + JVM_KnownToNotExist; + JVM_GetResourceLookupCacheURLs; + JVM_GetResourceLookupCache; JVM_ResumeThread; JVM_Send; JVM_SendTo; diff --git a/make/solaris/makefiles/mapfile-vers b/make/solaris/makefiles/mapfile-vers index f25b06119..7ebaaaad1 100644 --- a/make/solaris/makefiles/mapfile-vers +++ b/make/solaris/makefiles/mapfile-vers @@ -189,6 +189,9 @@ SUNWprivate_1.1 { JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; JVM_IsVMGeneratedMethodIx; + JVM_KnownToNotExist; + JVM_GetResourceLookupCacheURLs; + JVM_GetResourceLookupCache; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff --git a/src/share/vm/classfile/classLoader.cpp b/src/share/vm/classfile/classLoader.cpp index eab14700a..9b13e6dd3 100644 --- a/src/share/vm/classfile/classLoader.cpp +++ b/src/share/vm/classfile/classLoader.cpp @@ -610,7 +610,7 @@ bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) { } #endif -void ClassLoader::setup_search_path(const char *class_path) { +void ClassLoader::setup_search_path(const char *class_path, bool canonicalize) { int offset = 0; int len = (int)strlen(class_path); int end = 0; @@ -625,7 +625,13 @@ void ClassLoader::setup_search_path(const char *class_path) { char* path = NEW_RESOURCE_ARRAY(char, end - start + 1); strncpy(path, &class_path[start], end - start); path[end - start] = '\0'; - update_class_path_entry_list(path, false); + if (canonicalize) { + char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN + 1); + if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { + path = canonical_path; + } + } + update_class_path_entry_list(path, /*check_for_duplicates=*/canonicalize); #if INCLUDE_CDS if (DumpSharedSpaces) { check_shared_classpath(path); diff --git a/src/share/vm/classfile/classLoader.hpp b/src/share/vm/classfile/classLoader.hpp index 7c12f84e8..38063e1a4 100644 --- a/src/share/vm/classfile/classLoader.hpp +++ b/src/share/vm/classfile/classLoader.hpp @@ -129,8 +129,8 @@ class LazyClassPathEntry: public ClassPathEntry { bool _has_error; bool _throw_exception; volatile ClassPathEntry* _resolved_entry; - ClassPathEntry* resolve_entry(TRAPS); public: + ClassPathEntry* resolve_entry(TRAPS); bool is_jar_file(); const char* name() { return _path; } LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception); @@ -218,7 +218,7 @@ class ClassLoader: AllStatic { static void setup_meta_index(const char* meta_index_path, const char* meta_index_dir, int start_index); static void setup_bootstrap_search_path(); - static void setup_search_path(const char *class_path); + static void setup_search_path(const char *class_path, bool canonicalize=false); static void load_zip_library(); static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st, @@ -329,6 +329,10 @@ class ClassLoader: AllStatic { return e; } + static int num_classpath_entries() { + return _num_entries; + } + #if INCLUDE_CDS // Sharing dump and restore static void copy_package_info_buckets(char** top, char* end); diff --git a/src/share/vm/classfile/classLoaderExt.hpp b/src/share/vm/classfile/classLoaderExt.hpp index ee2e0ec68..677242594 100644 --- a/src/share/vm/classfile/classLoaderExt.hpp +++ b/src/share/vm/classfile/classLoaderExt.hpp @@ -64,6 +64,15 @@ public: ClassLoader::add_to_list(new_entry); } static void setup_search_paths() {} + + static void init_lookup_cache(TRAPS) {} + static void copy_lookup_cache_to_archive(char** top, char* end) {} + static char* restore_lookup_cache_from_archive(char* buffer) {return buffer;} + static inline bool is_lookup_cache_enabled() {return false;} + + static bool known_to_not_exist(JNIEnv *env, jobject loader, const char *classname, TRAPS) {return false;} + static jobjectArray get_lookup_cache_urls(JNIEnv *env, jobject loader, TRAPS) {return NULL;} + static jintArray get_lookup_cache(JNIEnv *env, jobject loader, const char *pkgname, TRAPS) {return NULL;} }; #endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp index 2c21e9db6..bbd350086 100644 --- a/src/share/vm/classfile/systemDictionary.hpp +++ b/src/share/vm/classfile/systemDictionary.hpp @@ -175,6 +175,8 @@ class Ticks; do_klass(URL_klass, java_net_URL, Pre ) \ do_klass(Jar_Manifest_klass, java_util_jar_Manifest, Pre ) \ do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \ + do_klass(sun_misc_Launcher_AppClassLoader_klass, sun_misc_Launcher_AppClassLoader, Pre ) \ + do_klass(sun_misc_Launcher_ExtClassLoader_klass, sun_misc_Launcher_ExtClassLoader, Pre ) \ do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \ \ /* It's NULL in non-1.4 JDKs. */ \ diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp index 168ad7787..1b3b50c7f 100644 --- a/src/share/vm/classfile/vmSymbols.hpp +++ b/src/share/vm/classfile/vmSymbols.hpp @@ -116,6 +116,7 @@ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \ + template(sun_misc_Launcher_AppClassLoader, "sun/misc/Launcher$AppClassLoader") \ template(sun_misc_Launcher_ExtClassLoader, "sun/misc/Launcher$ExtClassLoader") \ \ /* Java runtime version access */ \ diff --git a/src/share/vm/memory/metadataFactory.hpp b/src/share/vm/memory/metadataFactory.hpp index 0f9936802..0c8d3ba63 100644 --- a/src/share/vm/memory/metadataFactory.hpp +++ b/src/share/vm/memory/metadataFactory.hpp @@ -64,6 +64,12 @@ class MetadataFactory : AllStatic { template static void free_array(ClassLoaderData* loader_data, Array* data) { + if (DumpSharedSpaces) { + // FIXME: the freeing code is buggy, especially when PrintSharedSpaces is enabled. + // Disable for now -- this means if you specify bad classes in your classlist you + // may have wasted space inside the archive. + return; + } if (data != NULL) { assert(loader_data != NULL, "shouldn't pass null"); assert(!data->is_shared(), "cannot deallocate array in shared spaces"); diff --git a/src/share/vm/memory/metaspaceShared.cpp b/src/share/vm/memory/metaspaceShared.cpp index 4f9d4c337..bc64ceacc 100644 --- a/src/share/vm/memory/metaspaceShared.cpp +++ b/src/share/vm/memory/metaspaceShared.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/dictionary.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" #include "classfile/sharedClassUtil.hpp" @@ -39,6 +40,7 @@ #include "runtime/signature.hpp" #include "runtime/vm_operations.hpp" #include "runtime/vmThread.hpp" +#include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -533,6 +535,8 @@ void VM_PopulateDumpSharedSpace::doit() { ClassLoader::copy_package_info_table(&md_top, md_end); ClassLoader::verify(); + ClassLoaderExt::copy_lookup_cache_to_archive(&md_top, md_end); + // Write the other data to the output array. WriteClosure wc(md_top, md_end); MetaspaceShared::serialize(&wc); @@ -745,6 +749,8 @@ void MetaspaceShared::preload_and_dump(TRAPS) { } tty->print_cr("Loading classes to share: done."); + ClassLoaderExt::init_lookup_cache(THREAD); + if (PrintSharedSpaces) { tty->print_cr("Shared spaces: preloaded %d classes", class_count); } @@ -1056,6 +1062,8 @@ void MetaspaceShared::initialize_shared_spaces() { buffer += sizeof(intptr_t); buffer += len; + buffer = ClassLoaderExt::restore_lookup_cache_from_archive(buffer); + intptr_t* array = (intptr_t*)buffer; ReadClosure rc(&array); serialize(&rc); diff --git a/src/share/vm/memory/metaspaceShared.hpp b/src/share/vm/memory/metaspaceShared.hpp index db3443590..837625b7d 100644 --- a/src/share/vm/memory/metaspaceShared.hpp +++ b/src/share/vm/memory/metaspaceShared.hpp @@ -32,9 +32,9 @@ #define LargeSharedArchiveSize (300*M) #define HugeSharedArchiveSize (800*M) -#define ReadOnlyRegionPercentage 0.4 -#define ReadWriteRegionPercentage 0.55 -#define MiscDataRegionPercentage 0.03 +#define ReadOnlyRegionPercentage 0.39 +#define ReadWriteRegionPercentage 0.50 +#define MiscDataRegionPercentage 0.09 #define MiscCodeRegionPercentage 0.02 #define LargeThresholdClassCount 5000 #define HugeThresholdClassCount 40000 diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp index acbbfc97c..070bf88a5 100644 --- a/src/share/vm/prims/jvm.cpp +++ b/src/share/vm/prims/jvm.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" @@ -393,6 +394,14 @@ JVM_ENTRY(jobject, JVM_InitProperties(JNIEnv *env, jobject properties)) } } + const char* enableSharedLookupCache = "false"; +#if INCLUDE_CDS + if (ClassLoaderExt::is_lookup_cache_enabled()) { + enableSharedLookupCache = "true"; + } +#endif + PUTPROP(props, "sun.cds.enableSharedLookupCache", enableSharedLookupCache); + return properties; JVM_END @@ -766,6 +775,36 @@ JVM_ENTRY(void, JVM_ResolveClass(JNIEnv* env, jclass cls)) JVM_END +JVM_ENTRY(jboolean, JVM_KnownToNotExist(JNIEnv *env, jobject loader, const char *classname)) + JVMWrapper("JVM_KnownToNotExist"); +#if INCLUDE_CDS + return ClassLoaderExt::known_to_not_exist(env, loader, classname, CHECK_(false)); +#else + return false; +#endif +JVM_END + + +JVM_ENTRY(jobjectArray, JVM_GetResourceLookupCacheURLs(JNIEnv *env, jobject loader)) + JVMWrapper("JVM_GetResourceLookupCacheURLs"); +#if INCLUDE_CDS + return ClassLoaderExt::get_lookup_cache_urls(env, loader, CHECK_NULL); +#else + return NULL; +#endif +JVM_END + + +JVM_ENTRY(jintArray, JVM_GetResourceLookupCache(JNIEnv *env, jobject loader, const char *resource_name)) + JVMWrapper("JVM_GetResourceLookupCache"); +#if INCLUDE_CDS + return ClassLoaderExt::get_lookup_cache(env, loader, resource_name, CHECK_NULL); +#else + return NULL; +#endif +JVM_END + + // Returns a class loaded by the bootstrap class loader; or null // if not found. ClassNotFoundException is not thrown. // diff --git a/src/share/vm/prims/jvm.h b/src/share/vm/prims/jvm.h index 5da3e25b1..3b36b73ab 100644 --- a/src/share/vm/prims/jvm.h +++ b/src/share/vm/prims/jvm.h @@ -1548,6 +1548,31 @@ JVM_GetThreadStateValues(JNIEnv* env, jint javaThreadState); JNIEXPORT jobjectArray JNICALL JVM_GetThreadStateNames(JNIEnv* env, jint javaThreadState, jintArray values); +/* + * Returns true if the JVM's lookup cache indicates that this class is + * known to NOT exist for the given loader. + */ +JNIEXPORT jboolean JNICALL +JVM_KnownToNotExist(JNIEnv *env, jobject loader, const char *classname); + +/* + * Returns an array of all URLs that are stored in the JVM's lookup cache + * for the given loader. NULL if the lookup cache is unavailable. + */ +JNIEXPORT jobjectArray JNICALL +JVM_GetResourceLookupCacheURLs(JNIEnv *env, jobject loader); + +/* + * Returns an array of all URLs that *may* contain the resource_name for the + * given loader. This function returns an integer array, each element + * of which can be used to index into the array returned by + * JVM_GetResourceLookupCacheURLs of the same loader to determine the + * URLs. + */ +JNIEXPORT jintArray JNICALL +JVM_GetResourceLookupCache(JNIEnv *env, jobject loader, const char *resource_name); + + /* ========================================================================= * The following defines a private JVM interface that the JDK can query * for the JVM version and capabilities. sun.misc.Version defines diff --git a/src/share/vm/prims/whitebox.cpp b/src/share/vm/prims/whitebox.cpp index e2934f52b..f0024396e 100644 --- a/src/share/vm/prims/whitebox.cpp +++ b/src/share/vm/prims/whitebox.cpp @@ -104,6 +104,28 @@ WB_ENTRY(jboolean, WB_IsClassAlive(JNIEnv* env, jobject target, jstring name)) return closure.found(); WB_END +WB_ENTRY(jboolean, WB_ClassKnownToNotExist(JNIEnv* env, jobject o, jobject loader, jstring name)) + ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI + const char* class_name = env->GetStringUTFChars(name, NULL); + jboolean result = JVM_KnownToNotExist(env, loader, class_name); + env->ReleaseStringUTFChars(name, class_name); + return result; +WB_END + +WB_ENTRY(jobjectArray, WB_GetLookupCacheURLs(JNIEnv* env, jobject o, jobject loader)) + ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI + return JVM_GetResourceLookupCacheURLs(env, loader); +WB_END + +WB_ENTRY(jintArray, WB_GetLookupCacheMatches(JNIEnv* env, jobject o, jobject loader, jstring name)) + ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI + const char* resource_name = env->GetStringUTFChars(name, NULL); + jintArray result = JVM_GetResourceLookupCache(env, loader, resource_name); + + env->ReleaseStringUTFChars(name, resource_name); + return result; +WB_END + WB_ENTRY(jlong, WB_GetCompressedOopsMaxHeapSize(JNIEnv* env, jobject o)) { return (jlong)Arguments::max_heap_for_compressed_oops(); } @@ -939,6 +961,11 @@ static JNINativeMethod methods[] = { {CC"isObjectInOldGen", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen }, {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, + {CC"classKnownToNotExist", + CC"(Ljava/lang/ClassLoader;Ljava/lang/String;)Z",(void*)&WB_ClassKnownToNotExist}, + {CC"getLookupCacheURLs", CC"(Ljava/lang/ClassLoader;)[Ljava/net/URL;", (void*)&WB_GetLookupCacheURLs}, + {CC"getLookupCacheMatches", CC"(Ljava/lang/ClassLoader;Ljava/lang/String;)[I", + (void*)&WB_GetLookupCacheMatches}, {CC"parseCommandLine", CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", (void*) &WB_ParseCommandLine diff --git a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java index 02009ba34..e341959a6 100644 --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.function.Function; import java.util.stream.Stream; import java.security.BasicPermission; +import java.net.URL; import sun.hotspot.parser.DiagnosticCommand; @@ -84,6 +85,11 @@ public class WhiteBox { } private native boolean isClassAlive0(String name); + // Resource/Class Lookup Cache + public native boolean classKnownToNotExist(ClassLoader loader, String name); + public native URL[] getLookupCacheURLs(ClassLoader loader); + public native int[] getLookupCacheMatches(ClassLoader loader, String name); + // G1 public native boolean g1InConcurrentMark(); public native boolean g1IsHumongous(Object o); -- GitLab