hotspot/src/share/vm/memory/metaspaceShared.cpp
changeset 34257 4be3504cc03b
parent 33638 ef49ed90010b
child 35231 e89989198037
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Thu Nov 12 14:03:14 2015 +0100
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Tue Aug 18 11:27:23 2015 -0700
@@ -23,6 +23,8 @@
  */
 
 #include "precompiled.hpp"
+#include "classfile/classListParser.hpp"
+#include "classfile/classLoaderExt.hpp"
 #include "classfile/dictionary.hpp"
 #include "classfile/loaderConstraints.hpp"
 #include "classfile/placeholders.hpp"
@@ -42,6 +44,7 @@
 #include "runtime/signature.hpp"
 #include "runtime/vmThread.hpp"
 #include "runtime/vm_operations.hpp"
+#include "utilities/defaultStream.hpp"
 #include "utilities/hashtable.inline.hpp"
 
 int MetaspaceShared::_max_alignment = 0;
@@ -97,6 +100,10 @@
   }
 }
 
+static void collect_classes2(Klass* k, ClassLoaderData* class_data) {
+  collect_classes(k);
+}
+
 static void remove_unshareable_in_classes() {
   for (int i = 0; i < _global_klass_objects->length(); i++) {
     Klass* k = _global_klass_objects->at(i);
@@ -422,12 +429,15 @@
   VirtualSpace _mc_vs;
   CompactHashtableWriter* _string_cht;
   GrowableArray<MemRegion> *_string_regions;
+  char* _md_alloc_low;
+  char* _md_alloc_top;
+  char* _md_alloc_max;
+  static VM_PopulateDumpSharedSpace* _instance;
 
 public:
   VM_PopulateDumpSharedSpace(ClassLoaderData* loader_data,
                              GrowableArray<Klass*> *class_promote_order) :
     _loader_data(loader_data) {
-
     // Split up and initialize the misc code and data spaces
     ReservedSpace* shared_rs = MetaspaceShared::shared_rs();
     size_t metadata_size = SharedReadOnlySize + SharedReadWriteSize;
@@ -440,11 +450,43 @@
     _md_vs.initialize(md_rs, SharedMiscDataSize);
     _mc_vs.initialize(mc_rs, SharedMiscCodeSize);
     _class_promote_order = class_promote_order;
+
+    _md_alloc_low = _md_vs.low();
+    _md_alloc_top = _md_alloc_low + sizeof(char*);
+    _md_alloc_max = _md_vs.low() + SharedMiscDataSize;
+
+    assert(_instance == NULL, "must be singleton");
+    _instance = this;
+  }
+
+  ~VM_PopulateDumpSharedSpace() {
+    assert(_instance == this, "must be singleton");
+    _instance = NULL;
+  }
+
+  static VM_PopulateDumpSharedSpace* instance() {
+    assert(_instance != NULL, "sanity");
+    return _instance;
   }
 
   VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
   void doit();   // outline because gdb sucks
 
+  char* misc_data_space_alloc(size_t num_bytes) {
+    size_t alignment = sizeof(char*);
+    num_bytes = align_size_up(num_bytes, alignment);
+    _md_alloc_top = (char*)align_ptr_up(_md_alloc_top, alignment);
+    if (_md_alloc_top + num_bytes > _md_alloc_max) {
+      report_out_of_shared_space(SharedMiscData);
+    }
+
+    char* p = _md_alloc_top;
+    _md_alloc_top += num_bytes;
+
+    memset(p, 0, num_bytes);
+    return p;
+  }
+
 private:
   void handle_misc_data_space_failure(bool success) {
     if (!success) {
@@ -453,6 +495,7 @@
   }
 }; // class VM_PopulateDumpSharedSpace
 
+VM_PopulateDumpSharedSpace* VM_PopulateDumpSharedSpace::_instance;
 
 void VM_PopulateDumpSharedSpace::doit() {
   Thread* THREAD = VMThread::vm_thread();
@@ -475,7 +518,11 @@
   // that so we don't have to walk the SystemDictionary again.
   _global_klass_objects = new GrowableArray<Klass*>(1000);
   Universe::basic_type_classes_do(collect_classes);
-  SystemDictionary::classes_do(collect_classes);
+
+  // Need to call SystemDictionary::classes_do(void f(Klass*, ClassLoaderData*))
+  // as we may have some classes with NULL ClassLoaderData* in the dictionary. Other
+  // variants of SystemDictionary::classes_do will skip those classes.
+  SystemDictionary::classes_do(collect_classes2);
 
   tty->print_cr("Number of classes %d", _global_klass_objects->length());
   {
@@ -515,6 +562,10 @@
   char* mc_top = mc_low;
   char* mc_end = _mc_vs.high();
 
+  assert(_md_alloc_top != NULL, "sanity");
+  *(char**)_md_alloc_low = _md_alloc_top;
+  md_top = _md_alloc_top;
+
   // Reserve space for the list of Klass*s whose vtables are used
   // for patching others as needed.
 
@@ -735,6 +786,7 @@
 void MetaspaceShared::preload_and_dump(TRAPS) {
   TraceTime timer("Dump Shared Spaces", TraceStartupTime);
   ResourceMark rm;
+  char class_list_path_str[JVM_MAXPATHLEN];
 
   tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
                 MetaspaceShared::shared_rs()->size(),
@@ -747,7 +799,6 @@
     // Construct the path to the class list (in jre/lib)
     // Walk up two directories from the location of the VM and
     // optionally tack on "lib" (depending on platform)
-    char class_list_path_str[JVM_MAXPATHLEN];
     os::jvm_path(class_list_path_str, sizeof(class_list_path_str));
     for (int i = 0; i < 3; i++) {
       char *end = strrchr(class_list_path_str, *os::file_separator());
@@ -785,6 +836,11 @@
   static const char map_entry_array_sig[] = "[Ljava/util/Map$Entry;";
   SymbolTable::new_permanent_symbol(map_entry_array_sig, THREAD);
 
+  // Need to allocate the op here:
+  // op.misc_data_space_alloc() will be called during preload_and_dump().
+  ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
+  VM_PopulateDumpSharedSpace op(loader_data, class_promote_order);
+
   tty->print_cr("Loading classes to share ...");
   _has_error_classes = false;
   class_count += preload_and_dump(class_list_path, class_promote_order,
@@ -809,44 +865,27 @@
   link_and_cleanup_shared_classes(CATCH);
   tty->print_cr("Rewriting and linking classes: done");
 
-  // Create and dump the shared spaces.   Everything so far is loaded
-  // with the null class loader.
-  ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
-  VM_PopulateDumpSharedSpace op(loader_data, class_promote_order);
   VMThread::execute(&op);
-
   // Since various initialization steps have been undone by this process,
   // it is not reasonable to continue running a java process.
   exit(0);
 }
 
-int MetaspaceShared::preload_and_dump(const char * class_list_path,
+
+int MetaspaceShared::preload_and_dump(const char* class_list_path,
                                       GrowableArray<Klass*>* class_promote_order,
                                       TRAPS) {
-  FILE* file = fopen(class_list_path, "r");
-  char class_name[256];
+  ClassListParser parser(class_list_path);
   int class_count = 0;
 
-  if (file != NULL) {
-    while ((fgets(class_name, sizeof class_name, file)) != NULL) {
-      if (*class_name == '#') { // comment
-        continue;
-      }
-      // Remove trailing newline
-      size_t name_len = strlen(class_name);
-      if (class_name[name_len-1] == '\n') {
-        class_name[name_len-1] = '\0';
-      }
+    while (parser.parse_one_line()) {
+      Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD);
 
-      // Got a class name - load it.
-      TempNewSymbol class_name_symbol = SymbolTable::new_permanent_symbol(class_name, THREAD);
-      guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol.");
-      Klass* klass = SystemDictionary::resolve_or_null(class_name_symbol,
-                                                         THREAD);
       CLEAR_PENDING_EXCEPTION;
       if (klass != NULL) {
         if (PrintSharedSpaces && Verbose && WizardMode) {
-          tty->print_cr("Shared spaces preloaded: %s", class_name);
+          ResourceMark rm;
+          tty->print_cr("Shared spaces preloaded: %s", klass->external_name());
         }
 
         InstanceKlass* ik = InstanceKlass::cast(klass);
@@ -862,17 +901,8 @@
         guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
 
         class_count++;
-      } else {
-        //tty->print_cr("Preload failed: %s", class_name);
       }
     }
-    fclose(file);
-  } else {
-    char errmsg[JVM_MAXPATHLEN];
-    os::lasterror(errmsg, JVM_MAXPATHLEN);
-    tty->print_cr("Loading classlist failed: %s", errmsg);
-    exit(1);
-  }
 
   return class_count;
 }
@@ -908,6 +938,11 @@
   }
 }
 
+// Allocate misc data blocks during dumping.
+char* MetaspaceShared::misc_data_space_alloc(size_t num_bytes) {
+  return VM_PopulateDumpSharedSpace::instance()->misc_data_space_alloc(num_bytes);
+}
+
 // Closure for serializing initialization data in from a data area
 // (ptr_array) read from the shared file.
 
@@ -1033,6 +1068,8 @@
 
   char* buffer = mapinfo->header()->region_addr(md);
 
+  buffer = *((char**)buffer); // skip over the md_alloc'ed blocks
+
   // Skip over (reserve space for) a list of addresses of C++ vtables
   // for Klass objects.  They get filled in later.