8350208: CTW: GraphKit::add_safepoint_edges asserts "not enough operands for reexecution"#28597
8350208: CTW: GraphKit::add_safepoint_edges asserts "not enough operands for reexecution"#28597merykitty wants to merge 1 commit intoopenjdk:masterfrom
Conversation
|
👋 Welcome back qamai! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
|
@merykitty The following labels 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 lists. If you would like to change these labels, use the /label pull request command. |
| // Get the exception oop as known at compile time. | ||
| ex_node = use_exception_state(ex_map); | ||
| // The stack from before the throwing bytecode is gone, cannot reexecute here | ||
| jvms()->set_should_reexecute(false); |
There was a problem hiding this comment.
I agree there are situations where we need to set the reexecute flag explicitly and not base it on the bytecode. I recently fixed JDK-8370766 and filed JDK-8372846 as a followup for similar issues. I need to try out your test to understand this better. Does it cause a backwards-branch safepoint? I suspect that it may not be safe to set rexeecute to false here. If reexecute is false and -XX:+VerifyStack is set, deoptimization may fail if the operands are not on the stack.
There was a problem hiding this comment.
Yes, it is a backwards-branch safepoint.
Tbh, after looking deeper, I don't really understand what is happening here. I modified the test a little bit so the final compiled code does not elide the safepoint in the loop, and ran with -XX:+VerifyStack -XX:+DeoptimizeALot -XX:+SafepointALot, but the test still passed after 100 repeats. I think that the state is correct, but I don't see how the compiled code notifies the deoptimizater and the interpreter that it is in an exception state, and the interpreter needs to find an exception handler instead of continuing with the next bytecode. My guess is that the compiled code should store the exception into Thread::_pending_exception, or the deoptimizer needs to do so, and the interpreter needs to check that when being handed the control. But I have not yet found that.
|
It seems to be very difficult to force the back-edge safepoint to deoptimize. I tried creating a thread that calls System.gc(), but so far no crash. Still, I think the state is incorrect if reexecute=false. Setting reexecute to false means it will skip the current instruction. To correctly handle a deoptimization on the backwards branch, the debug state, bci, and exception location should match. I think we have 3 choices to prepare for maybe_add_safepoint():
|
| * @library /test/lib /test/jdk/java/lang/invoke/common / | ||
| * @build test.java.lang.invoke.lib.InstructionHelper | ||
| * | ||
| * @run main/othervm compiler.exceptions.TestDebugDuringExceptionCatching |
There was a problem hiding this comment.
| * @run main/othervm compiler.exceptions.TestDebugDuringExceptionCatching | |
| * @run main/othervm ${test.main.class} |
Drive-by comment.
|
@merykitty , I tried solution 1) and it seems to work, but I think I prefer solution 2) because it aligns better with my idea from JDK-8372846 of canonicalized exception states. If you like, I can take over this bug. |
|
@dean-long Thanks a lot, please take over this bug then.
I have been thinking about this approach, we can have additional parameter in the |
|
@merykitty This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply issue a |
Hi,
This PR fixes the issue of the compiler crashing with "not enough operands for reexecution". The issue here is that during
Parse::catch_inline_exceptions, the old stack is gone, and we cannot reexecute the current bytecode anymore. However, there are some places where we try to insert safepoints into the graph, such as if the handler is a backward jump, or if one of the exceptions in the handlers is not loaded. Since the_reexecutestate of the current jvms is "undefined", it is inferred automatically that it should reexecute for some bytecodes such asputfield. The solution then is to explicitly set_reexecuteto false.I can manage to write a unit test for the case of a backward handler, for the other cases, since the exceptions that can be thrown for a bytecode that is inferred to reexecute are
NullPointerException,ArrayIndexOutOfBoundsException, andArrayStoreException. I find it hard to construct such a test in which one of them is not loaded.Please kindly review, thanks a lot.
Progress
Issue
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/28597/head:pull/28597$ git checkout pull/28597Update a local copy of the PR:
$ git checkout pull/28597$ git pull https://git.openjdk.org/jdk.git pull/28597/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 28597View PR using the GUI difftool:
$ git pr show -t 28597Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/28597.diff
Using Webrev
Link to Webrev Comment