src/share/vm/classfile/classLoader.cpp

Print this page
rev 6841 : mq
rev 6842 : mq

@@ -24,19 +24,25 @@
 
 #include "precompiled.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
 #include "classfile/classLoader.hpp"
+#include "classfile/classLoaderExt.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/javaClasses.hpp"
+#if INCLUDE_CDS
+#include "classfile/sharedPathsMiscInfo.hpp"
+#include "classfile/sharedClassUtil.hpp"
+#endif
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "compiler/compileBroker.hpp"
 #include "gc_interface/collectedHeap.inline.hpp"
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/oopMapCache.hpp"
 #include "memory/allocation.inline.hpp"
+#include "memory/filemap.hpp"
 #include "memory/generation.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/universe.inline.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/instanceRefKlass.hpp"

@@ -112,12 +118,16 @@
 PerfCounter*    ClassLoader::_isUnsyncloadClass = NULL;
 PerfCounter*    ClassLoader::_load_instance_class_failCounter = NULL;
 
 ClassPathEntry* ClassLoader::_first_entry         = NULL;
 ClassPathEntry* ClassLoader::_last_entry          = NULL;
+int             ClassLoader::_num_entries         = 0;
 PackageHashtable* ClassLoader::_package_hash_table = NULL;
 
+#if INCLUDE_CDS
+SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
+#endif
 // helper routines
 bool string_starts_with(const char* str, const char* str_to_find) {
   size_t str_len = strlen(str);
   size_t str_to_find_len = strlen(str_to_find);
   if (str_to_find_len > str_len) {

@@ -192,10 +202,16 @@
     return NULL;
   }
   // check if file exists
   struct stat st;
   if (os::stat(path, &st) == 0) {
+#if INCLUDE_CDS
+    if (DumpSharedSpaces) {
+      ShouldNotReachHere();
+      ClassLoader::exit_with_path_failure("VM internal error. Classes can be loaded only from JAR files during dump time: %s", path);
+    }
+#endif
     // found file, open it
     int file_handle = os::open(path, 0, 0);
     if (file_handle != -1) {
       // read contents into resource array
       u1* buffer = NEW_RESOURCE_ARRAY(u1, st.st_size);

@@ -226,39 +242,53 @@
     (*ZipClose)(_zip);
   }
   FREE_C_HEAP_ARRAY(char, _zip_name, mtClass);
 }
 
-ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) {
+u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) {
   // enable call to C land
   JavaThread* thread = JavaThread::current();
   ThreadToNativeFromVM ttn(thread);
   // check whether zip archive contains name
-  jint filesize, name_len;
-  jzentry* entry = (*FindEntry)(_zip, name, &filesize, &name_len);
+  jint name_len;
+  jzentry* entry = (*FindEntry)(_zip, name, filesize, &name_len);
   if (entry == NULL) return NULL;
   u1* buffer;
   char name_buf[128];
   char* filename;
   if (name_len < 128) {
     filename = name_buf;
   } else {
     filename = NEW_RESOURCE_ARRAY(char, name_len + 1);
   }
 
-  // file found, get pointer to class in mmaped jar file.
+  // file found, get pointer to the entry in mmapped jar file.
   if (ReadMappedEntry == NULL ||
       !(*ReadMappedEntry)(_zip, entry, &buffer, filename)) {
-      // mmaped access not available, perhaps due to compression,
+      // mmapped access not available, perhaps due to compression,
       // read contents into resource array
-      buffer     = NEW_RESOURCE_ARRAY(u1, filesize);
+      int size = (*filesize) + ((nul_terminate) ? 1 : 0);
+      buffer = NEW_RESOURCE_ARRAY(u1, size);
       if (!(*ReadEntry)(_zip, entry, buffer, filename)) return NULL;
   }
+
+  // return result
+  if (nul_terminate) {
+    buffer[*filesize] = 0;
+  }
+  return buffer;
+}
+
+ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) {
+  jint filesize;
+  u1* buffer = open_entry(name, &filesize, false, CHECK_NULL);
+  if (buffer == NULL) {
+    return NULL;
+  }
   if (UsePerfData) {
     ClassLoader::perf_sys_classfile_bytes_read()->inc(filesize);
   }
-  // return result
   return new ClassFileStream(buffer, filesize, _zip_name);    // Resource allocated
 }
 
 // invoke function for each entry in the zip file
 void ClassPathZipEntry::contents_do(void f(const char* name, void* context), void* context) {

@@ -270,16 +300,17 @@
     if (ze == NULL) break;
     (*f)(ze->name, context);
   }
 }
 
-LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st) : ClassPathEntry() {
+LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() {
   _path = strdup(path);
   _st = *st;
   _meta_index = NULL;
   _resolved_entry = NULL;
   _has_error = false;
+  _throw_exception = throw_exception;
 }
 
 bool LazyClassPathEntry::is_jar_file() {
   return ((_st.st_mode & S_IFREG) == S_IFREG);
 }

@@ -287,11 +318,15 @@
 ClassPathEntry* LazyClassPathEntry::resolve_entry(TRAPS) {
   if (_resolved_entry != NULL) {
     return (ClassPathEntry*) _resolved_entry;
   }
   ClassPathEntry* new_entry = NULL;
-  new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, CHECK_NULL);
+  new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, _throw_exception, CHECK_NULL);
+  if (!_throw_exception && new_entry == NULL) {
+    assert(!HAS_PENDING_EXCEPTION, "must be");
+    return NULL;
+  }
   {
     ThreadCritical tc;
     if (_resolved_entry == NULL) {
       _resolved_entry = new_entry;
       return new_entry;

@@ -321,29 +356,91 @@
 
 bool LazyClassPathEntry::is_lazy() {
   return true;
 }
 
+u1* LazyClassPathEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) {
+  if (_has_error) {
+    return NULL;
+  }
+  ClassPathEntry* cpe = resolve_entry(THREAD);
+  if (cpe == NULL) {
+    _has_error = true;
+    return NULL;
+  } else if (cpe->is_jar_file()) {
+    return ((ClassPathZipEntry*)cpe)->open_entry(name, filesize, nul_terminate,THREAD);
+  } else {
+    ShouldNotReachHere();
+    filesize = 0;
+    return NULL;
+  }
+}
+
 static void print_meta_index(LazyClassPathEntry* entry,
                              GrowableArray<char*>& meta_packages) {
   tty->print("[Meta index for %s=", entry->name());
   for (int i = 0; i < meta_packages.length(); i++) {
     if (i > 0) tty->print(" ");
     tty->print("%s", meta_packages.at(i));
   }
   tty->print_cr("]");
 }
 
+#if INCLUDE_CDS
+void ClassLoader::exit_with_path_failure(const char* error, const char* message) {
+  assert(DumpSharedSpaces, "only called at dump time");
+  tty->print_cr("Hint: enable -XX:+TraceClassPaths to diagnose the failure");
+  vm_exit_during_initialization(error, message);
+}
+#endif
+
+void ClassLoader::trace_class_path(const char* msg, const char* name) {
+  if (TraceClassPaths) {
+    if (msg) {
+      tty->print("%s", msg);
+    }
+    if (name) {
+      if (strlen(name) < 256) {
+        tty->print("%s", name);
+      } else {
+        // For very long paths, we need to print each character separately,
+        // as print_cr() has a length limit
+        while (name[0] != '\0') {
+          tty->print("%c", name[0]);
+          name++;
+        }
+      }
+    }
+    if (msg && msg[0] == '[') {
+      tty->print_cr("]");
+    } else {
+      tty->cr();
+    }
+  }
+}
 
-void ClassLoader::setup_meta_index() {
+void ClassLoader::setup_bootstrap_meta_index() {
   // Set up meta index which allows us to open boot jars lazily if
   // class data sharing is enabled
+  const char* meta_index_path = Arguments::get_meta_index_path();
+  const char* meta_index_dir  = Arguments::get_meta_index_dir();
+  setup_meta_index(meta_index_path, meta_index_dir, 0);
+}
+
+void ClassLoader::setup_meta_index(const char* meta_index_path, const char* meta_index_dir, int start_index) {
   const char* known_version = "% VERSION 2";
-  char* meta_index_path = Arguments::get_meta_index_path();
-  char* meta_index_dir  = Arguments::get_meta_index_dir();
   FILE* file = fopen(meta_index_path, "r");
   int line_no = 0;
+#if INCLUDE_CDS
+  if (DumpSharedSpaces) {
+    if (file != NULL) {
+      _shared_paths_misc_info->add_required_file(meta_index_path);
+    } else {
+      _shared_paths_misc_info->add_nonexist_path(meta_index_path);
+    }
+  }
+#endif
   if (file != NULL) {
     ResourceMark rm;
     LazyClassPathEntry* cur_entry = NULL;
     GrowableArray<char*> boot_class_path_packages(10);
     char package_name[256];

@@ -374,23 +471,25 @@
         case '@':
         {
           // Hand off current packages to current lazy entry (if any)
           if ((cur_entry != NULL) &&
               (boot_class_path_packages.length() > 0)) {
-            if (TraceClassLoading && Verbose) {
+            if ((TraceClassLoading || TraceClassPaths) && Verbose) {
               print_meta_index(cur_entry, boot_class_path_packages);
             }
             MetaIndex* index = new MetaIndex(boot_class_path_packages.adr_at(0),
                                              boot_class_path_packages.length());
             cur_entry->set_meta_index(index);
           }
           cur_entry = NULL;
           boot_class_path_packages.clear();
 
           // Find lazy entry corresponding to this jar file
-          for (ClassPathEntry* entry = _first_entry; entry != NULL; entry = entry->next()) {
-            if (entry->is_lazy() &&
+          int count = 0;
+          for (ClassPathEntry* entry = _first_entry; entry != NULL; entry = entry->next(), count++) {
+            if (count >= start_index &&
+                entry->is_lazy() &&
                 string_starts_with(entry->name(), meta_index_dir) &&
                 string_ends_with(entry->name(), &package_name[2])) {
               cur_entry = (LazyClassPathEntry*) entry;
               break;
             }

@@ -423,60 +522,115 @@
       }
     }
     // Hand off current packages to current lazy entry (if any)
     if ((cur_entry != NULL) &&
         (boot_class_path_packages.length() > 0)) {
-      if (TraceClassLoading && Verbose) {
+      if ((TraceClassLoading || TraceClassPaths) && Verbose) {
         print_meta_index(cur_entry, boot_class_path_packages);
       }
       MetaIndex* index = new MetaIndex(boot_class_path_packages.adr_at(0),
                                        boot_class_path_packages.length());
       cur_entry->set_meta_index(index);
     }
     fclose(file);
   }
 }
 
+#if INCLUDE_CDS
+void ClassLoader::check_shared_classpath(const char *path) {
+  if (strcmp(path, "") == 0) {
+    exit_with_path_failure("Cannot have empty path in archived classpaths", NULL);
+  }
+
+  struct stat st;
+  if (os::stat(path, &st) == 0) {
+    if ((st.st_mode & S_IFREG) != S_IFREG) { // is directory
+      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 archived classpaths", NULL);
+      }
+    }
+  }
+}
+#endif
+
 void ClassLoader::setup_bootstrap_search_path() {
   assert(_first_entry == NULL, "should not setup bootstrap class search path twice");
   char* sys_class_path = os::strdup(Arguments::get_sysclasspath());
-  if (TraceClassLoading && Verbose) {
-    tty->print_cr("[Bootstrap loader class path=%s]", sys_class_path);
+  if (!PrintSharedArchiveAndExit) {
+    trace_class_path("[Bootstrap loader class path=", sys_class_path);
+  }
+#if INCLUDE_CDS
+  if (DumpSharedSpaces) {
+    _shared_paths_misc_info->add_boot_classpath(Arguments::get_sysclasspath());
   }
+#endif
+  setup_search_path(sys_class_path);
+}
+
+#if INCLUDE_CDS
+int ClassLoader::get_shared_paths_misc_info_size() {
+  return _shared_paths_misc_info->get_used_bytes();
+}
+
+void* ClassLoader::get_shared_paths_misc_info() {
+  return _shared_paths_misc_info->buffer();
+}
+
+bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) {
+  SharedPathsMiscInfo* checker = SharedClassUtil::allocate_shared_paths_misc_info((char*)buf, size);
+  bool result = checker->check();
+  delete checker;
+  return result;
+}
+#endif
 
-  int len = (int)strlen(sys_class_path);
+void ClassLoader::setup_search_path(char *class_path) {
+  int offset = 0;
+  int len = (int)strlen(class_path);
   int end = 0;
 
   // Iterate over class path entries
   for (int start = 0; start < len; start = end) {
-    while (sys_class_path[end] && sys_class_path[end] != os::path_separator()[0]) {
+    while (class_path[end] && class_path[end] != os::path_separator()[0]) {
       end++;
     }
-    char* path = NEW_C_HEAP_ARRAY(char, end-start+1, mtClass);
-    strncpy(path, &sys_class_path[start], end-start);
+    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';
     update_class_path_entry_list(path, false);
-    FREE_C_HEAP_ARRAY(char, path, mtClass);
-    while (sys_class_path[end] == os::path_separator()[0]) {
+#if INCLUDE_CDS
+    if (DumpSharedSpaces) {
+      check_shared_classpath(path);
+    }
+#endif
+    while (class_path[end] == os::path_separator()[0]) {
       end++;
     }
   }
 }
 
-ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct stat* st, bool lazy, TRAPS) {
+ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct stat* st,
+                                                     bool lazy, bool throw_exception, TRAPS) {
   JavaThread* thread = JavaThread::current();
   if (lazy) {
-    return new LazyClassPathEntry(path, st);
+    return new LazyClassPathEntry(path, st, throw_exception);
   }
   ClassPathEntry* new_entry = NULL;
   if ((st->st_mode & S_IFREG) == S_IFREG) {
     // Regular file, should be a zip file
     // Canonicalized filename
     char canonical_path[JVM_MAXPATHLEN];
     if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) {
       // This matches the classic VM
+      if (throw_exception) {
       THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL);
+      } else {
+        return NULL;
+      }
     }
     char* error_msg = NULL;
     jzfile* zip;
     {
       // enable call to C land

@@ -484,11 +638,11 @@
       HandleMark hm(thread);
       zip = (*ZipOpen)(canonical_path, &error_msg);
     }
     if (zip != NULL && error_msg == NULL) {
       new_entry = new ClassPathZipEntry(zip, path);
-      if (TraceClassLoading) {
+      if (TraceClassLoading || TraceClassPaths) {
         tty->print_cr("[Opened %s]", path);
       }
     } else {
       ResourceMark rm(thread);
       char *msg;

@@ -498,16 +652,20 @@
       } else {
         int len = (int)(strlen(path) + strlen(error_msg) + 128);
         msg = NEW_RESOURCE_ARRAY(char, len); ;
         jio_snprintf(msg, len - 1, "error in opening JAR file <%s> %s", error_msg, path);
       }
+      if (throw_exception) {
       THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL);
+      } else {
+        return NULL;
+      }
     }
   } else {
     // Directory
     new_entry = new ClassPathDirEntry(path);
-    if (TraceClassLoading) {
+    if (TraceClassLoading || TraceClassPaths) {
       tty->print_cr("[Path %s]", path);
     }
   }
   return new_entry;
 }

@@ -564,27 +722,41 @@
     } else {
       _last_entry->set_next(new_entry);
       _last_entry = new_entry;
     }
   }
+  _num_entries ++;
 }
 
-void ClassLoader::update_class_path_entry_list(char *path,
-                                               bool check_for_duplicates) {
+// Returns true IFF the file/dir exists and the entry was successfully created.
+bool ClassLoader::update_class_path_entry_list(char *path,
+                                               bool check_for_duplicates,
+                                               bool throw_exception) {
   struct stat st;
   if (os::stat(path, &st) == 0) {
     // File or directory found
     ClassPathEntry* new_entry = NULL;
     Thread* THREAD = Thread::current();
-    new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, CHECK);
+    new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, throw_exception, CHECK_(false));
+    if (new_entry == NULL) {
+      return false;
+    }
     // The kernel VM adds dynamically to the end of the classloader path and
     // doesn't reorder the bootclasspath which would break java.lang.Package
     // (see PackageInfo).
     // Add new entry to linked list
     if (!check_for_duplicates || !contains_entry(new_entry)) {
-      add_to_list(new_entry);
+      ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry);
     }
+    return true;
+  } else {
+#if INCLUDE_CDS
+    if (DumpSharedSpaces) {
+      _shared_paths_misc_info->add_nonexist_path(path);
+    }
+    return false;
+#endif
   }
 }
 
 void ClassLoader::print_bootclasspath() {
   ClassPathEntry* e = _first_entry;

@@ -732,59 +904,56 @@
       }
     }
     assert(n == number_of_entries(), "just checking");
   }
 
