src/hotspot/share/classfile/systemDictionaryShared.cpp
changeset 52514 f4e3900c8d08
parent 52468 e0fd97beab7e
child 53249 fbab5d82f3d7
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp	Tue Nov 13 21:43:10 2018 -0500
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp	Wed Nov 07 19:40:27 2018 -0800
@@ -53,12 +53,277 @@
 #include "runtime/javaCalls.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "utilities/hashtable.inline.hpp"
+#include "utilities/resourceHash.hpp"
 #include "utilities/stringUtils.hpp"
 
 
 objArrayOop SystemDictionaryShared::_shared_protection_domains  =  NULL;
 objArrayOop SystemDictionaryShared::_shared_jar_urls            =  NULL;
 objArrayOop SystemDictionaryShared::_shared_jar_manifests       =  NULL;
+DEBUG_ONLY(bool SystemDictionaryShared::_checked_excluded_classes = false;)
+
+class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
+public:
+  struct DTConstraint {
+    Symbol* _name;
+    Symbol* _from_name;
+    DTConstraint() : _name(NULL), _from_name(NULL) {}
+    DTConstraint(Symbol* n, Symbol* fn) : _name(n), _from_name(fn) {}
+  };
+
+  InstanceKlass*               _klass;
+  int                          _id;
+  int                          _clsfile_size;
+  int                          _clsfile_crc32;
+  bool                         _excluded;
+  GrowableArray<DTConstraint>* _verifier_constraints;
+  GrowableArray<char>*         _verifier_constraint_flags;
+
+  DumpTimeSharedClassInfo() {
+    _klass = NULL;
+    _id = -1;
+    _clsfile_size = -1;
+    _clsfile_crc32 = -1;
+    _excluded = false;
+    _verifier_constraints = NULL;
+    _verifier_constraint_flags = NULL;
+  }
+
+  void add_verification_constraint(InstanceKlass* k, Symbol* name,
+         Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object);
+
+  bool is_builtin() {
+    return SystemDictionaryShared::is_builtin(_klass);
+  }
+
+  int num_constraints() {
+    if (_verifier_constraint_flags != NULL) {
+      return _verifier_constraint_flags->length();
+    } else {
+      return 0;
+    }
+  }
+
+  void metaspace_pointers_do(MetaspaceClosure* it) {
+    it->push(&_klass);
+    if (_verifier_constraints != NULL) {
+      for (int i = 0; i < _verifier_constraints->length(); i++) {
+        DTConstraint* cons = _verifier_constraints->adr_at(i);
+        it->push(&cons->_name);
+        it->push(&cons->_from_name);
+      }
+    }
+  }
+};
+
+class DumpTimeSharedClassTable: public ResourceHashtable<
+  InstanceKlass*,
+  DumpTimeSharedClassInfo,
+  primitive_hash<InstanceKlass*>,
+  primitive_equals<InstanceKlass*>,
+  15889, // prime number
+  ResourceObj::C_HEAP>
+{
+  int _builtin_count;
+  int _unregistered_count;
+public:
+  DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k) {
+    DumpTimeSharedClassInfo* p = get(k);
+    if (p == NULL) {
+      assert(!SystemDictionaryShared::checked_excluded_classes(),
+             "no new classes can be added after check_excluded_classes");
+      put(k, DumpTimeSharedClassInfo());
+      p = get(k);
+      assert(p != NULL, "sanity");
+      p->_klass = k;
+    }
+    return p;
+  }
+
+  class CountClassByCategory : StackObj {
+    DumpTimeSharedClassTable* _table;
+  public:
+    CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {}
+    bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+      if (SystemDictionaryShared::is_builtin(k)) {
+        ++ _table->_builtin_count;
+      } else {
+        ++ _table->_unregistered_count;
+      }
+      return true; // keep on iterating
+    }
+  };
+
+  void update_counts() {
+    CountClassByCategory counter(this);
+    iterate(&counter);
+  }
+
+  int count_of(bool is_builtin) const {
+    if (is_builtin) {
+      return _builtin_count;
+    } else {
+      return _unregistered_count;
+    }
+  }
+};
+
+class RunTimeSharedClassInfo {
+public:
+  struct CrcInfo {
+    int _clsfile_size;
+    int _clsfile_crc32;
+  };
+
+  // This is different than  DumpTimeSharedClassInfo::DTConstraint. We use
+  // u4 instead of Symbol* to save space on 64-bit CPU.
+  struct RTConstraint {
+    u4 _name;
+    u4 _from_name;
+  };
+
+  InstanceKlass* _klass;
+  int _num_constraints;
+
+  // optional CrcInfo      _crc;  (only for UNREGISTERED classes)
+  // optional RTConstraint _verifier_constraints[_num_constraints]
+  // optional char         _verifier_constraint_flags[_num_constraints]
+
+private:
+  static size_t header_size_size() {
+    return sizeof(RunTimeSharedClassInfo);
+  }
+  static size_t crc_size(InstanceKlass* klass) {
+    if (!SystemDictionaryShared::is_builtin(klass)) {
+      return sizeof(CrcInfo);
+    } else {
+      return 0;
+    }
+  }
+  static size_t verifier_constraints_size(int num_constraints) {
+    return sizeof(RTConstraint) * num_constraints;
+  }
+  static size_t verifier_constraint_flags_size(int num_constraints) {
+    return sizeof(char) * num_constraints;
+  }
+
+public:
+  static size_t byte_size(InstanceKlass* klass, int num_constraints) {
+    return header_size_size() +
+           crc_size(klass) +
+           verifier_constraints_size(num_constraints) +
+           verifier_constraint_flags_size(num_constraints);
+  }
+
+private:
+  size_t crc_offset() const {
+    return header_size_size();
+  }
+  size_t verifier_constraints_offset() const {
+    return crc_offset() + crc_size(_klass);
+  }
+  size_t verifier_constraint_flags_offset() const {
+    return verifier_constraints_offset() + verifier_constraints_size(_num_constraints);
+  }
+
+  void check_constraint_offset(int i) const {
+    assert(0 <= i && i < _num_constraints, "sanity");
+  }
+
+public:
+  CrcInfo* crc() const {
+    assert(crc_size(_klass) > 0, "must be");
+    return (CrcInfo*)(address(this) + crc_offset());
+  }
+  RTConstraint* verifier_constraints() {
+    assert(_num_constraints > 0, "sanity");
+    return (RTConstraint*)(address(this) + verifier_constraints_offset());
+  }
+  RTConstraint* verifier_constraint_at(int i) {
+    check_constraint_offset(i);
+    return verifier_constraints() + i;
+  }
+
+  char* verifier_constraint_flags() {
+    assert(_num_constraints > 0, "sanity");
+    return (char*)(address(this) + verifier_constraint_flags_offset());
+  }
+
+  void init(DumpTimeSharedClassInfo& info) {
+    _klass = info._klass;
+    _num_constraints = info.num_constraints();
+    if (!SystemDictionaryShared::is_builtin(_klass)) {
+      CrcInfo* c = crc();
+      c->_clsfile_size = info._clsfile_size;
+      c->_clsfile_crc32 = info._clsfile_crc32;
+    }
+    if (_num_constraints > 0) {
+      RTConstraint* constraints = verifier_constraints();
+      char* flags = verifier_constraint_flags();
+      int i;
+      for (i = 0; i < _num_constraints; i++) {
+        constraints[i]._name      = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._name);
+        constraints[i]._from_name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._from_name);
+      }
+      for (i = 0; i < _num_constraints; i++) {
+        flags[i] = info._verifier_constraint_flags->at(i);
+      }
+    }
+  }
+
+  bool matches(int clsfile_size, int clsfile_crc32) const {
+    return crc()->_clsfile_size  == clsfile_size &&
+           crc()->_clsfile_crc32 == clsfile_crc32;
+  }
+
+  Symbol* get_constraint_name(int i) {
+    return (Symbol*)(SharedBaseAddress + verifier_constraint_at(i)->_name);
+  }
+  Symbol* get_constraint_from_name(int i) {
+    return (Symbol*)(SharedBaseAddress + verifier_constraint_at(i)->_from_name);
+  }
+
+  char get_constraint_flag(int i) {
+    check_constraint_offset(i);
+    return verifier_constraint_flags()[i];
+  }
+
+private:
+  // ArchiveCompactor::allocate() has reserved a pointer immediately before
+  // archived InstanceKlasses. We can use this slot to do a quick
+  // lookup of InstanceKlass* -> RunTimeSharedClassInfo* without
+  // building a new hashtable.
+  //
+  //  info_pointer_addr(klass) --> 0x0100   RunTimeSharedClassInfo*
+  //  InstanceKlass* klass     --> 0x0108   <C++ vtbl>
+  //                               0x0110   fields from Klass ...
+  static RunTimeSharedClassInfo** info_pointer_addr(InstanceKlass* klass) {
+    return &((RunTimeSharedClassInfo**)klass)[-1];
+  }
+
+public:
+  static RunTimeSharedClassInfo* get_for(InstanceKlass* klass) {
+    return *info_pointer_addr(klass);
+  }
+  static void set_for(InstanceKlass* klass, RunTimeSharedClassInfo* record) {
+    *info_pointer_addr(klass) = record;
+  }
+
+  // Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS
+  static inline bool EQUALS(
+       const RunTimeSharedClassInfo* value, Symbol* key, int len_unused) {
+    return (value->_klass->name() == key);
+  }
+};
+
+class RunTimeSharedDictionary : public OffsetCompactHashtable<
+  Symbol*,
+  const RunTimeSharedClassInfo*,
+  RunTimeSharedClassInfo::EQUALS> {};
+
+static DumpTimeSharedClassTable* _dumptime_table = NULL;
+static RunTimeSharedDictionary _builtin_dictionary;
+static RunTimeSharedDictionary _unregistered_dictionary;
 
 oop SystemDictionaryShared::shared_protection_domain(int index) {
   return _shared_protection_domains->obj_at(index);
@@ -478,9 +743,8 @@
       return NULL;
     }
 
