RFR: JDK-8199801: Finer grained primitive arrays bulk access barriers

Roman Kennke rkennke at redhat.com
Tue Mar 20 08:57:42 UTC 2018

Currently, for any bulk access on primitive arrays (e.g. *_at_addr()
family of methods, arraycopy, and the like), we do Access::resolve() on
the base arrayOop (via arrayOopDesc::base() ). This is safe and does the
right thing, but it is overly broad. In a garbage collector like
Shenandoah, Access::resolve() would have to do a write-barrier, which is
a copy-on-write. This could lead to double-copying of potentially large
arrays, i.e. resolving the src array would copy it from from-space to
to-space, and then it needs to be copied again from src to dst. This
adds unnecessary latency to Java threads. Most of the accesses via
_at_addr() are read-accesses, and they could use a weaker read-barrier,
which only chases the forwarding pointer.

This change splits Access<>::resolve() into resolve_for_read() and
resolve_for_write(). This is then used in all the relevant places. In

- typeArrayOop::*_at_addr() accessors now differentiate between
get_*_at_addr() and put_*_at_addr(), with the get_* accessors returning
a const T* to prevent/discourage writing to them. This percolates a
little bit through the code base, but in a positive sense (i.e. can use
all the utf8 methods with const arrays now).

- The part in c1_Runtime1.cpp will have to be rebased/eliminated once
Erik's patch goes in.

- arrayOopDesc::base_raw() and objArrayOopDesc::base_raw() go away, and
(remaining) uses replaced by ::base().

- The arraycopy stuff now calls obj_at_addr_raw() instead of
obj_at_addr(). The reason for this is that the actual objects are better
resolved in HeapAccess<>::arraycopy() methods, and the pointer passed
into it must really be within the array that's also passed in, and not
in another copy.

- objArrayOopDesc::atomic_compare_exchange_oop() now uses
oop_atomic_cmpxchg_at() ... the existing version does not allow to
resolve the target object. (this is only related in that it eliminates a
last remaining use of obj_at_addr()).

- oopDesc::field_addr() is only used in one place (DependencyContext)
which should be refactored to use proper oopDesc accessors, and then
field_addr() can be eliminated too. For now it uses resolve_for_write(),
b/c DependencyContext may write to the field.

- I noticed a bunch of memcpy() around the _at_addr() calls (e.g. in
jni.cpp).. I wonder if they should be replaced by corresponding Copy::
functions instead?

- jvmtiTagMap.cpp has an odd one:

-    // Don't use char_at_addr(0) if length is 0
-    value = (jchar*) s_value->base(T_CHAR);
+    value = s_value->get_char_at_addr(0);

In my mind, base(T_CHAR) should be equivalent to get_char_at_addr(0),
both return the address of the first element. I don't see the point. I
can see why we are not going into possible latin1 inflation for length==0.
- I refactored some stuff in heapDumper to accept const void* instead of
void* in write_raw().

Tests: build fastdebug/release (with+w/o PCH), passes hotspot/tier1
tests (fastdebug+release)


What do you think? Can I please get reviews?

Thanks, Roman

More information about the hotspot-runtime-dev mailing list