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