[concurrency-interest] lazy finals - was: Here's why Atomic*FieldReference access checking is broken

Peter Levart peter.levart at gmail.com
Thu Oct 9 11:21:35 EDT 2014

Hi Vladimir,

Thanks for explaining these things.

On 10/09/2014 12:23 PM, Vladimir Ivanov wrote:
> Peter,
>>> [1] http://cr.openjdk.java.net/~jrose/draft/lazy-final.html
>> That's great. I can see that there are two points encapsulated in this
>> lazy finals proposal. One is the lazy assignment that can occur any time
>> after constructor, restricted perhaps only to code of the declaring
>> class, and the other is that such fields are *really* final, or in other
>> words @Stable, meaning they can not be assigned twice, not even with
>> reflection, which enables compiler optimizations. It's a little odd that
>> in order to achieve *really* final behaviour and consequently better
>> optimization, you would have to give up on  the definitive assignment
>> rules help from javac.
> I don't see how it improves the situation, except allowing lazy 
> initialization. It suffers from the very same problems as final 
> fields, if you want to perform multiple updates. 

But since they are new kind of fields, multiple updates can be 
prohibited on them from day one. Who would want such a feature anyway. 
Lazy setting yes, but not multiple updates. Normal fields are meant to 
be updated multiple times, finals are special-purpose fields.

> And the price for lazy initialization is default value, which can't be 
> optimized anymore.

That's a pity yes, but as I understand, lazy-initialized finals are 
expected to be assigned a non-default value before they are used in hot 
code which can then benefit from constant folding, right?

>> But what about this idea:
>> Reflection supports updating ordinary final instance fields (via
>> privileged setAccessible(true)) in order to achieve just what the lazy
>> final fields are trying to achieve - lazy initialization outside
>> constructor. Mainly to support Java  and other kinds of
>> deserializations. I would say that any other uses of setAccessible(true)
>> which assigns final field more than once are rare or non-existent. So
>> why not making ordinary instance final fields *really* final by treating
>> them in reflection as lazy final fields with a little tweak - the
>> assignment of null/zero value to an "unassigned" field would not throw
>> exception, but just be a NOOP - leave the field in "unassinged" state.
>> This way deserialization of ordinary final fields would still work, but
>> VM compiler could treat them all as @Stable, immediately optimizing huge
>> codebases on a different level.
>> Am I not seeing something in that simplified picture?
> It's all about JIT compiler. Lazy finals/@Stable aren't a full match 
> for final field case, but they are close.
> The problem with treating final fields as lazy finals, is it can't be 
> limited only to accesses through Reflection API. The change should be 
> pervasive and default values should be treated specially everywhere, 
> forbidding constant-folding of loads from final fields w/ default 
> values. Do we really want that?

Well, it would not be worse than it is now when constant-folding can't 
be performed regardless of final field's value. null/zero value would 
become a second-class citizen then. Not very nice, but perhaps acceptable.

> Regarding constant folding of loads from final fields, Hotspot already 
> optimizes loads for static final fields and there's an experimental 
> flag TrustFinalNonStaticFields for final instance fields case.

So for static final fields, Hotspot already knows how to prove that some 
code can not observe uninitialized value before constant-folding it? 
Does it do any such thing for instance fields when this experimental 
flag is enabled or just trusts blindly that the code in question is only 
observing the "final" value when the time comes to optimize it? In other 
words, does this experimental flag guarantee correctness in all 
situations with the only exception being reflective final field updates?

> What HotSpot misses right now (to preserve correctness w.r.t. 
> Reflection API) is a way to track dependencies between final fields 
> and nmethods which embed their values. It would allow to invalidate 
> all nmethods which rely on stale value and ensure the updated value is 
> "visible" everywhere in the running application.

This would be a cool optimization for mostly read-only and rarely 
updated fields, but do we want to transform final instance fields into 
such thing just to support deserialization via reflection? If this is 
not a big deal to support than perhaps it is a better approach since it 
does not neglect null/zero values.

Regards, Peter

> Best regards,
> Vladimir Ivanov
>> Regards, Peter
>>>> Now let me try to get something similar from
>>>> AtomicReferenceFieldUpdater...
>>>> Regards, Peter
>>>> _______________________________________________
>>>> Concurrency-interest mailing list
>>>> Concurrency-interest at cs.oswego.edu
>>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

More information about the Concurrency-interest mailing list