Skip to content

Commit 8ca9916

Browse files
authored
Add arm64 support for EnC (dotnet#69679)
This adds support for EnC on arm64. A couple of notes on the implementation compared to x64: - On x64 we get the fixed stack size from unwind info. However, for the frames we set up on arm64 for EnC it is not possible to extract the frame size from there because their prologs generally look like stp fp, lr, [sp,#-16]! mov fp, sp sub sp, sp, #144 with unwind codes like the following: set_fp; mov fp, sp save_fplr_x #1 (0x01); tp fp, lr, [sp, #-16]! As can be seen, it is not possible to get the fixed stack size from unwind info in this case. Instead we pass it through the GC info that already has a section for EnC data. - On arm64 the JIT is required to place the PSPSym at the same offset from caller-SP for both the main function and for funclets. Due to this we try to allocate the PSPSym as early as possible in the main function and we must take some care in funclets. However, this conflicts with the EnC frame header that the JIT uses to place values that must be preserved on EnC transitions. This is currently callee-saved registers and the MonitorAcquired boolean. Before this change we were allocating PSPSym above (before) the monitor acquired boolean, but we now have to allocate MonitorAcquired first, particularly because the size of the preserved header cannot change on EnC transitions, while the PSPSym can disappear or appear. This changes frame allocation slightly for synchronized functions.
1 parent f6fe0f8 commit 8ca9916

21 files changed

+322
-140
lines changed

docs/design/coreclr/botr/clr-abi.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -653,41 +653,46 @@ Edit and Continue (EnC) is a special flavor of un-optimized code. The debugger h
653653

654654
In the current design, the JIT does not have access to the previous versions of the method and so it has to assume the worst case. EnC is designed for simplicity, not for performance of the generated code.
655655

656-
EnC is currently enabled on x86 and x64 only, but the same principles would apply if it is ever enabled on other platforms.
656+
EnC is currently enabled on x86, x64 and ARM64 only, but the same principles would apply if it is ever enabled on other platforms.
657657

658658
The following sections describe the various Edit and Continue code conventions that must be followed.
659659

660660
## EnC flag in GCInfo
661661

662-
The JIT records the fact that it has followed conventions for EnC code in GC Info. On x64, this flag is implied by recording the size of the stack frame region preserved between EnC edits (`GcInfoEncoder::SetSizeOfEditAndContinuePreservedArea`). For normal methods on JIT64, the size of this region is 2 slots (saved `RBP` and return address). On RyuJIT/AMD64, the size of this region is increased to include `RSI` and `RDI`, so that `rep stos` can be used for block initialization and block moves.
662+
The JIT records the fact that it has followed conventions for EnC code in GC Info. On x64/ARM64, this flag is implied by recording the size of the stack frame region preserved between EnC edits (`GcInfoEncoder::SetSizeOfEditAndContinuePreservedArea`). For x64 the size of this region is increased to include `RSI` and `RDI`, so that `rep stos` can be used for block initialization and block moves. ARM64 saves only the FP and LR registers when EnC is enabled and does not use other callee saved registers.
663+
664+
To successfully perform EnC transitions the runtime needs to know the size of the stack frames it is transitioning between. For x64 code the size can be extracted from unwind codes. This is not possible for arm64 code as the frames are set up in such a way that the unwind codes do not allow to retrieve this value. Therefore, on ARM64 the GC info contains also the size of the fixed stack frame to be used for EnC purposes.
663665

664666
## Allocating local variables backward
665667

666668
This is required to preserve addresses of the existing locals when an EnC edit appends new ones. In other words, the first local must be allocated at the highest stack address. Special care has to be taken to deal with alignment. The total size of the method frame can either grow (more locals added) or shrink (fewer temps needed) after the edit. The VM zeros out newly added locals.
667669

668670
## Fixed set of callee-saved registers
669671

670-
This eliminates need to deal with the different sets in the VM, and makes preservation of local addresses easier. On x64, we choose to always save `RBP` only. There are plenty of volatile registers and so lack of non-volatile registers does not impact quality of non-optimized code.
672+
This eliminates need to deal with the different sets in the VM, and makes preservation of local addresses easier. There are plenty of volatile registers and so lack of non-volatile registers does not heavily impact quality of non-optimized code.
673+
x64 currently saves RBP, RSI and RDI while ARM64 saves just FP and LR.
671674

672675
## EnC is supported for methods with EH
673676

674677
However, EnC remap is not supported inside funclets. The stack layout of funclets does not matter for EnC.
675678

676-
## Initial RSP == RBP == PSPSym
679+
## Considerations with regards to PSPSym
677680

678-
This invariant allows VM to compute new value of `RBP` and PSPSym after the edit without any additional information. Location of PSPSym is found via GC info.
681+
As explained previously in this document, on x64 we have Initial RSP == PSPSym. For EnC methods, as we disallow remappings after localloc (see below), we furthermore have RBP == PSPSym.
682+
For ARM64 we have Caller SP == PSPSym and the FP points to the previously saved FP/LR pair. For EnC the JIT always sets up the stack frame so that the FP/LR pair is at Caller SP - 16 and does not save any additional callee saves.
683+
These invariants allow the VM to compute new value of the frame pointer and PSPSym after the edit without any additional information. Note that the frame pointer and PSPSym do not change values or location on ARM64. However, EH may be added to a function in which case a new PSPSym needs to be materialized, even on ARM64. Location of PSPSym is found via GC info.
679684

680685
## Localloc
681686

682-
Localloc is allowed in EnC code, but remap is disallowed after the method has executed a localloc instruction. VM uses the invariant above (`RSP == RBP`) to detect whether localloc was executed by the method.
687+
Localloc is allowed in EnC code, but remap is disallowed after the method has executed a localloc instruction. VM uses the invariants above (`RSP == RBP` on x64, `FP + 16 == SP + stack size` on ARM64) to detect whether localloc was executed by the method.
683688

684689
## Security object
685690

686-
This does not require any special handling by the JIT on x64. (Different from x86). The security object is copied over by the VM during remap if necessary. Location of security object is found via GC info.
691+
This does not require any special handling by the JIT on x64/arm64. (Different from x86). The security object is copied over by the VM during remap if necessary. Location of security object is found via GC info.
687692

688693
## Synchronized methods
689694

690-
The extra state created by the JIT for synchronized methods (original `this` and lock taken flag) must be preserved during remap. The JIT stores this state in the preserved region, and increases the size of the preserved region reported in GC info accordingly.
695+
The extra state created by the JIT for synchronized methods (lock taken flag) must be preserved during remap. The JIT stores this state in the preserved region, and increases the size of the preserved region reported in GC info accordingly.
691696

692697
## Generics
693698

src/coreclr/clrdefinitions.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ endif(CLR_CMAKE_HOST_WIN32)
5656
if (NOT (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_UNIX))
5757
add_compile_definitions(EnC_SUPPORTED)
5858
endif()
59-
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_WIN32))
59+
if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64)
6060
if(CLR_CMAKE_TARGET_WIN32)
6161
add_compile_definitions(FEATURE_ENC_SUPPORTED)
6262
endif(CLR_CMAKE_TARGET_WIN32)
63-
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_WIN32))
63+
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64)
6464