-  void copy_table(char** top, char* end, PackageHashtable* table);
+  CDS_ONLY(void copy_table(char** top, char* end, PackageHashtable* table);)
 };
 
-
+#if INCLUDE_CDS
 void PackageHashtable::copy_table(char** top, char* end,
                                   PackageHashtable* table) {
   // Copy (relocate) the table to the shared space.
   BasicHashtable<mtClass>::copy_table(top, end);
 
   // Calculate the space needed for the package name strings.
   int i;
-  int n = 0;
-  for (i = 0; i < table_size(); ++i) {
-    for (PackageInfo* pp = table->bucket(i);
-                      pp != NULL;
-                      pp = pp->next()) {
-      n += (int)(strlen(pp->pkgname()) + 1);
-    }
-  }
-  if (*top + n + sizeof(intptr_t) >= end) {
-    report_out_of_shared_space(SharedMiscData);
-  }
-
-  // Copy the table data (the strings) to the shared space.
-  n = align_size_up(n, sizeof(HeapWord));
-  *(intptr_t*)(*top) = n;
-  *top += sizeof(intptr_t);
+  intptr_t* tableSize = (intptr_t*)(*top);
+  *top += sizeof(intptr_t);  // For table size
+  char* tableStart = *top;
 
   for (i = 0; i < table_size(); ++i) {
     for (PackageInfo* pp = table->bucket(i);
                       pp != NULL;
                       pp = pp->next()) {
       int n1 = (int)(strlen(pp->pkgname()) + 1);
+      if (*top + n1 >= end) {
+        report_out_of_shared_space(SharedMiscData);
+      }
       pp->set_pkgname((char*)memcpy(*top, pp->pkgname(), n1));
       *top += n1;
     }
   }
   *top = (char*)align_size_up((intptr_t)*top, sizeof(HeapWord));
+  if (*top >= end) {
+    report_out_of_shared_space(SharedMiscData);
+  }
+
+  // Write table size
+  intptr_t len = *top - (char*)tableStart;
+  *tableSize = len;
 }
 
 
 void ClassLoader::copy_package_info_buckets(char** top, char* end) {
   _package_hash_table->copy_buckets(top, end);
 }
 
 void ClassLoader::copy_package_info_table(char** top, char* end) {
   _package_hash_table->copy_table(top, end, _package_hash_table);
 }
