TrustFinalNonStaticFields clarification

John Rose john.r.rose at
Fri Apr 24 00:08:26 UTC 2015

On Apr 20, 2015, at 7:58 AM, Vitaly Davidovich <vitalyd at> wrote:
> Fixed the flag name in the subject.
> On Fri, Apr 17, 2015 at 9:07 PM, Vitaly Davidovich <vitalyd at <mailto:vitalyd at>> wrote:
> Hi guys,
> I'm hoping someone could clarify/confirm my understanding of this experimental flag's effects:
> 1) final instance array length is constant propagated? Even if array is passed in as ctor arg rather than being instantiated in the ctor?
If an array reference is a constant, its length is a constant, regardless of the experimental flag.

The same is true for any object's class, and for a variety of meta-data visible from methods on Class.

The value of a static final field is treated as a constant, regardless of the experimental flag.

If the experimental flag is true, a non-static final field is treated as a constant, *if* the containing object reference is a constant.

I.e., a getfield instruction can fold up if its input (the receiver) is constant, but only for final fields with the flag turned on.

The non-standard @Stable annotation also enables this same constant folding of getfield, but only if the field value is non-zero.

The non-standard @Stable annotation also enables some folding through array elements, again only if the element value is non-zero.
> 2) final instance fields seen as never null are forever considered as such? So even if a method call on that object is fully eliminated (e.g. the method is empty) no null check is left behind?
Non-nullness is logically independent from being a constant, and so would be tracked differently.  We don't track this presently.

If any value is a constant of course null checks on it will fold up.
> 3) concrete runtime type of the instance field is propagated to uses and no additional type checks are done? Say the declared type is an interface/abstract with multiple implementations loaded but only one type stored in the field - is a type check eliminated and calls are fully devirtualized?
Concrete type is also logically independent from being a constant.  Nothing to do with the experimental flag.

We track concrete types (at invoke sites, not at-rest data) using the type profiling mechanism.  This is enough for most purposes.
> 4) primitive type final fields have their value constant propagated if compiler sees only one value always stored?
We do little or no profiling of primitive value ranges, either at operation sites (cmp, add, xor, aaload, etc.) or at rest (fields, array elements).  But if a primitive value is constant, we can fold it at compile time.
> 5) do derived classes and base class share field profile or not? For example subclasses always store concrete type but each subclass stores a different type from the others.
Strictly speaking, field profiles are both fully shared and fully unshared.  This is possible because they are all empty.  That is, we don't have field profiles at present.  (Or am I missing a point here?  Is there a project I have forgotten about??)

> Also, there's been some talk about doing these optimizations automatically with invalidations builtin.  Just curious where that stands.
One thing that folks have been talking about for a long time is "effectively final" optimizations.  This requires some profiling of fields (at least, to detect multiple putfields).  A field is "effectively final" if it could have been written with a "final" keyword, at least with reference to all code paths that are live.  We might reserve the right to make a field stop being "effectively final", because we don't have an airtight analysis that proves the "one putfield before any use" invariant.  (Such analyses are hard to come by in the JVM, given various dynamisms and also reflection.)  In such cases, where an optimization can be invalidated, we track dependencies.


— John

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the hotspot-compiler-dev mailing list