diff a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -23,10 +23,11 @@
  */
 
 #include "precompiled.hpp"
 #include "cds/archiveUtils.hpp"
 #include "cds/cdsConfig.hpp"
+#include "cds/cdsEnumKlass.hpp"
 #include "cds/classListWriter.hpp"
 #include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
@@ -42,10 +43,11 @@
 #include "code/codeCache.hpp"
 #include "code/dependencyContext.hpp"
 #include "compiler/compilationPolicy.hpp"
 #include "compiler/compileBroker.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
+#include "interpreter/bytecodeHistogram.hpp"
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/oopMapCache.hpp"
 #include "interpreter/rewriter.hpp"
 #include "jvm.h"
 #include "jvmtifiles/jvmti.h"
@@ -69,10 +71,11 @@
 #include "oops/klass.inline.hpp"
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/recordComponent.hpp"
 #include "oops/symbol.hpp"
+#include "oops/trainingData.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "prims/methodComparator.hpp"
 #include "runtime/arguments.hpp"
@@ -757,10 +760,101 @@
   } else {
     assert(is_initialized(), "sanity check");
   }
 }
 
+static bool are_super_types_initialized(InstanceKlass* ik) {
+  InstanceKlass* s = ik->java_super();
+  if (s != nullptr && !s->is_initialized()) {
+    return false;
+  }
+
+  if (ik->has_nonstatic_concrete_methods()) {
+    // Only need to recurse if has_nonstatic_concrete_methods which includes declaring and
+    // having a superinterface that declares, non-static, concrete methods
+    Array<InstanceKlass*>* interfaces = ik->local_interfaces();
+    int len = interfaces->length();
+    for (int i = 0; i < len; i++) {
+      InstanceKlass* intf = interfaces->at(i);
+      if (!intf->is_initialized()) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+static void log_class_init_start(outputStream* st, JavaThread* current, InstanceKlass* ik, int init_id) {
+  ResourceMark rm;
+  const char* info = "";
+  if (ik->has_preinitialized_mirror() && CDSConfig::is_loading_heap()) {
+    info = " (preinitialized)";
+  } else if (ik->class_initializer() == nullptr) {
+    info = " (no method)";
+  }
+  st->print("%d Initializing ", init_id);
+  ik->name()->print_value_on(st);
+  st->print_cr("%s (" PTR_FORMAT ") by thread " PTR_FORMAT " \"%s\"", info, p2i(ik), p2i(current), current->name());
+}
+
+static int log_class_init(JavaThread* current, InstanceKlass* ik) {
+  int init_id = -1;
+  LogStreamHandle(Info,  init, class) lsh1;
+  LogStreamHandle(Debug, init)        lsh2;
+  if (lsh1.is_enabled() || lsh2.is_enabled()) {
+    static int call_class_initializer_counter = 0;  // for debugging
+    init_id = Atomic::fetch_then_add(&call_class_initializer_counter, 1);
+    if (lsh1.is_enabled()) {
+      log_class_init_start(&lsh1, current, ik, init_id);
+    }
+    if (lsh2.is_enabled() && ik->class_initializer() != nullptr && !ik->has_preinitialized_mirror()) {
+      log_class_init_start(&lsh2, current, ik, init_id);
+    }
+  }
+  return init_id;
+}
+
+void InstanceKlass::initialize_from_cds(TRAPS) {
+  if (is_initialized()) {
+    return;
+  }
+
+  if (has_preinitialized_mirror() && CDSConfig::is_loading_heap() &&
+      !ForceProfiling &&
+      !RecordTraining &&
+      are_super_types_initialized(this)) {
+    // FIXME: also check for events listeners such as JVMTI, JFR, etc
+    if (log_is_enabled(Info, cds, init)) {
+      ResourceMark rm;
+      log_info(cds, init)("%s (quickest)", external_name());
+    }
+
+    link_class(CHECK);
+
+#ifdef AZZERT
+    {
+      MonitorLocker ml(THREAD, _init_monitor);
+      assert(!initialized(), "sanity");
+      assert(!is_being_initialized(), "sanity");
+      assert(!is_in_error_state(), "sanity");
+    }
+#endif
+
+    log_class_init(THREAD, this);
+    set_init_thread(THREAD);
+    set_initialization_state_and_notify(fully_initialized, CHECK);
+    return;
+  }
+
+  if (log_is_enabled(Info, cds, init)) {
+    ResourceMark rm;
+    log_info(cds, init)("%s%s", external_name(),
+                        (has_preinitialized_mirror() && CDSConfig::is_loading_heap()) ? " (quicker)" : "");
+  }
+  initialize(THREAD);
+}
 
 bool InstanceKlass::verify_code(TRAPS) {
   // 1) Verify the bytecodes
   return Verifier::verify(this, should_verify_class(), THREAD);
 }
@@ -976,10 +1070,12 @@
 
 // Now relocate and link method entry points after class is rewritten.
 // This is outside is_rewritten flag. In case of an exception, it can be
 // executed more than once.
 void InstanceKlass::link_methods(TRAPS) {
+  PerfTraceElapsedTime timer(ClassLoader::perf_ik_link_methods_time());
+
   int len = methods()->length();
   for (int i = len-1; i >= 0; i--) {
     methodHandle m(THREAD, methods()->at(i));
 
     // Set up method entry points for compiler and interpreter    .
@@ -1084,10 +1180,25 @@
   bool wait = false;
   bool throw_error = false;
 
   JavaThread* jt = THREAD;
 
+  if (ForceProfiling) {
+    // Preallocate MDOs.
+    for (int i = 0; i < methods()->length(); i++) {
+      assert(!HAS_PENDING_EXCEPTION, "");
+      methodHandle m(THREAD, methods()->at(i));
+      Method::build_profiling_method_data(m, THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        ResourceMark rm;
+        log_warning(cds)("MDO preallocation failed for %s", external_name());
+        CLEAR_PENDING_EXCEPTION;
+        break;
+      }
+    }
+  }
+
   bool debug_logging_enabled = log_is_enabled(Debug, class, init);
 
   // refer to the JVM book page 47 for description of steps
   // Step 1
   {
@@ -1223,10 +1334,11 @@
 
   // Step 9
   if (!HAS_PENDING_EXCEPTION) {
     set_initialization_state_and_notify(fully_initialized, THREAD);
     debug_only(vtable().verify(tty, true);)
+    CompilationPolicy::replay_training_at_init(this, THREAD);
   }
   else {
     // Step 10 and 11
     Handle e(THREAD, PENDING_EXCEPTION);
     CLEAR_PENDING_EXCEPTION;
@@ -1253,11 +1365,10 @@
     }
   }
   DTRACE_CLASSINIT_PROBE_WAIT(end, -1, wait);
 }
 
-
 void InstanceKlass::set_initialization_state_and_notify(ClassState state, JavaThread* current) {
   MonitorLocker ml(current, _init_monitor);
 
   if (state == linked && UseVtableBasedCHA && Universe::is_fully_initialized()) {
     DeoptimizationScope deopt_scope;
@@ -1512,11 +1623,13 @@
   assert(!is_abstract() && !is_interface(), "Should not create this object");
   size_t size = size_helper();  // Query before forming handle.
   return (instanceOop)Universe::heap()->obj_allocate(this, size, CHECK_NULL);
 }
 
-instanceOop InstanceKlass::allocate_instance(oop java_class, TRAPS) {
+instanceOop InstanceKlass::allocate_instance(oop java_class,
+                                             const char* who,
+                                             TRAPS) {
   Klass* k = java_lang_Class::as_Klass(java_class);
   if (k == nullptr) {
     ResourceMark rm(THREAD);
     THROW_(vmSymbols::java_lang_InstantiationException(), nullptr);
   }
@@ -1580,12 +1693,10 @@
 
 ArrayKlass* InstanceKlass::array_klass_or_null() {
   return array_klass_or_null(1);
 }
 
-static int call_class_initializer_counter = 0;   // for debugging
-
 Method* InstanceKlass::class_initializer() const {
   Method* clinit = find_method(
       vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
   if (clinit != nullptr && clinit->has_valid_initializer_flags()) {
     return clinit;
@@ -1603,37 +1714,72 @@
 
 #if INCLUDE_CDS
   // This is needed to ensure the consistency of the archived heap objects.
   if (has_archived_enum_objs()) {
     assert(is_shared(), "must be");
-    bool initialized = HeapShared::initialize_enum_klass(this, CHECK);
+    bool initialized = CDSEnumKlass::initialize_enum_klass(this, CHECK);
     if (initialized) {
       return;
     }
+  } else if (has_preinitialized_mirror() && CDSConfig::is_loading_heap()) {
+    log_class_init(THREAD, this);
+    return;
   }
 #endif
 
   methodHandle h_method(THREAD, class_initializer());
   assert(!is_initialized(), "we cannot initialize twice");
+  int init_id = log_class_init(THREAD, this);
+  if (h_method() != nullptr) {
+    JavaCallArguments args; // No arguments
+    JavaValue result(T_VOID);
+    InstanceKlass* outer = THREAD->set_class_being_initialized(this);
+    jlong bc_start = (CountBytecodesPerThread ? THREAD->bc_counter_value() : BytecodeCounter::counter_value());
+
+    elapsedTimer timer;
+    {
+      PerfPauseTimer pt(THREAD->current_rt_call_timer(), THREAD->profile_rt_calls());
+      PauseRuntimeCallProfiling prcp(THREAD, THREAD->profile_rt_calls());
+
+      timer.start();
+      JavaCalls::call(&result, h_method, &args, THREAD); // Static call (no args)
+      timer.stop();
+    }
+
+    jlong bc_end = (CountBytecodesPerThread ? THREAD->bc_counter_value() : BytecodeCounter::counter_value());
+
+    jlong bc_executed = (bc_end - bc_start);
+    if (UsePerfData && outer == nullptr) { // outermost clinit
+      THREAD->inc_clinit_bc_counter_value(bc_executed);
+      ClassLoader::perf_class_init_bytecodes_count()->inc(bc_executed);
+    }
+
+    THREAD->set_class_being_initialized(outer);
+
+    LogStreamHandle(Debug, init) log;
+    if (log.is_enabled()) {
+      ResourceMark rm(THREAD);
+      log.print("%d Initialized in %.3fms (total: %ldms); ",
+                init_id, timer.seconds() * 1000.0, ClassLoader::class_init_time_ms());
+      if (CountBytecodes || CountBytecodesPerThread) {
+        log.print("executed %ld bytecodes; ", bc_executed);
+      }
+      name()->print_value_on(&log);
+      log.print_cr(" by thread " PTR_FORMAT " \"%s\" (" PTR_FORMAT ")",
+                   p2i(THREAD), THREAD->name(), p2i(this));
+    }
+  }
   LogTarget(Info, class, init) lt;
   if (lt.is_enabled()) {
     ResourceMark rm(THREAD);
     LogStream ls(lt);
-    ls.print("%d Initializing ", call_class_initializer_counter++);
+    ls.print("%d Initialized ", init_id);
     name()->print_value_on(&ls);
-    ls.print_cr("%s (" PTR_FORMAT ") by thread \"%s\"",
-                h_method() == nullptr ? "(no method)" : "", p2i(this),
-                THREAD->name());
-  }
-  if (h_method() != nullptr) {
-    JavaCallArguments args; // No arguments
-    JavaValue result(T_VOID);
-    JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)
+    ls.print_cr("%s (" PTR_FORMAT ")", h_method() == nullptr ? "(no method)" : "", p2i(this));
   }
 }
 
-
 void InstanceKlass::mask_for(const methodHandle& method, int bci,
   InterpreterOopMap* entry_for) {
   // Lazily create the _oop_map_cache at first request.
   // Load_acquire is needed to safely get instance published with CAS by another thread.
   OopMapCache* oop_map_cache = Atomic::load_acquire(&_oop_map_cache);
@@ -2390,11 +2536,11 @@
   DependencyContext dep_context(&_dep_context, &_dep_context_last_cleaned);
   return dep_context;
 }
 
 void InstanceKlass::mark_dependent_nmethods(DeoptimizationScope* deopt_scope, KlassDepChange& changes) {
-  dependencies().mark_dependent_nmethods(deopt_scope, changes);
+  dependencies().mark_dependent_nmethods(deopt_scope, changes, this);
 }
 
 void InstanceKlass::add_dependent_nmethod(nmethod* nm) {
   dependencies().add_dependent_nmethod(nm);
 }
@@ -2519,23 +2665,24 @@
         }
       }
     }
   }
 
+  it->push(&_nest_host);
   it->push(&_nest_members);
   it->push(&_permitted_subclasses);
   it->push(&_record_components);
 }
 
 #if INCLUDE_CDS
 void InstanceKlass::remove_unshareable_info() {
-
   if (is_linked()) {
     assert(can_be_verified_at_dumptime(), "must be");
     // Remember this so we can avoid walking the hierarchy at runtime.
     set_verified_at_dump_time();
   }
+  _misc_flags.set_has_init_deps_processed(false);
 
   Klass::remove_unshareable_info();
 
   if (SystemDictionaryShared::has_class_failed_verification(this)) {
     // Classes are attempted to link during dumping and may fail,
@@ -2553,11 +2700,12 @@
   { // Otherwise this needs to take out the Compile_lock.
     assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
     init_implementor();
   }
 
-  constants()->remove_unshareable_info();
+  // ConstantPool is cleaned separately. See ArchiveBuilder::make_klasses_shareable()
+  // constants()->remove_unshareable_info();
 
   for (int i = 0; i < methods()->length(); i++) {
     Method* m = methods()->at(i);
     m->remove_unshareable_info();
   }
@@ -2580,15 +2728,20 @@
 
   _init_thread = nullptr;
   _methods_jmethod_ids = nullptr;
   _jni_ids = nullptr;
   _oop_map_cache = nullptr;
-  // clear _nest_host to ensure re-load at runtime
-  _nest_host = nullptr;
+  if (ArchiveInvokeDynamic && HeapShared::is_lambda_proxy_klass(this)) {
+    // keep _nest_host
+  } else {
+    // clear _nest_host to ensure re-load at runtime
+    _nest_host = nullptr;
+  }
   init_shared_package_entry();
   _dep_context_last_cleaned = 0;
   _init_monitor = nullptr;
+  DEBUG_ONLY(_shared_class_load_count = 0);
 
   remove_unshareable_flags();
 }
 
 void InstanceKlass::remove_unshareable_flags() {
@@ -2693,21 +2846,31 @@
 
   // restore the monitor
   _init_monitor = create_init_monitor("InstanceKlassInitMonitorRestored_lock");
 }
 
-// Check if a class or any of its supertypes has a version older than 50.
-// CDS will not perform verification of old classes during dump time because
-// without changing the old verifier, the verification constraint cannot be
-// retrieved during dump time.
-// Verification of archived old classes will be performed during run time.
 bool InstanceKlass::can_be_verified_at_dumptime() const {
+  if (CDSConfig::preserve_all_dumptime_verification_states(this)) {
+    return true;
+  }
+
   if (MetaspaceShared::is_in_shared_metaspace(this)) {
     // This is a class that was dumped into the base archive, so we know
     // it was verified at dump time.
     return true;
   }
+
+  if (ArchiveInvokeDynamic) {
+    // FIXME: this works around JDK-8315719
+    return true;
+  }
+
+  // Check if a class or any of its supertypes has a version older than 50.
+  // CDS will not perform verification of old classes during dump time because
+  // without changing the old verifier, the verification constraint cannot be
+  // retrieved during dump time.
+  // Verification of archived old classes will be performed during run time.
   if (major_version() < 50 /*JAVA_6_VERSION*/) {
     return false;
   }
   if (java_super() != nullptr && !java_super()->can_be_verified_at_dumptime()) {
     return false;
@@ -2734,10 +2897,22 @@
       }
     }
   }
   return false;
 }
+
+int InstanceKlass::shared_class_loader_type() const {
+  if (is_shared_boot_class()) {
+    return ClassLoader::BOOT_LOADER;
+  } else if (is_shared_platform_class()) {
+    return ClassLoader::PLATFORM_LOADER;
+  } else if (is_shared_app_class()) {
+    return ClassLoader::APP_LOADER;
+  } else {
+    return ClassLoader::OTHER;
+  }
+}
 #endif // INCLUDE_CDS
 
 #if INCLUDE_JVMTI
 static void clear_all_breakpoints(Method* m) {
   m->clear_all_breakpoints();
@@ -3503,10 +3678,14 @@
 
 const char* InstanceKlass::init_state_name() const {
   return state_names[init_state()];
 }
 
+const char* InstanceKlass::state2name(ClassState s) {
+  return state_names[s];
+}
+
 void InstanceKlass::print_on(outputStream* st) const {
   assert(is_klass(), "must be klass");
   Klass::print_on(st);
 
   st->print(BULLET"instance size:     %d", size_helper());                        st->cr();
@@ -3845,10 +4024,27 @@
     } else {
       info_stream.print(" source: shared objects file");
     }
   }
 
+  info_stream.print(" loader:");
+  if (is_shared()) {
+    info_stream.print(" %s", SystemDictionaryShared::class_loader_name_for_shared((Klass*)this));
+  } else if (loader_data == ClassLoaderData::the_null_class_loader_data()) {
+    info_stream.print(" boot_loader");
+  } else {
+    oop class_loader = loader_data->class_loader();
+    if (class_loader != nullptr) {
+      info_stream.print(" %s", class_loader->klass()->external_name());
+      oop cl_name_and_id = java_lang_ClassLoader::nameAndId(class_loader);
+      if (cl_name_and_id != nullptr) {
+        info_stream.print(" %s", java_lang_String::as_utf8_string(cl_name_and_id));
+      }
+    } else {
+      info_stream.print(" null");
+    }
+  }
   msg.info("%s", info_stream.as_string());
 
   if (log_is_enabled(Debug, class, load)) {
     stringStream debug_stream;
 
