< prev index next >

src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2024, 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.
--- 1,7 ---
  /*
!  * Copyright (c) 2024, 2026, 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.

*** 20,10 ***
--- 20,11 ---
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   *
   */
  
+ #include "cds/aotCacheAccess.hpp"
  #include "cds/aotClassInitializer.hpp"
  #include "cds/aotClassLinker.hpp"
  #include "cds/aotLinkedClassBulkLoader.hpp"
  #include "cds/aotLinkedClassTable.hpp"
  #include "cds/cdsConfig.hpp"

*** 40,15 ***
--- 41,25 ---
  #include "oops/instanceKlass.hpp"
  #include "oops/klass.inline.hpp"
  #include "oops/trainingData.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/java.hpp"
+ #include "runtime/perfData.inline.hpp"
  #include "runtime/serviceThread.hpp"
  #include "utilities/growableArray.hpp"
  
+ static PerfCounter* _perf_classes_preloaded = nullptr;
+ static PerfTickCounters* _perf_class_preload_counters = nullptr;
+ 
  void AOTLinkedClassBulkLoader::serialize(SerializeClosure* soc) {
    AOTLinkedClassTable::get()->serialize(soc);
+ 
+   if (soc->reading() && UsePerfData) {
+     JavaThread* THREAD = JavaThread::current();
+     NEWPERFEVENTCOUNTER(_perf_classes_preloaded, SUN_CLS, "preloadedClasses");
+     NEWPERFTICKCOUNTERS(_perf_class_preload_counters, SUN_CLS, "classPreload");
+   }
  }
  
  // This function is called before the VM executes any Java code (include AOT-compiled Java methods).
  //
  // We populate the boot/platform/app class loaders with classes from the AOT cache. This is a fundamental

*** 91,10 ***
--- 102,14 ---
    if (classes == nullptr) {
      return;
    }
  
    for (int i = 0; i < classes->length(); i++) {
+     if (UsePerfData) {
+       _perf_classes_preloaded->inc();
+     }
+ 
      InstanceKlass* ik = classes->at(i);
      if (log_is_enabled(Info, aot, load)) {
        ResourceMark rm(THREAD);
        log_info(aot, load)("%-5s %s%s", category_name, ik->external_name(),
                            ik->is_hidden() ? " (hidden)" : "");

*** 114,15 ***
--- 129,23 ---
        precond(SystemDictionary::find_instance_klass(THREAD, ik->name(), loader) == ik);
      }
    }
  }
  
+ static bool _is_initializing_classes_early = false;
+ bool AOTLinkedClassBulkLoader::is_initializing_classes_early() {
+   return _is_initializing_classes_early;
+ }
+ 
  // Some cached heap objects may hold references to methods in aot-linked
  // classes (via MemberName). We need to make sure all classes are
  // linked before executing any bytecode.
  void AOTLinkedClassBulkLoader::link_classes(JavaThread* current) {
+   _is_initializing_classes_early = true;
    link_classes_impl(current);
+   _is_initializing_classes_early = false;
+ 
    if (current->has_pending_exception()) {
      exit_on_exception(current);
    }
  }
  

*** 133,10 ***
--- 156,17 ---
  
    link_classes_in_table(table->boot1(), CHECK);
    link_classes_in_table(table->boot2(), CHECK);
    link_classes_in_table(table->platform(), CHECK);
    link_classes_in_table(table->app(), CHECK);
+ 
+   init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), true, CHECK);
+   init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot2(), true, CHECK);
+   init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->platform(), true, CHECK);
+   init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->app(), true, CHECK);
+ 
+   log_info(aot, init)("------ finished early class init");
  }
  
  void AOTLinkedClassBulkLoader::link_classes_in_table(Array<InstanceKlass*>* classes, TRAPS) {
    if (classes != nullptr) {
      for (int i = 0; i < classes->length(); i++) {

*** 214,11 ***
    }
  }
  #endif
  
  void AOTLinkedClassBulkLoader::init_javabase_classes(JavaThread* current) {
!   init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), current);
    if (current->has_pending_exception()) {
      exit_on_exception(current);
    }
  }
  
--- 244,11 ---
    }
  }
  #endif
  
  void AOTLinkedClassBulkLoader::init_javabase_classes(JavaThread* current) {
!   init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), false, current);
    if (current->has_pending_exception()) {
      exit_on_exception(current);
    }
  }
  

*** 244,13 ***
  
    assert(h_platform_loader() != nullptr, "must be");
    assert(h_system_loader() != nullptr,   "must be");
  
    AOTLinkedClassTable* table = AOTLinkedClassTable::get();
!   init_classes_for_loader(Handle(), table->boot2(), CHECK);
!   init_classes_for_loader(h_platform_loader, table->platform(), CHECK);
!   init_classes_for_loader(h_system_loader, table->app(), CHECK);
  
    if (Universe::is_fully_initialized() && VerifyDuringStartup) {
      // Make sure we're still in a clean state.
      VM_Verify verify_op;
      VMThread::execute(&verify_op);
--- 274,13 ---
  
    assert(h_platform_loader() != nullptr, "must be");
    assert(h_system_loader() != nullptr,   "must be");
  
    AOTLinkedClassTable* table = AOTLinkedClassTable::get();
!   init_classes_for_loader(Handle(), table->boot2(), false, CHECK);
!   init_classes_for_loader(h_platform_loader, table->platform(), false, CHECK);
!   init_classes_for_loader(h_system_loader, table->app(), false, CHECK);
  
    if (Universe::is_fully_initialized() && VerifyDuringStartup) {
      // Make sure we're still in a clean state.
      VM_Verify verify_op;
      VMThread::execute(&verify_op);

*** 322,26 ***
        SystemDictionary::add_to_initiating_loader(current, ik, loader_data);
      }
    }
  }
  
  // Some AOT-linked classes for <class_loader> must be initialized early. This includes
  // - classes that were AOT-initialized by AOTClassInitializer
  // - the classes of all objects that are reachable from the archived mirrors of
  //   the AOT-linked classes for <class_loader>.
