< prev index next > src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp
Print this page
/*
- * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
+ * 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.
* 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"
#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
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)" : "");
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);
}
}
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++) {
}
}
#endif
void AOTLinkedClassBulkLoader::init_javabase_classes(JavaThread* current) {
- init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), current);
+ init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), false, current);
if (current->has_pending_exception()) {
exit_on_exception(current);
}
}
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);
+ 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);
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, TRAPS) {
+ 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");
- if (ik->has_aot_initialized_mirror()) {
- ik->initialize_with_aot_initialized_mirror(CHECK);
+
+ 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);
}
}
}
- HeapShared::init_classes_for_special_subgraph(class_loader, 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++) {
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 >