-
+#endif
 
 PackageInfo* ClassLoader::lookup_package(const char *pkgname) {
   const char *cp = strrchr(pkgname, '/');
   if (cp != NULL) {
     // Package prefix found

@@ -873,56 +1042,68 @@
 }
 
 
 instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
   ResourceMark rm(THREAD);
-  EventMark m("loading class %s", h_name->as_C_string());
+  const char* class_name = h_name->as_C_string();
+  EventMark m("loading class %s", class_name);
   ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
 
   stringStream st;
   // st.print() uses too much stack space while handling a StackOverflowError
   // st.print("%s.class", h_name->as_utf8());
   st.print_raw(h_name->as_utf8());
   st.print_raw(".class");
-  char* name = st.as_string();
+  const char* file_name = st.as_string();
+  ClassLoaderExt::Context context(class_name, file_name, THREAD);
 
   // Lookup stream for parsing .class file
   ClassFileStream* stream = NULL;
   int classpath_index = 0;
+  ClassPathEntry* e = NULL;
+  instanceKlassHandle h;
   {
     PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
                                ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(),
                                PerfClassTraceTime::CLASS_LOAD);
-    ClassPathEntry* e = _first_entry;
+    e = _first_entry;
     while (e != NULL) {
-      stream = e->open_stream(name, CHECK_NULL);
+      stream = e->open_stream(file_name, CHECK_NULL);
+      if (!context.check(stream, classpath_index)) {
+        return h; // NULL
+      }
       if (stream != NULL) {
         break;
       }
       e = e->next();
       ++classpath_index;
     }
   }
 
