diff a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
@@ -27,15 +27,19 @@
 #include "cds/archiveHeapLoader.hpp"
 #include "cds/archiveUtils.hpp"
 #include "cds/cdsConfig.hpp"
 #include "cds/classListParser.hpp"
 #include "cds/classListWriter.hpp"
+#include "cds/classPreinitializer.hpp"
 #include "cds/dynamicArchive.hpp"
 #include "cds/filemap.hpp"
+#include "cds/heapShared.hpp"
 #include "cds/cdsProtectionDomain.hpp"
 #include "cds/dumpTimeClassInfo.inline.hpp"
+#include "cds/lambdaFormInvokers.inline.hpp"
 #include "cds/metaspaceShared.hpp"
+#include "cds/methodDataDictionary.hpp"
 #include "cds/runTimeClassInfo.hpp"
 #include "classfile/classFileStream.hpp"
 #include "classfile/classLoader.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/classLoaderDataGraph.hpp"
@@ -59,10 +63,12 @@
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/klass.inline.hpp"
+#include "oops/methodData.hpp"
+#include "oops/trainingData.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/oopHandle.inline.hpp"
 #include "oops/typeArrayOop.inline.hpp"
@@ -78,10 +84,19 @@
 SystemDictionaryShared::ArchiveInfo SystemDictionaryShared::_dynamic_archive;
 
 DumpTimeSharedClassTable* SystemDictionaryShared::_dumptime_table = nullptr;
 DumpTimeLambdaProxyClassDictionary* SystemDictionaryShared::_dumptime_lambda_proxy_class_dictionary = nullptr;
 
+DumpTimeMethodInfoDictionary* SystemDictionaryShared::_dumptime_method_info_dictionary = nullptr;
+DumpTimeMethodInfoDictionary* SystemDictionaryShared::_cloned_dumptime_method_info_dictionary = nullptr;
+static Array<InstanceKlass*>* _archived_lambda_form_classes = nullptr;
+static Array<InstanceKlass*>* _archived_lambda_proxy_classes_boot = nullptr;
+static Array<InstanceKlass*>* _archived_lambda_proxy_classes_boot2 = nullptr;
+static Array<InstanceKlass*>* _archived_lambda_proxy_classes_platform = nullptr;
+static Array<InstanceKlass*>* _archived_lambda_proxy_classes_app = nullptr;
+static bool _ignore_new_classes = false;
+
 // Used by NoClassLoadingMark
 DEBUG_ONLY(bool SystemDictionaryShared::_class_loading_may_happen = true;)
 
 InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader(
                  Symbol* class_name, Handle class_loader, TRAPS) {
@@ -91,12 +106,15 @@
   if (ik != nullptr && !ik->shared_loading_failed()) {
     if ((SystemDictionary::is_system_class_loader(class_loader()) && ik->is_shared_app_class())  ||
         (SystemDictionary::is_platform_class_loader(class_loader()) && ik->is_shared_platform_class())) {
       SharedClassLoadingMark slm(THREAD, ik);
       PackageEntry* pkg_entry = CDSProtectionDomain::get_package_entry_from_class(ik, class_loader);
-      Handle protection_domain =
-        CDSProtectionDomain::init_security_info(class_loader, ik, pkg_entry, CHECK_NULL);
+      Handle protection_domain;
+      if (!class_name->starts_with("jdk/proxy")) // java/lang/reflect/Proxy$ProxyBuilder defines the proxy classes with a null protection domain.
+      {
+        protection_domain = CDSProtectionDomain::init_security_info(class_loader, ik, pkg_entry, CHECK_NULL);
+      }
       return load_shared_class(ik, class_loader, protection_domain, nullptr, pkg_entry, THREAD);
     }
   }
   return nullptr;
 }
@@ -179,24 +197,32 @@
 
 // Guaranteed to return non-null value for non-shared classes.
 // k must not be a shared class.
 DumpTimeClassInfo* SystemDictionaryShared::get_info(InstanceKlass* k) {
   MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
-  assert(!k->is_shared(), "sanity");
+//assert(!k->is_shared(), "sanity"); // FIXME new workflow
   return get_info_locked(k);
 }
 
 DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) {
   assert_lock_strong(DumpTimeTable_lock);
-  assert(!k->is_shared(), "sanity");
+//assert(!k->is_shared(), "sanity"); // FIXME new workflow
   DumpTimeClassInfo* info = _dumptime_table->get_info(k);
   assert(info != nullptr, "must be");
   return info;
 }
 