-    if (shared_dictionary() != NULL &&
-        (SystemDictionary::is_system_class_loader(class_loader()) ||
-         SystemDictionary::is_platform_class_loader(class_loader()))) {
+    if (SystemDictionary::is_system_class_loader(class_loader()) ||
+        SystemDictionary::is_platform_class_loader(class_loader())) {
       // Fix for 4474172; see evaluation for more details
       class_loader = Handle(
         THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
@@ -523,8 +787,7 @@
 InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader(
                  Symbol* class_name, Handle class_loader, TRAPS) {
   assert(UseSharedSpaces, "must be");
-  assert(shared_dictionary() != NULL, "already checked");
-  InstanceKlass* ik = shared_dictionary()->find_class_for_builtin_loader(class_name);
+  InstanceKlass* ik = find_builtin_class(class_name);
 
   if (ik != NULL) {
     if ((ik->is_shared_app_class() &&
@@ -536,7 +799,6 @@
       return load_shared_class(ik, class_loader, protection_domain, THREAD);
     }
   }
-
   return NULL;
 }
 
@@ -574,12 +836,12 @@
 }
 
 // This function is called for loading only UNREGISTERED classes
-InstanceKlass* SystemDictionaryShared::lookup_from_stream(const Symbol* class_name,
+InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name,
                                                           Handle class_loader,
                                                           Handle protection_domain,
                                                           const ClassFileStream* cfs,
                                                           TRAPS) {
-  if (shared_dictionary() == NULL) {
+  if (!UseSharedSpaces) {
     return NULL;
   }
   if (class_name == NULL) {  // don't do this for anonymous classes
@@ -592,27 +854,18 @@
     return NULL;
   }
 
-  ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
-  InstanceKlass* k;
-
-  { // UNREGISTERED loader
-    if (!shared_dictionary()->class_exists_for_unregistered_loader(class_name)) {
-      // No classes of this name for unregistered loaders.
-      return NULL;
-    }
-
-    int clsfile_size  = cfs->length();
-    int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
-
-    k = shared_dictionary()->find_class_for_unregistered_loader(class_name,
-                                                                clsfile_size, clsfile_crc32);
-  }
-
-  if (k == NULL) { // not archived
+  const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary, class_name);
+  if (record == NULL) {
     return NULL;
   }
 
-  return acquire_class_for_current_thread(k, class_loader,
+  int clsfile_size  = cfs->length();
+  int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+  if (!record->matches(clsfile_size, clsfile_crc32)) {
+    return NULL;
+  }
+
+  return acquire_class_for_current_thread(record->_klass, class_loader,
                                           protection_domain, THREAD);
 }
 
@@ -649,19 +902,27 @@
   return shared_klass;
 }
 
-bool SystemDictionaryShared::add_non_builtin_klass(Symbol* name,
-                                                   ClassLoaderData* loader_data,
-                                                   InstanceKlass* k,
-                                                   TRAPS) {
+static ResourceHashtable<
+  Symbol*, bool,
+  primitive_hash<Symbol*>,
+  primitive_equals<Symbol*>,
+  6661,                             // prime number
+  ResourceObj::C_HEAP> _loaded_unregistered_classes;
+
+bool SystemDictionaryShared::add_unregistered_class(InstanceKlass* k, TRAPS) {
   assert(DumpSharedSpaces, "only when dumping");
-  assert(boot_loader_dictionary() != NULL, "must be");
 
-  if (boot_loader_dictionary()->add_non_builtin_klass(name, loader_data, k)) {
-    MutexLocker mu_r(Compile_lock, THREAD); // not really necessary, but add_to_hierarchy asserts this.
-    add_to_hierarchy(k, CHECK_0);
+  Symbol* name = k->name();
+  if (_loaded_unregistered_classes.get(name) != NULL) {
+    // We don't allow duplicated unregistered classes of the same name.
+    return false;
+  } else {
+    bool isnew = _loaded_unregistered_classes.put(name, true);
+    assert(isnew, "sanity");
+    MutexLocker mu_r(Compile_lock, THREAD); // add_to_hierarchy asserts this.
+    SystemDictionary::add_to_hierarchy(k, CHECK_0);
     return true;
   }
-  return false;
 }
 
 // This function is called to resolve the super/interfaces of shared classes for
@@ -698,81 +959,138 @@
   }
 }
 
-struct SharedMiscInfo {
-  InstanceKlass* _klass;
-  int _clsfile_size;
-  int _clsfile_crc32;
-};
-
-static GrowableArray<SharedMiscInfo>* misc_info_array = NULL;
+DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for(InstanceKlass* k) {
+  if (_dumptime_table == NULL) {
+    _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
+  }
+  return _dumptime_table->find_or_allocate_info_for(k);
+}
 
 void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
   assert(DumpSharedSpaces, "only when dumping");
-  int clsfile_size  = cfs->length();
-  int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+  assert(!is_builtin(k), "must be unregistered class");
+  DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+  info->_clsfile_size  = cfs->length();
+  info->_clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+}
 
-  if (misc_info_array == NULL) {
-    misc_info_array = new (ResourceObj::C_HEAP, mtClass) GrowableArray<SharedMiscInfo>(20, /*c heap*/ true);
-  }
+void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) {
+  (void)find_or_allocate_info_for(k);
+}
+
+void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
+  _dumptime_table->remove(k);
+}
 
-  SharedMiscInfo misc_info;
-  DEBUG_ONLY({
-      for (int i=0; i<misc_info_array->length(); i++) {
-        misc_info = misc_info_array->at(i);
-        assert(misc_info._klass != k, "cannot call set_shared_class_misc_info twice for the same class");
-      }
-    });
+bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) {
+  while (k) {
+    if (k->name()->equals("jdk/internal/event/Event")) {
+      return true;
+    }
+    k = k->java_super();
+  }
+  return false;
+}
 
