Graal final field treatment with respect to optimizations

Vitaly Davidovich vitalyd at gmail.com
Mon Apr 27 18:38:07 UTC 2015


Ok, thanks Tom; a few comments below ...


> So to optimize final in the way a Java user might expect the compiler
> would have do semantic analysis of the initialization and use of the Java
> field to determine how it can be treated.


Yes, compiler would have to perform analysis on the constructor, but
naively it seems like the same type of analyses (or subset of) that it
already does for method compilations.


> My sense is that having the JIT do a perfect job here would likely have
> little impact on the performance of regular Java code.  When enough
> inlining occurs that all loads and stores are visible then those kinds of
> optimizations apply all fields.  Getting the remaining one is probably of
> limited value, even though it’s fairly ridiculous that we don’t.


Yes, I don't expect earth shattering performance improvement from doing
this.  However, there are places where certain checks left behind by
compiler (type checks, null checks, range checks, etc) are at least as
expensive as the "user code".  These things are amortized via CSE when
there are more uses of the checked value later on, but when you have these
things sprinkled across many leaf calls where not much CSE is available,
they kind of suck :).  In particular, the array length propagated as
constants (or lack thereof really) is very unfortunate.  It's also slightly
frustrating that I can't propagate/convey knowledge to the compiler in any
way; even if I check certain invariants in constructor and actually
guarantee those invariants, that knowledge is lost. :(


On Mon, Apr 27, 2015 at 2:24 PM, Tom Rodriguez <tom.rodriguez at oracle.com>
wrote:

>
> On Apr 27, 2015, at 10:39 AM, Vitaly Davidovich <vitalyd at gmail.com> wrote:
>
> Hi Tom,
>
> I'm with you in terms of how this should be treated.  However, Cliff Click
> wrote a couple of blog posts a few years back on this topic:
>
>
> http://www.azulsystems.com/blog/cliff/2011-10-17-writing-to-final-fields-via-reflection
> http://www.azulsystems.com/blog/cliff/2011-10-27-final-fields-part-2
>
> In short, some popular frameworks make use of this "feature”.
>
>
> I’m aware of that post.  I’m not sure I’d generalize from that too much
> though.  It’s unfortunate the semantics of these kinds of things aren't
> defined and enforced in a clear fashion.  Absent that I still say the right
> response is to say it's simply a bug.  It even likely violates the Java
> memory model since the proper semantics of final fields for immutable
> objects may require a barrier for other threads to see the store.
>
> I suspect the middle ground here would (or should) be to allow for that
> scenario, but have user specify which class/package/<some_other_grouping>
> should be excluded from JIT optimizations.  Alternatively, have the
> compiler track writes to final fields and then deopt without final field
> optimizations; I think that's what the C2 guys are contemplating, if I
> understand correctly.
>
>
> Yes, we’d discussed that as well.  Precise handling of this is a bit
> uglier because of things like Unsafe since you can’t interpose on those as
> easily.  You’d have to disallow final field optimizations for any field
> that had it’s offset asked for, so reading the field using Unsafe would
> also disable the optimization.
>
>
> However, the thing I'm particularly curious about is what types of
> additional optimizations, if any, Graal performs when it trusts final
> fields.
>
>
> I think you’re reading too much into the name of the flag.  Optimization
> of final fields in general requires a lot more work since it’s poorly
> specified and unchecked at the VM specification level.  The normal Java
> definite assignment rules are only enforced by javac.
>
> So to optimize final in the way a Java user might expect the compiler
> would have do semantic analysis of the initialization and use of the Java
> field to determine how it can be treated.
>
> In C2, this doesn't appear to do much.  In particular, final fields are
> treated as constants only if enclosing instance is also constant; the only
> practical difference that I found (in quick playing around with this flag)
> this makes is that Enum.ordinal() is treated as a constant in compiled
> code.  There were certain "obvious" cases that weren't optimized though,
> e.g.:
>
> 1) final array fields (even ones that were allocated inside the class
> ctor) didn't have their length propagated as a constant to uses.  In
> addition, range checks were performed on accesses that should be "known" to
> be legit.  Basically, they didn't get the same codegen treatment as static
> final arrays.
> 2) There didn't seem to be any "constraint" propagation of final fields.
> For example, if the constructor throws a NPE if the field is null, the
> field is still checked for null in uses.  Likewise, say if an int field was
> checked to be > 0, that info does not seem to make its way to uses.
>
>
> Generally these would fall out of proper CSE of final field accesses
> across possibly killing calls.  It also requires deciding what semantics
> are actually safe for final fields, which is unspecified at the VM level.
>
> My sense is that having the JIT do a perfect job here would likely have
> little impact on the performance of regular Java code.  When enough
> inlining occurs that all loads and stores are visible then those kinds of
> optimizations apply all fields.  Getting the remaining one is probably of
> limited value, even though it’s fairly ridiculous that we don’t.
>
> tom
>
>
> John Rose indicated that these types of optimizations aren't done because
> C2 doesn't do field profiling.  I'm not sure #1 counts as profiling as it
> seems like this type of thing could be detected at parse time.  #2 also
> isn't so much about profiling as about piggybacking on user checks that are
> then predicated on final fields being unchanged thereafter.
>
> Does Graal propagate this type of information to uses? Or more generally,
> does it perform some set of additional optimizations (even if they're
> peephole in nature) for final field uses?
>
> Thanks
>
> On Mon, Apr 27, 2015 at 1:07 PM, Tom Rodriguez <tom.rodriguez at oracle.com>
> wrote:
>
>>
>> > On Apr 24, 2015, at 6:55 AM, Vitaly Davidovich <vitalyd at gmail.com>
>> wrote:
>> >
>> > Hi guys,
>> >
>> > I recently had a thread on hotspot-compiler-dev where John Rose shed
>> some
>> > light on what the TrustNonStaticFinalFields experimental flag implies in
>> > the C2 compiler:
>> >
>> http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2015-April/017739.html
>> >
>> > Based on that exchange, I see that there are some scenarios where some
>> > optimization opportunities are missed, specifically due to missing field
>> > profiling.  That got me thinking -- how does Graal handle this, and
>> does it
>> > do something better here? Clearly Graal has to also be mindful of final
>> > fields being changed via reflection, but are there any speculative
>> > optimizations around trusting that final fields are mostly unchanged (or
>> > plans to do that)?
>>
>> We have a similar flag TrustFinalDefaultFields which defaults to true.  I
>> think anyone modifying final fields of published objects through reflection
>> should just be laughed at and told to go away.  The hole that allows
>> modification of final fields through reflection was introduced to support
>> deserialization. Any other use should just be considered undefined
>> behaviour.
>>
>> tom
>
>
>
>


More information about the graal-dev mailing list