+void SystemDictionaryShared::mark_required_class(InstanceKlass* k) {
+  DumpTimeClassInfo* info = _dumptime_table->get(k);
+  ResourceMark rm;
+  if (info != nullptr) {
+    info->set_is_required();
+  }
+}
+
 bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) {
-  if (MetaspaceShared::is_in_shared_metaspace(k)) {
+  if (!CDSConfig::is_dumping_final_static_archive() && MetaspaceShared::is_in_shared_metaspace(k)) {
     // We have reached a super type that's already in the base archive. Treat it
     // as "not excluded".
     assert(CDSConfig::is_dumping_dynamic_archive(), "must be");
     return false;
   }
@@ -258,11 +284,21 @@
   } else {
     return false;
   }
 }
 
+void SystemDictionaryShared::ignore_new_classes() {
+  _ignore_new_classes = true;
+}
+
+
 bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
+  if (CDSConfig::is_dumping_final_static_archive() && k->is_shared_unregistered_class()
+      && k->is_shared()) {
+    return false; // Do not exclude: unregistered classes are passed from preimage to final image.
+  }
+
   if (k->is_in_error_state()) {
     return warn_excluded(k, "In error state");
   }
   if (k->is_scratch_class()) {
     return warn_excluded(k, "A scratch class");
@@ -287,32 +323,35 @@
   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.
-    return warn_excluded(k, "JFR event class");
+    if (!CDSConfig::is_dumping_reflection_data()) { // FIXME: !!! HACK !!!
+      return warn_excluded(k, "JFR event class");
+    }
   }
 
-  if (!k->is_linked()) {
-    if (has_class_failed_verification(k)) {
-      return warn_excluded(k, "Failed verification");
-    }
-  } else {
-    if (!k->can_be_verified_at_dumptime()) {
-      // We have an old class that has been linked (e.g., it's been executed during
-      // dump time). This class has been verified using the old verifier, which
-      // doesn't save the verification constraints, so check_verification_constraints()
-      // won't work at runtime.
-      // As a result, we cannot store this class. It must be loaded and fully verified
-      // at runtime.
-      return warn_excluded(k, "Old class has been linked");
+  if (!CDSConfig::preserve_all_dumptime_verification_states(k)) {
+    if (!k->is_linked()) {
+      if (has_class_failed_verification(k)) {
+        return warn_excluded(k, "Failed verification");
+      }
+    } else {
+      if (!k->can_be_verified_at_dumptime()) {
+        // We have an old class that has been linked (e.g., it's been executed during
+        // dump time). This class has been verified using the old verifier, which
+        // doesn't save the verification constraints, so check_verification_constraints()
+        // won't work at runtime.
+        // As a result, we cannot store this class. It must be loaded and fully verified
+        // at runtime.
+        return warn_excluded(k, "Old class has been linked");
+      }
     }
   }
 
-  if (k->is_hidden() && !is_registered_lambda_proxy_class(k)) {
-    ResourceMark rm;
-    log_debug(cds)("Skipping %s: Hidden class", k->name()->as_C_string());
+  if (k->is_hidden() && !should_hidden_class_be_archived(k)) {
+    log_info(cds)("Skipping %s: Hidden class", k->name()->as_C_string());
     return true;
   }
 
   InstanceKlass* super = k->java_super();
   if (super != nullptr && check_for_exclusion(super, nullptr)) {
@@ -500,17 +539,25 @@
 void SystemDictionaryShared::initialize() {
   if (CDSConfig::is_dumping_archive()) {
     _dumptime_table = new (mtClass) DumpTimeSharedClassTable;
     _dumptime_lambda_proxy_class_dictionary =
                       new (mtClass) DumpTimeLambdaProxyClassDictionary;
+    _dumptime_method_info_dictionary = new (mtClass) DumpTimeMethodInfoDictionary;
   }
 }
 
 void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) {
   MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
   assert(SystemDictionaryShared::class_loading_may_happen(), "sanity");
-  _dumptime_table->allocate_info(k);
+  DumpTimeClassInfo* info = _dumptime_table->allocate_info(k);
+  if (_ignore_new_classes) {
+    if (!LambdaFormInvokers::may_be_regenerated_class(k->name())) {
+      ResourceMark rm;
+      log_debug(cds)("Skipping %s: Class loaded for lambda form invoker regeneration", k->name()->as_C_string());
+      info->set_excluded();
+    }
+  }
 }
 
 void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
   MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
   _dumptime_table->remove(k);
@@ -568,11 +615,14 @@
   assert(!class_loading_may_happen(), "class loading must be disabled");
   guarantee(info != nullptr, "Class %s must be entered into _dumptime_table", name);
   guarantee(!info->is_excluded(), "Should not attempt to archive excluded class %s", name);
   if (is_builtin(k)) {
     if (k->is_hidden()) {
-      assert(is_registered_lambda_proxy_class(k), "unexpected hidden class %s", name);
+      if (CDSConfig::is_dumping_invokedynamic()) { // FIXME -- clean up
+        return;
+      }
+      assert(should_hidden_class_be_archived(k), "unexpected hidden class %s", name);
     }
     guarantee(!k->is_shared_unregistered_class(),
               "Class loader type must be set for BUILTIN class %s", name);
 
   } else {
@@ -620,10 +670,35 @@
       }
     }
   }
 };
 
