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
8259937: guarantee(loc != NULL) failed: missing saved register with native invoker #2528
Conversation
|
@rwestrel |
Webrevs
|
@rwestrel 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 80 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.
|
The code here looks ok. I'm slightly concerned about the consequences of adding a new stack frame visible to stack walking code. Does this have the potential to break serviceability code that reports and/or analyzes stack frames (whether that's code in OpenJDK or 3rd party code)? |
Thanks for the review. The native invoker code is new in jdk 16 so it's unlikely tools already rely of some specific layout. @iwanowww are you the author of the native invoker code? What do you think? |
@adinn I'm not aware of any such use-cases (whether in the JDK or elsewhere). They would only be affected if they were using Panama native calls, which were introduce pretty recently, and are also still in incubator state. Inside the JDK the only place where this code is currently being used is in the jdk/java/foreign test stuite, as well as in the internal implementation of the Panama linker. If that test suite still passes I'm happy to call it safe. |
LGTM, but I've left some suggestions in line.
Thanks for cleaning up the frame layout code. Having a fixed frame is much better than repeatedly modifying the stack pointer.
I've also done some downstream stress testing with jextract, and everything works as expected.
|
||
__ movptr(Address(r15_thread, JavaThread::saved_rbp_address_offset()), rsp); // rsp points at saved RBP |
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.
The saved_rbp_address_offset
field was added to JavaFrameAnchor just to serve this particular use case. It should be cleaned up now that it is no longer used.
If you don't want to take care of that, we can file a followup.
There is code in frame_*.cpp
, thread_*.hpp
, and javaFrameAnchor_*.hpp
that deals with this field (not on all platforms/archs though). See https://github.com/openjdk/jdk/pull/634/files & https://github.com/openjdk/jdk/pull/1711/files for the original diffs.
|
||
public class TestLinkToNativeRBP { | ||
final static CLinker abi = CLinker.getInstance(); | ||
static final LibraryLookup lookup = LibraryLookup.ofDefault(); |
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.
The default library can be unreliable (but we've kept it in lieu of something better, which is still in the pipeline). We've had problems with it in the past since it acts differently in different environments, so we try to avoid it in tests.
It would be more robust to add a small test library that defines a dummy function and then depend on that instead.
If you've not done this before; you can just add a lib<Name>.c
file to the same directory as the main test file and the build system will compile it for you. You can then load it with LibraryLookup.ofLibrary("<Name>")
in the test. See the test/jdk/java/foreign/stackwalk directory for an example (one noteworthy thing is that the function has to be explicitly exported in order to work on Windows. See the example).
|
This reverts commit cb9dd24.
@JornVernee thanks for the review and the comments. The new commits should address them (cb9dd24 was pushed by accident and reverted). |
@JornVernee I'm not clear that your response addresses my point. I'm concerned that a thread stack dump reported by serviceability code may contain an extra frame for the stub call. This could occur while the Java thread is still in native and it could also include the case wher the native call re-enters into Java i.e. the extra frame could appear at the top of the stack dump or interleaved between Java method frames. I don't see how that problem is mitigated by your suggestion that this only relates to Panama API use. Code which consumes any such stack dump (incluing 3rd party code) that might be affected by the presence of this extra frame will not care (or even be aware) that the native callout is a Panama call. Anyway, since no one from the serviceability team has noted this as a potential problem I'm ok to see the patch proceed. |
Overall, the fix looks good. At some point, there was no frame for native invoker set up and native state transitions were put inline in generated code, but that was rewritten. Regarding the refactorings: I find newly introduced
|
Thanks for the review. I pushed a new change. Does that look ok to you now? |
/integrate |
@rwestrel Since your change was applied there have been 82 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit 6baecf3. |
We spotted this issue with Shenandoah and I managed to write a simple
test case that reproduces it reliably with Shenandoah but the issue is
independent of the GC.
The loop in the test case calls a native invoker with an oop live in
rbp. rbp is saved in the native invoker stub's frame. A safepoint is
triggered from the safepoint check in the native invoker. The stack
walking code sees that rbp contains an oop but can't find where that
oop is stored. That's because stack walking updates the caller's frame
with the location of rbp in the callee on calls to
frame::sender(). But the current code sets the last java frame to be
the compiled frame where rbp is live. So there's no call to
frame::sender() to update the location rbp. The fix I propose is that
the frame of the native invoker be visible by stack walking. On a
safepoint, stack walking starts from the native invoker thread, then
calls frame::sender() to move to the compiled frame. That causes rbp
to be properly recorded with its location in the native invoker frame.
Same problem affects both x86 and aarch64. I've tested this patch with:
make run-test TEST="java/foreign" TEST_VM_OPTS="-Xcomp" JTREG="TIMEOUT_FACTOR=10"
on both platforms.
/cc hotspot-compiler
Progress
Issue
Reviewers
Download
$ git fetch https://git.openjdk.java.net/jdk pull/2528/head:pull/2528
$ git checkout pull/2528