6565
# Features - please keep them alphabetically sorted
6666
if(CLR_CMAKE_TARGET_WIN32)

src/coreclr/debug/ee/arm64/arm64walker.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,22 @@ BYTE* NativeWalker::SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context,
127127
offset = offset | 0xFFFFFFFFFFE00000;
128128
}
129129

130+
PCODE finalAddr;
130131
if ((opcode & 0x80000000) != 0) //ADRP
131132
{
132133
offset = offset << 12;
133-
LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADRP X%d %p\n", opcode, RegNum, offset));
134+
finalAddr = (PCODE)(address + offset) & ~0xFFF;
135+
LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADRP X%d %p finalAddr = %p\n", opcode, RegNum, offset, finalAddr));
134136
}
135137
else
136138
{
137-
LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADR X%d %p\n", opcode, RegNum, offset));
139+
finalAddr = (PCODE)(address + offset);
140+
LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADR X%d %p finalAddr = %p\n", opcode, RegNum, offset, finalAddr));
138141
}
142+
143+
CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypass, 0xd503201f); //Add Nop in buffer
144+
SetReg(context, RegNum, finalAddr);
145+
return patchBypass;
139146
}
140147

141148
else if ((opcode & 0x3B000000) == 0x18000000) //LDR Literal (General or SIMD)

