RFR: 8189871: Refactor GC barriers to use declarative semantics
David Holmes
david.holmes at oracle.com
Thu Nov 16 01:51:05 UTC 2017
On 16/11/2017 2:42 AM, Erik Österlund wrote:
> Hi David,
>
> Thank you for the review.
>
> On 2017-11-15 08:47, David Holmes wrote:
>> Hi Erik,
>>
>> I really like the level of abstraction and encapsulation this provides.
>
> Glad to hear it!
>
>> Can't comment on the GC specific details or the template mechanics
>> directly, of course. :)
>>
>> A couple of comments:
>>
>> src/hotspot/share/oops/klass.hpp
>>
>> 412 // Is an oop/narrowOop null or subtype of this Klass?
>> 413 template <typename T>
>> 414 bool is_covariant(T element);
>>
>> I find "is_covariant" a very obscure way to name this. It may be
>> academically accurate but it's really just asking if the element is of
>> a type that is a subclass of the current klass. The null handling
>> complicates it, but it seems to me that:
>>
>> template <typename T>
>> bool Klass::is_instanceof_or_null(T element);
>>
>> would be more consistent with how we normally refer to things in the
>> VM (though the _or_null can be dropped from the name).
>
> Hmm, I see your point. I have renamed covariant/contravariant
> accordingly to fit better into our current notions.
>
> The ARRAYCOPY_CONTRAVARIANT decorator has been renamed ARRAYCOPY_CHECKCAST.
> The is_covariant check has been renamed is_instanceof_or_null as you
> proposed.
> The covariant_bound() method has been renamed to element_klass().
I completely missed contravariant in there :)
These changes look good.
Thanks.
David
-----
>> ---
>>
>> src/hotspot/share/oops/objArrayOop.cpp
>>
>> Klass* objArrayOopDesc::covariant_bound()
>>
>> There's that word again. :) If you really think you need to use
>> covariance within these API's you really need to add some comments to
>> the method declarations to explain them. Most of us probably have a
>> minimal recollection of covariance and contravariance from discussing
>> type-safety for method parameters and return types. :)
>
> Fixed as mentioned above.
>
>>
>> ---
>>
>> src/hotspot/share/prims/unsafe.cpp
>>
>> The changes from jobjects to oops made me uneasy, but I'm assuming the
>> places where MemoryAccess and GuardedMemoryAccess are used are
>> affectively all leave routines with no chance of hitting anything that
>> would respond to a safepoint request?
>
> Yes, that is correct. There are no thread transitions in those paths.
>
> Here is a new full webrev:
> http://cr.openjdk.java.net/~eosterlund/8189871/webrev.01/
>
> Incremental:
> http://cr.openjdk.java.net/~eosterlund/8189871/webrev.00_01/
>
> Thanks,
> /Erik
>
>> Thanks,
>> David
>> -----
>>
>> On 10/11/2017 3:00 AM, Erik Österlund wrote:
>>> Hi,
>>>
>>> In an effort to remove explicit calls to GC barriers (and other
>>> orthogonal forms of barriers, like encoding/decoding oops for
>>> compressed oops and fencing for memory ordering), I have built an API
>>> that I call "Access". Its purpose is to perform accesses with
>>> declarative semantics, to handle multiple orthogonal concerns that
>>> affect how an access is performed, including memory ordering,
>>> compressed oops, GC barriers for marking, reference strength, etc,
>>> and as a result making GCs more modular, and as a result allow new
>>> concurrently compacting GC schemes utilizing load barriers to live in
>>> harmony in hotspot without everyone going crazy manually inserting
>>> barriers if UseBlahGC is enabled.
>>>
>>> CR:
>>> https://bugs.openjdk.java.net/browse/JDK-8189871
>>>
>>> Webrev:
>>> http://cr.openjdk.java.net/~eosterlund/8189871/webrev.00/
>>>
>>> So there are three views of this I suppose:
>>>
>>> 1) The frontend: how this is actually used in shared code
>>> 2) The backends: how anyone writing a GC sticks their required
>>> barriers in there
>>> 3) The internals: how accesses find their way from the frontend to
>>> the corresponding backend
>>>
>>> == Frontend ==
>>>
>>> Let's start with the frontend. I hope I made this fairly simple! You
>>> can find it in runtime/access.hpp
>>> Each access annotates its declarative semantics with a set of
>>> "decorators", which is the name of the attributes/properties
>>> affecting how an access is performed.
>>> There is an Access<decorator> API that makes the declarative
>>> semantics possible.
>>>
>>> For example, if I want to perform a load acquire of an oop in the
>>> heap that has "weak" strength, I would do something like:
>>> oop result = Access<MO_ACQUIRE | IN_HEAP |
>>> ON_WEAK_OOP_REF>::oop_load_at(obj, offset);
>>>
>>> The Access API would then send the access through some GC backend,
>>> that overrides the whole access and tells it to perform a "raw" load
>>> acquire, and then possibly keep it alive if necessary (G1 SATB
>>> enqueue barriers).
>>>
>>> To make life easier, there are some helpers for the most common
>>> access patterns that merely add some default decorator for the
>>> involved type of access. For example, there is a RawAccess for
>>> performing AS_RAW accesses (that bypasses runtime checks and GC
>>> barriers), HeapAccess sets the IN_HEAP decorator and RootAccess sets
>>> the IN_ROOT decorator for accessing root oops. So for the previous
>>> call, I could simply do:
>>>
>>> oop result = HeapAccess<MO_ACQUIRE |
>>> ON_WEAK_OOP_REF>::oop_load_at(obj, offset);
>>>
>>> The access.hpp file introduces each decorator (belonging to some
>>> category) with an explanation what it is for. It also introduces all
>>> operations you can make with access (loads, stores, cmpxchg, xchg,
>>> arraycopy and clone).
>>>
>>> This changeset mostly introduces the Access API but is not complete
>>> in annotating the code more than where it gets very awkward if I don't.
>>>
>>> == Backend ==
>>>
>>> For a GC maintainer, the BarrierSet::AccessBarrier is the top level
>>> backend that provides basic accesses that may be overridden. By
>>> default, it just performs raw accesses without any GC barriers, that
>>> handle things like compressed oops and memory ordering only. The
>>> ModRef barrier set introduces the notion of pre/post write barriers,
>>> that can be overridden for each GC. The CardTableModRef barrier set
>>> overrides the post write barrier to mark cards, and G1 overrides it
>>> to mark cards slightly differently and do some SATB enqueueing. G1
>>> also overrides loads to see if we need to perform SATB enqueue on
>>> weak references.
>>>
>>> The raw accesses go to the RawAccessBarrier (living in
>>> accessBackend.hpp) that performs the actual accesses. It connects to
>>> Atomic and OrderAccess for accesses that require that.
>>>
>>> == Internals ==
>>>
>>> Internally, the accesses go through a number of stages in
>>> access.inline.hpp as documented at the top.
>>>
>>> 1) set default decorators and get rid of CV qualifiers etc. Sanity
>>> checking also happens here: we check that the decorators make sense
>>> for the access being performed, and that the passed in types are not
>>> bogus.
>>> 2) reduce types so if we have a different type of the address and
>>> value, then either it is not allowed or it implies we use compressed
>>> oops and remember that we know something about whether compressed
>>> oops are used or not, before erasing address type
>>> 3) pre-runtime dispatch: figure out if all runtime checks can be
>>> bypassed into a raw access
>>> 4) runtime dispatch: send the access through a function pointer that
>>> upon the first invocation resolves the intended GC AccessBarrier
>>> accessor on the BarrierSet that handles this access, as well as
>>> figures out whether we are using compressed oops or not while we are
>>> at it, and then calls it through the post-runtime dispatch
>>> 5) post-runtime dispatch: fix some erased types that were not known
>>> at compile time such as whether the address is a narrowOop* or oop*
>>> depending on whether compressed oops was selected at runtime or not,
>>> and call the resolved BarrierSet::AccessBarrier accessor
>>> (load/store/etc) with all the call-site build-time and run-time
>>> resolved decorators and type information that describes the access.
>>>
>>> Testing: mach5 tier1-5
>>>
>>> Thanks,
>>> /Erik
>
More information about the hotspot-dev
mailing list