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/aotClassInitializer.hpp"
26 #include "cds/aotLinkedClassBulkLoader.hpp"
27 #include "cds/archiveBuilder.hpp"
28 #include "cds/cdsConfig.hpp"
29 #include "cds/heapShared.hpp"
30 #include "cds/regeneratedClasses.hpp"
31 #include "classfile/symbolTable.hpp"
32 #include "classfile/systemDictionaryShared.hpp"
33 #include "classfile/vmSymbols.hpp"
34 #include "oops/instanceKlass.inline.hpp"
35 #include "oops/symbol.hpp"
36 #include "runtime/java.hpp"
37 #include "runtime/javaCalls.hpp"
38
39 DEBUG_ONLY(InstanceKlass* _aot_init_class = nullptr;)
40
41 bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
42 assert(!ArchiveBuilder::is_active() || !ArchiveBuilder::current()->is_in_buffer_space(ik), "must be source klass");
43 if (!CDSConfig::is_initing_classes_at_dump_time()) {
44 return false;
45 }
46
47 if (RegeneratedClasses::is_regenerated_object(ik)) {
48 ik = RegeneratedClasses::get_original_object(ik);
49 }
50
51 check_aot_annotations(ik);
52
53 if (!ik->is_initialized() && !ik->is_being_initialized()) {
54 if (ik->has_aot_safe_initializer()) {
55 ResourceMark rm;
56 log_info(aot, init)("Class %s is annotated with @AOTSafeClassInitializer but has not been initialized",
57 ik->external_name());
58 }
59 return false;
60 }
61
62 // About "static field that may hold a different value" errors:
63 //
64 // Automatic selection for aot-inited classes
65 // ==========================================
66 //
67 // When CDSConfig::is_initing_classes_at_dump_time is enabled,
68 // AOTArtifactFinder::find_artifacts() finds the classes of all
69 // heap objects that are reachable from HeapShared::_run_time_special_subgraph,
70 // and mark these classes as aot-inited. This preserves the initialized
71 // mirrors of these classes, and their <clinit> methods are NOT executed
72 // at runtime. See aotArtifactFinder.hpp for more info.
73 //
74 // For example, with -XX:+AOTInvokeDynamicLinking, _run_time_special_subgraph
75 // will contain some DirectMethodHandle objects. As a result, the DirectMethodHandle
76 // class is automatically marked as aot-inited.
77 //
78 // When a class is aot-inited, its static fields are already set up
79 // by executing the <clinit> method at AOT assembly time. Later on
80 // in the production run, when the class would normally be
81 // initialized, the VM performs guarding and synchronization as if
82 // it were going to run the <clinit> again, but instead it simply
83 // observes that that class was aot-inited. The VM assumes that, if
84 // it were to run <clinit> again, it would get a semantically
85 // equivalent set of final field values, so it just adopts the
86 // existing field values (from AOT assembly) and skips the call to
87 // <clinit>. There may at that point be fixups performed by ad hoc
88 // code, if the VM recognizes a request in the library.
89 //
90 // It is true that this is not generally correct for all possible
91 // Java code. A <clinit> method might have a side effect beyond
92 // initializing the static fields. It might send an email somewhere
93 // noting the current time of day. In that case, such an email
94 // would have been sent during the AOT assembly phase, and the email
95 // would NOT be sent again during production. This is clearly NOT
96 // what a user would want, if this were a general purpose facility.
97 // But in fact it is only for certain well-behaved classes, which
98 // are known NOT to have such side effects. We know this because
99 // the optimization (of skipping <clinit> for aot-init classes) is
100 // only applied to classes fully defined by the JDK.
101 //
102 // (A day may come when we figure out how to gracefully extend this
103 // optimization to untrusted third parties, but it is not this day.)
104 //
105 // Manual selection
106 // ================
107 //
108 // There are important cases where one aot-init class has a side
109 // effect on another aot-class, a side effect which is not captured
110 // in any static field value in either class. The simplest example
111 // is class A forces the initialization of class B. In that case,
112 // we need to aot-init either both classes or neither. From looking
113 // at the JDK state after AOT assembly is done, it is hard to tell
114 // that A "touched" B and B might escape our notice. Another common
115 // example is A copying a field value from B. We don't know where A
116 // got the value, but it would be wrong to re-initialize B at
117 // startup, while keeping the snapshot of the old B value in A. In
118 // general, if we aot-init A, we need to aot-init every class B that
119 // somehow contributed to A's initial state, and every class C that
120 // was somehow side-effected by A's initialization. We say that the
121 // aot-init of A is "init-coupled" to those of B and C.
122 //
123 // So there are init-coupled classes that cannot be automatically discovered. For
124 // example, DirectMethodHandle::IMPL_NAMES points to MethodHandles::IMPL_NAMES,
125 // but the MethodHandles class is not automatically marked because there are
126 // no archived instances of the MethodHandles type.
127 //
128 // If we aot-initialize DirectMethodHandle, but allow MethodHandles to be
129 // initialized at runtime, MethodHandles::IMPL_NAMES will get a different
130 // value than DirectMethodHandle::IMPL_NAMES. This *may or may not* be a problem,
131 // but to ensure compatibility, we should try to preserve the identity equality
132 // of these two fields.
133 //
134 // To do that, we add MethodHandles to the indy_specs[] table below.
135 //
136 // Luckily we do not need to be all-knowing in order to choose which
137 // items to add to that table. We have tools to help detect couplings.
138 //
139 // Automatic validation
140 // ====================
141 //
142 // CDSHeapVerifier is used to detect potential problems with identity equality.
143 //
144 // A class B is assumed to be init-coupled to some aot-init class if
145 // B has a field which points to a live object X in the AOT heap.
146 // The live object X was created by some other class A which somehow
147 // used B's reference to X, perhaps with the help of an intermediate
148 // class Z. Or, B pulled the reference to X from some other class
149 // Y, and B obtained that reference from Y (or an intermediate Z).
150 // It is not certain how X got into the heap, nor whether B
151 // contributed it, but it is a good heuristic that B is init-coupled
152 // to X's class or some other aot-init class. In any case, B should
153 // be made an aot-init class as well, unless a manual inspection
154 // shows that would be a problem. If there is a problem, then the
155 // JDK code for B and/or X probably needs refactoring. If there is
156 // no problem, we add B to the list. Typically the same scan will
157 // find any other accomplices Y, Z, etc. One failure would be a
158 // class Q whose only initialization action is to scribble a special
159 // value into B, from which the value X is derived and then makes
160 // its way into the heap. In that case, the heuristic does not
161 // identify Q. It is (currently) a human responsibility, of JDK
162 // engineers, not to write such dirty JDK code, or to repair it if
163 // it crops up. Eventually we may have tools, or even a user mode
164 // with design rules and checks, that will vet our code base more
165 // automatically.
166 //
167 // To see how the tool detects the problem with MethodHandles::IMPL_NAMES:
168 //
169 // - Comment out all the lines in indy_specs[] except the {nullptr} line.
170 // - Rebuild the JDK
171 //
172 // Then run the following:
173 // java -XX:AOTMode=record -XX:AOTConfiguration=jc.aotconfig com.sun.tools.javac.Main
174 // java -XX:AOTMode=create -Xlog:aot -XX:AOTCache=jc.aot -XX:AOTConfiguration=jc.aotconfig
175 //
176 // You will see an error like this:
177 //
178 // Archive heap points to a static field that may hold a different value at runtime:
179 // Field: java/lang/invoke/MethodHandles::IMPL_NAMES
180 // Value: java.lang.invoke.MemberName$Factory
181 // {0x000000060e906ae8} - klass: 'java/lang/invoke/MemberName$Factory' - flags:
182 //
183 // - ---- fields (total size 2 words):
184 // --- trace begin ---
185 // [ 0] {0x000000060e8deeb0} java.lang.Class (java.lang.invoke.DirectMethodHandle::IMPL_NAMES)
186 // [ 1] {0x000000060e906ae8} java.lang.invoke.MemberName$Factory
187 // --- trace end ---
188 //
189 // Trouble-shooting
190 // ================
191 //
192 // If you see a "static field that may hold a different value" error, it's probably
193 // because you've made some changes in the JDK core libraries (most likely
194 // java.lang.invoke).
195 //
196 // - Did you add a new static field to a class that could be referenced by
197 // cached object instances of MethodType, MethodHandle, etc? You may need
198 // to add that class to indy_specs[].
199 // - Did you modify the <clinit> of the classes in java.lang.invoke such that
200 // a static field now points to an object that should not be cached (e.g.,
201 // a native resource such as a file descriptior, or a Thread)?
202 //
203 // Note that these potential problems only occur when one class gets
204 // the aot-init treatment, AND another class is init-coupled to it,
205 // AND the coupling is not detected. Currently there are a number
206 // classes that get the aot-init treatment, in java.lang.invoke
207 // because of invokedynamic. They are few enough for now to be
208 // manually tracked. There may be more in the future.
209
210 {
211 if (ik == vmClasses::Object_klass()) {
212 // everybody's favorite super
213 return true;
214 }
215 }
216
217 if (CDSConfig::is_dumping_method_handles()) {
218 // The minimal list of @AOTSafeClassInitializer was created with the help of CDSHeapVerifier.
219 // Also, some $Holder classes are needed. E.g., Invokers.<clinit> explicitly
220 // initializes Invokers$Holder. Since Invokers.<clinit> won't be executed
221 // at runtime, we need to make sure Invokers$Holder is also aot-inited.
222 if (ik->has_aot_safe_initializer()) {
223 return true;
224 }
225 }
226
227 #ifdef ASSERT
228 if (ik == _aot_init_class) {
229 return true;
230 }
231 #endif
232
233 return false;
234 }
235
236 void AOTClassInitializer::call_runtime_setup(JavaThread* current, InstanceKlass* ik) {
237 assert(ik->has_aot_initialized_mirror(), "sanity");
238 if (ik->is_runtime_setup_required()) {
239 if (log_is_enabled(Info, aot, init)) {
240 ResourceMark rm;
241 log_info(aot, init)("Calling %s::runtimeSetup()", ik->external_name());
242 }
243 JavaValue result(T_VOID);
244 JavaCalls::call_static(&result, ik,
245 vmSymbols::runtimeSetup(),
246 vmSymbols::void_method_signature(), current);
247 if (current->has_pending_exception()) {
248 // We cannot continue, as we might have cached instances of ik in the heap, but propagating the
249 // exception would cause ik to be in an error state.
250 AOTLinkedClassBulkLoader::exit_on_exception(current);
251 }
252 }
253 }
254
255 template <typename FUNCTION>
256 void require_annotation_for_super_types(InstanceKlass* ik, const char* annotation, FUNCTION func) {
257 if (log_is_enabled(Info, aot, init)) {
258 ResourceMark rm;
259 log_info(aot, init)("Found %s class %s", annotation, ik->external_name());
260 }
261
262 // Since ik has this annotation, we require that
263 // - all super classes must have this annotation
264 // - all super interfaces that are interface_needs_clinit_execution_as_super()
265 // must have this annotation
266 // This avoid the situation where in the production run, we run the <clinit>
267 // of a supertype but not the <clinit> of ik
268
269 InstanceKlass* super = ik->java_super();
270 if (super != nullptr && !func(super)) {
271 ResourceMark rm;
272 log_error(aot, init)("Missing %s in superclass %s for class %s",
273 annotation, super->external_name(), ik->external_name());
274 AOTMetaspace::unrecoverable_writing_error();
275 }
276
277 int len = ik->local_interfaces()->length();
278 for (int i = 0; i < len; i++) {
279 InstanceKlass* intf = ik->local_interfaces()->at(i);
280 if (intf->interface_needs_clinit_execution_as_super() && !func(intf)) {
281 ResourceMark rm;
282 log_error(aot, init)("Missing %s in superinterface %s for class %s",
283 annotation, intf->external_name(), ik->external_name());
284 AOTMetaspace::unrecoverable_writing_error();
285 }
286 }
287 }
288
289 void AOTClassInitializer::check_aot_annotations(InstanceKlass* ik) {
290 if (ik->has_aot_safe_initializer()) {
291 require_annotation_for_super_types(ik, "@AOTSafeClassInitializer", [&] (const InstanceKlass* supertype) {
292 return supertype->has_aot_safe_initializer();
293 });
294 } else {
295 // @AOTRuntimeSetup only meaningful in @AOTSafeClassInitializer
296 if (ik->is_runtime_setup_required()) {
297 ResourceMark rm;
298 log_error(aot, init)("@AOTRuntimeSetup meaningless in non-@AOTSafeClassInitializer class %s",
299 ik->external_name());
300 }
301 }
302 }
303
304
305 #ifdef ASSERT
306 void AOTClassInitializer::init_test_class(TRAPS) {
307 // -XX:AOTInitTestClass is used in regression tests for adding additional AOT-initialized classes
308 // and heap objects into the AOT cache. The tests must be carefully written to avoid including
309 // any classes that cannot be AOT-initialized.
310 //
311 // -XX:AOTInitTestClass is NOT a general mechanism for including user-defined objects into
312 // the AOT cache. Therefore, this option is NOT available in product JVM.
313 if (AOTInitTestClass != nullptr && CDSConfig::is_initing_classes_at_dump_time()) {
314 log_info(aot)("Debug build only: force initialization of AOTInitTestClass %s", AOTInitTestClass);
315 TempNewSymbol class_name = SymbolTable::new_symbol(AOTInitTestClass);
316 Handle app_loader(THREAD, SystemDictionary::java_system_loader());
317 Klass* k = SystemDictionary::resolve_or_null(class_name, app_loader, CHECK);
318 if (k == nullptr) {
319 vm_exit_during_initialization("AOTInitTestClass not found", AOTInitTestClass);
320 }
321 if (!k->is_instance_klass()) {
322 vm_exit_during_initialization("Invalid name for AOTInitTestClass", AOTInitTestClass);
323 }
324
325 _aot_init_class = InstanceKlass::cast(k);
326 _aot_init_class->initialize(CHECK);
327 }
328 }
329
330 bool AOTClassInitializer::has_test_class() {
331 return _aot_init_class != nullptr;
332 }
333 #endif