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