RFR: 8189871: Refactor GC barriers to use declarative semantics

coleen.phillimore at oracle.com coleen.phillimore at oracle.com
Fri Nov 17 15:58:43 UTC 2017



On 11/17/17 9:39 AM, Erik Österlund wrote:
> 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.

Thanks!
>
>> 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.

Thanks, that helps a bit with readability.
>
>> 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 agree with you.  Let's see how these are used and adjust accordingly.

>> 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/

Looks good!!

Coleen

>
> 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