RFR: 8365047: Remove exception handler stub code in C2 [v2]
Andrew Dinn
adinn at openjdk.org
Mon Sep 1 09:54:45 UTC 2025
On Thu, 28 Aug 2025 22:25:24 GMT, Dean Long <dlong at openjdk.org> wrote:
>> Ruben has updated the pull request incrementally with one additional commit since the last revision:
>>
>> Address review comments
>
> If we end up adding a nop or illegal instruction, then we can also undo the work-around that we did in JDK-8172844 for a similar problem.
@dean-long I think there is an alternative fix for this that we should consider. The problem here arises because a return address for a legitimate call from the body may alias the nmethod's deopt_handler start. However, that aliasing is solely down to how we are recording and comparing addresses and I think we can easily and safely avoid it.
The nmethod's deopt handler offset is set to identify the start of the deopt handler code generated into the stubs area. We need to be able to identify that stub's first instruction because we have to patch it into the stack or link register as a return address and then return to it in order to initiate a deopt. Removing the exception handler means it is now possible for it to directly follow the main code and alias the return address of a trailing call.
We actually work hard to ensure that this same start address is recorded on the stack when we enter the deopt blob. The generated handler code always uses a jump to enter the deopt blob. However, it makes that jump look like a call by patching in a return address that equals the stub start. On Intel we make a fake call in order to push a return address and then carefully decrement the pushed address to refer to the stub start rather than the pushed address (i.e. the one that follows the fake call). On aarch64 it requires less work. The stub start is loaded into lr before jumping effectively simulating a call that just preceded the start address.
Doing all this fiddling of the return pc is what makes the frame code test for a deopt caller frame both *simple* -- just compare the pc to the nmethod's deopt address -- and *ambiguous* -- oops it could have been a trailing call in the main code. However, we can easily avoid the ambiguity. We can switch to an actual call in the generated code and adjust the deopt_pc test in the frame code to look for the nmethod's deopt address *plus* some arch-specific constant offset. The offset's size is determined by whatever instructions we need to plant in order to get to and make the call. We can make this safe against code changes by binding a label after the call and asserting that the difference between the label address and stub start address equals the relevant constant.
That will give correct results if we traverse the frame stack inside or below the deopt blob code. But what about when we fiddle the return stack to force a return into the deopt stub? i.e. when the return address is the nmethod's deopt stub address? I don't believe we will ever traverse the stack while it is in that state because it only happens transiently when we are returning into the deopt handler.
WDYT?
-------------
PR Comment: https://git.openjdk.org/jdk/pull/26678#issuecomment-3241676272
More information about the hotspot-dev
mailing list