1 /*
2 * Copyright (c) 2024, 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/aotClassLinker.hpp"
26 #include "cds/aotConstantPoolResolver.hpp"
27 #include "cds/aotLinkedClassTable.hpp"
28 #include "cds/archiveBuilder.hpp"
29 #include "cds/archiveUtils.inline.hpp"
30 #include "cds/cdsConfig.hpp"
31 #include "cds/heapShared.hpp"
32 #include "cds/lambdaFormInvokers.inline.hpp"
33 #include "classfile/classLoader.hpp"
34 #include "classfile/dictionary.hpp"
35 #include "classfile/systemDictionary.hpp"
36 #include "classfile/systemDictionaryShared.hpp"
37 #include "classfile/vmClasses.hpp"
38 #include "memory/resourceArea.hpp"
39 #include "oops/constantPool.inline.hpp"
40 #include "oops/instanceKlass.hpp"
41 #include "oops/klass.inline.hpp"
42 #include "runtime/handles.inline.hpp"
43
44 AOTClassLinker::ClassesTable* AOTClassLinker::_vm_classes = nullptr;
45 AOTClassLinker::ClassesTable* AOTClassLinker::_candidates = nullptr;
46 GrowableArrayCHeap<InstanceKlass*, mtClassShared>* AOTClassLinker::_sorted_candidates = nullptr;
47
48 #ifdef ASSERT
49 bool AOTClassLinker::is_initialized() {
50 assert(CDSConfig::is_dumping_archive(), "AOTClassLinker is for CDS dumping only");
51 return _vm_classes != nullptr;
52 }
53 #endif
54
55 void AOTClassLinker::initialize() {
56 assert(!is_initialized(), "sanity");
57
58 _vm_classes = new (mtClass)ClassesTable();
59 _candidates = new (mtClass)ClassesTable();
60 _sorted_candidates = new GrowableArrayCHeap<InstanceKlass*, mtClassShared>(1000);
61
62 for (auto id : EnumRange<vmClassID>{}) {
63 add_vm_class(vmClasses::klass_at(id));
64 }
65
66 assert(is_initialized(), "sanity");
67 }
68
69 void AOTClassLinker::dispose() {
70 assert(is_initialized(), "sanity");
71
72 delete _vm_classes;
73 delete _candidates;
74 delete _sorted_candidates;
75 _vm_classes = nullptr;
76 _candidates = nullptr;
77 _sorted_candidates = nullptr;
78
79 assert(!is_initialized(), "sanity");
80 }
81
82 bool AOTClassLinker::is_vm_class(InstanceKlass* ik) {
83 assert(is_initialized(), "sanity");
84 return (_vm_classes->get(ik) != nullptr);
85 }
86
87 void AOTClassLinker::add_vm_class(InstanceKlass* ik) {
88 assert(is_initialized(), "sanity");
89 bool created;
90 _vm_classes->put_if_absent(ik, &created);
91 if (created) {
92 if (CDSConfig::is_dumping_aot_linked_classes()) {
93 bool v = try_add_candidate(ik);
94 assert(v, "must succeed for VM class");
95 }
96 InstanceKlass* super = ik->super();
97 if (super != nullptr) {
98 add_vm_class(super);
99 }
100 Array<InstanceKlass*>* ifs = ik->local_interfaces();
101 for (int i = 0; i < ifs->length(); i++) {
102 add_vm_class(ifs->at(i));
103 }
104 }
105 }
106
107 bool AOTClassLinker::is_candidate(InstanceKlass* ik) {
108 return (_candidates->get(ik) != nullptr);
109 }
110
111 void AOTClassLinker::add_new_candidate(InstanceKlass* ik) {
112 assert(!is_candidate(ik), "caller need to check");
113 _candidates->put_when_absent(ik, true);
114 _sorted_candidates->append(ik);
115
116 if (log_is_enabled(Info, aot, link)) {
117 ResourceMark rm;
118 log_info(aot, link)("%s %s %p", class_category_name(ik), ik->external_name(), ik);
119 }
120 }
121
122 // ik is a candidate for aot-linking; see if it can really work
123 // that way, and return success or failure. Not only must ik itself
124 // look like a class that can be aot-linked but its supers must also be
125 // aot-linkable.
126 bool AOTClassLinker::try_add_candidate(InstanceKlass* ik) {
127 assert(is_initialized(), "sanity");
128 assert(CDSConfig::is_dumping_aot_linked_classes(), "sanity");
129
130 if (!SystemDictionaryShared::is_builtin(ik)) {
131 // not loaded by a class loader which we know about
132 return false;
133 }
134
135 if (is_candidate(ik)) { // already checked.
136 return true;
137 }
138
139 if (!ik->is_linked() && SystemDictionaryShared::has_class_failed_verification(ik)) {
140 return false;
141 }
142
143 if (ik->is_hidden()) {
144 assert(!ik->defined_by_other_loaders(), "hidden classes are archived only for builtin loaders");
145 if (!CDSConfig::is_dumping_method_handles()) {
146 return false;
147 }
148 if (HeapShared::is_lambda_proxy_klass(ik)) {
149 InstanceKlass* nest_host = ik->nest_host_not_null();
150 if (!try_add_candidate(nest_host)) {
151 ResourceMark rm;
152 log_warning(aot, link)("%s cannot be aot-linked because it nest host is not aot-linked", ik->external_name());
153 return false;
154 }
155 }
156 }
157
158 InstanceKlass* s = ik->super();
159 if (s != nullptr && !try_add_candidate(s)) {
160 return false;
161 }
162
163 Array<InstanceKlass*>* interfaces = ik->local_interfaces();
164 int num_interfaces = interfaces->length();
165 for (int index = 0; index < num_interfaces; index++) {
166 InstanceKlass* intf = interfaces->at(index);
167 if (!try_add_candidate(intf)) {
168 return false;
169 }
170 }
171
172 // There are no loops in the class hierarchy, and this function is always called single-threaded, so
173 // we know ik has not been added yet.
174 assert(CDSConfig::current_thread_is_vm_or_dumper(), "that's why we don't need locks");
175 add_new_candidate(ik);
176
177 return true;
178 }
179
180 void AOTClassLinker::add_candidates() {
181 assert_at_safepoint();
182 if (CDSConfig::is_dumping_aot_linked_classes()) {
183 GrowableArray<Klass*>* klasses = ArchiveBuilder::current()->klasses();
184 for (GrowableArrayIterator<Klass*> it = klasses->begin(); it != klasses->end(); ++it) {
185 Klass* k = *it;
186 if (k->is_instance_klass()) {
187 try_add_candidate(InstanceKlass::cast(k));
188 }
189 }
190 }
191 }
192
193 void AOTClassLinker::write_to_archive() {
194 assert(is_initialized(), "sanity");
195 assert_at_safepoint();
196
197 if (CDSConfig::is_dumping_aot_linked_classes()) {
198 AOTLinkedClassTable* table = AOTLinkedClassTable::get();
199 table->set_boot1(write_classes(nullptr, true));
200 table->set_boot2(write_classes(nullptr, false));
201 table->set_platform(write_classes(SystemDictionary::java_platform_loader(), false));
202 table->set_app(write_classes(SystemDictionary::java_system_loader(), false));
203 }
204 }
205
206 Array<InstanceKlass*>* AOTClassLinker::write_classes(oop class_loader, bool is_javabase) {
207 ResourceMark rm;
208 GrowableArray<InstanceKlass*> list;
209
210 for (int i = 0; i < _sorted_candidates->length(); i++) {
211 InstanceKlass* ik = _sorted_candidates->at(i);
212 if (ik->class_loader() != class_loader) {
213 continue;
214 }
215 if ((ik->module() == ModuleEntryTable::javabase_moduleEntry()) != is_javabase) {
216 continue;
217 }
218
219 list.append(ArchiveBuilder::current()->get_buffered_addr(ik));
220 }
221
222 if (list.length() == 0) {
223 return nullptr;
224 } else {
225 const char* category = class_category_name(list.at(0));
226 log_info(aot, link)("wrote %d class(es) for category %s", list.length(), category);
227 return ArchiveUtils::archive_array(&list);
228 }
229 }
230
231 int AOTClassLinker::num_platform_initiated_classes() {
232 if (CDSConfig::is_dumping_aot_linked_classes()) {
233 // AOTLinkedClassBulkLoader will initiate loading of all public boot classes in the platform loader.
234 return count_public_classes(nullptr);
235 } else {
236 return 0;
237 }
238 }
239
240 int AOTClassLinker::num_app_initiated_classes() {
241 if (CDSConfig::is_dumping_aot_linked_classes()) {
242 // AOTLinkedClassBulkLoader will initiate loading of all public boot/platform classes in the app loader.
243 return count_public_classes(nullptr) + count_public_classes(SystemDictionary::java_platform_loader());
244 } else {
245 return 0;
246 }
247 }
248
249 int AOTClassLinker::count_public_classes(oop loader) {
250 int n = 0;
251 for (int i = 0; i < _sorted_candidates->length(); i++) {
252 InstanceKlass* ik = _sorted_candidates->at(i);
253 if (ik->is_public() && !ik->is_hidden() && ik->class_loader() == loader) {
254 n++;
255 }
256 }
257
258 return n;
259 }
260
261 // Used in logging: "boot1", "boot2", "plat", "app" and "unreg", or "array"
262 const char* AOTClassLinker::class_category_name(Klass* k) {
263 if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space(k)) {
264 k = ArchiveBuilder::current()->get_source_addr(k);
265 }
266
267 if (k->is_array_klass()) {
268 return "array";
269 } else {
270 oop loader = k->class_loader();
271 if (loader == nullptr) {
272 if (k->module() != nullptr &&
273 k->module()->name() != nullptr &&
274 k->module()->name()->equals("java.base")) {
275 return "boot1"; // boot classes in java.base are loaded in the 1st phase
276 } else {
277 return "boot2"; // boot classes outside of java.base are loaded in the 2nd phase phase
278 }
279 } else {
280 if (loader == SystemDictionary::java_platform_loader()) {
281 return "plat";
282 } else if (loader == SystemDictionary::java_system_loader()) {
283 return "app";
284 } else {
285 return "unreg";
286 }
287 }
288 }
289 }
290
291 const char* AOTClassLinker::class_category_name(AOTLinkedClassCategory category) {
292 switch (category) {
293 case AOTLinkedClassCategory::BOOT1:
294 return "boot1";
295 case AOTLinkedClassCategory::BOOT2:
296 return "boot2";
297 case AOTLinkedClassCategory::PLATFORM:
298 return "plat";
299 case AOTLinkedClassCategory::APP:
300 return "app";
301 case AOTLinkedClassCategory::UNREGISTERED:
302 default:
303 return "unreg";
304 }
305 }