! void AOTLinkedClassBulkLoader::init_classes_for_loader(Handle class_loader, Array<InstanceKlass*>* classes, TRAPS) {
    if (classes != nullptr) {
      for (int i = 0; i < classes->length(); i++) {
        InstanceKlass* ik = classes->at(i);
        assert(ik->class_loader_data() != nullptr, "must be");
!       if (ik->has_aot_initialized_mirror()) {
!         ik->initialize_with_aot_initialized_mirror(CHECK);
        }
      }
    }
  
!   HeapShared::init_classes_for_special_subgraph(class_loader, CHECK);
  }
  
  void AOTLinkedClassBulkLoader::replay_training_at_init(Array<InstanceKlass*>* classes, TRAPS) {
    if (classes != nullptr) {
      for (int i = 0; i < classes->length(); i++) {
--- 352,79 ---
        SystemDictionary::add_to_initiating_loader(current, ik, loader_data);
      }
    }
  }
  
+ // Can we move ik into fully_initialized state before the JVM is able to execute
+ // bytecodes?
+ static bool is_early_init_possible(InstanceKlass* ik) {
+   if (ik->is_runtime_setup_required()) {
+     // Bytecodes need to be executed in order to initialize this class.
+     if (log_is_enabled(Debug, aot, init)) {
+       ResourceMark rm;
+       log_debug(aot, init)("No early init %s: needs runtimeSetup()",
+                            ik->external_name());
+     }
+     return false;
+   }
+ 
+   if (ik->super() != nullptr && !ik->super()->is_initialized()) {
+     // is_runtime_setup_required() == true for a super type
+     if (log_is_enabled(Debug, aot, init)) {
+       ResourceMark rm;
+       log_debug(aot, init)("No early init %s: super type %s not initialized",
+                            ik->external_name(), ik->super()->external_name());
+     }
+     return false;
+   }
+ 
+   Array<InstanceKlass*>* interfaces = ik->local_interfaces();
+   int num_interfaces = interfaces->length();
+   for (int i = 0; i < num_interfaces; i++) {
+     InstanceKlass* intf = interfaces->at(i);
+     if (!intf->is_initialized() && intf->interface_needs_clinit_execution_as_super(/*also_check_supers*/false)) {
+       // is_runtime_setup_required() == true for a super interface
+       if (log_is_enabled(Debug, aot, init)) {
+         ResourceMark rm;
+         log_debug(aot, init)("No early init %s: super type %s not initialized",
+                              ik->external_name(), intf->external_name());
+       }
+       return false;
+     }
+   }
+ 
+   return true;
+ }
+ 
  // Some AOT-linked classes for <class_loader> must be initialized early. This includes
  // - classes that were AOT-initialized by AOTClassInitializer
  // - the classes of all objects that are reachable from the archived mirrors of
  //   the AOT-linked classes for <class_loader>.
! void AOTLinkedClassBulkLoader::init_classes_for_loader(Handle class_loader, Array<InstanceKlass*>* classes, bool early_only, TRAPS) {
    if (classes != nullptr) {
      for (int i = 0; i < classes->length(); i++) {
        InstanceKlass* ik = classes->at(i);
        assert(ik->class_loader_data() != nullptr, "must be");
! 
!       bool do_init = ik->has_aot_initialized_mirror();
+       if (do_init && early_only) {
+         if (is_early_init_possible(ik)) {
+           precond(AOTCacheAccess::is_early_aot_inited_class(ik));
+         } else {
+           do_init = false;
+         }
+       }
+ 
+       if (do_init) {
+         ik->initialize_with_aot_initialized_mirror(early_only, CHECK);
        }
      }
    }
  
!   if (!early_only) {
+     HeapShared::init_classes_for_special_subgraph(class_loader, CHECK);
+   }
  }
  
  void AOTLinkedClassBulkLoader::replay_training_at_init(Array<InstanceKlass*>* classes, TRAPS) {
    if (classes != nullptr) {
      for (int i = 0; i < classes->length(); i++) {

*** 360,5 ***
--- 443,15 ---
      replay_training_at_init(table->boot2(),    CHECK);
      replay_training_at_init(table->platform(), CHECK);
      replay_training_at_init(table->app(),      CHECK);
    }
  }
+ 
+ void AOTLinkedClassBulkLoader::print_counters_on(outputStream* st) {
+   if (UsePerfData && _perf_class_preload_counters != nullptr) {
+     st->print_cr("AOTLinkedClassBulkLoader:");
+     st->print_cr("  preload:           " JLONG_FORMAT_W(6) "us (elapsed) " JLONG_FORMAT_W(6) " (thread) / " JLONG_FORMAT_W(5) " events",
+                  _perf_class_preload_counters->elapsed_counter_value_us(),
+                  _perf_class_preload_counters->thread_counter_value_us(),
+                  _perf_classes_preloaded->get_value());
+   }
+ }
< prev index next >