< prev index next >

src/hotspot/share/classfile/moduleEntry.cpp

Print this page

@@ -27,21 +27,26 @@
 #include "classfile/classLoader.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/moduleEntry.hpp"
 #include "logging/log.hpp"
+#include "memory/archiveUtils.hpp"
 #include "memory/filemap.hpp"
+#include "memory/heapShared.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "oops/oopHandle.inline.hpp"
 #include "oops/symbol.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/safepoint.hpp"
 #include "utilities/events.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.inline.hpp"
 #include "utilities/ostream.hpp"
+#include "utilities/quickSort.hpp"
+#include "utilities/resourceHash.hpp"
 
 ModuleEntry* ModuleEntryTable::_javabase_module = NULL;
 
 oop ModuleEntry::module() const { return _module.resolve(); }
 

@@ -106,19 +111,19 @@
   }
 }
 
 // Returns the shared ProtectionDomain
 oop ModuleEntry::shared_protection_domain() {
-  return _pd.resolve();
+  return _shared_pd.resolve();
 }
 
 // Set the shared ProtectionDomain atomically
 void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data,
                                                Handle pd_h) {
   // Create a handle for the shared ProtectionDomain and save it atomically.
-  // init_handle_locked checks if someone beats us setting the _pd cache.
-  loader_data->init_handle_locked(_pd, pd_h);
+  // init_handle_locked checks if someone beats us setting the _shared_pd cache.
+  loader_data->init_handle_locked(_shared_pd, pd_h);
 }
 
 // Returns true if this module can read module m
 bool ModuleEntry::can_read(ModuleEntry* m) const {
   assert(m != NULL, "No module to lookup in this module's reads list");

@@ -360,10 +365,191 @@
   }
   assert(number_of_entries() == 0, "should have removed all entries");
   assert(new_entry_free_list() == NULL, "entry present on ModuleEntryTable's free list");
 }
 
