-
Notifications
You must be signed in to change notification settings - Fork 130
8367151: [lworld] CorrectlyRestoreRfp.java triggers "bad oop found" during deoptimization #1751
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
Conversation
|
👋 Welcome back mchevalier! A progress list of the required criteria for merging this PR into |
|
@marc-chevalier 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 1 new commit pushed to the
Please see this link for an up-to-date comparison between the source branch of this pull request and the ➡️ To integrate this PR with the above commit message to the |
TobiHartmann
left a comment
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 for the detailed explanation, this is great for future reference!
The changes look good to me. Just a few comments.
I don't have much opinion about the names of compiled_frame_details and CompiledFramePointers, feel free to suggest better if you have a better idea.
Naming is fine with me but do we even need to factor this logic out? Do you expect it to be used in more places in the future?
| cfp.sender_pc_addr = (address*)(l_sender_sp - frame::return_addr_offset); | ||
|
|
||
| #ifdef ASSERT | ||
| // when the stack was extnded (so LR #1 and LR #2 are distinct) and LR #1 was patched |
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.
| // when the stack was extnded (so LR #1 and LR #2 are distinct) and LR #1 was patched | |
| // when the stack was extended (so LR #1 and LR #2 are distinct) and LR #1 was patched |
| // find FP/LR #1. This size is expressed in bytes. Be careful when using it | ||
| // from C++ in pointer arithmetic; you might need to divide it by wordSize. | ||
| // | ||
| // TODO 8371993 store fake values instyead of LR/FP#2 |
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.
| // TODO 8371993 store fake values instyead of LR/FP#2 | |
| // TODO 8371993 store fake values instead of LR/FP#2 |
|
There seems to be a merge conflict. |
|
@marc-chevalier this pull request can not be integrated into git checkout JDK-8367151
git fetch https://git.openjdk.org/valhalla.git lworld
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge lworld"
git push |
I suspect we might need a similar thing in virtual threads. I've seen other places where we do this trick of finding the increment and fixing the framesize to find the sp of the caller. For instance valhalla/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp Lines 56 to 81 in 29569fb
looks a lot like what was in |
|
Right, that makes sense to me. @pchilano might want to re-use that code when fixing the Virtual Threads part. |
|
/integrate Thanks @TobiHartmann! |
|
Going to push as commit 405db7a.
Your commit was automatically rebased without conflicts. |
|
@marc-chevalier Pushed as commit 405db7a. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
We are on aarch64.
When a function needs stack extension, we build a stack that has this shape:
valhalla/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
Lines 6040 to 6073 in b1d14c6
Currently, when leaving the frame, we use LR §1 (I use § not to mess with github rendering that interpret
#as PR references) as return address (because it can be patched for deoptimization), and FP §2 to restore x29 (because when it contains an oop, the GC is only aware of this copy).In our failing case, we have a C2-compiled frame that is being deoptimized when returning from a call to an interpreted method. During deoptimization, the function
frame::sender_for_compiled_frame(RegisterMap*) constis used to locate the location on the stack where rfp (x29) is saved.valhalla/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp
Line 446 in b1d14c6
Actually this function is a bit more general: it computes the sender frame of a compiled frame, and build the
RegisterMap. The problem is that during deoptimization, this function locates the wrong save of rfp (FP §1) because the C2 frame is being modified by the deoptimization process and it's not anymore recognized as a C2-compiled method that needs stack repairs. In this modified frame the sender's sp is correctly known (or the deoptimization mechanism would not work), and the saved FP is taken just 2 words above: that is FP §1. On top of that, if rfp contained an oop and the GC moved the pointed object during the call we are returning from, the value we get for rfp is not valid anymore.The good and bad news is that the GC also locates the saved location of rfp thanks to the same function. The bad news is that GC sees the C2 frame correctly, and so
sender_for_compiled_framecan locate FP §2. We can follow a few ideas:sender_for_compiled_framedetects when the deoptimized frame is the one of a C2 compiled method that needs stack repair. No idea how to do that! Also, it seems brittle, and more complicated than the next solution.In JDK-8365996, the problem was pretty much the opposite: remove_frame was using FP §1 to restore rfp but the GC only updates FP §2. So the solution was to restore from FP §2:
https://github.com/openjdk/valhalla/pull/1540/files#diff-0f4150a9c607ccd590bf256daa800c0276144682a92bc6bdced5e8bc1bb81f3aR6140-R6145
Here the solution is to revert this part (restore rfp from FP §1), and let GC knows about FP §1 only in
sender_for_compiled_frame. Overall, let's never speak about FP/LR §2. This way, we always have the sender's sp, the saved LR and FP consecutively. FP/LR §2 is only needed to make space between the unpacked arguments and the locals, as there would be between regular arguments and locals. They could have a fictive value and we should probably implement that.This make virtual thread tests fail massively. Surely because of mismatch between our choice of FP §1 or 2. Let's problem list this for now... To help with that, I introduced
frame::compiled_frame_details() constto do all this little tricks and return the location of LR/FP§1 and the sender's sp at once, without letting the frame users have to figure out the internal structure.I found the extraction of
compiled_frame_detailsa bit risky, so I proceded in steps: first making the function, calling it fromsender_for_compiled_frameand compare the results with the old way of getting everything. These temporary assert weren't triggered, so I actually used the returned value ofcompiled_frame_detailsand removed the newly useless code fromsender_for_compiled_frame. So I'm rather confident it does as good as before.I don't have much opinion about the names of
compiled_frame_detailsandCompiledFramePointers, feel free to suggest better if you have a better idea.Thanks,
Marc
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/valhalla.git pull/1751/head:pull/1751$ git checkout pull/1751Update a local copy of the PR:
$ git checkout pull/1751$ git pull https://git.openjdk.org/valhalla.git pull/1751/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1751View PR using the GUI difftool:
$ git pr show -t 1751Using diff file
Download this PR as a diff file:
https://git.openjdk.org/valhalla/pull/1751.diff
Using Webrev
Link to Webrev Comment