< prev index next >

src/java.base/share/classes/jdk/internal/vm/annotation/Stable.java

Print this page
*** 26,60 ***
  package jdk.internal.vm.annotation;
  
  import java.lang.annotation.*;
  
  /**
!  * A field may be annotated as stable if all of its component variables
!  * changes value at most once.
!  * A field's value counts as its component value.
!  * If the field is typed as an array, then all the non-null components
!  * of the array, of depth up to the rank of the field's array type,
!  * also count as component values.
!  * By extension, any variable (either array or field) which has annotated
!  * as stable is called a stable variable, and its non-null or non-zero
!  * value is called a stable value.
!  * <p>
!  * Since all fields begin with a default value of null for references
!  * (resp., zero for primitives), it follows that this annotation indicates
!  * that the first non-null (resp., non-zero) value stored in the field
!  * will never be changed.
-  * <p>
-  * If the field is not of an array type, there are no array elements,
-  * then the value indicated as stable is simply the value of the field.
-  * If the dynamic type of the field value is an array but the static type
-  * is not, the components of the array are <em>not</em> regarded as stable.
-  * <p>
-  * If the field is an array type, then both the field value and
-  * all the components of the field value (if the field value is non-null)
-  * are indicated to be stable.
-  * If the field type is an array type with rank {@code N > 1},
-  * then each component of the field value (if the field value is non-null),
-  * is regarded as a stable array of rank {@code N-1}.
   * <p>
   * Fields which are declared {@code final} may also be annotated as stable.
!  * Since final fields already behave as stable values, such an annotation
   * conveys no additional information regarding change of the field's value, but
!  * still conveys information regarding change of additional components values if
   * the type of the field is an array type (as described above).
   * <p>
!  * The HotSpot VM relies on this annotation to promote a non-null (resp.,
!  * non-zero) component value to a constant, thereby enabling superior
!  * optimizations of code depending on such a value (such as constant folding).
!  * More specifically, the HotSpot VM will process non-null stable fields (final
!  * or otherwise) in a similar manner to static final fields with respect to
!  * promoting the field's value to a constant.  Thus, placing aside the
!  * differences for null/non-null values and arrays, a final stable field is
!  * treated as if it is really final from both the Java language and the HotSpot
!  * VM.
!  * <p>
!  * It is (currently) undefined what happens if a field annotated as stable
!  * is given a third value (by explicitly updating a stable field, a component of
!  * a stable array, or a final stable field via reflection or other means).
!  * Since the HotSpot VM promotes a non-null component value to constant, it may
!  * be that the Java memory model would appear to be broken, if such a constant
!  * (the second value of the field) is used as the value of the field even after
!  * the field value has changed (to a third value).
   *
   * @implNote
   * This annotation only takes effect for fields of classes loaded by the boot
   * loader.  Annotations on fields of classes loaded outside of the boot loader
   * are ignored.
--- 26,328 ---
  package jdk.internal.vm.annotation;
  
  import java.lang.annotation.*;
  
  /**
!  * A field may be annotated as "stable" to indicate that it is a
!  * <em>stable variable</em>, expected to change its value just once.
!  * All Java fields are initialized by the VM with a default value
!  * (null or zero).  A properly used stable field will be set
!  * just once to a non-default value, and keep that value forever.
!  * While the field contains its default (null or zero) value,
!  * the VM treats it as an ordinary mutable variable.  When a
!  * non-default value is stored into the field, the VM is permitted
!  * to assume that no more significant changes will occur.  This in
!  * turn enables the VM to optimize uses of the stable variable, treating
!  * them as constant values.  This behavior is a useful building block
!  * for lazy evaluation or memoization of results.  In rare and subtle
!  * use cases, stable variables may also assume multiple values over
!  * time, with effects as described below.
   * <p>
+  * <em>(Warning: the {@code @Stable} annotation is intended for use in the
+  * JDK implemention, and with the HotSpot VM, to support optimization
+  * of classes and algorithms defined by the JDK.  It is unavailable
+  * outside the JDK.)</em>
+  *
+  * <h2><a id="lifecycle"></a>Stable Variable Life Cycle</h2>
+  *
+  * For example, suppose a class has two non-final fields of type
+  * {@code int} and {@code String}.  Annotating the field declarations
+  * with {@code @Stable} creates a pair of stable variables.  The
+  * fields are initialized to zero and the null reference,
+  * respectively, in the usual way, but storing a non-zero integer in
+  * the first field or a non-null reference in the second field will
+  * enable the VM to expect that the stored value is now the permanent
+  * value of the field, going forward.  This condition may be used by
+  * the VM compiler to improve code quality more aggressively,
+  * if the VM compiler runs after the stable variable has been
+  * given a permanent value, and chooses to observe that value.
+  * <p>
+  * Since all heap variables begin with a default null value for
+  * references (resp., zero for primitives), there is an ambiguity when
+  * the VM discovers a stable variable holding a null or primitive zero
+  * value.  Does the user intend the VM to constant fold that
+  * (uninteresting) value?  Or is the user waiting until later to
+  * assign a permanent value to the variable?  The VM does not
+  * systematically record stores of a null (resp., zero) to a stable variable,
+  * so there is no way for the VM to decide if a field's current value is
+  * its undisturbed initial value, or has been overwritten with
+  * an intentionally stored null (resp., zero).  This is why the
+  * programmer should store non-default values into stable variables,
+  * if the consequent optimization is desired.
+  * <p>
+  * A stable variable may be assigned its permanent value inside a class or
+  * object initializer, but in general (with lazy data structures)
+  * stable variables are assigned much later.  Depending on the value
+  * stored and what races are possible, safe publication may require
+  * special handling with a {@code VarHandle} atomic method.
+  * (See below.)
+  * <p>
+  * If an application requires constant folding of a stable variable
+  * whose permanent value may be the default value (null or zero),
+  * the variable can be refactored to add an extra indirection.
+  * This would represent the default value in a non-null "box",
+  * such as {@code Integer.valueOf(0)} or a lambda like
+  * {@code ()->null}.  Such a refactoring should always be possible,
+  * since stable variables should (obviously) never be part of public
+  * APIs.
+  *
+  * <h2><a id="arrays"></a>Stable Arrays</h2>
+  *
+  * So far, stable variables are fields, but they can be array
+  * components as well.  If a stable field is declared as an array
+  * type with one dimension, both that array as a whole, and its
+  * eventual components, are treated as independent stable variables.
+  * When a reference to an array of length <i>N</i> is stored to the
+  * field, then the array object itself is taken to be a constant, as
+  * with any stable field.  But then all <i>N</i> of the array
+  * components are <em>also</em> treated as independent stable
+  * variables.  Such a stable array may contain any type, reference or
+  * primitive.  Such an array may be also marked {@code final}, and
+  * initialized eagerly in the class or object initializer method.
+  * Whether any (or all) of its components are also initialized eagerly
+  * is up to the application.
+  * <p>
+  * More generally, if a stable field is declared as an array type with
+  * <em>D</em> dimensions, then all the non-null components of the
+  * array, and of any sub-arrays up to a nesting depth less than
+  * <em>D</em>, are treated as stable variables.  Thus, a stable field
+  * declared as an array potentially defines a tree (of fixed depth
+  * <em>D</em>) containing many stable variables, with each such stable
+  * variable being independently considered for optimization.  In this
+  * way, and depending on program execution, a single {@code Stable}
+  * annotation can potentially create many independent stable
+  * variables.  Since the top-level array reference is always stable,
+  * it is in general a bad idea to resize the array, even while keeping
+  * all existing components unchanged.  (This could be relaxed in the
+  * future, to allow expansion of stable arrays, if there were a use
+  * case that could deal correctly with races.  But it would require
+  * careful treatment by the compiler, to avoid folding the wrong
+  * version of an array.  Anyway, there are other options, such as
+  * tree structures, for organizing the expansion of bundles of stable
+  * variables.)
+  * <p>
+  * An array is never intrinsically stable.  There is no change made to
+  * an array as it is assigned to a stable variable of array type.
+  * This is true even though after such an assignment, the compiler may
+  * observe that array and treat its components as stable variables.
+  * If the array is aliased to some other variable, uses via that
+  * variable will not be treated as stable.  (Such aliasing is not
+  * recommended!)  Also, storing an array into a stable variable will
+  * not make that array's components into stable variables, unless the
+  * variable into which it is stored is statically typed as an array,
+  * in the declaration of the stable field which refers to that array,
+  * directly or indirectly.
+  *
+  * <h2><a id="examples"></a>Examples of Stable Variables</h2>
+  *
+  * In the following example, the only constant-foldable string stored
+  * in any stable variable is the string {@code "S"}.  All subarrays are
+  * constant.
+  *
+  * <pre>{@code
+  * @Stable String FIELD = null;  // no foldable value yet
+  * @Stable int IDNUM = 0;  // no foldable value yet
+  * @Stable boolean INITIALIZED = false;  // no foldable value yet
+  * @Stable Object[] ARRAY = {
+  *   "S",   // string "S" is foldable
+  *   new String[] { "X", "Y" },  // array is foldable, not elements
+  *   null  // null is not foldable
+  * };
+  * @Stable Object[][] MATRIX = {
+  *   { "S", "S" },   // constant value
+  *   { new String[] { "X", "Y" } },  // array is foldable, not elements
+  *   { null, "S" },  // array is foldable, but not the null
+  *   null       // could be a foldable subarray later
+  * };
+  * }</pre>
+  *
+  * When the following method is called, some of the above stable
+  * variables will gain their permanent value, a constant-foldable
+  * string "S", or a non-default primitive value.
+  *
+  * <pre>{@code
+  * void publishSomeStables() {
+  *   // store some more foldable "S" values:
+  *   FIELD = "S";
+  *   ARRAY[2] = "S";
+  *   MATRIX[2][0] = "S";
+  *   MATRIX[3] = new Object[] { "S", "S", null };
+  *   // and store some foldable primitives:
+  *   IDNUM = 42;
+  *   INITIALIZED = true;
+  *   VarHandle.releaseFence();  //optional, see below
+  * }
+  * }</pre>
+  *
+  * <p>
+  * Note that a stable boolean variable (i.e., a stable
+  * field like {@code INITIALIZED}, or a stable boolean
+  * array element) can be constant-folded,
+  * but only after it is set to {@code true}.  Even this simple
+  * optimization is sometimes useful for responding to a permanent
+  * one-shot state change, in such a way that the compiler can remove
+  * dead code associated with the initial state.  As with any stable
+  * variable, it is in general a bad idea to reset such a variable to
+  * its default (i.e., {@code false}), since compiled code might have
+  * captured the {@code true} value as a constant, and as long as that
+  * compiled code is in use, the reset value will go undetected.
+  *
+  * <h2><a id="final"></a>Final Variables, Stable Variables, and Memory Effects</h2>
+  *
   * Fields which are declared {@code final} may also be annotated as stable.
!  * Since final fields already behave as stable variables, such an annotation
   * conveys no additional information regarding change of the field's value, but
!  * it conveys information regarding changes to additional component variables if
   * the type of the field is an array type (as described above).
   * <p>
!  * In order to assist refactoring between {@code final} and
!  * {@code @Stable} field declarations, the Java Memory Model
!  * <em>freeze</em> operation is applied to both kinds of fields, when
!  * the assignment occurs in a class or object initializer (i.e.,
!  * static initialization code in {@code <clinit>} or constructor code
!  * in {@code <init>}).  The freezing of a final or stable field is
!  * (currently) triggered only when an actual assignment occurs, directly
!  * from the initializer method ({@code <clinit>} or {@code <init>}).
!  * It is implemented in HotSpot by an appropriate memory barrier
!  * instruction at the return point of the initializer method.  In this
!  * way, any non-null (or non-zero) value stored to a stable variable
!  * (either field or array component) will appear without races to any
!  * user of the class or object that has been initialized.
!  * <p>
!  * (Note: The barrier action of a class initializer is implicit in the
!  * unlocking operation specified in JVMS 5.5, Step 10.  The barrier
!  * action of an instance initializer is specified as a "freeze action"
+  * in JLS 17.5.1.  These disparate barrier actions have parallel
+  * effects on static and non-static final and stable variables.)
+  * <p>
+  * There is no such JMM freeze operation applied to stable field stores in
+  * any other context.  This implies that a constructor may choose to
+  * initialize a stable variable, rather than "leaving it for later".
+  * Such an initial value will be safely published, as if the field were
+  * {@code final}.  The stored value may (or may not) contain
+  * additional stable variables, not yet initialized.  Note that if a
+  * stable variable is written outside of the code of a constructor (or
+  * class initializer), then data races are possible, just the same as
+  * if there were no {@code @Stable} annotation, and the field were a
+  * regular mutable field.  In fact, the usual case for lazily
+  * evaluated data structures is to assign to stable variables much
+  * later than the enclosing data structure is created.  This means
+  * that racing reads and writes might observe nulls (or primitive
+  * zeroes) as well as non-default values.
+  *
+  * <h2><a id="usage"></a>Proper Handling of Stable Variables</h2>
+  *
+  * A stable variable can appear to be in either of two states,
+  * either uninitialized, or else set to a permanent, foldable value.
+  * Therefore, most code which reads stable variables should not assume
+  * that the value has been set, and should dynamically test for a null
+  * (or zero) value.  Code which cannot prove a previous initialization
+  * must perform a null (or zero) test on a value loaded
+  * from a stable variable.  Code which omits the null (or zero) test should be
+  * documented as to why the initialization order is reliable.  In
+  * general, some sort of critical section for initialization should be
+  * documented, as provably preceding all uses of the (unchecked)
+  * stable variable, or else reasons should be given why races are
+  * benign, or some other proof given that races are either excluded or
+  * benign.  See below for further discussion.
+  * <p>
+  * After constant folding, the compiler can make use of many aspects of
+  * the object: its dynamic type, its length (if it is an array), and
+  * the values of its fields (if they are themselves constants, either
+  * final or stable).  It is in general a bad idea to reset such
+  * variables to any other value, since compiled code might have folded
+  * an earlier stored value, and will never detect the reset value.
+  * <p>
+  * The HotSpot interpreter is not fully aware of stable annotations,
+  * and treats annotated fields (and any affected arrays) as regular
+  * mutable variables.  Thus, a field annotated as {@code @Stable} may
+  * be given a series of values, by explicit assignment, by reflection,
+  * or by some other means.  If the HotSpot compiler constant-folds a
+  * stable variable, then in some contexts (execution of fully
+  * optimized code) the variable will appear to have one "historical"
+  * value, observed, captured, and used within the compiled code to the
+  * exclusion of any other possible values.  Meanwhile, in other less
+  * optimized contexts, the stable variable will appear to have a more
+  * recent value.  Race conditions, if allowed, will make this even
+  * more complex, since with races there is no definable "most recent"
+  * value across all threads.  The compiler can observe any racing
+  * value, as it runs concurrently to the application, in its own
+  * thread.
+  * <p>
+  * It is no good to try to "reset" a stable variable by storing its
+  * default again, because there is (currently) no way to find and
+  * deoptimize any and all affected compiled code.  If you need the
+  * bookkeeping, try {@code SwitchPoint} or {@code MutableCallSite},
+  * which both are able to reset compiled code that has captured an
+  * intermediate state.
+  * <p>
+  * Note also each compilation task makes its own decisions about
+  * whether to observe stable variable values, and how aggressively to
+  * constant-fold them.  And a method that uses a stable variable might
+  * be inlined by many different compilation tasks.  The net result of
+  * all this is that, if stable variables are multiply assigned, the
+  * program execution may observe any "historical" value (if it was
+  * captured by some particular compilation task), as well as a "most
+  * recent" value observed by the interpreter or less-optimized code.
+  * <p>
+  * For all these reasons, a user who bends the rules for a stable
+  * variable, by assigning several values to it, must state the
+  * intended purposes carefully in warning documentation on the
+  * relevant stable field declaration.  That user's code must function
+  * correctly when observing any or all of the assigned values, at any
+  * time.  Alternatively, field assignments must be constrained
+  * appropriately so that unwanted values are not observable by
+  * compiled code.
+  * <p>
+  * Any class which uses this annotation is responsible for
+  * constraining assignments in such a way as not to violate API
+  * contracts of the class.  (If the chosen technique is unusual in
+  * some way, it should be documented in a comment on the field.)  Such
+  * constraints can be arranged in a variety of ways:
+  * <ul><li> using the {@code VarHandle} API to perform an explicit
+  * atomic operation such as {@code compareAndExchange},
+  * {@code setRelease}, {@code releaseFence}, or the like.
+  * </li><li> using regular variable access under explicit sychronization
+  * </li><li> using some other kind of critical section to avoid races
+  * which could affect compiled code
+  * </li><li> allowing multiple assignments under benign races, but
+  * only of some separately uniquified value
+  * </li><li> allowing multiple assignments under benign races, but
+  * only of semantically equivalent values, perhaps permitting
+  * occasional duplication of cached values
+  * </li><li> concealing the effects of multiple assignments in some
+  * other API-dependent way
+  * </li><li> providing some other internal proof of correctness, while
+  * accounting for all possible racing API accesses
+  * </li><li> making some appropriate disclaimer in the API about
+  * undefined behavior
+  * </li></ul>
+  * <p>
+  * There may be special times when constant folding of stable
+  * variables is disabled.  Such times would amount to a critical
+  * section locking out the compiler from reading stable variables.
+  * During such a critical section, an uninitialized stable variable
+  * can be changed in any way, just like a regular mutable variable
+  * (field or array component).  It can even be reset to its default.
+  * Specifically, this may happen during certain AOT operations.  If a
+  * stable variable can be updated multiple times during such a
+  * critical section, that fact must be clearly stated as a comment on
+  * the field declaration.  (In the future, there may be explicit
+  * AOT-related annotations to convey this use case.)  If there is no
+  * such warning, maintainers can safely disregard the possibility of
+  * an AOT critical section, since the author of the stable variable is
+  * relying on one of the other techniques listed above.
+  * <p>
+  * It is possible to imagine markings for foldable methods or fields,
+  * which can constant-fold a wider variety of states and values.  This
+  * annotation does not readily extend to such things, for the simple
+  * reason that extra VM bookkeeping would be required to record a
+  * wider variety of candidate states for constant folding.  Such
+  * higher-level mechanisms may be created in the future.  The present
+  * low-level annotation is designed as a potential building block to
+  * manage their bookkeeping.
   *
   * @implNote
   * This annotation only takes effect for fields of classes loaded by the boot
   * loader.  Annotations on fields of classes loaded outside of the boot loader
   * are ignored.
< prev index next >