-  misc_info._klass = k;
-  misc_info._clsfile_size = clsfile_size;
-  misc_info._clsfile_crc32 = clsfile_crc32;
-
-  misc_info_array->append(misc_info);
+void SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) {
+  ResourceMark rm;
+  log_warning(cds)("Skipping %s: %s", k->name()->as_C_string(), reason);
 }
 
-void SystemDictionaryShared::init_shared_dictionary_entry(InstanceKlass* k, DictionaryEntry* ent) {
-  SharedDictionaryEntry* entry = (SharedDictionaryEntry*)ent;
-  entry->_id = -1;
-  entry->_clsfile_size = -1;
-  entry->_clsfile_crc32 = -1;
-  entry->_verifier_constraints = NULL;
-  entry->_verifier_constraint_flags = NULL;
+bool SystemDictionaryShared::should_be_excluded(InstanceKlass* k) {
+  if (k->class_loader_data()->is_unsafe_anonymous()) {
+    return true; // unsafe anonymous classes are not archived, skip
+  }
+  if (k->is_in_error_state()) {
+    return true;
+  }
+  if (k->shared_classpath_index() < 0 && is_builtin(k)) {
+    // These are classes loaded from unsupported locations (such as those loaded by JVMTI native
+    // agent during dump time).
+    warn_excluded(k, "Unsupported location");
+    return true;
+  }
+  if (k->signers() != NULL) {
+    // We cannot include signed classes in the archive because the certificates
+    // used during dump time may be different than those used during
+    // runtime (due to expiration, etc).
+    warn_excluded(k, "Signed JAR");
+    return true;
+  }
+  if (is_jfr_event_class(k)) {
+    // We cannot include JFR event classes because they need runtime-specific
+    // instrumentation in order to work with -XX:FlightRecorderOptions=retransform=false.
+    // There are only a small number of these classes, so it's not worthwhile to
+    // support them and make CDS more complicated.
+    warn_excluded(k, "JFR event class");
+    return true;
+  }
+  return false;
+}
 
-  if (misc_info_array != NULL) {
-    for (int i=0; i<misc_info_array->length(); i++) {
-      SharedMiscInfo misc_info = misc_info_array->at(i);
-      if (misc_info._klass == k) {
-        entry->_clsfile_size = misc_info._clsfile_size;
-        entry->_clsfile_crc32 = misc_info._clsfile_crc32;
-        misc_info_array->remove_at(i);
-        return;
-      }
+// k is a class before relocating by ArchiveCompactor
+void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
+  ResourceMark rm;
+  const char* name = k->name()->as_C_string();
+  DumpTimeSharedClassInfo* info = _dumptime_table->get(k);
+  guarantee(info != NULL, "Class %s must be entered into _dumptime_table", name);
+  guarantee(!info->_excluded, "Should not attempt to archive excluded class %s", name);
+  if (is_builtin(k)) {
+    guarantee(k->loader_type() != 0,
+              "Class loader type must be set for BUILTIN class %s", name);
+  } else {
+    guarantee(k->loader_type() == 0,
+              "Class loader type must not be set for UNREGISTERED class %s", name);
+  }
+}
+
+class ExcludeDumpTimeSharedClasses : StackObj {
+public:
+  bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+    if (SystemDictionaryShared::should_be_excluded(k)) {
+      info._excluded = true;
     }
+    return true; // keep on iterating
   }
+};
+
+void SystemDictionaryShared::check_excluded_classes() {
+  ExcludeDumpTimeSharedClasses excl;
+  _dumptime_table->iterate(&excl);
+  DEBUG_ONLY(_checked_excluded_classes = true;)
+}
+
+bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
+  assert(_checked_excluded_classes, "sanity");
+  assert(DumpSharedSpaces, "only when dumping");
+  return find_or_allocate_info_for(k)->_excluded;
+}
+
+class IterateDumpTimeSharedClassTable : StackObj {
+  MetaspaceClosure *_it;
+public:
+  IterateDumpTimeSharedClassTable(MetaspaceClosure* it) : _it(it) {}
+
+  bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+    if (!info._excluded) {
+      info.metaspace_pointers_do(_it);
+    }
+    return true; // keep on iterating
+  }
+};
+
+void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
+  IterateDumpTimeSharedClassTable iter(it);
+  _dumptime_table->iterate(&iter);
 }
 
 bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
          Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
   assert(DumpSharedSpaces, "called at dump time only");
