changeset 7919:4cb90023bf2b

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
author iklam
date Mon, 13 Oct 2014 16:09:57 -0700
parents f5f752e74840
children d4562805b030
files make/bsd/makefiles/mapfile-vers-debug make/bsd/makefiles/mapfile-vers-product make/linux/makefiles/mapfile-vers-debug make/linux/makefiles/mapfile-vers-product make/solaris/makefiles/mapfile-vers src/share/vm/classfile/classLoader.cpp src/share/vm/classfile/classLoader.hpp src/share/vm/classfile/classLoaderExt.hpp src/share/vm/classfile/systemDictionary.hpp src/share/vm/classfile/vmSymbols.hpp src/share/vm/memory/metadataFactory.hpp src/share/vm/memory/metaspaceShared.cpp src/share/vm/memory/metaspaceShared.hpp src/share/vm/prims/jvm.cpp src/share/vm/prims/jvm.h src/share/vm/prims/whitebox.cpp test/testlibrary/whitebox/sun/hotspot/WhiteBox.java
diffstat 17 files changed, 155 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/make/bsd/makefiles/mapfile-vers-debug	Tue Oct 28 09:17:36 2014 +0100
+++ b/make/bsd/makefiles/mapfile-vers-debug	Mon Oct 13 16:09:57 2014 -0700
@@ -187,6 +187,9 @@
                 _JVM_IsSupportedJNIVersion
                 _JVM_IsThreadAlive
                 _JVM_IsVMGeneratedMethodIx
+                _JVM_KnownToNotExist
+                _JVM_GetResourceLookupCacheURLs
+                _JVM_GetResourceLookupCache
                 _JVM_LatestUserDefinedLoader
                 _JVM_Listen
                 _JVM_LoadClass0
--- a/make/bsd/makefiles/mapfile-vers-product	Tue Oct 28 09:17:36 2014 +0100
+++ b/make/bsd/makefiles/mapfile-vers-product	Mon Oct 13 16:09:57 2014 -0700
@@ -187,6 +187,9 @@
                 _JVM_IsSupportedJNIVersion
                 _JVM_IsThreadAlive
                 _JVM_IsVMGeneratedMethodIx
+                _JVM_KnownToNotExist
+                _JVM_GetResourceLookupCacheURLs
+                _JVM_GetResourceLookupCache
                 _JVM_LatestUserDefinedLoader
                 _JVM_Listen
                 _JVM_LoadClass0
--- a/make/linux/makefiles/mapfile-vers-debug	Tue Oct 28 09:17:36 2014 +0100
+++ b/make/linux/makefiles/mapfile-vers-debug	Mon Oct 13 16:09:57 2014 -0700
@@ -217,6 +217,9 @@
                 JVM_RegisterSignal;
                 JVM_ReleaseUTF;
                 JVM_ResolveClass;
+                JVM_KnownToNotExist;
+                JVM_GetResourceLookupCacheURLs;
+                JVM_GetResourceLookupCache;
                 JVM_ResumeThread;
                 JVM_Send;
                 JVM_SendTo;
--- a/make/linux/makefiles/mapfile-vers-product	Tue Oct 28 09:17:36 2014 +0100
+++ b/make/linux/makefiles/mapfile-vers-product	Mon Oct 13 16:09:57 2014 -0700
@@ -217,6 +217,9 @@
                 JVM_RegisterSignal;
                 JVM_ReleaseUTF;
                 JVM_ResolveClass;
+                JVM_KnownToNotExist;
+                JVM_GetResourceLookupCacheURLs;
+                JVM_GetResourceLookupCache;
                 JVM_ResumeThread;
                 JVM_Send;
                 JVM_SendTo;
--- a/make/solaris/makefiles/mapfile-vers	Tue Oct 28 09:17:36 2014 +0100
+++ b/make/solaris/makefiles/mapfile-vers	Mon Oct 13 16:09:57 2014 -0700
@@ -189,6 +189,9 @@
                 JVM_IsSupportedJNIVersion;
                 JVM_IsThreadAlive;
                 JVM_IsVMGeneratedMethodIx;
+                JVM_KnownToNotExist;
+                JVM_GetResourceLookupCacheURLs;
+                JVM_GetResourceLookupCache;
                 JVM_LatestUserDefinedLoader;
                 JVM_Listen;
                 JVM_LoadClass0;
--- a/src/share/vm/classfile/classLoader.cpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/classfile/classLoader.cpp	Mon Oct 13 16:09:57 2014 -0700
@@ -610,7 +610,7 @@
 }
 #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 @@
     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);
--- a/src/share/vm/classfile/classLoader.hpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/classfile/classLoader.hpp	Mon Oct 13 16:09:57 2014 -0700
@@ -129,8 +129,8 @@
   bool _has_error;
   bool _throw_exception;
   volatile ClassPathEntry* _resolved_entry;
+ public:
   ClassPathEntry* resolve_entry(TRAPS);
- public:
   bool is_jar_file();
   const char* name()  { return _path; }
   LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception);
@@ -218,7 +218,7 @@
   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 @@
     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);
--- a/src/share/vm/classfile/classLoaderExt.hpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/classfile/classLoaderExt.hpp	Mon Oct 13 16:09:57 2014 -0700
@@ -64,6 +64,15 @@
     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
--- a/src/share/vm/classfile/systemDictionary.hpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Mon Oct 13 16:09:57 2014 -0700
@@ -175,6 +175,8 @@
   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. */                                                                                       \
--- a/src/share/vm/classfile/vmSymbols.hpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Mon Oct 13 16:09:57 2014 -0700
@@ -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 */                                                               \
--- a/src/share/vm/memory/metadataFactory.hpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/memory/metadataFactory.hpp	Mon Oct 13 16:09:57 2014 -0700
@@ -64,6 +64,12 @@
 
   template <typename T>
   static void free_array(ClassLoaderData* loader_data, Array<T>* 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");
--- a/src/share/vm/memory/metaspaceShared.cpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/memory/metaspaceShared.cpp	Mon Oct 13 16:09:57 2014 -0700
@@ -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 @@
   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 @@
   }
   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 @@
   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);
--- a/src/share/vm/memory/metaspaceShared.hpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/memory/metaspaceShared.hpp	Mon Oct 13 16:09:57 2014 -0700
@@ -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
--- a/src/share/vm/prims/jvm.cpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/prims/jvm.cpp	Mon Oct 13 16:09:57 2014 -0700
@@ -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 @@
     }
   }
 
+  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_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.
 //
--- a/src/share/vm/prims/jvm.h	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/prims/jvm.h	Mon Oct 13 16:09:57 2014 -0700
@@ -1548,6 +1548,31 @@
 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
--- a/src/share/vm/prims/whitebox.cpp	Tue Oct 28 09:17:36 2014 +0100
+++ b/src/share/vm/prims/whitebox.cpp	Mon Oct 13 16:09:57 2014 -0700
@@ -104,6 +104,28 @@
   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 @@
   {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
--- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Tue Oct 28 09:17:36 2014 +0100
+++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Mon Oct 13 16:09:57 2014 -0700
@@ -30,6 +30,7 @@
 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 @@
   }
   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);