src/coreclr/gcinfo/gcinfoencoder.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ GcInfoSize& GcInfoSize::operator+=(const GcInfoSize& other)
344344
NumUntracked += other.NumUntracked;
345345
NumTransitions += other.NumTransitions;
346346
SizeOfCode += other.SizeOfCode;
347-
EncPreservedSlots += other.EncPreservedSlots;
347+
EncInfoSize += other.EncInfoSize;
348348

349349
UntrackedSlotSize += other.UntrackedSlotSize;
350350
NumUntrackedSize += other.NumUntrackedSize;
@@ -392,7 +392,7 @@ void GcInfoSize::Log(DWORD level, const char * header)
392392
LogSpew(LF_GCINFO, level, "NumUntracked: %Iu\n", NumUntracked);
393393
LogSpew(LF_GCINFO, level, "NumTransitions: %Iu\n", NumTransitions);
394394
LogSpew(LF_GCINFO, level, "SizeOfCode: %Iu\n", SizeOfCode);
395-
LogSpew(LF_GCINFO, level, "EncPreservedSlots: %Iu\n", EncPreservedSlots);
395+
LogSpew(LF_GCINFO, level, "EncInfoSize: %Iu\n", EncInfoSize);
396396

397397
LogSpew(LF_GCINFO, level, "---SIZES(bits)---\n");
398398
LogSpew(LF_GCINFO, level, "Total: %Iu\n", TotalSize);
@@ -484,6 +484,9 @@ GcInfoEncoder::GcInfoEncoder(
484484

485485
m_StackBaseRegister = NO_STACK_BASE_REGISTER;
486486
m_SizeOfEditAndContinuePreservedArea = NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA;
487+
#ifdef TARGET_ARM64
488+
m_SizeOfEditAndContinueFixedStackFrame = 0;
489+
#endif
487490
m_ReversePInvokeFrameSlot = NO_REVERSE_PINVOKE_FRAME;
488491
#ifdef TARGET_AMD64
489492
m_WantsReportOnlyLeaf = false;
@@ -760,6 +763,13 @@ void GcInfoEncoder::SetSizeOfEditAndContinuePreservedArea( UINT32 slots )
760763
m_SizeOfEditAndContinuePreservedArea = slots;
761764
}
762765

