RFR (S) 8150465: Unsafe methods to produce uninitialized arrays

Aleksey Shipilev aleksey.shipilev at oracle.com
Thu Feb 25 13:44:26 UTC 2016


On 02/25/2016 12:50 PM, Andrew Haley wrote:
> This is something of a loaded gun pointed at our feet.  We'll have to
> be extremely careful that we can prove that such arrays are never
> unsafely published.  It's the "generic case where a complicated
> processing is done after the allocation" I'm worried about.
> 
> The only way to guarantee safety is to prove that the array reference
> doesn't escape the thread until the array is fully initialized and a
> release barrier has been executed.

I think the large part of the concern is the protection of object
metadata. Current implementation does not eliminate the subsequent
barriers after storing the metadata, and so racy publication of
uninitialized array should not violate VM invariants. (Disallowing
non-primitive arrays is the second part of safeguards -- no garbage oops
in uninitialized arrays!)

See e.g. benchmark disassembly with PrintOptoAssembly:

Regular allocation:

100   B17: #    B18 <- B24  top-of-loop Freq: 95429.2
100     # TLS is in R15
100     movq    [R15 + #120 (8-bit)], RSI       # ptr
104     PREFETCHNTA [RSI + #192 (32-bit)]
10b     movq    [RBX], 0x0000000000000001       # ptr
112     PREFETCHNTA [RSI + #256 (32-bit)]
119     movl    [RBX + #8 (8-bit)], narrowklass: precise klass [B:
0x00007fa6b000e0e0:Constant:exact *  # compressed klass ptr
120     movl    [RBX + #12 (8-bit)], RDX        # int
123     PREFETCHNTA [RSI + #320 (32-bit)]
12a     movq    RDI, RBX        # spill
12d     addq    RDI, #16        # ptr
131     PREFETCHNTA [RSI + #384 (32-bit)]
138     shrq    RCX, #3
13c     addq    RCX, #-2        # long
140     xorq    rax, rax        # ClearArray:
        shlq    rcx,3   # Convert doublewords to bytes
        rep     stosb   # Store rax to *rdi++ while rcx--
14a     movq    RBP, R11        # spill
14d     movq    [rsp + #0], R8  # spill
151     movq    [rsp + #8], R10 # spill
156     movq    [rsp + #16], R9 # spill
156
15b   B18: #    B36 B19 <- B26 B17  Freq: 95438.9
15b
15b     MEMBAR-storestore (empty encoding)

There, a StoreStore membar at the end of allocation gives you a safe
semantics.

For comparison, Unsafe.allocateArrayUninit allocation:

100   B17: #    B18 <- B26  top-of-loop Freq: 79963.3
100     # TLS is in R15
100     movq    [R15 + #120 (8-bit)], RBX       # ptr
104     PREFETCHNTA [RBX + #192 (32-bit)]
10b     movq    [RAX], 0x0000000000000001       # ptr
112     PREFETCHNTA [RBX + #256 (32-bit)]
119     movl    [RAX + #8 (8-bit)], narrowklass: precise klass [B:
0x00007f5a1c00e0e0:Constant:exact *  # compressed klass ptr
120     movl    [RAX + #12 (8-bit)], RDX        # int
123     PREFETCHNTA [RBX + #320 (32-bit)]
12a     PREFETCHNTA [RBX + #384 (32-bit)]
131     movq    RBP, R8 # spill
134     movq    [rsp + #0], RCX # spill
138     movq    [rsp + #8], R9  # spill
13d     movq    [rsp + #16], R10        # spill
13d
142   B18: #    B41 B19 <- B28 B17  Freq: 79971.4
142
142     MEMBAR-storestore (empty encoding)

"ClearArray" parts are gone (we nuked it), but the StoreStore is still
at our guard, protecting the array metadata.

Of course, you will still see garbage data if after storing the array
elements into the uninitialized array you would publish it racily. But
the same is true for the "regular" allocations and subsequent writes.
The only difference is whether you see "real" garbage, or some
"synthetic" garbage like zeros. It is, of course, a caller
responsibility to publish array safely in both cases, if garbage is
unwanted.

Aside: I really wanted to coalesce the metadata barriers with final
field barriers one day, see
https://bugs.openjdk.java.net/browse/JDK-8032481.

Cheers,
-Aleksey



More information about the jdk9-dev mailing list