Unsafe for array access

Doug Lea dl at cs.oswego.edu
Wed May 7 11:30:04 UTC 2014

On 05/05/2014 11:20 AM, Paul Sandoz wrote:
> Hi,
> As part of some investigatory work for JEP 193: Enhanced Volatiles i have been looking at how enhanced (and safe) access to array elements could be implemented.
> The obvious and simple choice is to reach for unsafe with a few safety checks, for example:
>      @ForceInline
>      static void setVolatile(ArrayRefHandle handle, Object[] array, int index,
>              Object value) {
>          if (index < 0 || index >= array.length) // bounds and null check
>              throw new ArrayIndexOutOfBoundsException();
>          UNSAFE.putObjectVolatile(array,
>                                   (((long) index) << handle.ashift) + handle.abase,
>                                   castReference(handle.componentType, value));
>      }

Relatedly, it might be be nice to have an intrinsic boundsCheck(array, index)
that could be used in such cases that implemented using the more efficient
(using C): (unsigned)index >= (unsigned)array.length, plus relied on more
efficient VM throw mechanics on failure.

> Some context: ForkJoinPool is peppered with code like the following:
>                              int i = (((a.length - 1) & b) << ASHIFT) + ABASE;
>                              ForkJoinTask<?> t =
>                                  (ForkJoinTask<?>)U.getObjectVolatile(a, i);
> Any viable replacement for direct Unsafe usages in that code will want those strength reducing optimizations to kick in.

Similarly for ConcurrentHashMap. It's hard to say how typical
this style of use is outside of these two classes though. The need to
use Unsafe array access impacted overall class design. To maintain
a proper level of paranoia about using Unsafe, arrays are always
powers of two, indexes use masks and explicit int (not long) shifts
guaranteed so that offsets cannot escape bounds unless array lengths
are zero or >= than 1<<(31-sizeof(pointer)). Construction is
isolated to make it easily statically checkable (in principal)
that lengths are OK.

(Also, in FJ, these constructions are not often used in loops, so
loop optimizations will have less impact than just streamlining
get/put/cas, which are the main operations in fork() and work-stealing,
so slowdowns will have measurable impact.)


More information about the hotspot-compiler-dev mailing list