-
-  // Skip unsafe anonymous classes, which are not archived as they are not in
-  // dictionary (see assert_no_unsafe_anonymous_classes_in_dictionaries() in
-  // VM_PopulateDumpSharedSpace::doit()).
-  if (k->class_loader_data()->is_unsafe_anonymous()) {
-    return true; // unsafe anonymous classes are not archived, skip
-  }
-
-  SharedDictionaryEntry* entry = ((SharedDictionary*)(k->class_loader_data()->dictionary()))->find_entry_for(k);
-  ResourceMark rm;
-  // Lambda classes are not archived and will be regenerated at runtime.
-  if (entry == NULL) {
-    guarantee(strstr(k->name()->as_C_string(), "Lambda$") != NULL,
-              "class should be in dictionary before being verified");
-    return true;
-  }
-  entry->add_verification_constraint(name, from_name, from_field_is_protected,
-                                     from_is_array, from_is_object);
-  if (entry->is_builtin()) {
+  DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+  info->add_verification_constraint(k, name, from_name, from_field_is_protected,
+                                    from_is_array, from_is_object);
+  if (is_builtin(k)) {
     // For builtin class loaders, we can try to complete the verification check at dump time,
     // because we can resolve all the constraint classes.
     return false;
@@ -783,135 +1101,54 @@
   }
 }
 
