TrustFinalNonStaticFields clarification

Vitaly Davidovich vitalyd at
Fri Apr 24 01:51:47 UTC 2015

Hi John,

Thanks for the reply.  Besides static final fields, what else is considered
constant? For example, my intuitive understanding of this flag implies that
the following:

final class C {
     private final Object[] arr = new Object[10];

     int capacity () { return arr.length; }

     Object getFirst () { return arr [0]; }


capacity() should constant fold to return 10 and then constant propagated
into wherever it's inlined.  Instead when looking at generated asm, I see
the array length is loaded from the field.

getFirst () should not have range check but it does.

Both of these cases work as expected if I make arr static final.  So, how
do I make instance final behave in the above manner if not for this flag?
Note that I think the above should hold irrespective of whether the
enclosing instance is constant or not.

Likewise, here's another scenario.   Suppose I have a final field in an
object whose declared type is some abstract class.  I then have a "null
object" subclass (i.e. overriden methods are empty/nop).  At runtime, only
the null object subclass is loaded; CHA kicks in and effectively removes
the empty method invocation - great! Except, it leaves a pesky null check
behind.  But, if this field is final and set inside constructor only, why
still have the null check if I'm asking to trust instance final fields?


sent from my phone
On Apr 23, 2015 8:08 PM, "John Rose" <john.r.rose at> wrote:

> 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>
> 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