RFR: 8189871: Refactor GC barriers to use declarative semantics

Erik Österlund erik.osterlund at oracle.com
Fri Nov 17 14:39:11 UTC 2017


Hi Coleen,

On 2017-11-17 00:59, coleen.phillimore at oracle.com wrote:
>
> Hi Erik,
>
> I believe that the access API belongs in the "oops" directory, as that 
> is where the code uses them primarily.  Other than the location of the 
> access* files, I've read through much of the code and don't have 
> anything specific to add that would improve this change.  It's a bit 
> big, ie. the Access class is large but separating out the 
> implementations into access.inline.hpp doesn't seem like that useful 
> of an improvement.  The template heavy code starts to look like 
> boilerplate after a while.

I moved the Access API to the oops directory as you wished.

> The Access<decorator>::verify_decorators() could be made out-of-line 
> in access.inline.hpp file to make the class more readable but it's not 
> a strong request.

Fixed.

> The IN_CONCURRENT_ROOT decorator looks like something that can't be 
> used or is the default from the runtime perspective, but can be 
> removed or sorted out later.

I would like to defer the default discussion until later if that is 
okay. We definitely need the ability to have non-concurrent roots, they 
definitely are the norm and not the exception today, but eventually we 
might want to change that. But I don't know if we are quite there yet.

> I'd found a typo on first reading but now I don't know where it was.

If you find it again, I will happily remove it.

> Nice work!

Thanks! And thank you for the review.

The latest full webrev can be found here:
http://cr.openjdk.java.net/~eosterlund/8189871/webrev.02/

The latest incremental webrev can be found here:
http://cr.openjdk.java.net/~eosterlund/8189871/webrev.01_02/

Thanks,
/Erik

> Coleen
>
> On 11/14/17 7:37 PM, coleen.phillimore at oracle.com wrote:
>>
>> Hi,  Meta-comment: I think the access API should be in oops rather 
>> than the runtime directory.   This API is for accessing objects in 
>> the heap from other objects in the heap or in runtime code.   So that 
>> seems like it belongs in the oops directory to me (even though 
>> metadata is there for historical reasons).   The memory directory 
>> would be my second choice, and runtime third.
>>
>> I've been reading through much of the code with help and explanation 
>> of what these templates do from Kim.  They are pretty tricky but I 
>> can see why they are there and what they do.   I'm going to suggest 
>> some comments in places when I've gotten through more of this.
>>
>> Thanks,
>> Coleen
>>
>> On 11/9/17 12:00 PM, 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