Bounds checks with unsafe array access

John Rose john.r.rose at oracle.com
Thu Sep 11 20:51:01 UTC 2014


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/69f1befe/attachment.html>


More information about the hotspot-compiler-dev mailing list