src/hotspot/share/classfile/classLoader.cpp
changeset 47991 a474466c4fdb
parent 47765 b7c7428eaab9
child 48011 dac108a7b06a
--- a/src/hotspot/share/classfile/classLoader.cpp	Fri Nov 17 20:56:14 2017 +0300
+++ b/src/hotspot/share/classfile/classLoader.cpp	Sun Nov 19 23:30:41 2017 -0500
@@ -145,9 +145,9 @@
 ClassPathEntry* ClassLoader::_jrt_entry = NULL;
 ClassPathEntry* ClassLoader::_first_append_entry = NULL;
 ClassPathEntry* ClassLoader::_last_append_entry  = NULL;
-int             ClassLoader::_num_entries        = 0;
-int             ClassLoader::_num_boot_entries   = -1;
 #if INCLUDE_CDS
+ClassPathEntry* ClassLoader::_app_classpath_entries = NULL;
+ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL;
 GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL;
 GrowableArray<char*>* ClassLoader::_platform_modules_array = NULL;
 SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
@@ -660,20 +660,18 @@
 
 void ClassLoader::setup_bootstrap_search_path() {
   const char* sys_class_path = Arguments::get_sysclasspath();
-  const char* java_class_path = Arguments::get_appclasspath();
   if (PrintSharedArchiveAndExit) {
     // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily
     // the same as the bootcp of the shared archive.
   } else {
     trace_class_path("bootstrap loader class path=", sys_class_path);
-    trace_class_path("classpath: ", java_class_path);
   }
 #if INCLUDE_CDS
   if (DumpSharedSpaces) {
     _shared_paths_misc_info->add_boot_classpath(sys_class_path);
   }
 #endif
-  setup_search_path(sys_class_path, true);
+  setup_boot_search_path(sys_class_path);
 }
 
 #if INCLUDE_CDS
@@ -691,6 +689,36 @@
   delete checker;
   return result;
 }
+
+void ClassLoader::setup_app_search_path(const char *class_path) {
+
+  assert(DumpSharedSpaces, "Sanity");
+
+  Thread* THREAD = Thread::current();
+  int len = (int)strlen(class_path);
+  int end = 0;
+
+  // Iterate over class path entries
+  for (int start = 0; start < len; start = end) {
+    while (class_path[end] && class_path[end] != os::path_separator()[0]) {
+      end++;
+    }
+    EXCEPTION_MARK;
+    ResourceMark rm(THREAD);
+    char* path = NEW_RESOURCE_ARRAY(char, end - start + 1);
+    strncpy(path, &class_path[start], end - start);
+    path[end - start] = '\0';
+
+    check_shared_classpath(path);
+
+    update_class_path_entry_list(path, false, false);
+
+    while (class_path[end] == os::path_separator()[0]) {
+      end++;
+    }
+  }
+}
+
 #endif
 
 // Construct the array of module/path pairs as specified to --patch-module
@@ -764,10 +792,11 @@
   return false;
 }
 
