RFR: 8255471: ZGC: Rework root iterators and closures [v2]

Stefan Karlsson stefank at openjdk.java.net
Fri Oct 30 08:42:59 UTC 2020


On Thu, 29 Oct 2020 12:17:55 GMT, Erik Österlund <eosterlund at openjdk.org> wrote:

> In the patch, the heap iterator uses a ThreadToOopClosure, which implicitly uses a CodeBlobToOop closure for on-stack nmethods. I don't know how I feel about this. I think it might be desirable to use a ZThreadToOopClosure instead, that you pass in the explicitly passed in NMethodClosure to instead. Or something along those lines, the important thing being to pass in the NMethodClosure passed to the iterator, and not use a CodeBlobToOopClosure instead. Otherwise, it is rather confusing if you explicitly pass in an NMethodClosure to the strong root iterator, telling what should be done to strong nmethods, but then it is not applied to nmethods encountered on the stack. Instead, it is only applied to the code cache nmethods, when ClassUnloading is disabled. However, there does not seem to be any reason for distinguishing the two cases, AFAICT. The NMethodClosure describes what should be done to a strong nmethod, and how we found the strong nmethod (stack or code cache depending on Cl
 assUnloading), does not seem to make a difference. Differenting the two does however conflict with the goal of making the code more straight and understandable. If you pass in an NMethodClosure to the strong root iterator, I would expect that NMethodClosure to be applied to all strong nmethods found, and not have to deal with what happens with and without class unloading as a special case, that does not look like it would have to be special.

This part was a preexisiting "issue" that simply kept. Talked to Erik and I'll change this in a follow-up RFE.

> 
> On a different yet related note, I see that ZHeapIteratorRootOopClosure now always performs some kind of NativeAccess::oop_load on all oops, including misaligned nmethod oops. I'm not sure how I feel about that. I think it's fine, but let me elaborate my thoughts. I suppose the contract for how it is used is that the oops have already been fixed by nmethod barriers (under the per-nmethod lock) to be good, before loading potentially misaligned oops. That should imply that the oops are never self healed, which is a requirement to not cause undefined behaviour on the HW level, performing atomics on misaligned data. So I suppose ensuring the nmethod barrier has completed before reading is crucial here. When reading the NMethodClosure, it is clear how that is the case. We apply the nmethod barrier and then walk the oops. But using the CodeBlobToOopClosure, now with parallel iteration as of lately, does seem a bit scary. I guess it still is okay, because Thread::oops_do() calls finish_pr
 ocessing(), which ensures all on-stack nmethods enter their barriers before applying the OopClosure. So I guess this all works correctly, but again would read a bit more intuitively for me at least, if we had a ZThreadToOopClosure that you pass in the root iterator supplied NMethodClosure to. I think it works with and without that, but would be easier to understand why it works if the NMethodClosure was passed in to the [Z?]ThreadToOopClosure. Again, it might just be me thinking that would be easier to understand, but I would at least like to point that out, so I can hear your thoughts about it.

I didn't change this either, but I did drop the verification that showed that the nmethods had been handled by the stack watermark processing. I've pushed an update that reintroduces the verification. I'll fix the pre-existing problem as a separate RFE.

> 
> Apart from that, this looks great, and I think it is much more readable now that you can just tell the iterators what to do with various types of roots, without getting random callbacks that may or may not make sense. Great job!

Thanks Erik.

-------------

PR: https://git.openjdk.java.net/jdk/pull/928



More information about the hotspot-gc-dev mailing list