Skip to content

Commit fd30ae9

Browse files
committed
8350550: Preload classes from AOT cache during VM bootstrap
Reviewed-by: kvn, heidinga, asmehra
1 parent 61acdf6 commit fd30ae9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+704
-406
lines changed

src/hotspot/share/cds/aotClassInitializer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
#include "cds/aotClassInitializer.hpp"
26+
#include "cds/aotLinkedClassBulkLoader.hpp"
2627
#include "cds/archiveBuilder.hpp"
2728
#include "cds/cdsConfig.hpp"
2829
#include "cds/heapShared.hpp"

src/hotspot/share/cds/aotClassLinker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ void AOTClassLinker::write_to_archive() {
192192

193193
if (CDSConfig::is_dumping_aot_linked_classes()) {
194194
AOTLinkedClassTable* table = AOTLinkedClassTable::get();
195-
table->set_boot(write_classes(nullptr, true));
195+
table->set_boot1(write_classes(nullptr, true));
196196
table->set_boot2(write_classes(nullptr, false));
197197
table->set_platform(write_classes(SystemDictionary::java_platform_loader(), false));
198198
table->set_app(write_classes(SystemDictionary::java_system_loader(), false));

src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp

Lines changed: 169 additions & 267 deletions
Large diffs are not rendered by default.

src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,34 +39,40 @@ template <typename T> class Array;
3939
enum class AOTLinkedClassCategory : int;
4040

4141
// During a Production Run, the AOTLinkedClassBulkLoader loads all classes from
42-
// a AOTLinkedClassTable into their respective ClassLoaders. This happens very early
43-
// in the JVM bootstrap stage, before any application code is executed.
42+
// the AOTLinkedClassTable into their respective ClassLoaders. This happens very early
43+
// in the JVM bootstrap stage, before any Java bytecode is executed.
4444
//
45+
// IMPLEMENTATION NOTES:
46+
// We also proactively link all the classes in the AOTLinkedClassTable, and move
47+
// the AOT-initialized classes to the "initialized" state. Due to limitations
48+
// of the current JVM bootstrap sequence, link_or_init_javabase_classes() and
49+
// link_or_init_non_javabase_classes() need to be called after some Java bytecodes are
50+
// executed. Future RFEs will move these calls to earlier stages.
4551
class AOTLinkedClassBulkLoader : AllStatic {
46-
static bool _boot2_completed;
47-
static bool _platform_completed;
48-
static bool _app_completed;
49-
static bool _all_completed;
50-
static void load_classes_in_loader(JavaThread* current, AOTLinkedClassCategory class_category, oop class_loader_oop);
51-
static void load_classes_in_loader_impl(AOTLinkedClassCategory class_category, oop class_loader_oop, TRAPS);
52-
static void load_table(AOTLinkedClassTable* table, AOTLinkedClassCategory class_category, Handle loader, TRAPS);
53-
static void initiate_loading(JavaThread* current, const char* category, Handle initiating_loader, Array<InstanceKlass*>* classes);
54-
static void load_classes_impl(AOTLinkedClassCategory class_category, Array<InstanceKlass*>* classes,
55-
const char* category_name, Handle loader, TRAPS);
56-
static void load_hidden_class(ClassLoaderData* loader_data, InstanceKlass* ik, TRAPS);
57-
static void init_required_classes_for_loader(Handle class_loader, Array<InstanceKlass*>* classes, TRAPS);
52+
static void preload_classes_impl(TRAPS);
53+
static void preload_classes_in_table(Array<InstanceKlass*>* classes,
54+
const char* category_name, Handle loader, TRAPS);
55+
static void initiate_loading(JavaThread* current, const char* category, Handle initiating_loader,
56+
Array<InstanceKlass*>* classes);
57+
static void link_or_init_non_javabase_classes_impl(TRAPS);
58+
static void link_or_init_classes_for_loader(Handle class_loader, Array<InstanceKlass*>* classes, TRAPS);
5859
static void replay_training_at_init(Array<InstanceKlass*>* classes, TRAPS) NOT_CDS_RETURN;
60+
61+
#ifdef ASSERT
62+
static void validate_module_of_preloaded_classes();
63+
static void validate_module_of_preloaded_classes_in_table(Array<InstanceKlass*>* classes,
64+
const char* category_name, Handle loader);
65+
static void validate_module(Klass* k, const char* category_name, oop module_oop);
66+
#endif
67+
5968
public:
6069
static void serialize(SerializeClosure* soc) NOT_CDS_RETURN;
61-
62-
static void load_javabase_classes(JavaThread* current) NOT_CDS_RETURN;
63-
static void load_non_javabase_classes(JavaThread* current) NOT_CDS_RETURN;
64-
static void finish_loading_javabase_classes(TRAPS) NOT_CDS_RETURN;
70+
static void preload_classes(JavaThread* current);
71+
static void link_or_init_javabase_classes(JavaThread* current) NOT_CDS_RETURN;
72+
static void link_or_init_non_javabase_classes(JavaThread* current) NOT_CDS_RETURN;
6573
static void exit_on_exception(JavaThread* current);
6674

6775
static void replay_training_at_init_for_preloaded_classes(TRAPS) NOT_CDS_RETURN;
68-
static bool class_preloading_finished();
69-
static bool is_pending_aot_linked_class(Klass* k) NOT_CDS_RETURN_(false);
7076
};
7177

7278
#endif // SHARE_CDS_AOTLINKEDCLASSBULKLOADER_HPP

src/hotspot/share/cds/aotLinkedClassTable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
AOTLinkedClassTable AOTLinkedClassTable::_instance;
3131

3232
void AOTLinkedClassTable::serialize(SerializeClosure* soc) {
33-
soc->do_ptr((void**)&_boot);
33+
soc->do_ptr((void**)&_boot1);
3434
soc->do_ptr((void**)&_boot2);
3535
soc->do_ptr((void**)&_platform);
3636
soc->do_ptr((void**)&_app);

src/hotspot/share/cds/aotLinkedClassTable.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -41,26 +41,27 @@ class SerializeClosure;
4141
class AOTLinkedClassTable {
4242
static AOTLinkedClassTable _instance;
4343

44-
Array<InstanceKlass*>* _boot; // only java.base classes
45-
Array<InstanceKlass*>* _boot2; // boot classes in other modules
44+
Array<InstanceKlass*>* _boot1; // boot classes in java.base module
45+
Array<InstanceKlass*>* _boot2; // boot classes in all other (named and unnamed) modules,
46+
// including classes from -Xbootclasspath/a
4647
Array<InstanceKlass*>* _platform;
4748
Array<InstanceKlass*>* _app;
4849

4950
public:
5051
AOTLinkedClassTable() :
51-
_boot(nullptr), _boot2(nullptr),
52+
_boot1(nullptr), _boot2(nullptr),
5253
_platform(nullptr), _app(nullptr) {}
5354

5455
static AOTLinkedClassTable* get() {
5556
return &_instance;
5657
}
5758

58-
Array<InstanceKlass*>* boot() const { return _boot; }
59+
Array<InstanceKlass*>* boot1() const { return _boot1; }
5960
Array<InstanceKlass*>* boot2() const { return _boot2; }
6061
Array<InstanceKlass*>* platform() const { return _platform; }
6162
Array<InstanceKlass*>* app() const { return _app; }
6263

63-
void set_boot (Array<InstanceKlass*>* value) { _boot = value; }
64+
void set_boot1 (Array<InstanceKlass*>* value) { _boot1 = value; }
6465
void set_boot2 (Array<InstanceKlass*>* value) { _boot2 = value; }
6566
void set_platform(Array<InstanceKlass*>* value) { _platform = value; }
6667
void set_app (Array<InstanceKlass*>* value) { _app = value; }

src/hotspot/share/cds/aotMetaspace.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ bool AOTMetaspace::_use_optimized_module_handling = true;
124124
// These regions are aligned with AOTMetaspace::core_region_alignment().
125125
//
126126
// These 2 regions are populated in the following steps:
127-
// [0] All classes are loaded in AOTMetaspace::preload_classes(). All metadata are
127+
// [0] All classes are loaded in AOTMetaspace::load_classes(). All metadata are
128128
// temporarily allocated outside of the shared regions.
129129
// [1] We enter a safepoint and allocate a buffer for the rw/ro regions.
130130
// [2] C++ vtables are copied into the rw region.
@@ -823,20 +823,18 @@ void AOTMetaspace::link_shared_classes(TRAPS) {
823823
}
824824
}
825825

826-
// Preload classes from a list, populate the shared spaces and dump to a
827-
// file.
828-
void AOTMetaspace::preload_and_dump(TRAPS) {
826+
void AOTMetaspace::dump_static_archive(TRAPS) {
829827
CDSConfig::DumperThreadMark dumper_thread_mark(THREAD);
830828
ResourceMark rm(THREAD);
831-
HandleMark hm(THREAD);
829+
HandleMark hm(THREAD);
832830

833831
if (CDSConfig::is_dumping_final_static_archive() && AOTPrintTrainingInfo) {
834832
tty->print_cr("==================== archived_training_data ** before dumping ====================");
835833
TrainingData::print_archived_training_data_on(tty);
836834
}
837835

838836
StaticArchiveBuilder builder;
839-
preload_and_dump_impl(builder, THREAD);
837+
dump_static_archive_impl(builder, THREAD);
840838
if (HAS_PENDING_EXCEPTION) {
841839
if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
842840
aot_log_error(aot)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = "
@@ -902,7 +900,7 @@ void AOTMetaspace::get_default_classlist(char* default_classlist, const size_t b
902900
Arguments::get_java_home(), filesep, filesep);
903901
}
904902

905-
void AOTMetaspace::preload_classes(TRAPS) {
903+
void AOTMetaspace::load_classes(TRAPS) {
906904
char default_classlist[JVM_MAXPATHLEN];
907905
const char* classlist_path;
908906

@@ -929,8 +927,8 @@ void AOTMetaspace::preload_classes(TRAPS) {
929927
}
930928
}
931929

932-
// Some classes are used at CDS runtime but are not loaded, and therefore archived, at
933-
// dumptime. We can perform dummmy calls to these classes at dumptime to ensure they
930+
// Some classes are used at CDS runtime but are not yet loaded at this point.
931+
// We can perform dummmy calls to these classes at dumptime to ensure they
934932
// are archived.
935933
exercise_runtime_cds_code(CHECK);
936934

@@ -946,10 +944,10 @@ void AOTMetaspace::exercise_runtime_cds_code(TRAPS) {
946944
CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK);
947945
}
948946

949-
void AOTMetaspace::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) {
947+
void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS) {
950948
if (CDSConfig::is_dumping_classic_static_archive()) {
951949
// We are running with -Xshare:dump
952-
preload_classes(CHECK);
950+
load_classes(CHECK);
953951

954952
if (SharedArchiveConfigFile) {
955953
log_info(aot)("Reading extra data from %s ...", SharedArchiveConfigFile);

src/hotspot/share/cds/aotMetaspace.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,15 @@ class AOTMetaspace : AllStatic {
7272
n_regions = 5 // total number of regions
7373
};
7474

75-
static void preload_and_dump(TRAPS) NOT_CDS_RETURN;
75+
static void dump_static_archive(TRAPS) NOT_CDS_RETURN;
7676
#ifdef _LP64
7777
static void adjust_heap_sizes_for_dumping() NOT_CDS_JAVA_HEAP_RETURN;
7878
#endif
7979

8080
private:
8181
static void exercise_runtime_cds_code(TRAPS) NOT_CDS_RETURN;
82-
static void preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) NOT_CDS_RETURN;
83-
static void preload_classes(TRAPS) NOT_CDS_RETURN;
82+
static void dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS) NOT_CDS_RETURN;
83+
static void load_classes(TRAPS) NOT_CDS_RETURN;
8484

8585
public:
8686
static Symbol* symbol_rs_base() {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#include "cds/aotMetaspace.hpp"
26+
#include "cds/aotOopChecker.hpp"
27+
#include "cds/heapShared.hpp"
28+
#include "classfile/javaClasses.hpp"
29+
#include "classfile/symbolTable.hpp"
30+
#include "classfile/vmClasses.hpp"
31+
#include "oops/instanceKlass.inline.hpp"
32+
#include "runtime/fieldDescriptor.inline.hpp"
33+
#include "utilities/debug.hpp"
34+
35+
#if INCLUDE_CDS_JAVA_HEAP
36+
37+
oop AOTOopChecker::get_oop_field(oop obj, const char* name, const char* sig) {
38+
Symbol* name_sym = SymbolTable::probe(name, checked_cast<int>(strlen(name)));
39+
assert(name_sym != nullptr, "Symbol must have been resolved for an existing field of this obj");
40+
Symbol* sig_sym = SymbolTable::probe(sig, checked_cast<int>(strlen(sig)));
41+
assert(sig_sym != nullptr, "Symbol must have been resolved for an existing field of this obj");
42+
43+
fieldDescriptor fd;
44+
Klass* k = InstanceKlass::cast(obj->klass())->find_field(name_sym, sig_sym, &fd);
45+
assert(k != nullptr, "field must exist");
46+
precond(!fd.is_static());
47+
precond(fd.field_type() == T_OBJECT || fd.field_type() == T_ARRAY);
48+
return obj->obj_field(fd.offset());
49+
}
50+
51+
// Make sure we are not caching objects with assumptions that can be violated in
52+
// the production run.
53+
void AOTOopChecker::check(oop obj) {
54+
// Currently we only check URL objects, but more rules may be added in the future.
55+
56+
if (obj->klass()->is_subclass_of(vmClasses::URL_klass())) {
57+
// If URL could be subclassed, obj may have new fields that we don't know about.
58+
precond(vmClasses::URL_klass()->is_final());
59+
60+
// URLs are referenced by the CodeSources/ProtectDomains that are cached
61+
// for AOT-linked classes loaded by the platform/app loaders.
62+
//
63+
// Do not cache any URLs whose URLStreamHandler can be overridden by the application.
64+
// - "jrt" and "file" will always use the built-in URLStreamHandler. See
65+
// java.net.URL::isOverrideable().
66+
// - When an AOT-linked class is loaded from a JAR file, its URL is something
67+
// like file:HelloWorl.jar, and does NOT use the "jar" protocol.
68+
oop protocol = get_oop_field(obj, "protocol", "Ljava/lang/String;");
69+
if (!java_lang_String::equals(protocol, "jrt", 3) &&
70+
!java_lang_String::equals(protocol, "file", 4)) {
71+
ResourceMark rm;
72+
log_error(aot)("Must cache only URLs with jrt/file protocols but got: %s",
73+
java_lang_String::as_quoted_ascii(protocol));
74+
HeapShared::debug_trace();
75+
AOTMetaspace::unrecoverable_writing_error();
76+
}
77+
}
78+
}
79+
80+
#endif //INCLUDE_CDS_JAVA_HEAP
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#ifndef SHARE_CDS_AOTOOPCHECKER_HPP
26+
#define SHARE_CDS_AOTOOPCHECKER_HPP
27+
28+
#include "memory/allStatic.hpp"
29+
#include "oops/oopsHierarchy.hpp"
30+
31+
class AOTOopChecker : AllStatic {
32+
static oop get_oop_field(oop obj, const char* name, const char* sig);
33+
34+
public:
35+
// obj is an object that's about to be stored into the AOT cache. Check if it
36+
// can be safely cached.
37+
static void check(oop obj);
38+
};
39+
40+
#endif // SHARE_CDS_AOTOOPCHECKER_HPP

0 commit comments

Comments
 (0)