RFR: 8189871: Refactor GC barriers to use declarative semantics

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


Hi Kim,

Thank you for the review.

On 2017-11-16 20:43, Kim Barrett wrote:
>> On Nov 15, 2017, at 11:55 AM, Erik Österlund <erik.osterlund at oracle.com> wrote:
>>> http://cr.openjdk.java.net/~eosterlund/8189871/webrev.00/src/hotspot/share/runtime/access.hpp.html
>>>
>>> 240   template <typename T>
>>> 241   struct OopOrNarrowOopInternal: AllStatic {
>>> 242     typedef oop type;
>>> 243   };
>>> 244
>>> 245   template <>
>>> 246   struct OopOrNarrowOopInternal<narrowOop>: AllStatic {
>>> 247     typedef narrowOop type;
>>> 248   };
>>> 249
>>>
>>> Kim and I agree that we should not have the default template definition for oop and have two specializations instead.  Mostly I agree because this is confusing.
>>>
>>> 240   template <typename T>
>>> 241   struct OopOrNarrowOopInternal;
>>>
>>> 240   template <>
>>> 241   struct OopOrNarrowOopInternal<oop>: AllStatic {
>>> 242     typedef oop type;
>>> 243   };
>>> 244
>>> 245   template <>
>>> 246   struct OopOrNarrowOopInternal<narrowOop>: AllStatic {
>>> 247     typedef narrowOop type;
>>> 248   };
>>> 249
>>>
>> This choice is actually deliberate. The reason is that we pass in things that is-an oop but is not exactly oop, like for example arrayOop or oopDesc* and the whole subclass tree if oop. An earlier incarnation of the Access API used a new IsDerived<X, Y> metafunction to determine whether a type is-an oop.
>> However, in order to keep the solution simpler and introduce less type dependencies, I instead use this OopOrNarrowOop thing to pass oop-like things through it and narrow it down to oop or narrowOop. If a narrowOop is passed in, then it becomes narrowOop, if you pass in oopDesc*, arrayOop, oop, instanceOop, or whatever, then it results in an oop, and tries to implicitly convert whatever was passed in to oop. That will act as if the overload was "oop" in the way that you can pass in anything that is implicitly convertible to exactly oop or narrowOop, and once you make it past that layer, it will be treated only as oop or narrowOop.
>>
>> Sorry for any resulting confusion.
> Thanks for the explanation.  That wasn’t at all obvious.  It might be useful to add a comment that the default case handles all variants of oop and treats them all as oop.

I have added a comment for that.

>>> We were also trying to figure out how the runtime would know whether to use IN_CONCURRENT_ROOT vs IN_ROOT decorator, since it probably varies for GCs.  And requires runtime code to know whether the root is scanned concurrently or not, which we don't know.
>>>
>> The Access API needs to know whether this is scanned concurrently or not (because we *have* to perform different barriers then). So whatever data structure the access is performed on, needs to make sure this is known.
> The person writing the access call cannot be expected to accurately
> know whether or not the associated location will be scanned
> concurrently.  Even ignoring some of those people not being GC
> experts, there is the problem that the answer might not be knowable
> until runtime, because it may (will) depend on which GC is selected,
> and possibly other considerations as well.

I see your point.

> Does IN_CONCURRENT_ROOT really mean the location *might* be
> concurrently processed, and using that tag is a conservative choice
> that won't actually be wrong, but may be suboptimal?  (E.g. it should
> really be called IS_POSSIBLY_CONCURRENT_ROOT?)  Or are the choices
> between these really exclusive?  I'm guessing the former, but I'm not
> certain of that, and the descriptions are no help.  Nor do I know how
> bad such suboptimal behavior might be.  (If they really are exclusive,
> then I don't see how to use these at all.)

It is indeed the case that they *might* be concurrently processed 
concurrently.

> When we discussed this problem previously, we talked about having
> specific names associated with categories of off-heap references that
> might be handled differently by different collectors.  Some specific
> examples that came up in that discussion were JNI global (and weak)
> handles, and interned strings.  Even if we really expect all of our
> concurrent collectors to eventually process all of these concurrently,
> such features might be added on different schedules for different
> collectors.
>
> Without such a naming scheme, e.g. with only a generic
> IS_CONCURRENT_ROOT, different collectors may pay the cost for being
> conservative for different categories.  That might be acceptable if
> being conservative is cheap.  But then I would expect the possibly
> concurrent case to be pretty much the default, to be used nearly
> everywhere, since it is unreasonable to expect non-GC experts to stay
> up to date on which roots are never ever scanned concurrently by any
> collector.

Okay so I really want the ability to say my roots are definitely scanned 
in a pause, e.g. when storing oops in thread-local value type values 
that are considered semantically as part of the stack, and will 
definitely for all thinkable weird forseeable GC combinations be scanned 
in a pause.

At the moment it is really a special case with potentially concurrently 
scanned roots rather than the norm. So if that is okay, I would like to 
defer a decision to make concurrent root the default type of root. At 
least now that we are annotating the access, if any GC developer is 
adding concurrent processing of roots, it is very easy to find which 
where potential trouble lies.

Thanks,
/Erik


More information about the hotspot-dev mailing list