This class provides support for callee-saved registers to the rest of the VM.
For normal Java-to-Java calls, all registers are caller saved. That simplifies many things
related to stack walking because caller and callee frames are independent: all values in the
caller frame at a call site are spilled at a location known when compiling the caller frame.
But for slow-path stub calls, caller-saved registers have severe performance implications: all
registers must be spilled at the call site. This means every loop has at least one call (the
safepoint check) where all values are spilled. This degrades code quality. For stub calls,
therefore all registers should be callee saved. This means that for all practical use cases
either none or all registers are callee saved, which makes the implementation simpler.
For all methods with callee-saved registers, the memory area where the callee saves the register
to is located at the
same offset
relative to the caller frame, and
has the
same size
. This ensures that caller and callee are still
independent: the caller knows at which offset (relative to the stack pointer) a register is saved
by the callee. This is a
negative offset
relative to the caller frame's
stack pointer.
Callee-saved registers must be supported in reference maps for the GC, and in deoptimization
information. Because of the fixed offsets, there is no difference between a caller-spilled value
(a stack slot with a positive offset relative to the caller frame's stack pointer) and a
callee-saved value (a negative offset relative to the caller frame's stack pointer). So as long
as reference maps and deoptimization information support negative stack slot offsets, no special
handling for callee saved registers is necessary. Both
SubstrateReferenceMapBuilder.addLiveValue(jdk.vm.ci.meta.Value)
and
FrameInfoEncoder
use
CalleeSavedRegisters.getOffsetInFrame(jdk.vm.ci.code.Register)
to look up the callee-save offset for a register.