+void SystemDictionaryShared::scan_constant_pool(InstanceKlass* k) {
+  k->constants()->find_archivable_hidden_classes();
+}
+
+bool SystemDictionaryShared::should_hidden_class_be_archived(InstanceKlass* k) {
+  assert(k->is_hidden(), "sanity");
+  if (is_registered_lambda_proxy_class(k)) {
+    return true;
+  }
+
+  if (CDSConfig::is_dumping_invokedynamic()) {
+    if (HeapShared::is_archivable_hidden_klass(k)) {
+      return true;
+    }
+
+    // TODO: merge the following with HeapShared::is_archivable_hidden_klass()
+    DumpTimeClassInfo* info = _dumptime_table->get(k);
+    if (info != nullptr && info->is_required()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 void SystemDictionaryShared::check_excluded_classes() {
   assert(!class_loading_may_happen(), "class loading must be disabled");
   assert_lock_strong(DumpTimeTable_lock);
 
   if (CDSConfig::is_dumping_dynamic_archive()) {
@@ -633,17 +708,61 @@
     UnregisteredClassesDuplicationChecker dup_checker;
     _dumptime_table->iterate_all_live_classes(&dup_checker);
     dup_checker.mark_duplicated_classes();
   }
 
-  auto check_for_exclusion = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
-    SystemDictionaryShared::check_for_exclusion(k, &info);
+  ResourceMark rm;
+
+  // First, scan all non-hidden classes
+  auto check_non_hidden = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
+    if (!k->is_hidden()) {
+      SystemDictionaryShared::check_for_exclusion(k, &info);
+      if (!info.is_excluded() && !info.has_scanned_constant_pool()) {
+        scan_constant_pool(k);
+        info.set_has_scanned_constant_pool();
+      }
+    }
   };
-  _dumptime_table->iterate_all_live_classes(check_for_exclusion);
+  _dumptime_table->iterate_all_live_classes(check_non_hidden);
+
+  // Then, scan all that hidden classes that have been marked as required, until
+  // we reach a stable state.
+  bool made_progress;
+  do {
+    made_progress = false;
+    auto check_hidden = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
+      if (k->is_hidden() && should_hidden_class_be_archived(k)) {
+        SystemDictionaryShared::check_for_exclusion(k, &info);
+        if (info.is_excluded()) {
+          assert(!info.is_required(), "A required hidden class cannot be marked as excluded");
+        } else if (!info.has_scanned_constant_pool()) {
+          scan_constant_pool(k);
+          info.set_has_scanned_constant_pool();
+          // The CP entries in k *MAY* refer to other hidden classes, so scan
+          // every hidden class again.
+          made_progress = true;
+        }
+      }
+    };
+    _dumptime_table->iterate_all_live_classes(check_hidden);
+  } while (made_progress);
+
+  // Now, all hidden classes that have not yet been scanned should be excluded
+  auto exclude_remaining_hidden = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
+    if (k->is_hidden() && !info.has_checked_exclusion()) {
+      SystemDictionaryShared::check_for_exclusion(k, &info);
+      assert(info.is_excluded(), "Must be");
+    }
+  };
+  _dumptime_table->iterate_all_live_classes(exclude_remaining_hidden);
   _dumptime_table->update_counts();
 
   cleanup_lambda_proxy_class_dictionary();
+
+  cleanup_method_info_dictionary();
+
+  TrainingData::cleanup_training_data();
 }
 
 bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
   assert(!class_loading_may_happen(), "class loading must be disabled");
   assert_lock_strong(DumpTimeTable_lock);
