/*
   Examples of using stable booleans and nullable references,
   for tracking split initialization states.

   A split initialization state is a refactoring of a single
   class's static initialization logic (the <clinit> method)
   into two or more class initializers, which run during two
   distinct bootstrap phases.

   The first phase may be the Leyden Premain assembly phase, and may
   thus be marked AOT.  The last phase happens whenever the most
   complex API points of the original class are executed, during the
   full application run (and not during the assembly phase).

   A lazy static field (or a StableValue field) might defer that last
   phase of initialization arbitrarily far into the future, for a
   single field, but we do not give an example of that here.
   Still, field-wise split initializations will be the right
   tool to use in some cases.
*/
// JUNK TO MAKE IT COMPILE
import java.util.*;
interface SplitInitsWithStableFields {
@interface Stable { }
interface VM { static void ensureInitialization(Object... stuff) { } }
// END JUNK

class JDKStuff {
    /** This method is safe to call in the earliest phases. */
    public static int getVersion() {
        return 3;
    }
    /** This method is safe to call in the earliest phases,
     *  but it may return an incomplete result during an
     *  early phase.  It is non-public to reflect the fact
     *  that only bootstrap-sensitive code paths, internal
     *  to the JDK, should be calling it.
     */
    static Date getDateIfKnown() {
        // If we are in assembly phase, use an placeholder:
        if (!READY)  return new Date(0);

        // This next statement would trigger initialization,
        // except that if READY is true, it has happened.
        return RuntimeConfig.DATE;
    }

    /** This method will trigger all necessary
     *  initialization phases.  It might not
     *  be safe to call in the earliest phases.
     */
    public static Date getDate() {
        assert READY;  // catch bootstrap errors during assembly phase
        return RuntimeConfig.DATE;
    }

    /** Variation of getDate which uses a stable ref. */
    public static Date getDate2() {
        assert READY;  // catch bootstrap errors during assembly phase
        return STABLE_DATE;
    }

    // Here is the wiring to support the split initialization.

    // The variable is mutable to allow it to vary from phase
    // to phase.  The variable is stable so that the JIT can
    // inline its value, which happens only if it is true
    // (that is, not the default value false).
    @Stable private static boolean READY;

    // This variable is also stable so that the JIT can
    // inline its value, which happens only if it is
    // non-null (that is, not the default value null).
    @Stable private static Date STABLE_DATE;

    static {
        // By scheduling the later initialization phase,
        // split out from this class's <clinit> method,
        // we ensure that "assert READY" never fails
        // during production, only assembly phase.
        int LATER_PHASE = 1;  // some indication of "when later?"
        VM.ensureInitialization(RuntimeConfig.class, LATER_PHASE);
    }
    private static class RuntimeConfig {
        // This class exists to "split out" a separate
        // initialization event that is a followup to
        // the first initialization phase of JDKStuff.
        // In this case, we "look at the clock", a
        // classic operation that is unsafe to do
        // when assembling an AOT cache.
        private static final Date DATE = new Date();

        static {
            // Example of pushing init state to a nullable stable:
            JDKStuff.STABLE_DATE = DATE;

            // Now it is safe to execute all the API points.
            JDKStuff.READY = true;
        }
    }
    private static class AOTConfig {
        // There may sometimes be reasons to push the
        // AOT-specific logic into a private nested
        // class.  Such logic would go here.
        //
        // For example, there may be some special
        // coupling with the VM's C++ code to adjust
        // some AOT state during the assembly phase
        // before dumping the AOT cache, and the logic
        // might go here to keep it organized separately
        // from the main non-bootstrap logic of the
        // top-level class.
    }
}
}