Skip to content

Commit 848b11b

Browse files
committed
In deopt stub, save registers again using stub calling convention.
1 parent b887c36 commit 848b11b

File tree

3 files changed

+65
-64
lines changed

3 files changed

+65
-64
lines changed

substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -487,27 +487,19 @@ public SubstrateLIRGenerationResult(CompilationIdentifier compilationId, LIR lir
487487
super(compilationId, lir, frameMapBuilder, registerAllocationConfig, callingConvention);
488488
this.method = method;
489489

490-
/*
491-
* Besides for methods with callee saved registers, we reserve additional stack space
492-
* for lazyDeoptStub too. This is necessary because the lazy deopt stub might read
493-
* callee-saved register values in the callee of the function to be deoptimized, thus
494-
* that stack space must not be overwritten by the lazy deopt stub.
495-
*/
496-
if (method.hasCalleeSavedRegisters() || method.getDeoptStubType() == Deoptimizer.StubType.LazyEntryStub) {
490+
if (method.hasCalleeSavedRegisters()) {
497491
AArch64CalleeSavedRegisters calleeSavedRegisters = AArch64CalleeSavedRegisters.singleton();
498492
FrameMap frameMap = ((FrameMapBuilderTool) frameMapBuilder).getFrameMap();
499493
int registerSaveAreaSizeInBytes = calleeSavedRegisters.getSaveAreaSize();
500494
StackSlot calleeSaveArea = frameMap.allocateStackMemory(registerSaveAreaSizeInBytes, frameMap.getTarget().wordSize);
501495

502-
if (method.hasCalleeSavedRegisters()) {
503-
/*
504-
* The offset of the callee save area must be fixed early during image
505-
* generation. It is accessed when compiling methods that have a call with
506-
* callee-saved calling convention. Here we verify that offset computed earlier
507-
* is the same as the offset actually reserved.
508-
*/
509-
calleeSavedRegisters.verifySaveAreaOffsetInFrame(calleeSaveArea.getRawOffset());
510-
}
496+
/*
497+
* The offset of the callee save area must be fixed early during image generation.
498+
* It is accessed when compiling methods that have a call with callee-saved calling
499+
* convention. Here we verify that offset computed earlier is the same as the offset
500+
* actually reserved.
501+
*/
502+
calleeSavedRegisters.verifySaveAreaOffsetInFrame(calleeSaveArea.getRawOffset());
511503
}
512504

513505
if (method.canDeoptimize() || method.isDeoptTarget()) {
@@ -1042,9 +1034,8 @@ public void returned(CompilationResultBuilder crb) {
10421034
}
10431035

10441036
/**
1045-
* Generates the prologue of a
1046-
* {@link com.oracle.svm.core.deopt.Deoptimizer.StubType#EagerEntryStub} or
1047-
* {@link com.oracle.svm.core.deopt.Deoptimizer.StubType#LazyEntryStub} method.
1037+
* Generates the prologue of a {@link com.oracle.svm.core.deopt.Deoptimizer.StubType#EntryStub}
1038+
* method.
10481039
*/
10491040
protected static class DeoptEntryStubContext extends SubstrateAArch64FrameContext {
10501041
protected final CallingConvention callingConvention;
@@ -1058,9 +1049,13 @@ protected DeoptEntryStubContext(SharedMethod method, CallingConvention callingCo
10581049
public void enter(CompilationResultBuilder crb) {
10591050
AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
10601051
RegisterConfig registerConfig = crb.frameMap.getRegisterConfig();
1052+
Register frameRegister = registerConfig.getFrameRegister();
10611053
Register gpReturnReg = registerConfig.getReturnRegister(JavaKind.Object);
10621054
Register fpReturnReg = registerConfig.getReturnRegister(JavaKind.Double);
10631055

1056+
/* Create the frame. */
1057+
super.enter(crb);
1058+
10641059
/* Pass the general purpose and floating point registers to the deopt stub. */
10651060
Register secondParameter = ValueUtil.asRegister(callingConvention.getArgument(1));
10661061
masm.mov(64, secondParameter, gpReturnReg);
@@ -1073,9 +1068,7 @@ public void enter(CompilationResultBuilder crb) {
10731068
* the first argument register may overlap with the object return register.
10741069
*/
10751070
Register firstParameter = ValueUtil.asRegister(callingConvention.getArgument(0));
1076-
masm.mov(64, firstParameter, registerConfig.getFrameRegister());
1077-
1078-
super.enter(crb);
1071+
masm.add(64, firstParameter, frameRegister, crb.frameMap.totalFrameSize());
10791072
}
10801073
}
10811074

@@ -1343,7 +1336,7 @@ public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult
13431336
}
13441337

13451338
protected FrameContext createFrameContext(SharedMethod method, Deoptimizer.StubType stubType, CallingConvention callingConvention) {
1346-
if (stubType == Deoptimizer.StubType.EagerEntryStub || stubType == Deoptimizer.StubType.LazyEntryStub) {
1339+
if (stubType == Deoptimizer.StubType.EntryStub) {
13471340
return new DeoptEntryStubContext(method, callingConvention);
13481341
} else if (stubType == Deoptimizer.StubType.ExitStub) {
13491342
return new DeoptExitStubContext(method, callingConvention);

substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -564,27 +564,19 @@ public SubstrateLIRGenerationResult(CompilationIdentifier compilationId, LIR lir
564564
super(compilationId, lir, frameMapBuilder, registerAllocationConfig, callingConvention);
565565
this.method = method;
566566

567-
/*
568-
* Besides for methods with callee saved registers, we reserve additional stack space
569-
* for lazyDeoptStub too. This is necessary because the lazy deopt stub might read
570-
* callee-saved register values in the callee of the function to be deoptimized, thus
571-
* that stack space must not be overwritten by the lazy deopt stub.
572-
*/
573-
if (method.hasCalleeSavedRegisters() || method.getDeoptStubType() == Deoptimizer.StubType.LazyEntryStub) {
567+
if (method.hasCalleeSavedRegisters()) {
574568
AMD64CalleeSavedRegisters calleeSavedRegisters = AMD64CalleeSavedRegisters.singleton();
575569
FrameMap frameMap = ((FrameMapBuilderTool) frameMapBuilder).getFrameMap();
576570
int registerSaveAreaSizeInBytes = calleeSavedRegisters.getSaveAreaSize();
577571
StackSlot calleeSaveArea = frameMap.allocateStackMemory(registerSaveAreaSizeInBytes, frameMap.getTarget().wordSize);
578572

579-
if (method.hasCalleeSavedRegisters()) {
580-
/*
581-
* The offset of the callee save area must be fixed early during image
582-
* generation. It is accessed when compiling methods that have a call with
583-
* callee-saved calling convention. Here we verify that offset computed earlier
584-
* is the same as the offset actually reserved.
585-
*/
586-
calleeSavedRegisters.verifySaveAreaOffsetInFrame(calleeSaveArea.getRawOffset());
587-
}
573+
/*
574+
* The offset of the callee save area must be fixed early during image generation.
575+
* It is accessed when compiling methods that have a call with callee-saved calling
576+
* convention. Here we verify that offset computed earlier is the same as the offset
577+
* actually reserved.
578+
*/
579+
calleeSavedRegisters.verifySaveAreaOffsetInFrame(calleeSaveArea.getRawOffset());
588580
}
589581

590582
if (method.canDeoptimize() || method.isDeoptTarget()) {
@@ -1344,9 +1336,8 @@ public void returned(CompilationResultBuilder crb) {
13441336
}
13451337

13461338
/**
1347-
* Generates the prologue of a
1348-
* {@link com.oracle.svm.core.deopt.Deoptimizer.StubType#EagerEntryStub} or
1349-
* {@link com.oracle.svm.core.deopt.Deoptimizer.StubType#LazyEntryStub} method.
1339+
* Generates the prologue of a {@link com.oracle.svm.core.deopt.Deoptimizer.StubType#EntryStub}
1340+
* method.
13501341
*/
13511342
protected static class DeoptEntryStubContext extends SubstrateAMD64FrameContext {
13521343
protected DeoptEntryStubContext(SharedMethod method, CallingConvention callingConvention) {
@@ -1357,24 +1348,18 @@ protected DeoptEntryStubContext(SharedMethod method, CallingConvention callingCo
13571348
public void enter(CompilationResultBuilder tasm) {
13581349
AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm;
13591350
RegisterConfig registerConfig = tasm.frameMap.getRegisterConfig();
1351+
Register frameRegister = registerConfig.getFrameRegister();
13601352
Register gpReturnReg = registerConfig.getReturnRegister(JavaKind.Long);
13611353
Register fpReturnReg = registerConfig.getReturnRegister(JavaKind.Double);
1362-
13631354
Register firstArgument = ValueUtil.asRegister(callingConvention.getArgument(0));
13641355
assert !firstArgument.equals(gpReturnReg) : "overwriting return register";
1356+
13651357
/*
13661358
* Since this is the target for all deoptimizations we must mark the start of this
13671359
* routine as an indirect target.
13681360
*/
13691361
asm.maybeEmitIndirectTargetMarker();
13701362

1371-
/* Pass the address of the frame to deoptimize as first argument. */
1372-
asm.movq(firstArgument, registerConfig.getFrameRegister());
1373-
1374-
/* Copy the original return registers values into the argument registers. */
1375-
asm.movq(ValueUtil.asRegister(callingConvention.getArgument(1)), gpReturnReg);
1376-
asm.movdq(ValueUtil.asRegister(callingConvention.getArgument(2)), fpReturnReg);
1377-
13781363
/*
13791364
* Keep the return address slot. This keeps the stack walkable, which is crucial for the
13801365
* interruptible phase of lazy deoptimization. (The return address points to the deopt
@@ -1383,7 +1368,15 @@ public void enter(CompilationResultBuilder tasm) {
13831368
* This also ensures that the stack pointer is aligned properly.
13841369
*/
13851370
asm.subq(registerConfig.getFrameRegister(), FrameAccess.returnAddressSize());
1371+
13861372
super.enter(tasm);
1373+
1374+
/* Pass the address of the frame to deoptimize as first argument. */
1375+
asm.leaq(firstArgument, new AMD64Address(frameRegister, tasm.frameMap.totalFrameSize()));
1376+
1377+
/* Copy the original return registers values into the argument registers. */
1378+
asm.movq(ValueUtil.asRegister(callingConvention.getArgument(1)), gpReturnReg);
1379+
asm.movdq(ValueUtil.asRegister(callingConvention.getArgument(2)), fpReturnReg);
13871380
}
13881381
}
13891382

@@ -1392,7 +1385,7 @@ public void enter(CompilationResultBuilder tasm) {
13921385
* method.
13931386
*
13941387
* Note no special handling is necessary for CFI as this will be a direct call from the
1395-
* {@link com.oracle.svm.core.deopt.Deoptimizer.StubType#EagerEntryStub}.
1388+
* {@link com.oracle.svm.core.deopt.Deoptimizer.StubType#EntryStub}.
13961389
*/
13971390
protected static class DeoptExitStubContext extends SubstrateAMD64FrameContext {
13981391
protected DeoptExitStubContext(SharedMethod method, CallingConvention callingConvention) {
@@ -1918,7 +1911,7 @@ protected AMD64MacroAssembler createAssembler(OptionValues options) {
19181911
}
19191912

19201913
protected FrameContext createFrameContext(SharedMethod method, Deoptimizer.StubType stubType, CallingConvention callingConvention) {
1921-
if (stubType == Deoptimizer.StubType.EagerEntryStub || stubType == Deoptimizer.StubType.LazyEntryStub) {
1914+
if (stubType == Deoptimizer.StubType.EntryStub) {
19221915
return new DeoptEntryStubContext(method, callingConvention);
19231916
} else if (stubType == Deoptimizer.StubType.ExitStub) {
19241917
return new DeoptExitStubContext(method, callingConvention);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import com.oracle.svm.core.config.ConfigurationValues;
6060
import com.oracle.svm.core.deopt.DeoptimizedFrame.RelockObjectData;
6161
import com.oracle.svm.core.deopt.DeoptimizedFrame.VirtualFrame;
62+
import com.oracle.svm.core.graal.code.StubCallingConvention;
6263
import com.oracle.svm.core.heap.GCCause;
6364
import com.oracle.svm.core.heap.Heap;
6465
import com.oracle.svm.core.heap.ReferenceAccess;
@@ -754,15 +755,7 @@ public enum StubType {
754755
/**
755756
* Custom prologue: save all of the architecture's return registers onto the stack.
756757
*/
757-
EagerEntryStub,
758-
759-
/**
760-
* Custom prologue: same custom Prologue as the EagerEntryStub, but we also reserve some
761-
* additional memory on the stack when this stub is entered, because the lazyDeoptStub might
762-
* need to access callee-saved values in the frame of the callee of the method to be
763-
* deoptimized.
764-
*/
765-
LazyEntryStub,
758+
EntryStub,
766759

767760
/**
768761
* Custom prologue: set the stack pointer to the first method parameter.
@@ -812,7 +805,27 @@ private static boolean isNonNullValue(UnsignedWord pointer) {
812805
return pointer != Word.nullPointer();
813806
}
814807

815-
@DeoptStub(stubType = StubType.LazyEntryStub)
808+
/**
809+
* Entry point for the lazy deopt stub.
810+
* <p>
811+
* This method uses {@link StubCallingConvention} for when the callee (the return of which is
812+
* intercepted) also uses stub calling convention. In that case, the callee (rather than the
813+
* caller) has initially saved the values of registers, and these values are required for
814+
* constructing the deopt frame. The values have already been restored to their registers before
815+
* the return to this stub, and using stub calling convention here saves them again to the same
816+
* expected locations.
817+
* <p>
818+
* Usually, the saved register values would still be present below the stack pointer, but could
819+
* also have been overwritten by an interrupt or signal handler. The ABI might guarantee a safe
820+
* zone below the stack pointer to prevent this, but such zones are typically also not large
821+
* enough to fit all saved registers, especially with vector registers.
822+
* <p>
823+
* If the callee does not use stub calling convention, this method unnecessarily saves
824+
* registers, but it avoids having additional stubs and selecting between them and should not
825+
* have significant impact.
826+
*/
827+
@StubCallingConvention
828+
@DeoptStub(stubType = StubType.EntryStub)
816829
@Uninterruptible(reason = "Rewriting stack; gpReturnValue holds object reference.")
817830
public static UnsignedWord lazyDeoptStubObjectReturn(Pointer originalStackPointer, UnsignedWord gpReturnValue, UnsignedWord fpReturnValue) {
818831
try {
@@ -837,7 +850,9 @@ public static UnsignedWord lazyDeoptStubObjectReturn(Pointer originalStackPointe
837850
}
838851
}
839852

840-
@DeoptStub(stubType = StubType.LazyEntryStub)
853+
/** See {@link #lazyDeoptStubObjectReturn}. */
854+
@StubCallingConvention
855+
@DeoptStub(stubType = StubType.EntryStub)
841856
@Uninterruptible(reason = "Rewriting stack.")
842857
public static UnsignedWord lazyDeoptStubPrimitiveReturn(Pointer originalStackPointer, UnsignedWord gpReturnValue, UnsignedWord fpReturnValue) {
843858
/*
@@ -987,7 +1002,7 @@ private static DeoptimizedFrame constructLazilyDeoptimizedFrameInterruptibly0(Po
9871002
* when the deopt stub was reached. It must be restored to the register before
9881003
* completion of the stub.
9891004
*/
990-
@DeoptStub(stubType = StubType.EagerEntryStub)
1005+
@DeoptStub(stubType = StubType.EntryStub)
9911006
@Uninterruptible(reason = "Frame holds Objects in unmanaged storage.")
9921007
public static UnsignedWord eagerDeoptStub(Pointer originalStackPointer, UnsignedWord gpReturnValue, UnsignedWord fpReturnValue) {
9931008
try {

0 commit comments

Comments
 (0)