RFR: 8365047: Remove exception handler stub code in C2 [v7]
Ruben
duke at openjdk.org
Thu Oct 23 08:52:10 UTC 2025
On Tue, 21 Oct 2025 13:56:57 GMT, Andrew Dinn <adinn at openjdk.org> wrote:
> What it does is a 4 byte read at the supplied pc (i.e one instruction's worth of data) to test whether those bytes encode a nop instruction
I meant to refer to this `check` implementation, which reads 8 bytes from where `LR` points to and checks whether they contain the NOP+MOVK sequence.
https://github.com/openjdk/jdk/blob/dcf46a0a195d7386ed0bc872f60eb9c586425cc8/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp#L531
class NativePostCallNop: public NativeInstruction {
public:
bool check() const {
uint64_t insns = *(uint64_t*)addr_at(0);
// Check for two instructions: nop; movk zr, xx
// These instructions only ever appear together in a post-call
// NOP, so it's unnecessary to check that the third instruction is
// a MOVK as well.
return (insns & 0xffe0001fffffffff) == 0xf280001fd503201f;
}
```
In case of deoptimization, the LR is pointing to the entry point of the deoptimization handler stub code located one instruction before the end of the code blob - in this case, `0x0000f7cf03c5fffc`:
0x0000f7cf03c5fff8: b 0x0000f7cf0383d180
0x0000f7cf03c5fffc: b 0x0000f7cf03c5fff8
If I understand correctly, the `si_addr` reported by the kernel for the SIGSEGV is the address of memory location which caused the SIGSEGV. In this case it would be reported as follows, both in case the memory access was 8-byte starting at `0x0000f7cf03c5fffc` or 4-byte starting at `0x0000f7cf03c60000`:
siginfo: si_signo: 11 (SIGSEGV), si_code: 2 (SEGV_ACCERR), si_addr: 0x0000f7cf03c60000
It should be possible to solve this by either using SafeFetch or by checking for NOP and MOVK separately in 4-byte reads. Both should work, however it appears the latter might be preferrable: the outcome of the check should not depend on anything outside the current code blob. Using SafeFetch can hide the issue.
@theRealAph, thank you for the advice on the SafeFetch interface - I wasn't aware it exists.
However, as it might introduce performance overhead on what appears to be designed as a fast path, and potentially might hide this kind of issue where content outside the code blob is checked, would it be suitable for you if the alternative is implemented?
The `check` is only meant to access the bytes pointed to by return address. I believe it wouldn't be correct for it to check an arbitrary location as there are no guarantees to match the constraints expected by the NativePostCallNop logic outside the compiled code. So, it should only be reading within the compiled code. When continuations are enabled, every call site should have the post-call NOP sequences following it.
The exception to this is deoptimization - where the perceived call site actually is within the deoptimization handler stub code and, with this change, is followed by the entry point of the stub code. The entry point is never going to be a NOP, so checking for NOP first would prevent the second read checking for MOVK.
-------------
PR Comment: https://git.openjdk.org/jdk/pull/26678#issuecomment-3435796978
More information about the serviceability-dev
mailing list