+#if INCLUDE_CDS_JAVA_HEAP
+typedef ResourceHashtable<
+  const ModuleEntry*,
+  ModuleEntry*,
+  primitive_hash<const ModuleEntry*>,
+  primitive_equals<const ModuleEntry*>,
+  557, // prime number
+  ResourceObj::C_HEAP> ArchivedModuleEntries;
+static ArchivedModuleEntries* _archive_modules_entries = NULL;
+
+ModuleEntry* ModuleEntry::allocate_archived_entry() const {
+  assert(is_named(), "unnamed packages/modules are not archived");
+  ModuleEntry* archived_entry = (ModuleEntry*)MetaspaceShared::read_write_space_alloc(sizeof(ModuleEntry));
+  memcpy((void*)archived_entry, (void*)this, sizeof(ModuleEntry));
+
+  if (_archive_modules_entries == NULL) {
+    _archive_modules_entries = new (ResourceObj::C_HEAP, mtClass)ArchivedModuleEntries();
+  }
+  assert(_archive_modules_entries->get(this) == NULL, "Each ModuleEntry must not be shared across ModuleEntryTables");
+  _archive_modules_entries->put(this, archived_entry);
+
+  return archived_entry;
+}
+
+ModuleEntry* ModuleEntry::get_archived_entry(ModuleEntry* orig_entry) {
+  ModuleEntry** ptr = _archive_modules_entries->get(orig_entry);
+  assert(ptr != NULL && *ptr != NULL, "must have been allocated");
+  return *ptr;
+}
+
+// GrowableArrays cannot be directly archived, as they need to be expandable at runtime.
+// Write it out as an Array, and convert it back to GrowableArray at runtime.
+Array<ModuleEntry*>* ModuleEntry::write_archived_entry_array(GrowableArray<ModuleEntry*>* array) {
+  Array<ModuleEntry*>* archived_array = NULL;
+  int length = (array == NULL) ? 0 : array->length();
+  if (length > 0) {
+    archived_array = MetaspaceShared::new_ro_array<ModuleEntry*>(length);
+    for (int i = 0; i < length; i++) {
+      ModuleEntry* archived_entry = get_archived_entry(array->at(i));
+      archived_array->at_put(i, archived_entry);
+      ArchivePtrMarker::mark_pointer((address*)archived_array->adr_at(i));
+    }
+  }
+
+  return archived_array;
+}
+
+GrowableArray<ModuleEntry*>* ModuleEntry::read_archived_entry_array(Array<ModuleEntry*>* archived_array) {
+  GrowableArray<ModuleEntry*>* array = NULL;
+  int length = (archived_array == NULL) ? 0 : archived_array->length();
+  if (length > 0) {
+    array = new (ResourceObj::C_HEAP, mtModule)GrowableArray<ModuleEntry*>(length, mtModule);
+    for (int i = 0; i < length; i++) {
+      ModuleEntry* archived_entry = archived_array->at(i);
+      array->append(archived_entry);
+    }
+  }
+
+  return array;
+}
+
+void ModuleEntry::init_as_archived_entry() {
+  Array<ModuleEntry*>* archived_reads = write_archived_entry_array(_reads);
+
+  set_next(NULL);
+  set_hash(0x0);        // re-init at runtime
+  _loader_data = NULL;  // re-init at runtime
+  _shared_path_index = FileMapInfo::get_module_shared_path_index(_location);
+  if (literal() != NULL) {
+    set_literal(MetaspaceShared::get_relocated_symbol(literal()));
+    ArchivePtrMarker::mark_pointer((address*)literal_addr());
+  }
+  _reads = (GrowableArray<ModuleEntry*>*)archived_reads;
+  if (_version != NULL) {
+    _version = MetaspaceShared::get_relocated_symbol(_version);
+  }
+  if (_location != NULL) {
+    _location = MetaspaceShared::get_relocated_symbol(_location);
+  }
+
+  ArchivePtrMarker::mark_pointer((address*)&_reads);
+  ArchivePtrMarker::mark_pointer((address*)&_version);
+  ArchivePtrMarker::mark_pointer((address*)&_location);
+}
+
+void ModuleEntry::init_archived_oops() {
+  assert(DumpSharedSpaces, "static dump only");
+  oop module_obj = module();
+  if (module_obj != NULL) {
+    oop m = HeapShared::find_archived_heap_object(module_obj);
+    assert(m != NULL, "sanity");
+    _archived_module_narrow_oop = CompressedOops::encode(m);
+  }
+  assert(shared_protection_domain() == NULL, "never set during -Xshare:dump");
+  // Clear handles and restore at run time. Handles cannot be archived.
+  OopHandle null_handle;
+  _module = null_handle;
+}
+
+void ModuleEntry::load_from_archive(ClassLoaderData* loader_data) {
+  set_loader_data(loader_data);
+  _reads = read_archived_entry_array((Array<ModuleEntry*>*)_reads);
+  JFR_ONLY(INIT_ID(this);)
+}
+
+void ModuleEntry::restore_archive_oops(ClassLoaderData* loader_data) {
+  Handle module_handle(Thread::current(), HeapShared::materialize_archived_object(_archived_module_narrow_oop));
+  assert(module_handle.not_null(), "huh");
+  set_module(loader_data->add_handle(module_handle));
+
+  // This was cleared to zero during dump time -- we didn't save the value
+  // because it may be affected by archive relocation.
+  java_lang_Module::set_module_entry(module_handle(), this);
+
+  if (loader_data->class_loader() != NULL) {
+    java_lang_Module::set_loader(module_handle(), loader_data->class_loader());
+  }
+}
+
+static int compare_module_by_name(ModuleEntry* a, ModuleEntry* b) {
+  return a->name()->fast_compare(b->name());
+}
+
+Array<ModuleEntry*>* ModuleEntryTable::allocate_archived_entries() {
+  Array<ModuleEntry*>* archived_modules = MetaspaceShared::new_rw_array<ModuleEntry*>(number_of_entries());
+  int n = 0;
+  for (int i = 0; i < table_size(); ++i) {
+    for (ModuleEntry* m = bucket(i); m != NULL; m = m->next()) {
+      archived_modules->at_put(n++, m);
+    }
+  }
+  if (n > 1) {
+    // Always allocate in the same order to produce deterministic archive.
+    QuickSort::sort(archived_modules->data(), n, (_sort_Fn)compare_module_by_name, true);
+  }
+  for (int i = 0; i < n; i++) {
+    archived_modules->at_put(i, archived_modules->at(i)->allocate_archived_entry());
+    ArchivePtrMarker::mark_pointer((address*)archived_modules->adr_at(i));
+  }
+  return archived_modules;
+}
+
+void ModuleEntryTable::init_archived_entries(Array<ModuleEntry*>* archived_modules) {
+  assert(DumpSharedSpaces, "dump time only");
+  for (int i = 0; i < archived_modules->length(); i++) {
+    ModuleEntry* archived_entry = archived_modules->at(i);
+    archived_entry->init_as_archived_entry();
+  }
+}
+
+void ModuleEntryTable::init_archived_oops(Array<ModuleEntry*>* archived_modules) {
+  assert(DumpSharedSpaces, "dump time only");
+  for (int i = 0; i < archived_modules->length(); i++) {
+    ModuleEntry* archived_entry = archived_modules->at(i);
+    archived_entry->init_archived_oops();
+  }
+}
+
+void ModuleEntryTable::load_archived_entries(ClassLoaderData* loader_data,
+                                             Array<ModuleEntry*>* archived_modules) {
+  assert(UseSharedSpaces, "runtime only");
+
+  for (int i = 0; i < archived_modules->length(); i++) {
+    ModuleEntry* archived_entry = archived_modules->at(i);
+    archived_entry->load_from_archive(loader_data);
+
+    unsigned int hash = compute_hash(archived_entry->name());
+    archived_entry->set_hash(hash);
+    add_entry(hash_to_index(hash), archived_entry);
+  }
+}
+
+void ModuleEntryTable::restore_archived_oops(ClassLoaderData* loader_data, Array<ModuleEntry*>* archived_modules) {
+  assert(UseSharedSpaces, "runtime only");
+  for (int i = 0; i < archived_modules->length(); i++) {
+    ModuleEntry* archived_entry = archived_modules->at(i);
+    archived_entry->restore_archive_oops(loader_data);
+  }
+}
+#endif // INCLUDE_CDS_JAVA_HEAP
+
 ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle,
                                          bool is_open, Symbol* name,
                                          Symbol* version, Symbol* location,
                                          ClassLoaderData* loader_data) {
   assert(Module_lock->owned_by_self(), "should have the Module_lock");
< prev index next >