From 831a6f90556254aa9d59f00fe3cff5820508103d Mon Sep 17 00:00:00 2001
From: Synzura <867380348@qq.com>
Date: Fri, 6 Mar 2026 15:33:10 +0800
Subject: [PATCH] JProfileCache: add JProfileCache Conservative Init

---
 .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp   |  17 +-
 src/hotspot/cpu/aarch64/globals_aarch64.hpp   |   8 +-
 src/hotspot/share/compiler/compileBroker.cpp  |  24 ++-
 .../share/jprofilecache/jitProfileCache.cpp   |  13 +-
 .../jitProfileCacheFileParser.cpp             |  24 ++-
 .../jitProfileCacheFileParser.hpp             |   4 +-
 .../jprofilecache/jitProfileClassChain.cpp    | 195 ++++++++++++++++--
 .../jprofilecache/jitProfileClassChain.hpp    |  15 +-
 .../share/jprofilecache/jitProfileRecord.cpp  |  64 ++++--
 .../share/jprofilecache/jitProfileRecord.hpp  |  28 ++-
 src/hotspot/share/oops/instanceKlass.cpp      |  20 +-
 src/hotspot/share/runtime/arguments.cpp       |   6 +
 .../share/services/diagnosticCommand.cpp      |  27 +++
 .../share/services/diagnosticCommand.hpp      |  18 ++
 14 files changed, 403 insertions(+), 60 deletions(-)

diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
index 594673db7..7064215eb 100644
--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
@@ -34,6 +34,7 @@
 #include "c1/c1_ValueStack.hpp"
 #include "ci/ciArrayKlass.hpp"
 #include "ci/ciInstance.hpp"
+#include "compiler/compileTask.hpp"
 #include "code/compiledIC.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "gc/shared/gc_globals.hpp"
@@ -74,6 +75,18 @@ static void select_different_registers(Register preserve,
   assert_different_registers(preserve, tmp1, tmp2);
 }
 