-void SystemDictionaryShared::finalize_verification_constraints_for(InstanceKlass* k) {
-  if (!k->is_unsafe_anonymous()) {
-    SharedDictionaryEntry* entry = ((SharedDictionary*)(k->class_loader_data()->dictionary()))->find_entry_for(k);
-    entry->finalize_verification_constraints();
-  }
-}
-
-void SystemDictionaryShared::finalize_verification_constraints() {
-  MutexLocker mcld(ClassLoaderDataGraph_lock);
-  ClassLoaderDataGraph::dictionary_classes_do(finalize_verification_constraints_for);
-}
-
-void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
-                                                             TRAPS) {
-  assert(!DumpSharedSpaces && UseSharedSpaces, "called at run time with CDS enabled only");
-  SharedDictionaryEntry* entry = shared_dictionary()->find_entry_for(klass);
-  assert(entry != NULL, "call this only for shared classes");
-  entry->check_verification_constraints(klass, THREAD);
-}
-
-SharedDictionaryEntry* SharedDictionary::find_entry_for(InstanceKlass* klass) {
-  Symbol* class_name = klass->name();
-  unsigned int hash = compute_hash(class_name);
-  int index = hash_to_index(hash);
-
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash && entry->literal() == klass) {
-      return entry;
-    }
-  }
-
-  return NULL;
-}
-
-void SharedDictionaryEntry::add_verification_constraint(Symbol* name,
+void DumpTimeSharedClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name,
          Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
   if (_verifier_constraints == NULL) {
-    _verifier_constraints = new(ResourceObj::C_HEAP, mtClass) GrowableArray<Symbol*>(8, true, mtClass);
+    _verifier_constraints = new(ResourceObj::C_HEAP, mtClass) GrowableArray<DTConstraint>(4, true, mtClass);
   }
   if (_verifier_constraint_flags == NULL) {
     _verifier_constraint_flags = new(ResourceObj::C_HEAP, mtClass) GrowableArray<char>(4, true, mtClass);
   }
-  GrowableArray<Symbol*>* vc_array = (GrowableArray<Symbol*>*)_verifier_constraints;
-  for (int i=0; i<vc_array->length(); i+= 2) {
-    if (name      == vc_array->at(i) &&
-        from_name == vc_array->at(i+1)) {
+  GrowableArray<DTConstraint>* vc_array = _verifier_constraints;
+  for (int i = 0; i < vc_array->length(); i++) {
+    DTConstraint* p = vc_array->adr_at(i);
+    if (name == p->_name && from_name == p->_from_name) {
       return;
     }
   }
-  vc_array->append(name);
-  vc_array->append(from_name);
+  DTConstraint cons(name, from_name);
+  vc_array->append(cons);
 
-  GrowableArray<char>* vcflags_array = (GrowableArray<char>*)_verifier_constraint_flags;
+  GrowableArray<char>* vcflags_array = _verifier_constraint_flags;
   char c = 0;
-  c |= from_field_is_protected ? FROM_FIELD_IS_PROTECTED : 0;
-  c |= from_is_array           ? FROM_IS_ARRAY           : 0;
-  c |= from_is_object          ? FROM_IS_OBJECT          : 0;
+  c |= from_field_is_protected ? SystemDictionaryShared::FROM_FIELD_IS_PROTECTED : 0;
+  c |= from_is_array           ? SystemDictionaryShared::FROM_IS_ARRAY           : 0;
+  c |= from_is_object          ? SystemDictionaryShared::FROM_IS_OBJECT          : 0;
   vcflags_array->append(c);
 
   if (log_is_enabled(Trace, cds, verification)) {
     ResourceMark rm;
     log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s",
-                                 instance_klass()->external_name(), from_name->as_klass_external_name(),
+                                 k->external_name(), from_name->as_klass_external_name(),
                                  name->as_klass_external_name());
   }
 }
 
-int SharedDictionaryEntry::finalize_verification_constraints() {
-  assert(DumpSharedSpaces, "called at dump time only");
-  Thread* THREAD = Thread::current();
-  ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
-  GrowableArray<Symbol*>* vc_array = (GrowableArray<Symbol*>*)_verifier_constraints;
-  GrowableArray<char>* vcflags_array = (GrowableArray<char>*)_verifier_constraint_flags;
-
-  if (vc_array != NULL) {
-    if (log_is_enabled(Trace, cds, verification)) {
-      ResourceMark rm;
-      log_trace(cds, verification)("finalize_verification_constraint: %s",
-                                   literal()->external_name());
-    }
+void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
+                                                            TRAPS) {
+  assert(!DumpSharedSpaces && UseSharedSpaces, "called at run time with CDS enabled only");
+  RunTimeSharedClassInfo* record = RunTimeSharedClassInfo::get_for(klass);
 
-    // Copy the constraints from C_HEAP-alloced GrowableArrays to Metaspace-alloced
-    // Arrays
-    int size = 0;
-    {
-      // FIXME: change this to be done after relocation, so we can use symbol offset??
-      int length = vc_array->length();
-      Array<Symbol*>* out = MetadataFactory::new_array<Symbol*>(loader_data, length, 0, THREAD);
-      assert(out != NULL, "Dump time allocation failure would have aborted VM");
-      for (int i=0; i<length; i++) {
-        out->at_put(i, vc_array->at(i));
-      }
-      _verifier_constraints = out;
-      size += out->size() * BytesPerWord;
-      delete vc_array;
-    }
-    {
-      int length = vcflags_array->length();
-      Array<char>* out = MetadataFactory::new_array<char>(loader_data, length, 0, THREAD);
-      assert(out != NULL, "Dump time allocation failure would have aborted VM");
-      for (int i=0; i<length; i++) {
-        out->at_put(i, vcflags_array->at(i));
-      }
-      _verifier_constraint_flags = out;
-      size += out->size() * BytesPerWord;
-      delete vcflags_array;
-    }
+  int length = record->_num_constraints;
+  if (length > 0) {
+    for (int i = 0; i < length; i++) {
+      Symbol* name      = record->get_constraint_name(i);
+      Symbol* from_name = record->get_constraint_from_name(i);
+      char c            = record->get_constraint_flag(i);
 
-    return size;
-  }
-  return 0;
-}
-
-void SharedDictionaryEntry::check_verification_constraints(InstanceKlass* klass, TRAPS) {
-  Array<Symbol*>* vc_array = (Array<Symbol*>*)_verifier_constraints;
-  Array<char>* vcflags_array = (Array<char>*)_verifier_constraint_flags;
-
-  if (vc_array != NULL) {
-    int length = vc_array->length();
-    for (int i=0; i<length; i+=2) {
-      Symbol* name      = vc_array->at(i);
-      Symbol* from_name = vc_array->at(i+1);
-      char c = vcflags_array->at(i/2);
-
-      bool from_field_is_protected = (c & FROM_FIELD_IS_PROTECTED) ? true : false;
-      bool from_is_array           = (c & FROM_IS_ARRAY)           ? true : false;
-      bool from_is_object          = (c & FROM_IS_OBJECT)          ? true : false;
+      bool from_field_is_protected = (c & SystemDictionaryShared::FROM_FIELD_IS_PROTECTED) ? true : false;
+      bool from_is_array           = (c & SystemDictionaryShared::FROM_IS_ARRAY)           ? true : false;
+      bool from_is_object          = (c & SystemDictionaryShared::FROM_IS_OBJECT)          ? true : false;
 
       bool ok = VerificationType::resolve_and_check_assignability(klass, name,
          from_name, from_field_is_protected, from_is_array, from_is_object, CHECK);
@@ -930,132 +1167,100 @@
   }
 }
 
-void SharedDictionaryEntry::metaspace_pointers_do(MetaspaceClosure* it) {
-  it->push((Array<Symbol*>**)&_verifier_constraints);
-  it->push((Array<char>**)&_verifier_constraint_flags);
+class CopySharedClassInfoToArchive : StackObj {
+  CompactHashtableWriter* _writer;
+  bool _is_builtin;
+public:
+  CopySharedClassInfoToArchive(CompactHashtableWriter* writer, bool is_builtin)
+    : _writer(writer), _is_builtin(is_builtin) {}
+
+  bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+    if (!info._excluded && info.is_builtin() == _is_builtin) {
+      size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_constraints());
+      RunTimeSharedClassInfo* record =
+        (RunTimeSharedClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
+      record->init(info);
+
+      unsigned int hash = primitive_hash<Symbol*>(info._klass->name());
+      _writer->add(hash, MetaspaceShared::object_delta_u4(record));
+
+      // Save this for quick runtime lookup of InstanceKlass* -> RunTimeSharedClassInfo*
+      RunTimeSharedClassInfo::set_for(info._klass, record);
+    }
+    return true; // keep on iterating
+  }
+};
+
+void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin) {
+  CompactHashtableStats stats;
+  dictionary->reset();
+  int num_buckets = CompactHashtableWriter::default_num_buckets(_dumptime_table->count_of(is_builtin));
+  CompactHashtableWriter writer(num_buckets, &stats);
+  CopySharedClassInfoToArchive copy(&writer, is_builtin);
+  _dumptime_table->iterate(&copy);
+  writer.dump(dictionary, is_builtin ? "builtin dictionary" : "unregistered dictionary");
 }
 
-bool SharedDictionary::add_non_builtin_klass(const Symbol* class_name,
-                                             ClassLoaderData* loader_data,
-                                             InstanceKlass* klass) {
-
-  assert(DumpSharedSpaces, "supported only when dumping");
-  assert(klass != NULL, "adding NULL klass");
-  assert(klass->name() == class_name, "sanity check on name");
-  assert(klass->shared_classpath_index() < 0,
-         "the shared classpath index should not be set for shared class loaded by the custom loaders");
-
-  // Add an entry for a non-builtin class.
-  // For a shared class for custom class loaders, SystemDictionary::resolve_or_null will
-  // not find this class, because is_builtin() is false.
-  unsigned int hash = compute_hash(class_name);
-  int index = hash_to_index(hash);
-
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash) {
-      InstanceKlass* klass = entry->instance_klass();
-      if (klass->name() == class_name && klass->class_loader_data() == loader_data) {
-        // There is already a class defined with the same name
-        return false;
-      }
-    }
-  }
-
-  assert(Dictionary::entry_size() >= sizeof(SharedDictionaryEntry), "must be big enough");
-  SharedDictionaryEntry* entry = (SharedDictionaryEntry*)new_entry(hash, klass);
-  add_entry(index, entry);
-
-  assert(entry->is_unregistered(), "sanity");
-  assert(!entry->is_builtin(), "sanity");
-  return true;
+void SystemDictionaryShared::write_to_archive() {
+  _dumptime_table->update_counts();
+  write_dictionary(&_builtin_dictionary, true);
+  write_dictionary(&_unregistered_dictionary, false);
 }
 
-
-//-----------------
-// SharedDictionary
-//-----------------
-
-
-InstanceKlass* SharedDictionary::find_class_for_builtin_loader(const Symbol* name) const {
-  SharedDictionaryEntry* entry = get_entry_for_builtin_loader(name);
-  return entry != NULL ? entry->instance_klass() : (InstanceKlass*)NULL;
-}
-
-InstanceKlass* SharedDictionary::find_class_for_unregistered_loader(const Symbol* name,
-                                                            int clsfile_size,
-                                                            int clsfile_crc32) const {
-
-  const SharedDictionaryEntry* entry = get_entry_for_unregistered_loader(name,
-                                                                         clsfile_size,
-                                                                         clsfile_crc32);
-  return entry != NULL ? entry->instance_klass() : NULL;
+void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc) {
+  _builtin_dictionary.serialize_header(soc);
+  _unregistered_dictionary.serialize_header(soc);
 }
 
-void SharedDictionary::update_entry(InstanceKlass* klass, int id) {
-  assert(DumpSharedSpaces, "supported only when dumping");
-  Symbol* class_name = klass->name();
-  unsigned int hash = compute_hash(class_name);
-  int index = hash_to_index(hash);
+const RunTimeSharedClassInfo*
+SystemDictionaryShared::find_record(RunTimeSharedDictionary* dict, Symbol* name) {
+  if (UseSharedSpaces) {
+    unsigned int hash = primitive_hash<Symbol*>(name);
+    return dict->lookup(name, hash, 0);
+  } else {
+    return NULL;
+  }
+}
 
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash && entry->literal() == klass) {
-      entry->_id = id;
-      return;
-    }
+InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) {
+  const RunTimeSharedClassInfo* record = find_record(&_builtin_dictionary, name);
+  if (record) {
+    return record->_klass;
+  } else {
+    return NULL;
   }
+}
 
-  ShouldNotReachHere();
+void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) {
+  assert(DumpSharedSpaces, "supported only when dumping");
+  DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
+  info->_id = id;
 }
 