-void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_search) {
+// Set up the _jrt_entry if present and boot append path
+void ClassLoader::setup_boot_search_path(const char *class_path) {
   int len = (int)strlen(class_path);
   int end = 0;
-  bool set_base_piece = bootstrap_search;
+  bool set_base_piece = true;
 
   // Iterate over class path entries
   for (int start = 0; start < len; start = end) {
@@ -780,10 +809,10 @@
     strncpy(path, &class_path[start], end - start);
     path[end - start] = '\0';
 
-    // The first time through the bootstrap_search setup, it must be determined
-    // what the base or core piece of the boot loader search is.  Either a java runtime
-    // image is present or this is an exploded module build situation.
     if (set_base_piece) {
+      // The first time through the bootstrap_search setup, it must be determined
+      // what the base or core piece of the boot loader search is.  Either a java runtime
+      // image is present or this is an exploded module build situation.
       assert(string_ends_with(path, MODULES_IMAGE_NAME) || string_ends_with(path, JAVA_BASE_NAME),
              "Incorrect boot loader search path, no java runtime image or " JAVA_BASE_NAME " exploded build");
       struct stat st;
@@ -797,13 +826,7 @@
           assert(_jrt_entry == NULL, "should not setup bootstrap class search path twice");
           assert(new_entry != NULL && new_entry->is_modules_image(), "No java runtime image present");
           _jrt_entry = new_entry;
-          ++_num_entries;
-#if INCLUDE_CDS
-          if (DumpSharedSpaces) {
-            JImageFile *jimage = _jrt_entry->jimage();
-            assert(jimage != NULL, "No java runtime image file present");
-          }
-#endif
+          assert(_jrt_entry->jimage() != NULL, "No java runtime image");
         }
       } else {
         // If path does not exist, exit
@@ -813,7 +836,7 @@
     } else {
       // Every entry on the system boot class path after the initial base piece,
       // which is set by os::set_boot_path(), is considered an appended entry.
-      update_class_path_entry_list(path, false, bootstrap_search);
+      update_class_path_entry_list(path, false, true);
     }
 
 #if INCLUDE_CDS
@@ -968,7 +991,7 @@
   return false;
 }
 
-void ClassLoader::add_to_list(ClassPathEntry *new_entry) {
+void ClassLoader::add_to_boot_append_entries(ClassPathEntry *new_entry) {
   if (new_entry != NULL) {
     if (_last_append_entry == NULL) {
       assert(_first_append_entry == NULL, "boot loader's append class path entry list not empty");
@@ -978,11 +1001,48 @@
       _last_append_entry = new_entry;
     }
   }
-  _num_entries++;
 }
 
-void ClassLoader::add_to_list(const char *apath) {
-  update_class_path_entry_list((char*)apath, false, false);
+// Record the path entries specified in -cp during dump time. The recorded
+// information will be used at runtime for loading the archived app classes.
+//
+// Note that at dump time, ClassLoader::_app_classpath_entries are NOT used for
+// loading app classes. Instead, the app class are loaded by the
+// jdk/internal/loader/ClassLoaders$AppClassLoader instance.
+void ClassLoader::add_to_app_classpath_entries(const char* path,
+                                               ClassPathEntry* entry,
+                                               bool check_for_duplicates) {
+#if INCLUDE_CDS
+  assert(entry != NULL, "ClassPathEntry should not be NULL");
+  ClassPathEntry* e = _app_classpath_entries;
+  if (check_for_duplicates) {
+    while (e != NULL) {
+      if (strcmp(e->name(), entry->name()) == 0) {
+        // entry already exists
+        return;
+      }
+      e = e->next();
+    }
+  }
+
+  // The entry does not exist, add to the list
+  if (_app_classpath_entries == NULL) {
+    assert(_last_app_classpath_entry == NULL, "Sanity");
+    _app_classpath_entries = _last_app_classpath_entry = entry;
+  } else {
+    _last_app_classpath_entry->set_next(entry);
+    _last_app_classpath_entry = entry;
+  }
+
+  if (entry->is_jar_file()) {
+    ClassLoaderExt::process_jar_manifest(entry, check_for_duplicates);
+  } else {
+    if (!os::dir_is_empty(path)) {
+      tty->print_cr("Error: non-empty directory '%s'", path);
+      exit_with_path_failure("Cannot have non-empty directory in app classpaths", NULL);
+    }
+  }
+#endif
 }
 
 // Returns true IFF the file/dir exists and the entry was successfully created.
@@ -1002,8 +1062,10 @@
 
     // Do not reorder the bootclasspath which would break get_system_package().
     // Add new entry to linked list
-    if (!check_for_duplicates || !contains_append_entry(new_entry->name())) {
-      ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry);
+    if (is_boot_append) {
+      add_to_boot_append_entries(new_entry);
+    } else {
+      add_to_app_classpath_entries(path, new_entry, check_for_duplicates);
     }
     return true;
   } else {
@@ -1323,6 +1385,7 @@
   return NULL;
 }
 
+// Called by the boot classloader to load classes
 InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS) {
   assert(name != NULL, "invariant");
   assert(THREAD->is_Java_thread(), "must be a JavaThread");
@@ -1402,11 +1465,6 @@
 
     e = _first_append_entry;
     while (e != NULL) {
-      if (DumpSharedSpaces && classpath_index >= _num_boot_entries) {
-        // Do not load any class from the app classpath using the boot loader. Let
-        // the built-in app class laoder load them.
-        break;
-      }
       stream = e->open_stream(file_name, CHECK_NULL);
       if (!context.check(stream, classpath_index)) {
         return NULL;
@@ -1442,7 +1500,11 @@
     return NULL;
   }
 
-  return context.record_result(name, e, classpath_index, result, THREAD);
+  if (!add_package(file_name, classpath_index, THREAD)) {
+    return NULL;
+  }
+
+  return result;
 }
 
 #if INCLUDE_CDS
@@ -1465,7 +1527,9 @@
   return source;
 }
 
-void ClassLoader::record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream) {
+// Record the shared classpath index and loader type for classes loaded
+// by the builtin loaders at dump time.
+void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream) {
   assert(DumpSharedSpaces, "sanity");
   assert(stream != NULL, "sanity");
 
@@ -1474,7 +1538,8 @@
     return;
   }
 
