diff a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp
--- a/src/hotspot/share/runtime/init.cpp
+++ b/src/hotspot/share/runtime/init.cpp
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.
@@ -21,19 +21,23 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "cds/metaspaceShared.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "code/SCCache.hpp"
 #include "compiler/compiler_globals.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "gc/shared/gcHeapSummary.hpp"
 #include "interpreter/bytecodes.hpp"
 #include "logging/logAsyncWriter.hpp"
 #include "memory/universe.hpp"
 #include "nmt/memTracker.hpp"
+#include "oops/trainingData.hpp"
 #include "prims/downcallLinker.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/methodHandles.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/continuation.hpp"
@@ -44,10 +48,11 @@
 #include "runtime/init.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "sanitizers/leak.hpp"
 #include "utilities/macros.hpp"
+#include "utilities/xmlstream.hpp"
 #if INCLUDE_JVMCI
 #include "jvmci/jvmci.hpp"
 #endif
 
 // Initialization done by VM thread in vm_init_globals()
@@ -86,10 +91,18 @@
 bool compilerOracle_init();
 bool compileBroker_init();
 void dependencyContext_init();
 void dependencies_init();
 
+// initialize upcalls before class loading
+bool runtimeUpcalls_open_registration();
+bool runtimeUpcallNop_register_upcalls();
+#if INCLUDE_CDS
+bool cdsEndTrainingUpcall_register_upcalls();
+#endif // INCLUDE_CDS
+void runtimeUpcalls_close_registration();
+
 // Initialization after compiler initialization
 bool universe_post_init();  // must happen after compiler_init
 void javaClasses_init();    // must happen after vtable initialization
 void compiler_stubs_init(bool in_compiler_thread); // compiler's StubRoutines stubs
 void final_stubs_init();    // final StubRoutines stubs
@@ -98,10 +111,12 @@
 // JNI/JVM/JVMTI functions and signal handlers to work properly
 // during VM shutdown
 void perfMemory_exit();
 void ostream_exit();
 
+void perf_jvm_init();
+
 void vm_init_globals() {
   check_ThreadShadow();
   basic_types_init();
   eventlog_init();
   mutex_init();
@@ -111,10 +126,13 @@
   ExternalsRecorder_init(); // After mutex_init() and before CodeCache_init
 }
 
 
 jint init_globals() {
+  perf_jvm_init();
+  MethodHandles::init_counters();
+
   management_init();
   JvmtiExport::initialize_oop_storage();
 #if INCLUDE_JVMTI
   if (AlwaysRecordEvolDependencies) {
     JvmtiExport::set_can_hotswap_or_post_breakpoint(true);
@@ -122,29 +140,30 @@
   }
 #endif
   bytecodes_init();
   classLoader_init1();
   compilationPolicy_init();
+  MetaspaceShared::open_static_archive();
   codeCache_init();
   VM_Version_init();              // depends on codeCache_init for emitting code
   // stub routines in initial blob are referenced by later generated code
   initial_stubs_init();
   // stack overflow exception blob is referenced by the interpreter
   SharedRuntime::generate_initial_stubs();
   jint status = universe_init();  // dependent on codeCache_init and
                                   // initial_stubs_init and metaspace_init.
   if (status != JNI_OK)
     return status;
-
+  SCCache::initialize();
 #ifdef LEAK_SANITIZER
   {
     // Register the Java heap with LSan.
     VirtualSpaceSummary summary = Universe::heap()->create_heap_space_summary();
     LSAN_REGISTER_ROOT_REGION(summary.start(), summary.reserved_size());
   }
 #endif // LEAK_SANITIZER
-
+  SCCache::init2();        // depends on universe_init
   AsyncLogWriter::initialize();
   gc_barrier_stubs_init();   // depends on universe_init, must be before interpreter_init
   continuations_init();      // must precede continuation stub generation
   continuation_stubs_init(); // depends on continuations_init
 #if INCLUDE_JFR
@@ -158,10 +177,23 @@
   return JNI_OK;
 }
 
 jint init_globals2() {
   universe2_init();          // dependent on codeCache_init and initial_stubs_init
+
+  // initialize upcalls before class loading / initialization
+  runtimeUpcalls_open_registration();
+  if (!runtimeUpcallNop_register_upcalls()) {
+    return JNI_EINVAL;
+  }
+#if INCLUDE_CDS
+  if (!cdsEndTrainingUpcall_register_upcalls()) {
+    return JNI_EINVAL;
+  }
+#endif // INCLUDE_CDS
+  runtimeUpcalls_close_registration();
+
   javaClasses_init();        // must happen after vtable initialization, before referenceProcessor_init
   interpreter_init_code();   // after javaClasses_init and before any method gets linked
   referenceProcessor_init();
   jni_handles_init();
 #if INCLUDE_VM_STRUCTS
@@ -182,10 +214,14 @@
   if (EnableJVMCI) {
     JVMCI::initialize_globals();
   }
 #endif
 
+  if (TrainingData::have_data() || TrainingData::need_data()) {
+    TrainingData::initialize();
+  }
+
   if (!universe_post_init()) {
     return JNI_ERR;
   }
   compiler_stubs_init(false /* in_compiler_thread */); // compiler's intrinsics stubs
   final_stubs_init();    // final StubRoutines stubs
@@ -193,10 +229,12 @@
 
   // All the flags that get adjusted by VM_Version_init and os::init_2
   // have been set so dump the flags now.
   if (PrintFlagsFinal || PrintFlagsRanges) {
     JVMFlag::printFlags(tty, false, PrintFlagsRanges);
+  } else if (RecordTraining && xtty != nullptr) {
+    JVMFlag::printFlags(xtty->log_only(), false, PrintFlagsRanges);
   }
 
   return JNI_OK;
 }
 
