-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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
8328702: C2: Crash during parsing because sub type check is not folded #18512
Conversation
👋 Welcome back chagedorn! A progress list of the required criteria for merging this PR into |
@chhagedorn This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. 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 89 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
@chhagedorn The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
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 to me.
int dummy; | ||
bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM); | ||
if (!this_one->is_loaded() || !other->is_loaded() || this_top_or_bottom) { | ||
if (!this_one->is_loaded() || !other->is_loaded()) { | ||
return true; | ||
} | ||
if (this_one->is_instance_type(other)) { | ||
return other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces); |
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.
TypeInterfaces
has a contains
method that does intersection_with
+ eq
. Could we use it here? i.e. this_one->_interfaces->contains(other->_interfaces)
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.
That would definitely be better but I've seen that there are three other uses of intersection_with
+ eq
. We should probably update them all together but not sure if I should squeeze this in here. Should I follow up with an RFE?
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.
That sounds good to me.
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.
Filed JDK-8329201 - will do a follow up PR.
Do we want to retire |
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.
Thanks Roland for your review!
When running with -XX:+ExpandSubTypeCheckAtParseTime
Do we want to retire
ExpandSubTypeCheckAtParseTime
? Is there any reason to keep it?
I'm not sure about how much benefit it gives us. A quick JBS search for "ExpandSubTypeCheckAtParseTime" revealed a few issues - but would need to double check how many of them really only triggered with that flag and were real bugs. So, apart from having it as a stress option, I don't see a real benefit for it - but that might be a good enough reason to keep it for now.
What do you think?
int dummy; | ||
bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM); | ||
if (!this_one->is_loaded() || !other->is_loaded() || this_top_or_bottom) { | ||
if (!this_one->is_loaded() || !other->is_loaded()) { | ||
return true; | ||
} | ||
if (this_one->is_instance_type(other)) { | ||
return other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces); |
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.
That would definitely be better but I've seen that there are three other uses of intersection_with
+ eq
. We should probably update them all together but not sure if I should squeeze this in here. Should I follow up with an RFE?
It also has a maintenance cost (you had to make a code change for it in this PR and I also remember having to take |
You're right, it indeed has a maintenance cost (as proved again here) which I'm also not so sure of whether it's worth. Removing the flag sounds reasonable from that standpoint. |
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.
/integrate |
Going to push as commit e5e21a8.
Your commit was automatically rebased without conflicts. |
@chhagedorn Pushed as commit e5e21a8. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
/backport jdk22u |
@chhagedorn the backport was successfully created on the branch backport-chhagedorn-e5e21a8a in my personal fork of openjdk/jdk22u. To create a pull request with this backport targeting openjdk/jdk22u:master, just click the following link: The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:
If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk22u:
|
The test case shows a problem where data is folded during parsing while control is not. This leaves the graph in a broken state and we fail with an assertion.
We have the following (pseudo) code for some class
X
:For the
checkcast
, C2 knows that the type ofo
is some kind of array, i.e. type[bottom
. But this cannot be a sub type ofX
. Therefore, theCheckCastPP
node created for thecheckcast
result is replaced by top by the type system. However, theSubTypeCheckNode
for thecheckcast
is not folded and the graph is broken.The problem of not folding the
SubTypeCheckNode
can be traced back toSubTypeCheckNode::sub
callingstatic_subtype_check()
when transforming the node after it's creation.static_subtype_check()
should detect that the sub type check is always wrong here:jdk/src/hotspot/share/opto/compile.cpp
Lines 4454 to 4460 in d0a2650
But it does not because these two checks return the following:
o
a sub type ofX
? -> returns no, so far so good.o
be a sub type ofX
? -> returns no which is wrong![bottom
is only a sub type ofObject
and can never be a subtype ofX
In
maybe_java_subtype_of_helper_for_arr()
, we wrongly conclude that any array with a base element typebottom
could be a sub type of anything:jdk/src/hotspot/share/opto/type.cpp
Lines 6462 to 6465 in d0a2650
But this is only true if the super class is also an array class - but not if
other
(super klass) is an instance klass as in this case.The fix for this is to first check the immediately following check which handles the case of comparing an array klass to an instance klass: An array klass can only ever be a sub class of an instance klass if it's the
Object
class. But in our case, we haveX
and this would return false:jdk/src/hotspot/share/opto/type.cpp
Lines 6466 to 6468 in d0a2650
The very same problem can also be triggered with
X
being an interface instead. There are tests for both these cases.Additionally Required Fix
When running with
-XX:+ExpandSubTypeCheckAtParseTime
, we eagerly expand the sub type check during parsing and therefore do not emit aSubTypeCheckNode
. When additionally running with-XX:+StressReflectiveCode
, the static sub type performed instatic_subtype_check()
is skipped when emitting the expanded sub type check (skip
is default-initialized with the flag value ofStressReflectiveCode
):jdk/src/hotspot/share/opto/compile.cpp
Lines 4450 to 4452 in d0a2650
And again, the graph is left in a broken state because the sub type check cannot be folded.
I therefore propose to always perform the static sub type check when a sub type check is expanded during parsing (i.e. if
ExpandSubTypeCheckAtParseTime
is set). I've added a run with these flags as well.Thanks,
Christian
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/18512/head:pull/18512
$ git checkout pull/18512
Update a local copy of the PR:
$ git checkout pull/18512
$ git pull https://git.openjdk.org/jdk.git pull/18512/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 18512
View PR using the GUI difftool:
$ git pr show -t 18512
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/18512.diff
Webrev
Link to Webrev Comment