-  if (stream->source() == NULL) {
+  char* src = (char*)stream->source();
+  if (src == NULL) {
     if (ik->class_loader() == NULL) {
       // JFR classes
       ik->set_shared_classpath_index(0);
@@ -1486,56 +1551,42 @@
   assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build");
 
   ModuleEntry* module = ik->module();
-  ClassPathEntry* e = NULL;
-  int classpath_index = 0;
+  int classpath_index = -1;
+  ResourceMark rm;
+  char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
 
-  // Check if the class is from the runtime image
-  if (module != NULL && (module->location() != NULL) &&
-      (module->location()->starts_with("jrt:"))) {
-    e = _jrt_entry;
-    classpath_index = 0;
-  } else {
-    classpath_index = 1;
-    ResourceMark rm;
-    char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
-    for (e = _first_append_entry; e != NULL; e = e->next()) {
-      if (get_canonical_path(e->name(), canonical_path, JVM_MAXPATHLEN)) {
-        char* src = (char*)stream->source();
-        // save the path from the file: protocol or the module name from the jrt: protocol
-        // if no protocol prefix is found, src is the same as stream->source() after the following call
-        src = skip_uri_protocol(src);
-        if (strcmp(canonical_path, os::native_path((char*)src)) == 0) {
-          break;
-        }
-        classpath_index ++;
+  // 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()
+  char* path = skip_uri_protocol(src);
+  for (int i = 0; i < FileMapInfo::get_number_of_share_classpaths(); i++) {
+    SharedClassPathEntry* ent = FileMapInfo::shared_classpath(i);
+    if (get_canonical_path(ent->name(), canonical_path, JVM_MAXPATHLEN)) {
+      // If the path (from the class stream srouce) is the same as the shared
+      // class path, then we have a match. For classes from module image loaded by the
+      // PlatformClassLoader, the stream->source() is not the name of the module image.
+      // Need to look for 'jrt:' explicitly.
+      if (strcmp(canonical_path, os::native_path((char*)path)) == 0 ||
+          (i == 0 && string_starts_with(src, "jrt:"))) {
+        classpath_index = i;
+        break;
       }
     }
-    if (e == NULL) {
-      assert(ik->shared_classpath_index() < 0,
-        "must be a class from a custom jar which isn't in the class path or boot class path");
-      return;
-    }
+  }
+  if (classpath_index < 0) {
+    // Shared classpath entry table only contains boot class path and -cp path.
+    // No path entry found for this class. Must be a shared class loaded by the
+    // user defined classloader.
+    assert(ik->shared_classpath_index() < 0, "Sanity");
+    return;
   }
 
-  if (classpath_index < _num_boot_entries) {
-    // ik is either:
-    // 1) a boot class loaded from the runtime image during vm initialization (classpath_index = 0); or
-    // 2) a user's class from -Xbootclasspath/a (classpath_index > 0)
-    // In the second case, the classpath_index, classloader_type will be recorded via
-    // context.record_result() in ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS).
-    if (classpath_index > 0) {
-      return;
-    }
-  }
-
-  ResourceMark rm;
   const char* const class_name = ik->name()->as_C_string();
   const char* const file_name = file_name_for_class_name(class_name,
                                                          ik->name()->utf8_length());
   assert(file_name != NULL, "invariant");
   Thread* THREAD = Thread::current();
   ClassLoaderExt::Context context(class_name, file_name, CATCH);
-  context.record_result(ik->name(), e, classpath_index, ik, THREAD);
+  context.record_result(ik->name(), classpath_index, ik, THREAD);
 }
 #endif // INCLUDE_CDS
 
@@ -1623,7 +1674,6 @@
 #if INCLUDE_CDS
 void ClassLoader::initialize_shared_path() {
   if (DumpSharedSpaces) {
-    _num_boot_entries = _num_entries;
     ClassLoaderExt::setup_search_paths();
     _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
   }