-SharedDictionaryEntry* SharedDictionary::get_entry_for_builtin_loader(const Symbol* class_name) const {
-  assert(!DumpSharedSpaces, "supported only when at runtime");
-  unsigned int hash = compute_hash(class_name);
-  const int index = hash_to_index(hash);
+class SharedDictionaryPrinter : StackObj {
+  outputStream* _st;
+  int _index;
+public:
+  SharedDictionaryPrinter(outputStream* st) : _st(st), _index(0) {}
 
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash && entry->equals(class_name)) {
-      if (entry->is_builtin()) {
-        return entry;
-      }
-    }
+  void do_value(const RunTimeSharedClassInfo* record) {
+    ResourceMark rm;
+    _st->print_cr("%4d:  %s", (_index++), record->_klass->external_name());
   }
-  return NULL;
+};
+
+void SystemDictionaryShared::print_on(outputStream* st) {
+  if (UseSharedSpaces) {
+    st->print_cr("Shared Dictionary");
+    SharedDictionaryPrinter p(st);
+    _builtin_dictionary.iterate(&p);
+    _unregistered_dictionary.iterate(&p);
+  }
 }
 
-SharedDictionaryEntry* SharedDictionary::get_entry_for_unregistered_loader(const Symbol* class_name,
-                                                                           int clsfile_size,
-                                                                           int clsfile_crc32) const {
-  assert(!DumpSharedSpaces, "supported only when at runtime");
-  unsigned int hash = compute_hash(class_name);
-  int index = hash_to_index(hash);
-
-  for (SharedDictionaryEntry* entry = bucket(index);
-                              entry != NULL;
-                              entry = entry->next()) {
-    if (entry->hash() == hash && entry->equals(class_name)) {
-      if (entry->is_unregistered()) {
-        if (clsfile_size == -1) {
-          // We're called from class_exists_for_unregistered_loader. At run time, we want to
-          // compute the CRC of a ClassFileStream only if there is an UNREGISTERED class
-          // with the matching name.
-          return entry;
-        } else {
-          // We're called from find_class_for_unregistered_loader
-          if (entry->_clsfile_size && clsfile_crc32 == entry->_clsfile_crc32) {
-            return entry;
-          }
-        }
-
-        // There can be only 1 class with this name for unregistered loaders.
-        return NULL;
-      }
-    }
+void SystemDictionaryShared::print_table_statistics(outputStream* st) {
+  if (UseSharedSpaces) {
+    _builtin_dictionary.print_table_statistics(st, "Builtin Shared Dictionary");
+    _unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
   }
-  return NULL;
 }