766+
#ifdef TARGET_ARM64
767+
void GcInfoEncoder::SetSizeOfEditAndContinueFixedStackFrame( UINT32 size )
768+
{
769+
m_SizeOfEditAndContinueFixedStackFrame = size;
770+
}
771+
#endif
772+
763773
#ifdef TARGET_AMD64
764774
void GcInfoEncoder::SetWantsReportOnlyLeaf()
765775
{
@@ -1157,7 +1167,10 @@ void GcInfoEncoder::Build()
11571167

11581168
if (m_SizeOfEditAndContinuePreservedArea != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA)
11591169
{
1160-
GCINFO_WRITE_VARL_U(m_Info1, m_SizeOfEditAndContinuePreservedArea, SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE, EncPreservedSlots);
1170+
GCINFO_WRITE_VARL_U(m_Info1, m_SizeOfEditAndContinuePreservedArea, SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE, EncInfoSize);
1171+
#ifdef TARGET_ARM64
1172+
GCINFO_WRITE_VARL_U(m_Info1, m_SizeOfEditAndContinueFixedStackFrame, SIZE_OF_EDIT_AND_CONTINUE_FIXED_STACK_FRAME_ENCBASE, EncInfoSize);
1173+
#endif
11611174
}
11621175

11631176
if (hasReversePInvokeFrame)

src/coreclr/inc/gcinfodecoder.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ enum GcInfoHeaderFlags
238238
#elif defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64)
239239
GC_INFO_HAS_TAILCALLS = 0x80,
240240
#endif // TARGET_AMD64
241-
GC_INFO_HAS_EDIT_AND_CONTINUE_PRESERVED_SLOTS = 0x100,
241+
GC_INFO_HAS_EDIT_AND_CONTINUE_INFO = 0x100,
242242
GC_INFO_REVERSE_PINVOKE_FRAME = 0x200,
243243

244244
GC_INFO_FLAGS_BIT_SIZE_VERSION_1 = 9,
@@ -547,6 +547,9 @@ class GcInfoDecoder
547547
UINT32 GetCodeLength();
548548
UINT32 GetStackBaseRegister();
549549
UINT32 GetSizeOfEditAndContinuePreservedArea();
550+
#ifdef TARGET_ARM64
551+
UINT32 GetSizeOfEditAndContinueFixedStackFrame();
552+
#endif
550553
size_t GetNumBytesRead();
551554

552555
#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
@@ -578,6 +581,9 @@ class GcInfoDecoder
578581
UINT32 m_CodeLength;
579582
UINT32 m_StackBaseRegister;
580583
UINT32 m_SizeOfEditAndContinuePreservedArea;
584+
#ifdef TARGET_ARM64
585+
UINT32 m_SizeOfEditAndContinueFixedStackFrame;
586+
#endif
581587
ReturnKind m_ReturnKind;
582588
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
583589
UINT32 m_NumSafePoints;

src/coreclr/inc/gcinfoencoder.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ struct GcInfoSize
118118
size_t NumUntracked;
119119
size_t NumTransitions;
120120
size_t SizeOfCode;
121-
size_t EncPreservedSlots;
121+
size_t EncInfoSize;
122122

123123
size_t UntrackedSlotSize;
124124
size_t NumUntrackedSize;
@@ -434,6 +434,9 @@ class GcInfoEncoder
434434

435435
// Number of slots preserved during EnC remap
436436
void SetSizeOfEditAndContinuePreservedArea( UINT32 size );
437+
#ifdef TARGET_ARM64
438+
void SetSizeOfEditAndContinueFixedStackFrame( UINT32 size );
439+
#endif
437440

438441
#ifdef TARGET_AMD64
439442
// Used to only report a frame once for the leaf function/funclet
@@ -510,6 +513,9 @@ class GcInfoEncoder
510513
UINT32 m_CodeLength;
511514
UINT32 m_StackBaseRegister;
512515
UINT32 m_SizeOfEditAndContinuePreservedArea;
516+
#ifdef TARGET_ARM64
517+
UINT32 m_SizeOfEditAndContinueFixedStackFrame;
518+
#endif
513519
INT32 m_ReversePInvokeFrameSlot;
514520
InterruptibleRange* m_pLastInterruptibleRange;
515521

src/coreclr/inc/gcinfotypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ void FASTCALL decodeCallPattern(int pattern,
753753
#define STACK_BASE_REGISTER_ENCBASE 2 // FP encoded as 0, SP as 2.
754754
#define SIZE_OF_STACK_AREA_ENCBASE 3
755755
#define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 4
756+
#define SIZE_OF_EDIT_AND_CONTINUE_FIXED_STACK_FRAME_ENCBASE 4
756757
#define REVERSE_PINVOKE_FRAME_ENCBASE 6
757758
#define NUM_REGISTERS_ENCBASE 3
758759
#define NUM_STACK_SLOTS_ENCBASE 2

src/coreclr/jit/codegenarm.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2454,12 +2454,16 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo()
24542454
unsigned preSpillRegArgSize = genCountBits(regSet.rsMaskPreSpillRegs(true)) * REGSIZE_BYTES;
24552455
genFuncletInfo.fiFunctionCallerSPtoFPdelta = preSpillRegArgSize + 2 * REGSIZE_BYTES;
24562456

2457-
regMaskTP rsMaskSaveRegs = regSet.rsMaskCalleeSaved;
2458-
unsigned saveRegsCount = genCountBits(rsMaskSaveRegs);
2459-
unsigned saveRegsSize = saveRegsCount * REGSIZE_BYTES; // bytes of regs we're saving
2457+
regMaskTP rsMaskSaveRegs = regSet.rsMaskCalleeSaved;
2458+
unsigned saveRegsCount = genCountBits(rsMaskSaveRegs);
2459+
unsigned saveRegsSize = saveRegsCount * REGSIZE_BYTES; // bytes of regs we're saving
2460+
unsigned saveSizeWithPSP = saveRegsSize + REGSIZE_BYTES /* PSP sym */;
2461+
if (compiler->lvaMonAcquired != BAD_VAR_NUM)
2462+
{
2463+
saveSizeWithPSP += TARGET_POINTER_SIZE;
2464+
}
24602465
assert(compiler->lvaOutgoingArgSpaceSize % REGSIZE_BYTES == 0);
2461-
unsigned funcletFrameSize =
2462-
preSpillRegArgSize + saveRegsSize + REGSIZE_BYTES /* PSP slot */ + compiler->lvaOutgoingArgSpaceSize;
2466+
unsigned funcletFrameSize = preSpillRegArgSize + saveSizeWithPSP + compiler->lvaOutgoingArgSpaceSize;
24632467

24642468
unsigned funcletFrameSizeAligned = roundUp(funcletFrameSize, STACK_ALIGN);
24652469
unsigned funcletFrameAlignmentPad = funcletFrameSizeAligned - funcletFrameSize;

src/coreclr/jit/codegenarm64.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,14 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo()
16921692
saveRegsPlusPSPSize += MAX_REG_ARG * REGSIZE_BYTES;
16931693
}
16941694

1695+
if (compiler->lvaMonAcquired != BAD_VAR_NUM && !compiler->opts.IsOSR())
1696+
{
1697+
// We furthermore allocate the "monitor acquired" bool between PSP and
1698+
// the saved registers because this is part of the EnC header.
1699+
// Note that OSR methods reuse the monitor bool created by tier 0.
1700+
saveRegsPlusPSPSize += compiler->lvaLclSize(compiler->lvaMonAcquired);
1701+
}
1702+
16951703
unsigned const saveRegsPlusPSPSizeAligned = roundUp(saveRegsPlusPSPSize, STACK_ALIGN);
16961704

16971705
assert(compiler->lvaOutgoingArgSpaceSize % REGSIZE_BYTES == 0);

src/coreclr/jit/codegenarmarch.cpp

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4159,24 +4159,37 @@ void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize,
41594159
{
41604160
// what we have to preserve is called the "frame header" (see comments in VM\eetwain.cpp)
41614161
// which is:
4162-
// -return address
4163-
// -saved off RBP
4164-
// -saved 'this' pointer and bool for synchronized methods
4162+
// -return address (saved lr)
4163+
// -saved off FP
4164+
// -all callee-preserved registers in case of varargs
4165+
// -saved bool for synchronized methods
41654166

4166-
// 4 slots for RBP + return address + RSI + RDI
4167-
int preservedAreaSize = 4 * REGSIZE_BYTES;
4167+
int preservedAreaSize = (2 + genCountBits(RBM_ENC_CALLEE_SAVED)) * REGSIZE_BYTES;
4168+
4169+
if (compiler->info.compIsVarArgs)
4170+
{
4171+
// Varargs save all int registers between saved registers and PSP.
4172+
preservedAreaSize += MAX_REG_ARG * REGSIZE_BYTES;
4173+
}
41684174

41694175
if (compiler->info.compFlags & CORINFO_FLG_SYNCH)
41704176
{
4171-
if (!(compiler->info.compFlags & CORINFO_FLG_STATIC))
4172-
preservedAreaSize += REGSIZE_BYTES;
4177+
// bool in synchronized methods that tracks whether the lock has been taken (takes a full pointer sized
4178+
// slot)
4179+
preservedAreaSize += TARGET_POINTER_SIZE;
41734180

4174-
preservedAreaSize += 1; // bool for synchronized methods
4181+
// Verify that MonAcquired bool is at the bottom of the frame header
4182+
assert(compiler->lvaGetCallerSPRelativeOffset(compiler->lvaMonAcquired) == -preservedAreaSize);
41754183
}
41764184

41774185
// Used to signal both that the method is compiled for EnC, and also the size of the block at the top of the
41784186
// frame
41794187
gcInfoEncoder->SetSizeOfEditAndContinuePreservedArea(preservedAreaSize);
4188+
gcInfoEncoder->SetSizeOfEditAndContinueFixedStackFrame(genTotalFrameSize());
4189+
4190+
JITDUMP("EnC info:\n");
4191+
JITDUMP(" EnC preserved area size = %d\n", preservedAreaSize);
4192+
JITDUMP(" Fixed stack frame size = %d\n", genTotalFrameSize());
41804193
}
41814194

41824195
#endif // TARGET_ARM64
@@ -4694,6 +4707,8 @@ void CodeGen::genPushCalleeSavedRegisters()
46944707
// |-----------------------|
46954708
// |Callee saved registers | // not including FP/LR; multiple of 8 bytes
46964709
// |-----------------------|
4710+
// | MonitorAcquired |
4711+
// |-----------------------|
46974712
// | PSP slot | // 8 bytes (omitted in NativeAOT ABI)
46984713
// |-----------------------|
46994714
// | locals, temps, etc. |
@@ -4725,6 +4740,8 @@ void CodeGen::genPushCalleeSavedRegisters()
47254740
// |-----------------------|
47264741
// |Callee saved registers | // not including FP/LR; multiple of 8 bytes
47274742
// |-----------------------|
4743+
// | MonitorAcquired |
4744+
// |-----------------------|
47284745
// | PSP slot | // 8 bytes (omitted in NativeAOT ABI)
47294746
// |-----------------------|
47304747
// | locals, temps, etc. |
@@ -4822,7 +4839,7 @@ void CodeGen::genPushCalleeSavedRegisters()
48224839
maskSaveRegsInt &= ~(RBM_FP | RBM_LR); // We've already saved FP/LR
48234840
offset = (int)compiler->compLclFrameSize + 2 * REGSIZE_BYTES; // 2 for FP/LR
48244841
}
4825-
else if (totalFrameSize <= 512)
4842+
else if ((totalFrameSize <= 512) && !compiler->opts.compDbgEnC)
48264843
{
48274844
// Case #2.
48284845
//
@@ -4956,6 +4973,7 @@ void CodeGen::genPushCalleeSavedRegisters()
49564973
}
49574974
else
49584975
{
4976+
assert(!compiler->opts.compDbgEnC);
49594977
JITDUMP("Frame type 3 (save FP/LR at bottom). #outsz=%d; #framesz=%d; LclFrameSize=%d\n",
49604978
unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, compiler->compLclFrameSize);
49614979

@@ -5110,15 +5128,23 @@ void CodeGen::genPushCalleeSavedRegisters()
51105128
establishFramePointer = false;
51115129

51125130
int remainingFrameSz = totalFrameSize - calleeSaveSpDelta;
5113-
assert(remainingFrameSz > 0);
5114-
assert((remainingFrameSz % 16) == 0); // this is guaranteed to be 16-byte aligned because each component --
5115-
// totalFrameSize and calleeSaveSpDelta -- is 16-byte aligned.
5131+
if (remainingFrameSz > 0)
5132+
{
5133+
assert((remainingFrameSz % 16) == 0); // this is guaranteed to be 16-byte aligned because each component --
5134+
// totalFrameSize and calleeSaveSpDelta -- is 16-byte aligned.
51165135

5117-
JITDUMP(" remainingFrameSz=%d\n", remainingFrameSz);
5136+
JITDUMP(" remainingFrameSz=%d\n", remainingFrameSz);
51185137

5119-
// We've already established the frame pointer, so no need to report the stack pointer change to unwind info.
5120-
genStackPointerAdjustment(-remainingFrameSz, initReg, pInitRegZeroed, /* reportUnwindData */ false);
5121-
offset += remainingFrameSz;
5138+
// We've already established the frame pointer, so no need to report the stack pointer change to unwind
5139+
// info.
5140+
genStackPointerAdjustment(-remainingFrameSz, initReg, pInitRegZeroed, /* reportUnwindData */ false);
5141+
offset += remainingFrameSz;
5142+
}
5143+
else
5144+
{
5145+
// Should only have picked this frame type for EnC.
5146+
assert(compiler->opts.compDbgEnC);
5147+
}
51225148
}
51235149
else
51245150
{

0 commit comments

Comments
 (0)