Skip to content

Commit be1cdd9

Browse files
committed
8344140: Refactor the discovery of AOT cache artifacts
Reviewed-by: ccheung, asmehra
1 parent 973c630 commit be1cdd9

29 files changed

+677
-793
lines changed
+263
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
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 "precompiled.hpp"
26+
#include "cds/aotClassLinker.hpp"
27+
#include "cds/aotArtifactFinder.hpp"
28+
#include "cds/aotClassInitializer.hpp"
29+
#include "cds/dumpTimeClassInfo.inline.hpp"
30+
#include "cds/heapShared.hpp"
31+
#include "classfile/systemDictionaryShared.hpp"
32+
#include "logging/log.hpp"
33+
#include "memory/metaspaceClosure.hpp"
34+
#include "oops/instanceKlass.hpp"
35+
#include "oops/objArrayKlass.hpp"
36+
#include "utilities/resourceHash.hpp"
37+
38+
// All the classes that should be included in the AOT cache (in at least the "allocated" state)
39+
static GrowableArrayCHeap<Klass*, mtClassShared>* _all_cached_classes = nullptr;
40+
41+
// This is a stack that tracks all the AOT-inited classes that are waiting to be passed
42+
// to HeapShared::copy_and_rescan_aot_inited_mirror().
43+
static GrowableArrayCHeap<InstanceKlass*, mtClassShared>* _pending_aot_inited_classes = nullptr;
44+
45+
static const int TABLE_SIZE = 15889; // prime number
46+
using ClassesTable = ResourceHashtable<Klass*, bool, TABLE_SIZE, AnyObj::C_HEAP, mtClassShared>;
47+
static ClassesTable* _seen_classes; // all classes that have been seen by AOTArtifactFinder
48+
static ClassesTable* _aot_inited_classes; // all classes that need to be AOT-initialized.
49+
50+
void AOTArtifactFinder::initialize() {
51+
_all_cached_classes = new GrowableArrayCHeap<Klass*, mtClassShared>();
52+
_pending_aot_inited_classes = new GrowableArrayCHeap<InstanceKlass*, mtClassShared>();
53+
_seen_classes = new (mtClass)ClassesTable();
54+
_aot_inited_classes = new (mtClass)ClassesTable();
55+
}
56+
57+
void AOTArtifactFinder::dispose() {
58+
delete _all_cached_classes;
59+
delete _seen_classes;
60+
delete _aot_inited_classes;
61+
delete _pending_aot_inited_classes;
62+
_all_cached_classes = nullptr;
63+
_seen_classes = nullptr;
64+
_aot_inited_classes = nullptr;
65+
_pending_aot_inited_classes = nullptr;
66+
}
67+
68+
// Find all Klasses and oops that should be included in the AOT cache. See aotArtifactFinder.hpp
69+
void AOTArtifactFinder::find_artifacts() {
70+
// Some classes might have been marked as excluded as a side effect of running
71+
// AOTConstantPoolResolver. Make sure we check all the remaining ones.
72+
//
73+
// Note, if a class is not excluded, it does NOT mean it will be automatically included
74+
// into the AOT cache -- that will be decided by the code below.
75+
SystemDictionaryShared::finish_exclusion_checks();
76+
77+
start_scanning_for_oops();
78+
79+
// Add the primitive array classes
80+
for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
81+
BasicType bt = (BasicType)i;
82+
if (is_java_primitive(bt)) {
83+
add_cached_type_array_class(Universe::typeArrayKlass(bt));
84+
}
85+
}
86+
87+
#if INCLUDE_CDS_JAVA_HEAP
88+
// Add the mirrors that aren't associated with a Klass
89+
// - primitive mirrors (E.g., "int.class" in Java code)
90+
// - mirror of fillerArrayKlass
91+
if (CDSConfig::is_dumping_heap()) {
92+
for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
93+
BasicType bt = (BasicType)i;
94+
if (!is_reference_type(bt)) {
95+
oop orig_mirror = Universe::java_mirror(bt);
96+
oop scratch_mirror = HeapShared::scratch_java_mirror(bt);
97+
HeapShared::scan_java_mirror(orig_mirror);
98+
log_trace(cds, heap, mirror)(
99+
"Archived %s mirror object from " PTR_FORMAT,
100+
type2name(bt), p2i(scratch_mirror));
101+
Universe::set_archived_basic_type_mirror_index(bt, HeapShared::append_root(scratch_mirror));
102+
}
103+
}
104+
105+
// Universe::fillerArrayKlass() isn't in the class hierarchy, so handle it specially.
106+
HeapShared::scan_java_mirror(Universe::fillerArrayKlass()->java_mirror());
107+
}
108+
#endif
109+
110+
// Add all the InstanceKlasses (and their array classes) that are always included.
111+
SystemDictionaryShared::dumptime_table()->iterate_all_live_classes([&] (InstanceKlass* ik, DumpTimeClassInfo& info) {
112+
if (!info.is_excluded()) {
113+
bool add = false;
114+
if (!ik->is_hidden()) {
115+
// All non-hidden classes are always included into the AOT cache
116+
add = true;
117+
} else {
118+
if (!CDSConfig::is_dumping_invokedynamic()) {
119+
// Legacy support of lambda proxies -- these are always included into the AOT cache
120+
if (SystemDictionaryShared::is_registered_lambda_proxy_class(ik)) {
121+
add = true;
122+
}
123+
} else {
124+
assert(!SystemDictionaryShared::is_registered_lambda_proxy_class(ik),
125+
"registered lambda proxies are only for legacy lambda proxy support");
126+
}
127+
}
128+
129+
if (add) {
130+
add_cached_instance_class(ik);
131+
if (AOTClassInitializer::can_archive_initialized_mirror(ik)) {
132+
add_aot_inited_class(ik);
133+
}
134+
}
135+
}
136+
});
137+
138+
#if INCLUDE_CDS_JAVA_HEAP
139+
// Keep scanning until we discover no more class that need to be AOT-initialized.
140+
if (CDSConfig::is_initing_classes_at_dump_time()) {
141+
while (_pending_aot_inited_classes->length() > 0) {
142+
InstanceKlass* ik = _pending_aot_inited_classes->pop();
143+
HeapShared::copy_and_rescan_aot_inited_mirror(ik);
144+
}
145+
}
146+
#endif
147+
148+
// Exclude all the (hidden) classes that have not been discovered by the code above.
149+
SystemDictionaryShared::dumptime_table()->iterate_all_live_classes([&] (InstanceKlass* k, DumpTimeClassInfo& info) {
150+
if (!info.is_excluded() && _seen_classes->get(k) == nullptr) {
151+
info.set_excluded();
152+
assert(k->is_hidden(), "must be");
153+
if (log_is_enabled(Info, cds)) {
154+
ResourceMark rm;
155+
log_info(cds)("Skipping %s: Hidden class", k->name()->as_C_string());
156+
}
157+
}
158+
});
159+
160+
end_scanning_for_oops();
161+
}
162+
163+
void AOTArtifactFinder::start_scanning_for_oops() {
164+
#if INCLUDE_CDS_JAVA_HEAP
165+
if (CDSConfig::is_dumping_heap()) {
166+
HeapShared::start_scanning_for_oops();
167+
}
168+
#endif
169+
}
170+
171+
void AOTArtifactFinder::end_scanning_for_oops() {
172+
#if INCLUDE_CDS_JAVA_HEAP
173+
if (CDSConfig::is_dumping_heap()) {
174+
HeapShared::end_scanning_for_oops();
175+
}
176+
#endif
177+
}
178+
179+
void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) {
180+
if (CDSConfig::is_initing_classes_at_dump_time()) {
181+
assert(ik->is_initialized(), "must be");
182+
add_cached_instance_class(ik);
183+
184+
bool created;
185+
_aot_inited_classes->put_if_absent(ik, &created);
186+
if (created) {
187+
_pending_aot_inited_classes->push(ik);
188+
189+
InstanceKlass* s = ik->java_super();
190+
if (s != nullptr) {
191+
add_aot_inited_class(s);
192+
}
193+
194+
Array<InstanceKlass*>* interfaces = ik->local_interfaces();
195+
int len = interfaces->length();
196+
for (int i = 0; i < len; i++) {
197+
InstanceKlass* intf = interfaces->at(i);
198+
if (intf->is_initialized()) {
199+
add_aot_inited_class(intf);
200+
}
201+
}
202+
}
203+
}
204+
}
205+
206+
void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) {
207+
bool created;
208+
_seen_classes->put_if_absent(ik, &created);
209+
if (created) {
210+
_all_cached_classes->append(ik);
211+
scan_oops_in_instance_class(ik);
212+
if (ik->is_hidden() && CDSConfig::is_initing_classes_at_dump_time()) {
213+
bool succeed = AOTClassLinker::try_add_candidate(ik);
214+
guarantee(succeed, "All cached hidden classes must be aot-linkable");
215+
add_aot_inited_class(ik);
216+
}
217+
}
218+
}
219+
220+
void AOTArtifactFinder::add_cached_type_array_class(TypeArrayKlass* tak) {
221+
bool created;
222+
_seen_classes->put_if_absent(tak, &created);
223+
if (created) {
224+
_all_cached_classes->append(tak);
225+
scan_oops_in_array_class(tak);
226+
}
227+
}
228+
229+
void AOTArtifactFinder::add_cached_class(Klass* k) {
230+
if (k->is_typeArray_klass()) {
231+
add_cached_type_array_class(TypeArrayKlass::cast(k));
232+
} else if (k->is_objArray_klass()) {
233+
add_cached_class(ObjArrayKlass::cast(k)->element_klass());
234+
} else {
235+
add_cached_instance_class(InstanceKlass::cast(k));
236+
}
237+
}
238+
239+
void AOTArtifactFinder::scan_oops_in_instance_class(InstanceKlass* ik) {
240+
#if INCLUDE_CDS_JAVA_HEAP
241+
if (CDSConfig::is_dumping_heap()) {
242+
HeapShared::scan_java_class(ik);
243+
scan_oops_in_array_class(ik->array_klasses());
244+
}
245+
#endif
246+
}
247+
248+
void AOTArtifactFinder::scan_oops_in_array_class(ArrayKlass* ak) {
249+
#if INCLUDE_CDS_JAVA_HEAP
250+
if (CDSConfig::is_dumping_heap()) {
251+
while (ak != nullptr) {
252+
HeapShared::scan_java_class(ak);
253+
ak = ak->array_klass_or_null();
254+
}
255+
}
256+
#endif
257+
}
258+
259+
void AOTArtifactFinder::all_cached_classes_do(MetaspaceClosure* it) {
260+
for (int i = 0; i < _all_cached_classes->length(); i++) {
261+
it->push(_all_cached_classes->adr_at(i));
262+
}
263+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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_AOTARTIFACTFINDER_HPP
26+
#define SHARE_CDS_AOTARTIFACTFINDER_HPP
27+
28+
#include "memory/allStatic.hpp"
29+
#include "utilities/exceptions.hpp"
30+
31+
class ArrayKlass;
32+
class InstanceKlass;
33+
class MetaspaceClosure;
34+
class TypeArrayKlass;
35+
36+
// AOTArtifactFinder finds (the roots of) all artifacts that should be included in the AOT cache. These include:
37+
// [1] C++ Klasses
38+
// [2] Java heap objects
39+
// It also decides what Klasses must be cached in aot-initialized state.
40+
//
41+
// ArchiveBuilder uses [1] as roots to scan for all MetaspaceObjs that need to be cached.
42+
// ArchiveHeapWriter uses [2] to create an image of the archived heap.
43+
//
44+
// [1] is stored in _all_cached_classes in aotArtifactFinder.cpp.
45+
// [2] is stored in HeapShared::archived_object_cache().
46+
//
47+
// Although many Klasses and heap objects are created in the assembly phase, we only store a subset of them into
48+
// the AOT cache. For example:
49+
// - Klasses that fail verification are excluded
50+
// - Many Klasses are stored in non-initialized state, so any initialized static fields in their
51+
// java mirrors must be cleared.
52+
// - To conserve space, we exclude any hidden classes that are not referenced.
53+
//
54+
// The discovery of [1] and [2] is interdependent, and is done inside AOTArtifactFinder::find()
55+
// - We first add a set of roots that must be included in the AOT cache
56+
// - mirrors of primitive classes (e.g., int.class in Java source code).
57+
// - primitive array classes
58+
// - non hidden classes
59+
// - registered lambda proxy classes
60+
// - Whenever a class is added, we scan its constant pool. This will discover references
61+
// to hidden classes. All such hidden classes are added.
62+
// - As heap objects (**Note2) and classes are discovered, we find out what classes must
63+
// be AOT-initialized:
64+
// - If we discover at least one instance of class X, then class X is AOT-initialized (** Note1).
65+
// - If AOTClassInitializer::can_archive_initialized_mirror(X) is true, then X is AOT-initialized.
66+
// - For each AOT-initialized class, we scan all the static fields in its java mirror. This will in
67+
// turn discover more Klasses and java heap objects.
68+
// - The scanning continues until we reach a steady state.
69+
//
70+
// Note1: See TODO comments in HeapShared::archive_object() for exceptions to this rule.
71+
//
72+
// Note2: The scanning of Java objects is done in heapShared.cpp. Please see calls into the HeapShared class
73+
// from AOTArtifactFinder.
74+
75+
class AOTArtifactFinder : AllStatic {
76+
static void start_scanning_for_oops();
77+
static void end_scanning_for_oops();
78+
static void scan_oops_in_instance_class(InstanceKlass* ik);
79+
static void scan_oops_in_array_class(ArrayKlass* ak);
80+
static void add_cached_type_array_class(TypeArrayKlass* tak);
81+
static void add_cached_instance_class(InstanceKlass* ik);
82+
public:
83+
static void initialize();
84+
static void find_artifacts();
85+
static void add_cached_class(Klass* k);
86+
static void add_aot_inited_class(InstanceKlass* ik);
87+
static void all_cached_classes_do(MetaspaceClosure* it);
88+
static void dispose();
89+
};
90+
91+
#endif // SHARE_CDS_AOTARTIFACTFINDER_HPP

0 commit comments

Comments
 (0)