Bounds checks with unsafe array access
Vitaly Davidovich
vitalyd at gmail.com
Thu Sep 11 21:36:56 UTC 2014
>
> Also, comparing against zero is sometimes better than comparing against a
> variable in a register.
> The addressing idiom a[i & a.length-1] does not have to inspect 'i' vs.
> 'a.length', just 'a.length' vs. zero.
Yes, but not doing a comparison at all is even better :).
Certainly in cases where an array's length can be 0 and that drives logic,
it's nice that JIT can piggyback on that. But there are certainly plenty
of cases where arrays are "known" to never have length of zero. If you
guys can at least detect that for arrays stored in final fields (as part of
the general final field work) and then omit cmp's for those, it would be a
good compromise. In those cases, if a user's index calculation is
guaranteed to produce valid ranges (i.e. the examples discussed here), and
assuming the compiler has enough horizon to see that, it would be great if
no range checks were emitted at all. Further, if a final field array is
seen to be allocated with a compile time constant length and then indexed
into it with a compile constant, it'd be nice to not emit a range check
there, e.g.:
final Object[] array = new Object[2];
void someMethod() {
Object o = array[0]; // no range check
o = array[1]; // no range check
o = array[>1]; // automatic exception
}
Basically, the same way this is currently optimized out for static final
arrays.
Thanks
On Thu, Sep 11, 2014 at 4:51 PM, John Rose <john.r.rose at oracle.com> wrote:
> On Sep 11, 2014, at 10:04 AM, Vladimir Ivanov <
> vladimir.x.ivanov at oracle.com> wrote:
>
> On 9/11/14, 8:40 PM, Vitaly Davidovich wrote:
>
> Thanks Vladimir.
>
> If a guard is used for arraylength, then that guard would have to be
> checked each time anyway, right? In that case, given the guard would
> perform a cmp against 0 (or a test), isn't the whole point defeated
> (i.e. no range/length check)?
>
> In some situations, yes. But it can be moved out of inner loops and
> performed less frequently.
>
>
> Also, comparing against zero is sometimes better than comparing against a
> variable in a register.
> The addressing idiom a[i & a.length-1] does not have to inspect 'i' vs.
> 'a.length', just 'a.length' vs. zero.
>
> Profiling is a good way to inject tests the user didn't think to write.
> It's almost as much of a silver bullet as inlining.
>
> In some cases of highly tuned code the author can work with the JIT
> engineer to insert the right code shapes from the start.
> The "test length against zero" code shape is one of these, and can often
> be merged with a check that is required any way (e.g., is the data
> structure logically empty?).
> For example:
>
> http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/f08705540498/src/java.base/share/classes/java/util/HashMap.java#l569
>
>
> Right, currently dependencies are at the class level. But it sounded to
> me like this will be extended to support dependencies on fields (i.e. to
> support final fields)?
>
> IMO changes to final variables through Reflection API are rare, so current
> dependency tracking mechanism should work pretty well. Conservatively
> invalidating all methods with embedded constants from objects of some
> particular type may pay off.
>
>
> Yup.
>
> It's not the case with arrays, since array writes are very common.
>
>
> Array writes do have some implicit checks which might be widenable to
> include some kinds of guards. We'll see... The real problem with arrays
> dependencies would be to avoid having to deoptimize the world when
> something goes wrong.
>
> Dependency checks work best when you can associate the speculation with a
> narrow region of code, so you can deoptimize only that code when the
> speculation fails.
> This works out trivially if the speculation can be tested by a poll inside
> the speculating code itself; often it can be done as a loop invariant.
> But if you have "push" dependencies, you need to have the speculating code
> register interest in some token which will be and posted to whenever the
> speculation might be violated.
> The classic version of this is devirtualization, where a speculator says
> "the method K::m is never overridden". It registers a dependency on K::m,
> and the class loader knows to re-evaluate the speculation whenever a
> subclass of K is loaded.
> This pattern probably adapts well enough to immutable fields, but for
> array elements (as Vladimir says) it is harder to keep a narrow context.
>
> — John
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20140911/cf34bc5c/attachment-0001.html>
More information about the hotspot-compiler-dev
mailing list