-
Notifications
You must be signed in to change notification settings - Fork 758
Z: Restore Non Volatile GPRs in jitExitInterpreter0RestoreAll #22128
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
runtime/oti/zhelpers.m4
Outdated
@@ -729,6 +729,7 @@ ifelse(eval(ASM_JAVA_SPEC_VERSION >= 24), 1, { | |||
define({RESTORE_ALL_REGS},{ | |||
RESTORE_C_VOLATILE_REGS($1) | |||
RESTORE_C_NONVOLATILE_REGS | |||
RESTORE_PRESERVED_REGS_AND_SWITCH_TO_JAVA_STACK |
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.
Does this work if you simply switch to the java stack? The previous two lines have restored all of the registers already.
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.
Note that the C interpreter has already executed RESTORE_PRESERVED_REGS_AND_SWITCH_TO_JAVA_STACK
before jumping to the restore all target.
Can this be solved by storing the registers you don't want overwritten before doing the restores above?
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.
We should arguably be restoring the hiword registers here as well, though we have no 31-bit builds any more.
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.
RESTORE_C_VOLATILE_REGS($1)
RESTORE_C_NONVOLATILE_REGS
Are no-ops on Z
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.
Do we need to switch to java stack, dont we do that when we exit the interpreter in https://github.com/eclipse-openj9/openj9/blob/master/runtime/vm/zcinterp.m4#L85 ?
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.
I'll check out the other platforms to make sure they aren't suffering from similar issues.
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.
This code is somewhat confusing as the registers are stored in the monitor enter helper before calling the C support code, but they are not restored by the helper - we instead branch out to the yield helper which calls in to the C interpreter. The interpreter returns back to the JIT as if it were a method call once the monitor enter is complete.
Yes, that mix of different linkages is confusing.
I'm not sure if that's true - the C interpreter has only restored the registers that are preserved in the JIT private linkage before jumping to the helper.
I am looking at the JIT private linkage, on Z - we would GPR5 to GPR13 is considered preserved register - (GPR5 and GPR13 being J9SP and J9VMThread respectively), while C ABI on LoZ will consider GPR6 to GPR13 preserved). For Linux on Z, as private linkage and helper linkage are bit similar, it may be not that bad, but we would have issue on z/OS where C linkage bit different then the private linkage.
I think there's also the FPR/VR registers to be considered - none of the them are preserved in the JIT private linkage, so none will have been restored in the C interpteter transition code.
IIRC, we did not expect JIT helpers (The ones that were changed to use New Dual Mode helper code) to use Vector Registers or FPRs in the path. i.e, I do not see any FPRs/VRFs being preserved in Glue code when such C code helper is called. JIT dispatch sequence would preserve any C volatile register that is being used in the JIT compiled code.
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.
Remember that the JIT code called jitMonitorEntry
initially - the contract for this (and every other helper) is that all registers are preserved (with the possible exception of a return value, which does not exist in this case). When we resume after the yield, we effectively return from the monitor enter call, so all registers will need to be restored by the post-yield return point.
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.
Yes, correct. So just to ensure I understand clearly and what I am seeing is correct, On Z, we have divided the preservation of all registers in two parts for Dual mode helpers such as jitMonitorEnter/jitMonitorExit. All the registers (GPR/FPR/VRF) which are considered volatile in C linkage on Z are preserved before JIT calls out to assembly glue code in 'znathelp.m4' [1]. If we do not need to enter slow path helper - we do not touch any of the register which are non-volatiles (Which C code should be preserving, and there is not interpreter / GC call there so no need to keep track of them).
If we need to call slow path, we execute the sequence in [2] that preserves the registers considered non volatile in the C ABI.
Now for JIT monitor entry, for thread to yield, the call is made at [3].
Given the exit point from JIT compiled code would preserve the registers considered volatile in C, all kinds of non volatile registers are needed to be restored right ?
[1]. https://github.com/eclipse-openj9/openj9/blob/0dcff38ad68b6336717667681c8217eab9e8b8a5/runtime/
codert_vm/znathelp.m4#L203-L266
[2].
openj9/runtime/codert_vm/znathelp.m4
Lines 215 to 216 in 0dcff38
SAVE_C_NONVOLATILE_GPRS | |
SAVE_C_NONVOLATILE_REGS |
[3].
openj9/runtime/codert_vm/znathelp.m4
Lines 222 to 223 in 0dcff38
je LABEL_NAME(CONCAT(L_SLOW_,SYM_COUNT)) | |
br CRINT |
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.
All the registers (GPR/FPR/VRF) which are considered volatile in C linkage on Z are preserved before JIT calls out to assembly glue code in 'znathelp.m4' .
This is incorrect - the contract is that all of the JIT helpers called from compiled code maintain and update ALL registers (in the case that a register holds an object pointer across a GC). This means FPR/VR as well.
In this case, the compiled code has called to jitMonitorEntry
and is expecting a return from there with all registers intact/correct.
I am converting this as draft - as going through the code, the interpreter loop and the code [1], which I think is the code being executed when returning from to the code that called jitMonitorEntry that was yielded. So we should be restoring the register in the interpreter as @gacholio said as we would have executed the code in [2]. The problem specifically is with the GPR8 and GPR9 being used to hold the object as in past when I marked those registers as volatile in JIT dispatch, failure goes away. The problem is execution of [3] that happens after JIT restores preserved registers. This stub uses R8 and R9 to check if Vector registers are enabled or not to restore them, in process modifying the value of GPR8 and GPR9 which would have right objects. I know how to fix this exactly. I will update the PR once I have made the change and tested it. [1]. openj9/runtime/vm/BytecodeInterpreter.hpp Lines 5878 to 5885 in 0dcff38
[2]. Lines 73 to 86 in 0dcff38
[3]. openj9/runtime/oti/zhelpers.m4 Lines 713 to 721 in f91146b
|
8ae3fdc
to
b10f8b5
Compare
@gacholio This is ready for review, in last changes, I have added routines to save and restore preserved FPRs and Vector registers as per s390x Linux and z/OS (31-bit/64-bit) in a4ab6ed. In b10f8b5 I added routines for S390 linux. I kept the routine exposed to only the NEW_DUAL_MODE_HELPER routines only and have tested out IBM SDK8 ( |
When calling new dual mode helper such as jitMonitorEnter, it is possible that the thread will be unmounted from the career thread, upon returning, when entering the monitor in blocking mode, virtual thread can be mounted different thread. To ensure that all the non volatile registers are preserved across such transition, change in this PR adds assembly routines to save and restore non volatile FPRs and Vector Registers and updates the jitExitInterpreter0RestoreAll to restore them. Signed-off-by: Rahil Shah <rahil@ca.ibm.com>
I have squashed commits. @gacholio Can I request a review from you as well? In parallel, I am launching PR test as well. |
Jenkins test sanity zlinux jdk8,jdk21,jdk24 |
When calling out jitMonitorEnter helper call, in case of the thread needs to yield when entering monitor in blocking mode and later when it is continued on other thread, return path back to JIT compiled code was missing preserving the Non Volatile GPRs and switching back to java stack - This commit adds the routine to switch stack and restore preserve registers.