-  instanceKlassHandle h;
   if (stream != NULL) {
-
     // class file found, parse it
     ClassFileParser parser(stream);
     ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
     Handle protection_domain;
     TempNewSymbol parsed_name = NULL;
     instanceKlassHandle result = parser.parseClassFile(h_name,
                                                        loader_data,
                                                        protection_domain,
                                                        parsed_name,
-                                                       false,
-                                                       CHECK_(h));
-
-    // add to package table
-    if (add_package(name, classpath_index, THREAD)) {
-      h = result;
+                                                       context.should_verify(classpath_index),
+                                                       THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      ResourceMark rm;
+      if (DumpSharedSpaces) {
+        tty->print_cr("Preload Error: Failed to load %s", class_name);
+      }
+      return h;
+    }
+    h = context.record_result(classpath_index, e, result, THREAD);
+  } else {
+    if (DumpSharedSpaces) {
+      tty->print_cr("Preload Error: Cannot find %s", class_name);
     }
   }
 
   return h;
 }

@@ -1013,18 +1194,31 @@
     }
   }
 
   // lookup zip library entry points
   load_zip_library();
+#if INCLUDE_CDS
   // initialize search path
+  if (DumpSharedSpaces) {
+    _shared_paths_misc_info = SharedClassUtil::allocate_shared_paths_misc_info();
+  }
+#endif
   setup_bootstrap_search_path();
   if (LazyBootClassLoader) {
     // set up meta index which makes boot classpath initialization lazier
-    setup_meta_index();
+    setup_bootstrap_meta_index();
   }
 }
 
+#if INCLUDE_CDS
+void ClassLoader::initialize_shared_path() {
+  if (DumpSharedSpaces) {
+    ClassLoaderExt::setup_search_paths();
+    _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
+  }
+}
+#endif
 
 jlong ClassLoader::classloader_time_ms() {
   return UsePerfData ?
     Management::ticks_to_ms(_perf_accumulated_time->get_value()) : -1;
 }