New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8254980: ZGC: ZHeapIterator visits armed nmethods with -XX:-ClassUnloading #801
8254980: ZGC: ZHeapIterator visits armed nmethods with -XX:-ClassUnloading #801
Conversation
|
Webrevs
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good in general. Found 2 VerifyDisarmed that should probably be None instead as I don't think they ever touch an nmethod. If you agree, then I am good with the rest.
virtual void do_oop(narrowOop* p) override; | ||
|
||
virtual ZNMethodEntry nmethod_entry() const override { | ||
return ZNMethodEntry::VerifyDisarmed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't see that this will trigger any verification. The ZPhantomKeepAliveOopClosure is used in ZProcessWeakRootsTask, and it does not visit nmethods. Even if it did, it could still not assert that the visited nmethods are not disarmed, because it could have a single oop that is live, despite the nmethod not being entered.
virtual void do_oop(narrowOop* p) override; | ||
|
||
virtual ZNMethodEntry nmethod_entry() const override { | ||
return ZNMethodEntry::VerifyDisarmed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, except the ZPhantomCleanOopClosure is used from ZProcessConcurrentWeakRootsTask which also does not visit any nmethods. Similar argument that if it did, it still would not make sense to verify that nmethods have been disarmed.
Yes, I agree. I revisited my prototype to completely get rid of should_disarm_nmethods/nmethod_entry(), and I came to the same conclusion when updating the code. |
src/hotspot/share/gc/z/zMark.cpp
Outdated
@@ -582,8 +582,9 @@ class ZMarkConcurrentRootsIteratorClosure : public ZRootsIteratorClosure { | |||
ZThreadLocalAllocBuffer::publish_statistics(); | |||
} | |||
|
|||
virtual bool should_disarm_nmethods() const { | |||
return true; | |||
virtual ZNMethodEntry nmethod_entry() const override { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the stye-guide we shouldn't use override
yet. It's used in a few more places in this patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if there's a ticket for revising the style guide to include override
, which does make the overriding more explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see; thank you.
src/hotspot/share/gc/z/zNMethod.cpp
Outdated
if (_entry == ZNMethodEntry::VerifyDisarmed) { | ||
// Only verify | ||
assert(!ZNMethod::is_armed(nm), "Must be disarmed"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra white space can be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you insist. I think this style makes the code easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please, to me it looks unintended, especially since we don't use that style elsewhere. Maybe flipping the if (VerifyDisarmed)
and else if(Disarm)
would make it read better?
src/hotspot/share/gc/z/zNMethod.cpp
Outdated
if (_entry == ZNMethodEntry::VerifyDisarmed) { | ||
// Only verify | ||
assert(!ZNMethod::is_armed(nm), "Must be disarmed"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please, to me it looks unintended, especially since we don't use that style elsewhere. Maybe flipping the if (VerifyDisarmed)
and else if(Disarm)
would make it read better?
virtual ZNMethodEntry nmethod_entry() const override { | ||
return ZNMethodEntry::VerifyDisarmed; | ||
virtual ZNMethodEntry nmethod_entry() const { | ||
return ZNMethodEntry::None; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about letting ZRootsIteratorClosure::nmethod_entry()
be
ShouldNotReachHere();
return ZNMethodEntry::None;
instead of pure virtual, so that we can remove these unused overrides and catch errors in case a closure doesn't override this but we then apply it on nmethods? Alternatively add a ShouldNotReachHere()
in these unused overrides?
Found that during the pre-review of this the code was rearranged and called ZNMethod::nmethod_oops_do twice, when run from the marking code. I've restructured to code to fix that, which at the same time removes stylistic 'else if (' newline. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
@stefank This change now passes all automated pre-integration checks. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 2 new commits pushed to the
Please see this link for an up-to-date comparison between the source branch of this pull request and the
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
Thanks! I'll now ... /integrate |
@stefank Since your change was applied there have been 3 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit cf56c7e. |
When class unloading is turned off (-XX:-ClassUnloading) we consider all nmethods in the code cache to be "concurrent roots":
This means that they are concurrently fixed up. See ZMarkConcurrentRootsTask and ZMarkConcurrentRootsIteratorClosure. Java threads that want to engage with an nmethod, needs to go through an nmethod entry barrier in case the concurrent roots have not been processed yet. When the ZHeapIterator is used, we rely on the fact that the vm operation the heap iteration is running in, has done a pre-step to fix all thread stacks (including "entering" the relevant nmethods"). See code using:
// You may override skip_thread_oop_barriers to return true if the operation
// does not access thread-private oops (including frames).
virtual bool skip_thread_oop_barriers() const { return false; }
So, this works when we don't use the entire code cache as root. However, when running with -XX:-ClassUnloading, there's no guarantee that the _code_cache.oops_do(cl) call above has run when the heap iteration is executing. So, the heap iteration code could end up reading oops from an nmethod that has not been entered. Currently, this is benign, since we do apply appropriate load barriers to handle this. However, it would be better if we had a clearer model that only entered/disarmed nmethods are visited.
The proposed patch extends the previous should_disarm_nmethods() bool, into an enum stating what "enter" operation ZNMethodToOopsDoClosure should perform.
I think the names of the values quite self-explanatory:
The tricky one is
Disarm
, which is only used by the marking code. It's used to provide an optimized entry barrier for the marking code. However, since the marking code only provides an OopClosure, and not an NMethodClosuer, we have to put the disarming code here. I have some ideas on how to make all this simpler, but I first want some simplifications that it requires some other patches around our weak root handling to trickle in first.Progress
Testing
Issue
Reviewers
Download
$ git fetch https://git.openjdk.java.net/jdk pull/801/head:pull/801
$ git checkout pull/801