Graal final field treatment with respect to optimizations
Vitaly Davidovich
vitalyd at gmail.com
Mon Apr 27 19:25:21 UTC 2015
Tom,
The cases where this type of optimization would help, I think, is when
you're calling into "islands" of code, and can't amortize the cost of the
safety checks. Think of looping over Foo instances (using my example
above) and calling getFirst() on each one. There's nothing to CSE here, so
each access is going to trigger a range check.
Another practical example, as I mentioned to John, is efficiently handling
the Null Object pattern. If I only have a null object impl loaded at
runtime which has nop implementations of methods, CHA correctly figures
this out and eliminates the calls to those empty methods. However, the
null check is left behind even though the field is final and definitely
assigned a non-null value in constructor. The test instruction that gets
emitted *is* cheap, but it loads a cacheline that may not otherwise be
needed in the "meat" of the method. Had compiler determined that the field
could never be null, this could be completely zero-cost abstraction
provided a second impl is never loaded.
On Mon, Apr 27, 2015 at 2:35 PM, Tom Rodriguez <tom.rodriguez at oracle.com>
wrote:
>
> > On Apr 27, 2015, at 11:02 AM, Vitaly Davidovich <vitalyd at gmail.com>
> wrote:
> >
> > Thanks Gilles.
> >
> > Why is there a restriction that receiver has to be constant as well? In
> > addition, why does the value have to be *not* default? Specifically, an
> > example I mentioned to John was akin to this:
> >
> > final class Foo {
> > private final Object[] _arr = new Object[10];
> >
> > int capacity() { return _arr.length; }
> >
> > Object getFirst() { return _arr[0]; }
> > }
> >
> > What's the reason capacity() cannot be constant folded to 10 if the
> > receiver is non-constant? Likewise with getFirst(). Is this again
> because
> > there's no field profiling? I suspect so, but just want to double check.
> >
> > Has any thought been given to doing some (basic) field profiling?
> Actually,
> > I'm reluctant to call the above profiling since it seems like it could be
> > done at parse/compile time? To me profiling sounds more like "there's a
> > final field of interface type Foo, and we profile to see that at runtime
> we
> > only have 1 real type stored there, FooImpl", or something like that.
>
> I agree field profiling doesn’t seem like it’s the solution you’re talking
> about here.
>
> Years ago I build something like this for HotSpot that did a local
> symbolic analysis of all field initializations for a class to detect things
> like your example. At the byte code level you can identify fields which
> are only stored in the constructor and capture symbolic properties of those
> initializations. You don’t really need to care about final either, just
> that the amount of code you need to analyze is restricted through the use
> of access controls. You can dynamically trap all stores except the ones
> you’ve analyzying to treat fields as effectively final. In your example the
> fact that _arr is exactly Object[] is more interesting than having a
> constant length since store checks aren’t required for Object[].
>
> My experience was that it did some really clever things but that it
> largely didn’t translate into performance since you’re just shaving a tiny
> bits of work off something which is generally well optimized in the first
> place. Type profiling and other speculative optimizations often pick up
> the interesting things here and maybe that’s what John was getting at with
> suggesting field profiling.
>
> tom
>
> >
> > Thanks
> >
> >
> > On Mon, Apr 27, 2015 at 1:45 PM, Gilles Duboscq <gilwooden at gmail.com>
> wrote:
> >
> >> Hi Vitaly,
> >>
> >> We currently do not respect the TrustNonStaticFinalFields field.
> >> We have a "@Stable-like" behaviour for non-static final fields:
> >>
> >> * static final:
> >> We always constant fold
> >>
> >> * final
> >> We constant fold if the receiver is constant and if the value is not
> >> default (null, 0, 0.0, false...). This is not what HotSpot normally does
> >> and we just enabled this to see what would happen. At some point we'll
> >> probably change to only do that if TrustNonStaticFinalFields is true
> just
> >> to respect HotSpot's wish though.
> >>
> >> * @Stable final array[]
> >> We constant fold if the receiver is constant and if the value is not
> >> default (null, 0, 0.0, false...) and we apply the @Stable final property
> >> for the elements of the array (up to the declared field's dimension).
> i.e.
> >> an access like array[0] would also be constant folded (this would not be
> >> done for final: we would access a constant array object the the load
> from
> >> this array would stay).
> >>
> >> * Some fields are automatically promoted to @Stable
> >> The String.value field and synthetic $VALUES, ENUM$VALUES, $SwitchMap$
> >> and $SWITCH_TABLE$ fields (from enums) are automatically promoted to
> >> @Stable.
> >>
> >> We do not do any additional profiling of fields in the runtime.
> >>
> >>
> >>
> >> On Fri, Apr 24, 2015 at 3:57 PM 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)?
> >>>
> >>> Thanks
> >>>
> >>
>
>
More information about the graal-dev
mailing list