+#ifdef ASSERT
+static bool is_linked_jprofile_conservative_c1_compilation(ciMethod* method, Compilation* compilation) {
+  CompileTask* task = compilation->env()->task();
+  return task != nullptr &&
+         task->is_jprofilecache_compilation() &&
+         JProfilingCacheCompileAdvance &&
+         !ProfileCacheAggressiveInit &&
+         method->holder()->is_instance_klass() &&
+         method->holder()->is_linked();
+}
+#endif
+
 
 
 static void select_different_registers(Register preserve,
@@ -318,7 +331,9 @@ int LIR_Assembler::check_icache() {
 
 void LIR_Assembler::clinit_barrier(ciMethod* method) {
   assert(VM_Version::supports_fast_class_init_checks(), "sanity");
-  assert(!method->holder()->is_not_initialized(), "initialization should have been started");
+  assert(!method->holder()->is_not_initialized() ||
+         is_linked_jprofile_conservative_c1_compilation(method, compilation()),
+         "initialization should have been started or be a linked JProfileCache conservative C1 compile");
 
   Label L_skip_barrier;
 
diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp
index 844138136..9a834a779 100644
--- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp
@@ -125,6 +125,11 @@ define_pd_global(intx, InlineSmallCode,          1000);
   product(bool, JProfilingCacheCompileAdvance, false, EXPERIMENTAL,     \
           "Enable JProfilingCacheCompileAdvance from a log file")       \
                                                                         \
+  product(bool, ProfileCacheAggressiveInit, false, EXPERIMENTAL,         \
+          "JProfileCache replay precompile strategy: "\
+          "false=conservative (link-only verify+prepare, no proactive <clinit>); "\
+          "true=aggressive (proactively initialize replay classes)")      \
+                                                                        \
   product(ccstr, CompilationProfileCacheExclude, nullptr, EXPERIMENTAL, \
           "JProfilingCacheCompileAdvance excluding list ")              \
                                                                         \
@@ -133,7 +138,8 @@ define_pd_global(intx, InlineSmallCode,          1000);
                                                                         \
   product(uintx, JProfilingCacheDelayLoadTime, 1000, EXPERIMENTAL,      \
           "Sleep time (in milliseconds) before JProfileCache loads "    \
-          "classes and methods profile ")                               \
+          "classes and methods profile. In aggressive replay mode, "    \
+          "values smaller than 50 are adjusted to 50 automatically.")   \
           range(0, 3600000)                                             \
                                                                         \
   develop(bool, CompilationProfileCacheResolveClassEagerly, true,       \
diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
index 66771cf32..f54cd05e5 100644
--- a/src/hotspot/share/compiler/compileBroker.cpp
+++ b/src/hotspot/share/compiler/compileBroker.cpp
@@ -1149,6 +1149,21 @@ void CompileBroker::mark_on_stack() {
 // CompileBroker::compile_method
 //
 // Request compilation of a method.
+#ifdef ASSERT
+static bool is_linked_jprofile_conservative_compilation(const methodHandle& method,
+                                                        CompileTask::CompileReason compile_reason) {
+#ifdef AARCH64
+  return compile_reason == CompileTask::CompileReason::Reason_JitProfile &&
+         JProfilingCacheCompileAdvance &&
+         !ProfileCacheAggressiveInit &&
+         method->method_holder()->is_instance_klass() &&
+         method->method_holder()->is_linked();
+#else
+  return false;
+#endif
+}
+#endif
+
 void CompileBroker::compile_method_base(const methodHandle& method,
                                         int osr_bci,
                                         int comp_level,
@@ -1160,8 +1175,9 @@ void CompileBroker::compile_method_base(const methodHandle& method,
   guarantee(!method->is_abstract(), "cannot compile abstract methods");
   assert(method->method_holder()->is_instance_klass(),
          "sanity check");
-  assert(!method->method_holder()->is_not_initialized(),
-         "method holder must be initialized");
+  assert(!method->method_holder()->is_not_initialized() ||
+         is_linked_jprofile_conservative_compilation(method, compile_reason),
+         "method holder must be initialized or be a linked JProfileCache conservative compile");
   assert(!method->is_method_handle_intrinsic(), "do not enqueue these guys");
 
   if (CIPrintRequests) {
@@ -1363,7 +1379,9 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
   assert(method->method_holder()->is_instance_klass(), "not an instance method");
   assert(osr_bci == InvocationEntryBci || (0 <= osr_bci && osr_bci < method->code_size()), "bci out of range");
   assert(!method->is_abstract() && (osr_bci == InvocationEntryBci || !method->is_native()), "cannot compile abstract/native methods");
-  assert(!method->method_holder()->is_not_initialized(), "method holder must be initialized");
+  assert(!method->method_holder()->is_not_initialized() ||
+         is_linked_jprofile_conservative_compilation(method, compile_reason),
+         "method holder must be initialized or be a linked JProfileCache conservative compile");
   // return quickly if possible
 
   // lock, make sure that the compilation
diff --git a/src/hotspot/share/jprofilecache/jitProfileCache.cpp b/src/hotspot/share/jprofilecache/jitProfileCache.cpp
index f1a926a27..df34b9f5a 100644
--- a/src/hotspot/share/jprofilecache/jitProfileCache.cpp
+++ b/src/hotspot/share/jprofilecache/jitProfileCache.cpp
@@ -120,12 +120,15 @@ JitProfileCache::JitProfileCacheState JitProfileCache::flush_recorder() {
   if(_jit_profile_cache_state == IS_ERR) {
     return _jit_profile_cache_state;
   }
-  _jit_profile_cache_recorder->flush_record();
-  if (_jit_profile_cache_recorder->is_valid()) {
-    _jit_profile_cache_state = IS_OK;
-  } else {
+  if (!_jit_profile_cache_recorder->flush_record()) {
+    // Dump I/O failures are transient. Keep recorder/cache state so next jcmd can retry.
+    return IS_ERR;
+  }
+  if (!_jit_profile_cache_recorder->is_valid()) {
     _jit_profile_cache_state = IS_ERR;
+    return _jit_profile_cache_state;
   }
+  _jit_profile_cache_state = IS_OK;
   return _jit_profile_cache_state;
 }
 
@@ -284,4 +287,4 @@ void JitProfileCacheInfo::init() {
     parser.increment_parsed_number_count();
   }
   log_info(jprofilecache)("JProfileCache [INFO]: parsed method number %d successful loaded %" PRIu64, parser.parsed_methods(), _method_loaded_count);
-}
\ No newline at end of file
+}
diff --git a/src/hotspot/share/jprofilecache/jitProfileCacheFileParser.cpp b/src/hotspot/share/jprofilecache/jitProfileCacheFileParser.cpp
index e59d34fc5..69c4b3018 100644
--- a/src/hotspot/share/jprofilecache/jitProfileCacheFileParser.cpp
+++ b/src/hotspot/share/jprofilecache/jitProfileCacheFileParser.cpp
@@ -81,6 +81,7 @@ JitProfileCacheFileParser::JitProfileCacheFileParser(randomAccessFileStream* fs,
           _position(0),
           _parsed_method_count(0),
           _total_recorder_method(0),
+          _parsed_version(0),
           _file_stream(fs),
           _max_symbol_length(0),
           _parse_str_buf(nullptr),
@@ -211,11 +212,13 @@ bool JitProfileCacheFileParser::parse_header() {
   u4 appid = read_u4();
   unsigned int version = JitProfileCache::instance()->version();
 
-  if (parse_version != version) {
+  if (parse_version < JITPROFILECACHE_VERSION_V1 || parse_version > version) {
     _is_valid = false;
-    log_error(jprofilecache)("[JitProfileCache] ERROR : Version mismatch, expect %d but %d", version, parse_version);
+    log_error(jprofilecache)("unsupported profile version %d, supported range is [%d, %d]",
+                             parse_version, JITPROFILECACHE_VERSION_V1, version);
     return false;
   }
+  _parsed_version = parse_version;
   if (parse_magic_number != JPROFILECACHE_MAGIC_NUMBER
       || (long)parse_file_size != this->file_size()) {
     _is_valid = false;
@@ -260,6 +263,7 @@ bool JitProfileCacheFileParser::parse_class() {
   int end_position = begin_position + (int)section_size;
   u4 parse_cnt = read_u4();
   logparse_illegal_count_check(parse_cnt, false, end_position);
+  const bool has_clinit_status = parsed_version() >= JITPROFILECACHE_VERSION_V2;
 
   ProfileCacheClassChain* chain = new ProfileCacheClassChain(parse_cnt);
   info_holder()->set_chain(chain);
@@ -271,6 +275,17 @@ bool JitProfileCacheFileParser::parse_class() {
     logparse_illegal_check(parse_loader_char, false, end_position);
     const char* parse_path_char = read_string();
     logparse_illegal_check(parse_path_char, false, end_position);
+    bool clinit_succeeded = true;
+    if (has_clinit_status) {
+      u1 parse_clinit_status = read_u1();
+      logparse_illegal_count_check(parse_clinit_status, false, end_position);
+      if (parse_clinit_status != 0 && parse_clinit_status != 1) {
+        log_error(jprofilecache)("illegal class init status %u", parse_clinit_status);
+        _position = end_position;
+        return false;
+      }
+      clinit_succeeded = parse_clinit_status == 1;
+    }
     Symbol* name = create_symbol(parse_name_char);
     Symbol* loader_name = create_symbol(parse_loader_char);
     Symbol* path = create_symbol(parse_path_char);
@@ -278,6 +293,7 @@ bool JitProfileCacheFileParser::parse_class() {
     chain->at(i)->set_class_name(name);
     chain->at(i)->set_class_loader_name(loader_name);
     chain->at(i)->set_class_path(path);
+    chain->at(i)->set_recorded_clinit_succeeded(clinit_succeeded);
 
     check_class(i, name, loader_name, path, chain);
 
@@ -285,7 +301,7 @@ bool JitProfileCacheFileParser::parse_class() {
 
   // check section size
   if (_position - begin_position != (int)section_size) {
-    log_error(jprofilecache)("[JitProfileCache] ERROR : JitProfile class parse fail");
+    log_error(jprofilecache)("class section parse failed");
     return false;
   }
   return true;
@@ -430,4 +446,4 @@ void JitProfileCacheFileParser::parse_profile_data(ProfileCacheMethodHold* mh) {
     profile_list->append(bpr);
     count--;
   }
-}
\ No newline at end of file
+}
diff --git a/src/hotspot/share/jprofilecache/jitProfileCacheFileParser.hpp b/src/hotspot/share/jprofilecache/jitProfileCacheFileParser.hpp
index 7c4f8c4dc..1619c9496 100644
--- a/src/hotspot/share/jprofilecache/jitProfileCacheFileParser.hpp
+++ b/src/hotspot/share/jprofilecache/jitProfileCacheFileParser.hpp
@@ -58,6 +58,7 @@ public:
 
     int parsed_methods() { return _parsed_method_count; }
     int total_recorder_method()  { return _total_recorder_method; }
+    unsigned int parsed_version() const { return _parsed_version; }
 
     long file_size()              { return _file_size; }
     void set_file_size(long size) { _file_size = size; }
@@ -81,6 +82,7 @@ private:
     int                     _position;
     int                     _parsed_method_count;
     int                     _total_recorder_method;
+    unsigned int            _parsed_version;
     randomAccessFileStream* _file_stream;
 
     int                     _max_symbol_length;
@@ -97,4 +99,4 @@ private:
 };
 
 
-#endif // LINUX_AARCH64_NORMAL_SERVER_FASTDEBUG_JITPROFILECACHELOGPARSER_H
\ No newline at end of file
+#endif // LINUX_AARCH64_NORMAL_SERVER_FASTDEBUG_JITPROFILECACHELOGPARSER_H
diff --git a/src/hotspot/share/jprofilecache/jitProfileClassChain.cpp b/src/hotspot/share/jprofilecache/jitProfileClassChain.cpp
index e6e2fbf73..81dea4bee 100644
--- a/src/hotspot/share/jprofilecache/jitProfileClassChain.cpp
+++ b/src/hotspot/share/jprofilecache/jitProfileClassChain.cpp
@@ -79,6 +79,20 @@ bool ProfileCacheClassChain::ProfileCacheClassChainEntry::is_all_initialized() {
   return true;
 }
 
+bool ProfileCacheClassChain::ProfileCacheClassChainEntry::is_all_linked() {
+  int len = resolved_klasses()->length();
+  if (len == 0) {
+    return false;
+  }
+  for (int i = 0; i < len; i++) {
+    InstanceKlass* k = resolved_klasses()->at(i);
+    if (k != nullptr && !k->is_linked() && !k->is_in_error_state()) {
+      return false;
+    }
+  }
+  return true;
+}
+
 bool ProfileCacheClassChain::ProfileCacheClassChainEntry::contains_redefined_class() {
   int len = resolved_klasses()->length();
   for (int i = 0; i < len; i++) {
@@ -105,6 +119,17 @@ InstanceKlass* ProfileCacheClassChain::ProfileCacheClassChainEntry::get_first_un
   return nullptr;
 }
 
+InstanceKlass* ProfileCacheClassChain::ProfileCacheClassChainEntry::get_first_unlinked_klass() {
+  int len = resolved_klasses()->length();
+  for (int i = 0; i < len; i++) {
+    InstanceKlass* k = resolved_klasses()->at(i);
+    if (k != nullptr && !k->is_linked() && !k->is_in_error_state()) {
+      return k;
+    }
+  }
+  return nullptr;
+}
+
 ProfileCacheClassChain::ProfileCacheClassChain(unsigned int size)
   : _class_chain_inited_index(-1),
     _loaded_class_index(-1),
@@ -274,6 +299,23 @@ void ProfileCacheClassChain::update_loaded_index(int index) {
   set_loaded_index(index - 1);
 }
 
+static bool mark_skipped_if_redefined(ProfileCacheClassChain::ProfileCacheClassChainEntry* entry) {
+  if (entry->contains_redefined_class()) {
+    entry->set_skipped();
+    return true;
+  }
+  return false;
+}
+
+static void enqueue_methods(ProfileCacheClassChain::ProfileCacheClassChainEntry* entry,
+                            Stack<ProfileCacheMethodHold*, mtInternal>& compile_queue) {
+  ProfileCacheMethodHold* mh = entry->method_holder();
+  while (mh != nullptr) {
+    compile_queue.push(mh);
+    mh = mh->next();
+  }
+}
+
 void ProfileCacheClassChain::compile_methodholders_queue(Stack<ProfileCacheMethodHold*, mtInternal>& compile_queue) {
   while (!compile_queue.is_empty()) {
     ProfileCacheMethodHold* pmh = compile_queue.pop();
@@ -290,14 +332,134 @@ void ProfileCacheClassChain::compile_methodholders_queue(Stack<ProfileCacheMetho
 }
 
 void ProfileCacheClassChain::precompilation() {
-  Thread* THREAD = Thread::current();
   if (!try_transition_to_state(PROFILECACHE_COMPILING)) {
     log_warning(jprofilecache)("JProfileCache [WARNING]: The compilation cannot be started in the current state");
     return;
   }
 
+  const bool aggressive_mode = ProfileCacheAggressiveInit;
+  log_info(jprofilecache)("precompile mode=%s",
+                          aggressive_mode ? "aggressive" : "conservative");
+  if (aggressive_mode) {
+    precompile_aggressive();
+  } else {
+    precompile_conservative();
+  }
+}
+
+void ProfileCacheClassChain::precompile_conservative() {
+  Thread* THREAD = Thread::current();
   bool cancel_precompilation = false;
+  for (int index = 0; index < length(); index++) {
+    if (cancel_precompilation) {
+      break;
+    }
+    InstanceKlass* klass = nullptr;
+    Stack<ProfileCacheMethodHold*, mtInternal> compile_queue;
+    {
+      MutexLocker mu(ProfileCacheClassChain_lock);
+      ProfileCacheClassChainEntry* entry = &_entries[index];
+      switch (entry->class_state()) {
+        case ProfileCacheClassChainEntry::_not_loaded:
+          // Keep conservative mode consistent so index refresh can progress.
+          entry->set_skipped();
+        case ProfileCacheClassChainEntry::_load_skipped:
+          break;
+        case ProfileCacheClassChainEntry::_class_loaded:
+          klass = entry->get_first_unlinked_klass();
+          if (klass == nullptr && entry->is_all_linked()) {
+            entry->set_inited();
+            if (!mark_skipped_if_redefined(entry)) {
+              enqueue_methods(entry, compile_queue);
+            }
+          }
+          break;
+        case ProfileCacheClassChainEntry::_class_inited:
+          if (!mark_skipped_if_redefined(entry)) {
+            enqueue_methods(entry, compile_queue);
+          }
+          break;
+        default:
+          {
+            ResourceMark rm;
+            log_error(jprofilecache)("[JitProfileCache] ERROR: class %s has an invalid state %d",
+                              entry->class_name()->as_C_string(),
+                              entry->class_state());
+            return;
+          }
+      }
+    }
+
+    // Conservative mode is link-only: drive verify+prepare without proactive <clinit>.
+    while (klass != nullptr) {
+      assert(THREAD->is_Java_thread(), "sanity check");
+      klass->link_class((JavaThread*)THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        Symbol* loader = JitProfileCacheUtils::get_class_loader_name(klass->class_loader_data());
+        ResourceMark rm;
+        log_warning(jprofilecache)("[JitProfileCache] WARNING: Exceptions happened in linking %s being loaded by %s",
+                            klass->name()->as_C_string(), loader->as_C_string());
+        CLEAR_PENDING_EXCEPTION;
+        MutexLocker mu(ProfileCacheClassChain_lock);
+        _entries[index].set_skipped();
+        klass = nullptr;
+        break;
+      }
+
+      {
+        MutexLocker mu(ProfileCacheClassChain_lock);
+        ProfileCacheClassChainEntry* entry = &_entries[index];
+        klass = entry->get_first_unlinked_klass();
+        if (klass == nullptr && entry->is_loaded() && entry->is_all_linked()) {
+          entry->set_inited();
+          if (!mark_skipped_if_redefined(entry)) {
+            enqueue_methods(entry, compile_queue);
+          }
+        }
+      }
+    }
+
+    {
+      MutexLocker mu(ProfileCacheClassChain_lock);
+      refresh_indexes();
+      if (index > class_chain_inited_index()) {
+        cancel_precompilation = true;
+      }
+    }
+
+    compile_methodholders_queue(compile_queue);
+  }
+}
+
+void ProfileCacheClassChain::precompile_aggressive() {
+  Thread* THREAD = Thread::current();
+  bool cancel_precompilation = false;
+  int aggressive_upper_bound = length() - 1;
+  int first_recorded_clinit_failure_index = -1;
+  {
+    MutexLocker mu(ProfileCacheClassChain_lock);
+    for (int i = 0; i < length(); i++) {
+      if (!_entries[i].recorded_clinit_succeeded()) {
+        first_recorded_clinit_failure_index = i;
+        aggressive_upper_bound = i - 1;
+        break;
+      }
+    }
+  }
+  if (first_recorded_clinit_failure_index >= 0) {
+    log_info(jprofilecache)("aggressive replay stops before first recorded <clinit> failure at index=%d (upper_bound=%d)",
+                            first_recorded_clinit_failure_index, aggressive_upper_bound);
+  } else {
+    log_info(jprofilecache)("aggressive replay has no recorded <clinit> failure (upper_bound=%d)",
+                            aggressive_upper_bound);
+  }
+
   for ( int index = 0; index < length(); index++ ) {
+    if (index > aggressive_upper_bound) {
+      log_info(jprofilecache)("aggressive replay reached configured stop index=%d",
+                              aggressive_upper_bound);
+      break;
+    }
     if (cancel_precompilation) {
       break;
     }
@@ -372,19 +534,24 @@ bool ProfileCacheClassChain::compile_method(ProfileCacheMethodHold* mh) {
   }
 
   InstanceKlass* klass = m->constants()->pool_holder();
-
-  // if klass not initialize return
-  if (!klass->is_initialized()) {
-    return false;
+  const int comp_level = mh->compile_level();
+  if (!ProfileCacheAggressiveInit) {
+    // Conservative replay keeps class handling at link-only.
+    if (!klass->is_linked() || klass->is_in_error_state()) {
+      return false;
+    }
+  } else {
+    // Aggressive mode keeps initialized gate.
+    if (!klass->is_initialized()) {
+      return false;
+    }
   }
 
-  m->set_compiled_by_jprofilecache(true);
-  m->set_jpc_method_holder(mh);
-  int bci = InvocationEntryBci;
-
-  // commit compile
-  bool ret = JitProfileCacheUtils::commit_compilation(m, mh->compile_level(), bci, t);
+  const int bci = InvocationEntryBci;
+  bool ret = JitProfileCacheUtils::commit_compilation(m, comp_level, bci, t);
   if (ret) {
+    m->set_compiled_by_jprofilecache(true);
+    m->set_jpc_method_holder(mh);
     ResourceMark rm;
     log_info(jprofilecache)("[JitProfileCache] method %s successfully compiled",
                      m->name_and_sig_as_C_string());
@@ -396,6 +563,7 @@ void ProfileCacheClassChain::refresh_indexes() {
   assert_lock_strong(ProfileCacheClassChain_lock);
   int loaded = loaded_index();
   int inited = class_chain_inited_index();
+  const bool use_linked_gate = !ProfileCacheAggressiveInit;
   for (int i = inited + 1; i < length(); i++) {
     ProfileCacheClassChainEntry* e = &_entries[i];
     int len = e->resolved_klasses()->length();
@@ -404,7 +572,7 @@ void ProfileCacheClassChain::refresh_indexes() {
     }
     if (e->is_loaded()) {
       assert(len > 0, "class init chain entry state error");
-      if (e->is_all_initialized()) {
+      if (use_linked_gate ? e->is_all_linked() : e->is_all_initialized()) {
         e->set_inited();
       }
     }
@@ -514,10 +682,11 @@ void ProfileCacheClassChain::preload_class_in_constantpool() {
     }
 
     if (current_k != nullptr) {
+      ResourceMark rm;
       current_k->constants()->preload_jprofilecache_classes(JavaThread::current());
       log_info(jprofilecache)("[JitProfileCache] class %s is preloaded",
                                current_k->internal_name());
     }
     klass_index++;
   }
-}
\ No newline at end of file
+}
diff --git a/src/hotspot/share/jprofilecache/jitProfileClassChain.hpp b/src/hotspot/share/jprofilecache/jitProfileClassChain.hpp
index dbed77d11..ec2b2de22 100644
--- a/src/hotspot/share/jprofilecache/jitProfileClassChain.hpp
+++ b/src/hotspot/share/jprofilecache/jitProfileClassChain.hpp
@@ -79,6 +79,7 @@ public:
         _class_loader_name(nullptr),
         _class_path(nullptr),
         _class_state(_not_loaded),
+        _recorded_clinit_succeeded(true),
         _method_holder(nullptr),
         _resolved_klasses(new (mtClass) GrowableArray<InstanceKlass*>(1, mtClass)),
         _method_keep_holders(new (mtClass) GrowableArray<jobject>(1, mtClass)) {  }
@@ -88,6 +89,7 @@ public:
         _class_loader_name(loader_name),
         _class_path(path),
         _class_state(_not_loaded),
+        _recorded_clinit_succeeded(true),
         _method_holder(nullptr),
         _resolved_klasses(new (mtClass) GrowableArray<InstanceKlass*>(1, mtClass)),
         _method_keep_holders(new (mtClass) GrowableArray<jobject>(1, mtClass)) {  }
@@ -127,6 +129,8 @@ public:
     void           set_class_state(int state)   { _class_state = state;}
 
     int            class_state()                { return _class_state; }
+    bool           recorded_clinit_succeeded() const { return _recorded_clinit_succeeded; }
+    void           set_recorded_clinit_succeeded(bool value) { _recorded_clinit_succeeded = value; }
 
     void add_method_holder(ProfileCacheMethodHold* h) {
       h->set_next(_method_holder);
@@ -135,10 +139,14 @@ public:
 
     bool is_all_initialized();
 
+    bool is_all_linked();
+
     bool contains_redefined_class();
 
     InstanceKlass* get_first_uninitialized_klass();
 
+    InstanceKlass* get_first_unlinked_klass();
+
     ProfileCacheMethodHold* method_holder()  { return _method_holder; }
 
   private:
@@ -147,6 +155,7 @@ public:
     Symbol*                              _class_loader_name;
     Symbol*                              _class_path;
     int                                  _class_state;
+    bool                                 _recorded_clinit_succeeded;
 
     ProfileCacheMethodHold*              _method_holder;
     GrowableArray<InstanceKlass*>*       _resolved_klasses;
@@ -220,6 +229,10 @@ private:
 
   void update_class_chain(InstanceKlass* ky, int chain_index);
 
+  void precompile_conservative();
+
+  void precompile_aggressive();
+
   void compile_methodholders_queue(Stack<ProfileCacheMethodHold*, mtInternal>& compile_queue);
 
   void update_loaded_index(int index);
@@ -228,4 +241,4 @@ private:
                                            ProfileCacheClassHolder* holder);
 };
 
-#endif // SHARED_VM_JPROFILECACHE_JITPROFILECLASSCHAIN_HPP
\ No newline at end of file
+#endif // SHARED_VM_JPROFILECACHE_JITPROFILECLASSCHAIN_HPP
diff --git a/src/hotspot/share/jprofilecache/jitProfileRecord.cpp b/src/hotspot/share/jprofilecache/jitProfileRecord.cpp
index 530ce49ca..e29351ec2 100644
--- a/src/hotspot/share/jprofilecache/jitProfileRecord.cpp
+++ b/src/hotspot/share/jprofilecache/jitProfileRecord.cpp
@@ -77,18 +77,19 @@ JitProfileRecorder::JitProfileRecorder():
           _max_symbol_length(0),
           _pos(0),
           _class_init_order_num(-1),
-          _flushed(false),
           _record_file_name(nullptr),
           _profilelog(nullptr),
           _recorder_state(NOT_INIT),
           _class_init_list(nullptr),
           _init_list_tail_node(nullptr),
+          _class_init_nodes(nullptr),
           _profile_record_dict(nullptr){}
 
 JitProfileRecorder::~JitProfileRecorder() {
   if (!ProfilingCacheFile) {
     os::free((void*)logfile_name());
   }
+  delete _class_init_nodes;
   delete _class_init_list;
 }
 
@@ -156,6 +157,7 @@ void JitProfileRecorder::init() {
   }
 
   _class_init_list = new (mtInternal) LinkedListImpl<ClassSymbolEntry>();
+  _class_init_nodes = new (mtInternal) GrowableArray<LinkedListNode<ClassSymbolEntry>*>(128, mtInternal);
   _profile_record_dict = new JitProfileRecordDictionary(PROFILE_RECORDER_HT_SIZE);
   _recorder_state = IS_OK;
 
@@ -174,14 +176,19 @@ int JitProfileRecorder::assign_class_init_order(InstanceKlass* klass) {
     return -1;
   }
   MutexLocker mu(JitProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
+  LinkedListNode<ClassSymbolEntry>* node = nullptr;
   if (_init_list_tail_node == nullptr) {
-    _class_init_list->add(ClassSymbolEntry(record_name, record_loader_name, record_path));
-    _init_list_tail_node = _class_init_list->head();
+    node = _class_init_list->add(ClassSymbolEntry(record_name, record_loader_name, record_path));
+    _init_list_tail_node = node;
   } else {
-    _class_init_list->insert_after(ClassSymbolEntry(record_name, record_loader_name, record_path),
-                                   _init_list_tail_node);
-    _init_list_tail_node = _init_list_tail_node->next();
+    node = _class_init_list->insert_after(ClassSymbolEntry(record_name, record_loader_name, record_path),
+                                          _init_list_tail_node);
+    _init_list_tail_node = node;
   }
+  if (node == nullptr) {
+    return -1;
+  }
+  _class_init_nodes->append(node);
   _class_init_order_num++;
 #ifndef PRODUCT
   klass->set_initialize_order(_class_init_order_num);
@@ -189,12 +196,22 @@ int JitProfileRecorder::assign_class_init_order(InstanceKlass* klass) {
   return _class_init_order_num;
 }
 
-void JitProfileRecorder::add_method(Method* method, int method_bci) {
+void JitProfileRecorder::mark_class_init_result(int init_order, bool success) {
+  if (init_order < 0) {
+    return;
+  }
   MutexLocker mu(JitProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
-  // if is flushed, stop adding method
-  if (is_flushed()) {
+  if (_class_init_nodes == nullptr || init_order >= _class_init_nodes->length()) {
     return;
   }
+  LinkedListNode<ClassSymbolEntry>* node = _class_init_nodes->at(init_order);
+  if (node != nullptr) {
+    node->data()->set_clinit_succeeded(success);
+  }
+}
+
+void JitProfileRecorder::add_method(Method* method, int method_bci) {
+  MutexLocker mu(JitProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
   // not deal with OSR Compilation
   if (method_bci != InvocationEntryBci) {
     return;
@@ -375,6 +392,7 @@ void JitProfileRecorder::write_inited_class() {
   write_u4((u4)class_init_count());
 
   int cnt = 0;
+  int success_cnt = 0;
   const LinkedListNode<ClassSymbolEntry>* node = class_init_list()->head();
   while (node != nullptr) {
     const ClassSymbolEntry* record_entry = node->peek();
@@ -394,10 +412,16 @@ void JitProfileRecorder::write_inited_class() {
     write_string(record_class_name, strlen(record_class_name));
     write_string(record_class_loader_name, strlen(record_class_loader_name));
     write_string(path, strlen(path));
+    write_u1(record_entry->clinit_succeeded() ? (u1)1 : (u1)0);
+    if (record_entry->clinit_succeeded()) {
+      success_cnt++;
+    }
     node = node->next();
     cnt++;
   }
   assert(cnt == class_init_count(), "error happened in profile info record");
+  log_info(jprofilecache)("class init records total=%d success=%d failed=%d",
+                          cnt, success_cnt, cnt - success_cnt);
   unsigned int end_position = _pos;
   unsigned int section_size = end_position - begin_position;
   overwrite_u4(section_size, size_anchor);
@@ -538,12 +562,13 @@ void JitProfileRecorder::record_method_info(Method *method, ConstMethod* const_m
 void JitProfileRecorder::write_profilecache_footer() {
 }
 
-void JitProfileRecorder::flush_record() {
+bool JitProfileRecorder::flush_record() {
   MutexLocker mu(JitProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
-  if (!is_valid() || is_flushed()) {
-    return;
+  if (!is_valid()) {
+    return false;
   }
-  set_flushed(true);
+  _pos = 0;
+  _max_symbol_length = 0;
 
   // open randomAccessFileStream
   if (JProfilingCacheAutoArchiveDir != nullptr) {
@@ -552,8 +577,7 @@ void JitProfileRecorder::flush_record() {
     int fd = open(logfile_name(), O_CREAT, S_IRUSR | S_IWUSR);
     if (fd < 0) {
       log_error(jprofilecache)("[JitProfileCache] ERROR : open log file fail! path is %s", logfile_name());
-      _recorder_state = IS_ERR;
-      return;
+      return false;
     }
     close(fd);
 
@@ -561,8 +585,9 @@ void JitProfileRecorder::flush_record() {
   }
   if (_profilelog == nullptr || !_profilelog->is_open()) {
     log_error(jprofilecache)("[JitProfileCache] ERROR : open log file fail! path is %s", logfile_name());
-    _recorder_state = IS_ERR;
-    return;
+    delete _profilelog;
+    _profilelog = nullptr;
+    return false;
   }
 
   // head section
@@ -598,7 +623,7 @@ void JitProfileRecorder::flush_record() {
       _profilelog = nullptr;
       ::unlink(logfile_name());
       log_error(jprofilecache)("[JitProfileCache] Autogenerate jprofilecache file failed to rename!");
-      return;
+      return false;
     }
   }
 
@@ -607,4 +632,5 @@ void JitProfileRecorder::flush_record() {
   _profilelog = nullptr;
 
   log_info(jprofilecache)("[JitProfileCache] Profile information output completed. File: %s", logfile_name());
-}
\ No newline at end of file
+  return true;
+}
diff --git a/src/hotspot/share/jprofilecache/jitProfileRecord.hpp b/src/hotspot/share/jprofilecache/jitProfileRecord.hpp
index 1fc80c5d4..30543eb91 100644
--- a/src/hotspot/share/jprofilecache/jitProfileRecord.hpp
+++ b/src/hotspot/share/jprofilecache/jitProfileRecord.hpp
@@ -30,6 +30,7 @@
 #include "oops/method.hpp"
 #include "oops/methodData.hpp"
 #include "utilities/linkedlist.hpp"
+#include "utilities/growableArray.hpp"
 
 class JitProfileRecorderEntry : public HashtableEntry<Method*, mtInternal> {
 public:
@@ -83,10 +84,11 @@ private:
 
 class ClassSymbolEntry {
 public:
-    ClassSymbolEntry(Symbol* class_name, Symbol* class_loader_name, Symbol* path)
+    ClassSymbolEntry(Symbol* class_name, Symbol* class_loader_name, Symbol* path, bool clinit_succeeded = false)
         : _class_name(class_name),
         _class_loader_name(class_loader_name),
-        _class_path(path) {
+        _class_path(path),
+        _clinit_succeeded(clinit_succeeded) {
         if (_class_name != nullptr) _class_name->increment_refcount();
         if (_class_loader_name != nullptr) _class_loader_name->increment_refcount();
         if (_class_path != nullptr) _class_path->increment_refcount();
@@ -95,7 +97,8 @@ public:
     ClassSymbolEntry()
         : _class_name(nullptr),
         _class_loader_name(nullptr),
-        _class_path(nullptr) {
+        _class_path(nullptr),
+        _clinit_succeeded(false) {
     }
 
     ~ClassSymbolEntry() {
@@ -107,6 +110,8 @@ public:
     Symbol* class_name() const { return _class_name; }
     Symbol* class_loader_name() const { return _class_loader_name; }
     Symbol* path() const { return _class_path; }
+    bool clinit_succeeded() const { return _clinit_succeeded; }
+    void set_clinit_succeeded(bool succeeded) { _clinit_succeeded = succeeded; }
 
     bool equals(const ClassSymbolEntry& rhs) const {
         return _class_name == rhs._class_name;
@@ -116,11 +121,14 @@ private:
     Symbol* _class_name;
     Symbol* _class_loader_name;
     Symbol* _class_path;
+    bool _clinit_succeeded;
 };
 
 #define KNUTH_HASH_MULTIPLIER  2654435761UL
 #define ADDR_CHANGE_NUMBER 3
-#define JITPROFILECACHE_VERSION  0x1
+#define JITPROFILECACHE_VERSION_V1 0x1
+#define JITPROFILECACHE_VERSION_V2 0x2
+#define JITPROFILECACHE_VERSION  JITPROFILECACHE_VERSION_V2
 
 class JitProfileRecorder : public CHeapObj<mtInternal> {
 public:
@@ -141,9 +149,6 @@ public:
 
     address current_init_order_addr() { return (address)&_class_init_order_num;}
 
-    unsigned int is_flushed()                { return _flushed; }
-    void         set_flushed(bool value)  { _flushed = value; }
-
     const char*  logfile_name()                      { return _record_file_name; }
 
     unsigned int recorded_count() { return _profile_record_dict->count(); }
@@ -158,9 +163,10 @@ public:
 
     void add_method(Method* method, int method_bci);
 
-    void flush_record();
+    bool flush_record();
 
     int assign_class_init_order(InstanceKlass* klass);
+    void mark_class_init_result(int init_order, bool success);
 
     unsigned int compute_hash(Method* method) {
         uint64_t m_addr = (uint64_t)method;
@@ -179,7 +185,6 @@ private:
     int                                          _max_symbol_length;
     unsigned int                                 _pos;
     volatile int                                 _class_init_order_num;
-    volatile bool                                _flushed;
     const char*                                  _record_file_name;
     static const char*                           _auto_jpcfile_name;
     static const char*                           _auto_temp_jpcfile_name;
@@ -189,7 +194,8 @@ private:
     RecorderState                                _recorder_state;
     LinkedListImpl<ClassSymbolEntry>*            _class_init_list;
     LinkedListNode<ClassSymbolEntry>*            _init_list_tail_node;
-    JitProfileRecordDictionary*                     _profile_record_dict;
+    GrowableArray<LinkedListNode<ClassSymbolEntry>*>* _class_init_nodes;
+    JitProfileRecordDictionary*                   _profile_record_dict;
 
 private:
   void write_u1(u1 value);
@@ -210,4 +216,4 @@ private:
   void update_max_symbol_length(int len);
 };
 
-#endif // SHARED_VM_JPROFILECACHE_JITPROFILERECORD_HPP
\ No newline at end of file
+#endif // SHARED_VM_JPROFILECACHE_JITPROFILERECORD_HPP
diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
index a4792348a..89c2d7aad 100644
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -1070,6 +1070,9 @@ void InstanceKlass::initialize_impl(TRAPS) {
   bool wait = false;
 
   JavaThread* jt = THREAD;
+#ifdef AARCH64
+  int jpc_init_order = -1;
+#endif
 
   bool debug_logging_enabled = log_is_enabled(Debug, class, init);
 
@@ -1152,7 +1155,7 @@ void InstanceKlass::initialize_impl(TRAPS) {
 
 #ifdef AARCH64
   if (JProfilingCacheRecording) {
-    JitProfileCache::instance()->recorder()->assign_class_init_order(this);
+    jpc_init_order = JitProfileCache::instance()->recorder()->assign_class_init_order(this);
   }
 #endif
   }
@@ -1177,6 +1180,11 @@ void InstanceKlass::initialize_impl(TRAPS) {
     if (HAS_PENDING_EXCEPTION) {
       Handle e(THREAD, PENDING_EXCEPTION);
       CLEAR_PENDING_EXCEPTION;
+#ifdef AARCH64
+      if (JProfilingCacheRecording) {
+        JitProfileCache::instance()->recorder()->mark_class_init_result(jpc_init_order, false);
+      }
+#endif
       {
         EXCEPTION_MARK;
         add_initialization_error(THREAD, e);
@@ -1215,12 +1223,22 @@ void InstanceKlass::initialize_impl(TRAPS) {
   // Step 9
   if (!HAS_PENDING_EXCEPTION) {
     set_initialization_state_and_notify(fully_initialized, CHECK);
+#ifdef AARCH64
+    if (JProfilingCacheRecording) {
+      JitProfileCache::instance()->recorder()->mark_class_init_result(jpc_init_order, true);
+    }
+#endif
     debug_only(vtable().verify(tty, true);)
   }
   else {
     // Step 10 and 11
     Handle e(THREAD, PENDING_EXCEPTION);
     CLEAR_PENDING_EXCEPTION;
+#ifdef AARCH64
+    if (JProfilingCacheRecording) {
+      JitProfileCache::instance()->recorder()->mark_class_init_result(jpc_init_order, false);
+    }
+#endif
     // JVMTI has already reported the pending exception
     // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
     JvmtiExport::clear_detected_exception(jt);
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
index 3e7118e34..6adb6bb1a 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -3227,6 +3227,12 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
       }
     }
   }
+
+  if (JProfilingCacheCompileAdvance && ProfileCacheAggressiveInit && JProfilingCacheDelayLoadTime < 50) {
+    warning("JProfilingCacheDelayLoadTime (%u) is too small in aggressive replay mode, adjusted to 50 ms",
+            (uint)JProfilingCacheDelayLoadTime);
+    JProfilingCacheDelayLoadTime = 50;
+  }
 #endif
 
   return JNI_OK;
diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp
index ecc65ac5f..852dad4c8 100644
--- a/src/hotspot/share/services/diagnosticCommand.cpp
+++ b/src/hotspot/share/services/diagnosticCommand.cpp
@@ -35,6 +35,9 @@
 #include "compiler/directivesParser.hpp"
 #include "gc/shared/gcVMOperations.hpp"
 #include "gc/shared/gcArguments.hpp"
+#ifdef AARCH64
+#include "jprofilecache/jitProfileCache.hpp"
+#endif
 #include "jvm.h"
 #include "memory/metaspace/metaspaceDCmd.hpp"
 #include "memory/resourceArea.hpp"
@@ -103,6 +106,9 @@ void DCmd::register_dcmds(){
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMDynamicLibrariesDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMInfoDCmd>(full_export, true, false));
+#ifdef AARCH64
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JProfileCacheDumpDCmd>(full_export, true, false));
+#endif
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapInfoDCmd>(full_export, true, false));
@@ -400,6 +406,27 @@ void VMInfoDCmd::execute(DCmdSource source, TRAPS) {
   VMError::print_vm_info(_output);
 }
 
+#ifdef AARCH64
+void JProfileCacheDumpDCmd::execute(DCmdSource source, TRAPS) {
+  if (!JProfilingCacheRecording) {
+    output()->print_cr("JProfileCache recording is not enabled.");
+    return;
+  }
+
+  JitProfileCache* jpc = JitProfileCache::instance();
+  if (jpc == nullptr) {
+    output()->print_cr("JProfileCache is not initialized.");
+    return;
+  }
+
+  if (jpc->flush_recorder() == JitProfileCache::IS_OK) {
+    output()->print_cr("JProfileCache dump completed.");
+  } else {
+    output()->print_cr("JProfileCache dump failed.");
+  }
+}
+#endif
+
 void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
   Universe::heap()->collect(GCCause::_dcmd_gc_run);
 }
diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp
index 98ffa4f57..75fc9a43d 100644
--- a/src/hotspot/share/services/diagnosticCommand.hpp
+++ b/src/hotspot/share/services/diagnosticCommand.hpp
@@ -248,6 +248,24 @@ public:
   virtual void execute(DCmdSource source, TRAPS);
 };
 
+#ifdef AARCH64
+class JProfileCacheDumpDCmd : public DCmd {
+public:
+  JProfileCacheDumpDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
+  static const char* name() { return "VM.jprofilecache_dump"; }
+  static const char* description() {
+    return "Dump JProfileCache recording data immediately.";
+  }
+  static const char* impact() { return "Low"; }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", nullptr};
+    return p;
+  }
+  virtual void execute(DCmdSource source, TRAPS);
+};
+#endif
+
 class SystemGCDCmd : public DCmd {
 public:
   SystemGCDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
-- 
2.43.0