--- old/src/share/vm/memory/metaspaceShared.cpp 2015-10-29 21:53:07.713673014 -0700 +++ new/src/share/vm/memory/metaspaceShared.cpp 2015-10-29 21:53:07.597668633 -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; @@ -96,6 +99,10 @@ ik->array_klasses_do(collect_classes); } } + +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++) { @@ -422,12 +429,15 @@ VirtualSpace _mc_vs; CompactHashtableWriter* _string_cht; GrowableArray *_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 *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(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* 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.