@@ -679,11 +798,14 @@
 
 void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
   assert_lock_strong(DumpTimeTable_lock);
 
   auto do_klass = [&] (InstanceKlass* k, DumpTimeClassInfo& info) {
-    if (k->is_loader_alive() && !info.is_excluded()) {
+    if (CDSConfig::is_dumping_final_static_archive() && !k->is_loaded()) {
+      assert(k->is_shared_unregistered_class(), "must be");
+      info.metaspace_pointers_do(it);
+    } else if (k->is_loader_alive() && !info.is_excluded()) {
       info.metaspace_pointers_do(it);
     }
   };
   _dumptime_table->iterate_all_live_classes(do_klass);
 
@@ -692,15 +814,31 @@
       info.metaspace_pointers_do(it);
       key.metaspace_pointers_do(it);
     }
   };
   _dumptime_lambda_proxy_class_dictionary->iterate_all(do_lambda);
+
+  auto do_method_info = [&] (MethodDataKey& key, DumpTimeMethodDataInfo& info) {
+    info.metaspace_pointers_do(it);
+    key.metaspace_pointers_do(it);
+  };
+  _dumptime_method_info_dictionary->iterate_all(do_method_info);
 }
 
 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(CDSConfig::is_dumping_archive(), "sanity");
+  if (CDSConfig::is_dumping_dynamic_archive() && k->is_shared()) {
+    // k is a new class in the static archive, but one of its supertypes is an old class, so k wasn't
+    // verified during dump time. No need to record constraints as k won't be included in the dynamic archive.
+    return false;
+  }
+  if (PreloadSharedClasses && is_builtin(k)) {
+    // There's no need to save verification constraints
+    return false;
+  }
+
   DumpTimeClassInfo* info = get_info(k);
   info->add_verification_constraint(k, name, from_name, from_field_is_protected,
                                     from_is_array, from_is_object);
 
   if (CDSConfig::is_dumping_dynamic_archive()) {
@@ -746,10 +884,18 @@
                                                     Symbol* invoked_type,
                                                     Symbol* method_type,
                                                     Method* member_method,
                                                     Symbol* instantiated_method_type,
                                                     TRAPS) {
+  if (CDSConfig::is_dumping_invokedynamic()) {
+    // The proxy classes will be accessible through the archived CP entries.
+    return;
+  }
+  if (CDSConfig::is_dumping_preimage_static_archive() || CDSConfig::is_dumping_final_static_archive()) {
+    // TODO: not supported in new workflow
+    return;
+  }
 
   assert(caller_ik->class_loader() == lambda_ik->class_loader(), "mismatched class loader");
   assert(caller_ik->class_loader_data() == lambda_ik->class_loader_data(), "mismatched class loader data");
   assert(java_lang_Class::class_data(lambda_ik->java_mirror()) == nullptr, "must not have class data");
 
@@ -783,10 +929,13 @@
                                                                      Symbol* invoked_name,
                                                                      Symbol* invoked_type,
                                                                      Symbol* method_type,
                                                                      Method* member_method,
                                                                      Symbol* instantiated_method_type) {
+  if (CDSConfig::is_dumping_final_static_archive()) {
+    return nullptr;
+  }
   MutexLocker ml(CDSLambda_lock, Mutex::_no_safepoint_check_flag);
   LambdaProxyClassKey key(caller_ik, invoked_name, invoked_type,
                           method_type, member_method, instantiated_method_type);
 
   // Try to retrieve the lambda proxy class from static archive.
@@ -831,11 +980,11 @@
       prev_klass->set_next_link(nullptr);
       proxy_klass = curr_klass;
       proxy_klass->clear_lambda_proxy_is_available();
       if (log_is_enabled(Debug, cds)) {
         ResourceMark rm;
-        log_debug(cds)("Loaded lambda proxy: %s ", proxy_klass->external_name());
+        log_debug(cds)("Loaded lambda proxy: " PTR_FORMAT " %s ", p2i(proxy_klass), proxy_klass->external_name());
       }
     }
   }
   return proxy_klass;
 }
