For a class or interface X annotated with @AOTSafeClassInitializer, it will
be initialized in the AOT assembly phase under two circumstances:
java.lang.invoke package but it may include other cases as well.
If X is initialized during the AOT assembly phase, the VM will store
the values of the static fields of X in the AOT cache. Consequently,
during the production run that uses this AOT cache, the static initializer
(<clinit>) of X will not be executed. X will appear to be in the
"initialized" state and all the cached values of the static field of X
will be available immediately upon the start of the prodcution run.
Currently, this annotation is used mainly for two purposes:
jdk.internal.math.MathUtils class.
java.lang.invoke package.
In more detail, the AOT assembly phase performs the following:
<clinit> for each such class or interface).
@AOTSafeClassInitializer
that was initialized during the training run is proactively initialized.
Thus, in order to determine that a class or interface X is safe to
AOT-initialize requires evaluating every other class or interface Y that
the <clinit> of X will initialize (during AOT cache assembly), and
ensuring that each such Y is (recursively) safe to AOT-initialize.
For example, an AOT-resolved constant pool entry for an invokedynamic or invokehandle bytecode can have direct or indirect references to Java objects. To ensure the correctness of the AOT-resolved constant pool entrties, the VM must AOT-initialize the classes of such Java objects.
In addition, such Java objects may have references to static fields whose
object identity is important. For example, PrimitiveClassDescImpl::CD_void.
To ensure correctness, we must also store classes like PrimitiveClassDescImpl
in the initialized state. The VM requires implementor to manually annotate
such classes with @AOTSafeClassInitializer.
There is one more requirement for a class to be safe for AOT initialization, and that is compatibility with all eventual production runs. The state of an AOT-initialized class X must not contain any data (anything reachable from X) that is incompatible with the eventual production run.
In general, if some sort of computed datum, environmental setting, or variable behavior may differ between the AOT assembly phase and the production run, it may not be immutably bound to X, if X is to be marked AOT-initialized. Here are specific examples:
The value of an environment string (if it may differ in the production run).
A transient configuration parameter specific to this VM run, such as wall clock time, process ID, host name, temporary directory names, etc.
A random seed or key that may need to be re-sampled at production startup.
What is more, if the initialization of X computes with some value V obtained from some other class Y, Y should also be safe for AOT initialization, if there is any way for X to detect a mismatch between the version of V produced at AOT time, and the version of V produced in the production run. Specifically, if V has an object identity, X should not test that identity (compare it against another or get its hashcode) unless Y is also marked for AOT initialization.
Thus, to support AOT-time linkage, a class X should be marked for (possible)
AOT initialization whenever objects it creates (such as MethodHandles)
may be required to execute a java.lang.invoke API request, or (more
remotely) if the execution of such an API touches X for initialization,
or even if such an API request is in any way sensitive to values stored in
the fields of X, even if the sensitivity is a simple reference identity
test.
The author of an AOT-initialized class may elect to patch some states at
production startup, using an AOTRuntimeSetup method, as long as the
pre-patched field values (present during AOT assembly) are determined to be
compatible with the post-patched values that apply to the production run.
Before adding this annotation to a class X, the author must determine that it's safe to execute the static initializer of X during the AOT assembly phase. In addition, all supertypes of X must also have this annotation. If a supertype of X is found to be missing this annotation, the AOT assembly phase will fail.
This annotation is only recognized on privileged code and is ignored elsewhere.