@@ -890,11 +1039,11 @@
   return loaded_lambda;
 }
 
 void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass,
                                                             TRAPS) {
-  assert(!CDSConfig::is_dumping_static_archive() && CDSConfig::is_using_archive(), "called at run time with CDS enabled only");
+  //assert(!CDSConfig::is_dumping_static_archive() && CDSConfig::is_using_archive(), "called at run time with CDS enabled only");
   RunTimeClassInfo* record = RunTimeClassInfo::get_for(klass);
 
   int length = record->_num_verifier_constraints;
   if (length > 0) {
     for (int i = 0; i < length; i++) {
@@ -1000,11 +1149,11 @@
 }
 
 // returns true IFF there's no need to re-initialize the i/v-tables for klass for
 // the purpose of checking class loader constraints.
 bool SystemDictionaryShared::check_linking_constraints(Thread* current, InstanceKlass* klass) {
-  assert(!CDSConfig::is_dumping_static_archive() && CDSConfig::is_using_archive(), "called at run time with CDS enabled only");
+  //assert(!CDSConfig::is_dumping_static_archive() && CDSConfig::is_using_archive(), "called at run time with CDS enabled only");
   LogTarget(Info, class, loader, constraints) log;
   if (klass->is_shared_boot_class()) {
     // No class loader constraint check performed for boot classes.
     return true;
   }
@@ -1129,15 +1278,20 @@
   size_t bytesize = align_up(sizeof(RunTimeLambdaProxyClassInfo), SharedSpaceObjectAlignment);
   total_size +=
       (bytesize * _dumptime_lambda_proxy_class_dictionary->_count) +
       CompactHashtableWriter::estimate_size(_dumptime_lambda_proxy_class_dictionary->_count);
 
+  size_t method_info_byte_size = align_up(sizeof(RunTimeMethodDataInfo), SharedSpaceObjectAlignment);
+  total_size +=
+      (method_info_byte_size * _dumptime_method_info_dictionary->_count) +
+      CompactHashtableWriter::estimate_size(_dumptime_method_info_dictionary->_count);
+
   return total_size;
 }
 
 unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) {
-  if (ArchiveBuilder::is_active()) {
+  if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space(ptr)) {
     uintx offset = ArchiveBuilder::current()->any_to_offset(ptr);
     unsigned int hash = primitive_hash<uintx>(offset);
     DEBUG_ONLY({
         if (MetaspaceObj::is_shared((const MetaspaceObj*)ptr)) {
           assert(hash == SystemDictionaryShared::hash_for_shared_dictionary_quick(ptr), "must be");
@@ -1246,10 +1400,44 @@
   CopyLambdaProxyClassInfoToArchive copy(&writer);
   _dumptime_lambda_proxy_class_dictionary->iterate(&copy);
   writer.dump(dictionary, "lambda proxy class dictionary");
 }
 
+class CopyMethodDataInfoToArchive : StackObj {
+  CompactHashtableWriter* _writer;
+  ArchiveBuilder* _builder;
+public:
+  CopyMethodDataInfoToArchive(CompactHashtableWriter* writer)
+      : _writer(writer), _builder(ArchiveBuilder::current()) {}
+
+  bool do_entry(MethodDataKey& key, DumpTimeMethodDataInfo& info) {
+    Method* holder = key.method();
+    log_info(cds,dynamic)("Archiving method info for %s", holder->external_name());
+
+    size_t byte_size = sizeof(RunTimeMethodDataInfo);
+    RunTimeMethodDataInfo* record = (RunTimeMethodDataInfo*)ArchiveBuilder::ro_region_alloc(byte_size);
+
+    DumpTimeMethodDataInfo data(info.method_data(), info.method_counters());
+    record->init(key, data);
+
+    uint hash = SystemDictionaryShared::hash_for_shared_dictionary((address)holder);
+    u4 delta = _builder->buffer_to_offset_u4((address)record);
+    _writer->add(hash, delta);
+
+    return true;
+  }
+};
+
+void SystemDictionaryShared::write_method_info_dictionary(MethodDataInfoDictionary* dictionary) {
+  CompactHashtableStats stats;
+  dictionary->reset();
+  CompactHashtableWriter writer(_dumptime_method_info_dictionary->_count, &stats);
+  CopyMethodDataInfoToArchive copy(&writer);
+  _dumptime_method_info_dictionary->iterate(&copy);
+  writer.dump(dictionary, "method info dictionary");
+}
+
 void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary,
                                               bool is_builtin) {
   CompactHashtableStats stats;
   dictionary->reset();
   CompactHashtableWriter writer(_dumptime_table->count_of(is_builtin), &stats);
@@ -1264,30 +1452,68 @@
 
   write_dictionary(&archive->_builtin_dictionary, true);
   write_dictionary(&archive->_unregistered_dictionary, false);
 
   write_lambda_proxy_class_dictionary(&archive->_lambda_proxy_class_dictionary);
+
+  write_method_info_dictionary(&archive->_method_info_dictionary);
 }
 
 void SystemDictionaryShared::adjust_lambda_proxy_class_dictionary() {
   AdjustLambdaProxyClassInfo adjuster;
   _dumptime_lambda_proxy_class_dictionary->iterate(&adjuster);
 }
 
+class AdjustMethodInfo : StackObj {
+public:
+  AdjustMethodInfo() {}
+  bool do_entry(MethodDataKey& key, DumpTimeMethodDataInfo& info) {
+    // TODO: is it possible for the data to become stale/invalid?
+    MethodData*     md = info.method_data();
+    MethodCounters* mc = info.method_counters();
+    if (md != nullptr) {
+      md = ArchiveBuilder::current()->get_buffered_addr(md);
+    }
+    if (mc != nullptr) {
+      mc = ArchiveBuilder::current()->get_buffered_addr(mc);
+    }
+    assert(ArchiveBuilder::current()->is_in_buffer_space(md) || md == nullptr, "must be");
+    assert(ArchiveBuilder::current()->is_in_buffer_space(mc) || mc == nullptr, "must be");
+    if (md != nullptr) {
+      md->remove_unshareable_info();
+    }
+    if (mc != nullptr) {
+      mc->remove_unshareable_info();
+    }
+    return true;
+  }
+};
+
+void SystemDictionaryShared::adjust_method_info_dictionary() {
+  AdjustMethodInfo adjuster;
+  _dumptime_method_info_dictionary->iterate(&adjuster);
+}
+
 void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc,
                                                           bool is_static_archive) {
   ArchiveInfo* archive = get_archive(is_static_archive);
 
   archive->_builtin_dictionary.serialize_header(soc);
   archive->_unregistered_dictionary.serialize_header(soc);
   archive->_lambda_proxy_class_dictionary.serialize_header(soc);
+  archive->_method_info_dictionary.serialize_header(soc);
 }
 
 void SystemDictionaryShared::serialize_vm_classes(SerializeClosure* soc) {
   for (auto id : EnumRange<vmClassID>{}) {
     soc->do_ptr(vmClasses::klass_addr_at(id));
   }
+  soc->do_ptr((void**)&_archived_lambda_form_classes);
+  soc->do_ptr((void**)&_archived_lambda_proxy_classes_boot);
+  soc->do_ptr((void**)&_archived_lambda_proxy_classes_boot2);
+  soc->do_ptr((void**)&_archived_lambda_proxy_classes_platform);
+  soc->do_ptr((void**)&_archived_lambda_proxy_classes_app);
 }
 
 const RunTimeClassInfo*
 SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTimeSharedDictionary* dynamic_dict, Symbol* name) {
   if (!CDSConfig::is_using_archive() || !name->is_shared()) {
@@ -1298,14 +1524,11 @@
   unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(name);
   const RunTimeClassInfo* record = nullptr;
   if (DynamicArchive::is_mapped()) {
     // Use the regenerated holder classes in the dynamic archive as they
     // have more methods than those in the base archive.
-    if (name == vmSymbols::java_lang_invoke_Invokers_Holder() ||
-        name == vmSymbols::java_lang_invoke_DirectMethodHandle_Holder() ||
-        name == vmSymbols::java_lang_invoke_LambdaForm_Holder() ||
-        name == vmSymbols::java_lang_invoke_DelegatingMethodHandle_Holder()) {
+    if (LambdaFormInvokers::may_be_regenerated_class(name)) {
       record = dynamic_dict->lookup(name, hash, 0);
       if (record != nullptr) {
         return record;
       }
     }
@@ -1346,11 +1569,11 @@
   assert(CDSConfig::is_dumping_static_archive(), "class ID is used only for static dump (from classlist)");
   DumpTimeClassInfo* info = get_info(k);
   info->_id = id;
 }
 
-static const char* class_loader_name_for_shared(Klass* k) {
+const char* SystemDictionaryShared::class_loader_name_for_shared(Klass* k) {
   assert(k != nullptr, "Sanity");
   assert(k->is_shared(), "Must be");
   assert(k->is_instance_klass(), "Must be");
   InstanceKlass* ik = InstanceKlass::cast(k);
   if (ik->is_shared_boot_class()) {
@@ -1373,11 +1596,11 @@
   SharedDictionaryPrinter(outputStream* st) : _st(st), _index(0) {}
 
   void do_value(const RunTimeClassInfo* record) {
     ResourceMark rm;
     _st->print_cr("%4d: %s %s", _index++, record->_klass->external_name(),
-        class_loader_name_for_shared(record->_klass));
+        SystemDictionaryShared::class_loader_name_for_shared(record->_klass));
     if (record->_klass->array_klasses() != nullptr) {
       record->_klass->array_klasses()->cds_print_value_on(_st);
       _st->cr();
     }
   }
@@ -1394,17 +1617,59 @@
     if (record->proxy_klass_head()->lambda_proxy_is_available()) {
       ResourceMark rm;
       Klass* k = record->proxy_klass_head();
       while (k != nullptr) {
         _st->print_cr("%4d: %s %s", _index++, k->external_name(),
-                      class_loader_name_for_shared(k));
+                      SystemDictionaryShared::class_loader_name_for_shared(k));
         k = k->next_link();
       }
     }
   }
 };
 
+class SharedMethodInfoDictionaryPrinter : StackObj {
+  outputStream* _st;
+  int _index;
+
+private:
+  static const char* tag(void* p) {
+    if (p == nullptr) {
+      return "   ";
+    } else if (MetaspaceShared::is_shared_dynamic(p)) {
+      return "<D>";
+    } else if (MetaspaceShared::is_in_shared_metaspace(p)) {
+      return "<S>";
+    } else {
+      return "???";
+    }
+  }
+public:
+  SharedMethodInfoDictionaryPrinter(outputStream* st) : _st(st), _index(0) {}
+
+  void do_value(const RunTimeMethodDataInfo* record) {
+    ResourceMark rm;
+    Method*         m  = record->method();
+    MethodCounters* mc = record->method_counters();
+    MethodData*     md = record->method_data();
+
+    _st->print_cr("%4d: %s" PTR_FORMAT " %s" PTR_FORMAT " %s" PTR_FORMAT " %s", _index++,
+                  tag(m), p2i(m),
+                  tag(mc), p2i(mc),
+                  tag(md), p2i(md),
+                  m->external_name());
+    if (Verbose) {
+      if (mc != nullptr) {
+        mc->print_on(_st);
+      }
+      if (md != nullptr) {
+        md->print_on(_st);
+      }
+      _st->cr();
+    }
+  }
+};
+
 void SystemDictionaryShared::ArchiveInfo::print_on(const char* prefix,
                                                    outputStream* st) {
   st->print_cr("%sShared Dictionary", prefix);
   SharedDictionaryPrinter p(st);
   st->print_cr("%sShared Builtin Dictionary", prefix);
@@ -1414,18 +1679,24 @@
   if (!_lambda_proxy_class_dictionary.empty()) {
     st->print_cr("%sShared Lambda Dictionary", prefix);
     SharedLambdaDictionaryPrinter ldp(st, p.index());
     _lambda_proxy_class_dictionary.iterate(&ldp);
   }
+  if (!_method_info_dictionary.empty()) {
+    st->print_cr("%sShared MethodData Dictionary", prefix);
+    SharedMethodInfoDictionaryPrinter mdp(st);
+    _method_info_dictionary.iterate(&mdp);
+  }
 }
 
 void SystemDictionaryShared::ArchiveInfo::print_table_statistics(const char* prefix,
                                                                  outputStream* st) {
   st->print_cr("%sArchve Statistics", prefix);
   _builtin_dictionary.print_table_statistics(st, "Builtin Shared Dictionary");
   _unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
   _lambda_proxy_class_dictionary.print_table_statistics(st, "Lambda Shared Dictionary");
+  _method_info_dictionary.print_table_statistics(st, "MethodData Dictionary");
 }
 
 void SystemDictionaryShared::print_shared_archive(outputStream* st, bool is_static) {
   if (CDSConfig::is_using_archive()) {
     if (is_static) {
@@ -1487,5 +1758,77 @@
 void SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary() {
   assert_lock_strong(DumpTimeTable_lock);
   CleanupDumpTimeLambdaProxyClassTable cleanup_proxy_classes;
   _dumptime_lambda_proxy_class_dictionary->unlink(&cleanup_proxy_classes);
 }
+
+class CleanupDumpTimeMethodInfoTable : StackObj {
+public:
+  bool do_entry(MethodDataKey& key, DumpTimeMethodDataInfo& info) {
+    assert_lock_strong(DumpTimeTable_lock);
+    assert(MetaspaceShared::is_in_shared_metaspace(key.method()), "");
+    InstanceKlass* holder = key.method()->method_holder();
+    bool is_excluded = SystemDictionaryShared::check_for_exclusion(holder, nullptr);
+    return is_excluded;
+  }
+};
+
+void SystemDictionaryShared::cleanup_method_info_dictionary() {
+  assert_lock_strong(DumpTimeTable_lock);
+
+  CleanupDumpTimeMethodInfoTable cleanup_method_info;
+  _dumptime_method_info_dictionary->unlink(&cleanup_method_info);
+}
+
+void SystemDictionaryShared::create_loader_positive_lookup_cache(TRAPS) {
+  GrowableArray<InstanceKlass*> shared_classes_list;
+  {
+    // With static dumping, we have only a single Java thread (see JVM_StartThread) so
+    // no no other threads should be loading classes. Otherwise, the code below may miss some
+    // classes that are loaded concurrently.
+    assert(CDSConfig::is_dumping_static_archive(), "no other threads should be loading classes");
+
+    MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
+    _dumptime_table->iterate_all_classes_in_builtin_loaders([&](InstanceKlass* k, DumpTimeClassInfo& info) {
+        if (!k->is_hidden() && !check_for_exclusion(k, &info)) {
+          shared_classes_list.append(k);
+        }
+      }
+    );
+  }
+
+  InstanceKlass* ik = vmClasses::Class_klass();
+  objArrayOop r = oopFactory::new_objArray(ik, shared_classes_list.length(), CHECK);
+  objArrayHandle array_h(THREAD, r);
+
+  for (int i = 0; i < shared_classes_list.length(); i++) {
+    oop mirror = shared_classes_list.at(i)->java_mirror();
+    Handle mirror_h(THREAD, mirror);
+    array_h->obj_at_put(i, mirror_h());
+  }
+
+  TempNewSymbol method = SymbolTable::new_symbol("generatePositiveLookupCache");
+  TempNewSymbol signature = SymbolTable::new_symbol("([Ljava/lang/Class;)V");
+
+  JavaCallArguments args(Handle(THREAD, SystemDictionary::java_system_loader()));
+  args.push_oop(array_h);
+  JavaValue result(T_VOID);
+  JavaCalls::call_virtual(&result,
+                          vmClasses::jdk_internal_loader_ClassLoaders_AppClassLoader_klass(),
+                          method,
+                          signature,
+                          &args,
+                          CHECK);
+
+  if (HAS_PENDING_EXCEPTION) {
+    Handle exc_handle(THREAD, PENDING_EXCEPTION);
+    CLEAR_PENDING_EXCEPTION;
+    ResourceMark rm(THREAD);
+
+    log_warning(cds)("Exception during AppClassLoader::generatePositiveLookupCache() call");
+    LogStreamHandle(Debug, cds) log;
+    if (log.is_enabled()) {
+      java_lang_Throwable::print_stack_trace(exc_handle, &log);
+    }
+    return;
+  }
+}
