Skip to content

Commit 74b2327

Browse files
authored
Merge pull request dotnet/coreclr#7015 from ramarag/fixup_precode
Implement FixupPrecode for Arm64 Commit migrated from dotnet/coreclr@1a1735f
2 parents d79e325 + a2793cf commit 74b2327

File tree

6 files changed

+170
-26
lines changed

6 files changed

+170
-26
lines changed

src/coreclr/src/inc/jithelpers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@
315315

316316
JITHELPER(CORINFO_HELP_EE_PRESTUB, ThePreStub, CORINFO_HELP_SIG_NO_ALIGN_STUB)
317317

318-
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
318+
#if defined(HAS_FIXUP_PRECODE)
319319
JITHELPER(CORINFO_HELP_EE_PRECODE_FIXUP, PrecodeFixupThunk, CORINFO_HELP_SIG_NO_ALIGN_STUB)
320320
#else
321321
JITHELPER(CORINFO_HELP_EE_PRECODE_FIXUP, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB)

src/coreclr/src/vm/arm64/asmconstants.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,19 @@ ASMCONSTANTS_C_ASSERT(CONTEXT_Pc == offsetof(T_CONTEXT,Pc))
147147
ASMCONSTANTS_C_ASSERT(SIZEOF__FaultingExceptionFrame == sizeof(FaultingExceptionFrame));
148148
ASMCONSTANTS_C_ASSERT(FaultingExceptionFrame__m_fFilterExecuted == offsetof(FaultingExceptionFrame, m_fFilterExecuted));
149149

150+
#define SIZEOF__FixupPrecode 24
151+
#define Offset_PrecodeChunkIndex 15
152+
#define Offset_MethodDescChunkIndex 14
153+
#define MethodDesc_ALIGNMENT_SHIFT 3
154+
#define FixupPrecode_ALIGNMENT_SHIFT_1 3
155+
#define FixupPrecode_ALIGNMENT_SHIFT_2 4
156+
157+
ASMCONSTANTS_C_ASSERT(SIZEOF__FixupPrecode == sizeof(FixupPrecode));
158+
ASMCONSTANTS_C_ASSERT(Offset_PrecodeChunkIndex == offsetof(FixupPrecode, m_PrecodeChunkIndex));
159+
ASMCONSTANTS_C_ASSERT(Offset_MethodDescChunkIndex == offsetof(FixupPrecode, m_MethodDescChunkIndex));
160+
ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT);
161+
ASMCONSTANTS_C_ASSERT((1<<FixupPrecode_ALIGNMENT_SHIFT_1) + (1<<FixupPrecode_ALIGNMENT_SHIFT_2) == sizeof(FixupPrecode));
162+
150163
#ifndef CROSSGEN_COMPILE
151164
#define ResolveCacheElem__target 0x10
152165
#define ResolveCacheElem__pNext 0x18

src/coreclr/src/vm/arm64/asmhelpers.asm

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,25 @@ Done
193193
NESTED_END
194194

195195
; ------------------------------------------------------------------
196-
; ARM64TODO: Implement PrecodeFixupThunk when PreCode is Enabled
196+
; The call in fixup precode initally points to this function.
197+
; The pupose of this function is to load the MethodDesc and forward the call to prestub.
197198
NESTED_ENTRY PrecodeFixupThunk
198-
brk #0
199+
200+
; x12 = FixupPrecode *
201+
; On Exit
202+
; x12 = MethodDesc*
203+
; x13, x14 Trashed
204+
; Inline computation done by FixupPrecode::GetMethodDesc()
205+
ldrb w13, [x12, #Offset_PrecodeChunkIndex] ; m_PrecodeChunkIndex
206+
ldrb w14, [x12, #Offset_MethodDescChunkIndex] ; m_MethodDescChunkIndex
207+
208+
add x12,x12,w13,uxtw #FixupPrecode_ALIGNMENT_SHIFT_1
209+
add x13,x12,w13,uxtw #FixupPrecode_ALIGNMENT_SHIFT_2
210+
ldr x13, [x13,#SIZEOF__FixupPrecode]
211+
add x12,x13,w14,uxtw #MethodDesc_ALIGNMENT_SHIFT
212+
213+
b ThePreStub
214+
199215
NESTED_END
200216
; ------------------------------------------------------------------
201217

src/coreclr/src/vm/arm64/cgencpu.h

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ class ComCallMethodDesc;
3838

3939
#define USE_INDIRECT_CODEHEADER
4040

41-
//#define HAS_FIXUP_PRECODE 1
42-
//#define HAS_FIXUP_PRECODE_CHUNKS 1
41+
#define HAS_FIXUP_PRECODE 1
42+
#define HAS_FIXUP_PRECODE_CHUNKS 1
4343

4444
// ThisPtrRetBufPrecode one is necessary for closed delegates over static methods with return buffer
4545
#define HAS_THISPTR_RETBUF_PRECODE 1
@@ -613,44 +613,76 @@ typedef DPTR(NDirectImportPrecode) PTR_NDirectImportPrecode;
613613

614614
struct FixupPrecode {
615615

616-
static const int Type = 0xfc;
616+
static const int Type = 0x0C;
617617

618-
// mov r12, pc
619-
// ldr pc, [pc, #4] ; =m_pTarget
618+
// adr x12, #0
619+
// ldr x11, [pc, #12] ; =m_pTarget
620+
// br x11
620621
// dcb m_MethodDescChunkIndex
621622
// dcb m_PrecodeChunkIndex
623+
// 2 byte padding
622624
// dcd m_pTarget
623-
WORD m_rgCode[3];
625+
626+
627+
UINT32 m_rgCode[3];
628+
BYTE padding[2];
624629
BYTE m_MethodDescChunkIndex;
625630
BYTE m_PrecodeChunkIndex;
626631
TADDR m_pTarget;
627632

628633
void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int iMethodDescChunkIndex = 0, int iPrecodeChunkIndex = 0);
634+
void InitCommon()
635+
{
636+
WRAPPER_NO_CONTRACT;
637+
int n = 0;
638+
639+
m_rgCode[n++] = 0x1000000C; // adr x12, #0
640+
m_rgCode[n++] = 0x5800006B; // ldr x11, [pc, #12] ; =m_pTarget
641+
642+
_ASSERTE((UINT32*)&m_pTarget == &m_rgCode[n + 2]);
643+
644+
m_rgCode[n++] = 0xD61F0160; // br x11
645+
646+
_ASSERTE(n == _countof(m_rgCode));
647+
}
629648

630649
TADDR GetBase()
631650
{
632-
_ASSERTE(!"ARM64:NYI");
633-
return NULL;
651+
LIMITED_METHOD_CONTRACT;
652+
SUPPORTS_DAC;
653+
654+
return dac_cast<TADDR>(this) + (m_PrecodeChunkIndex + 1) * sizeof(FixupPrecode);
634655
}
635656

636657
TADDR GetMethodDesc();
637658

638659
PCODE GetTarget()
639660
{
640-
_ASSERTE(!"ARM64:NYI");
641-
return NULL;
661+
LIMITED_METHOD_DAC_CONTRACT;
662+
return m_pTarget;
642663
}
643664

644665
BOOL SetTargetInterlocked(TADDR target, TADDR expected)
645666
{
646-
_ASSERTE(!"ARM64:NYI");
647-
return NULL;
667+
CONTRACTL
668+
{
669+
THROWS;
670+
GC_TRIGGERS;
671+
}
672+
CONTRACTL_END;
673+
674+
EnsureWritableExecutablePages(&m_pTarget);
675+
return (TADDR)InterlockedCompareExchange64(
676+
(LONGLONG*)&m_pTarget, (TADDR)target, (TADDR)expected) == expected;
648677
}
649678

650679
static BOOL IsFixupPrecodeByASM(PCODE addr)
651680
{
652-
_ASSERTE(!"ARM64:NYI");
653-
return NULL;
681+
PTR_DWORD pInstr = dac_cast<PTR_DWORD>(PCODEToPINSTR(addr));
682+
return
683+
(pInstr[0] == 0x1000000C) &&
684+
(pInstr[1] == 0x5800006B) &&
685+
(pInstr[2] == 0xD61F0160);
654686
}
655687

656688
#ifdef FEATURE_PREJIT

src/coreclr/src/vm/arm64/stubs.cpp

Lines changed: 91 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -494,14 +494,22 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
494494

495495
TADDR FixupPrecode::GetMethodDesc()
496496
{
497-
_ASSERTE(!"ARM64:NYI");
498-
return NULL;
497+
LIMITED_METHOD_DAC_CONTRACT;
498+
499+
// This lookup is also manually inlined in PrecodeFixupThunk assembly code
500+
TADDR base = *PTR_TADDR(GetBase());
501+
if (base == NULL)
502+
return NULL;
503+
return base + (m_MethodDescChunkIndex * MethodDesc::ALIGNMENT);
499504
}
500505

501506
#ifdef DACCESS_COMPILE
502507
void FixupPrecode::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
503508
{
504-
_ASSERTE(!"ARM64:NYI");
509+
SUPPORTS_DAC;
510+
DacEnumMemoryRegion(dac_cast<TADDR>(this), sizeof(FixupPrecode));
511+
512+
DacEnumMemoryRegion(GetBase(), sizeof(TADDR));
505513
}
506514
#endif // DACCESS_COMPILE
507515

@@ -574,19 +582,78 @@ void NDirectImportPrecode::Fixup(DataImage *image)
574582

575583
void FixupPrecode::Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int iMethodDescChunkIndex /*=0*/, int iPrecodeChunkIndex /*=0*/)
576584
{
577-
_ASSERTE(!"ARM64:NYI");
585+
WRAPPER_NO_CONTRACT;
586+
587+
InitCommon();
588+
589+
// Initialize chunk indices only if they are not initialized yet. This is necessary to make MethodDesc::Reset work.
590+
if (m_PrecodeChunkIndex == 0)
591+
{
592+
_ASSERTE(FitsInU1(iPrecodeChunkIndex));
593+
m_PrecodeChunkIndex = static_cast<BYTE>(iPrecodeChunkIndex);
594+
}
595+
596+
if (iMethodDescChunkIndex != -1)
597+
{
598+
if (m_MethodDescChunkIndex == 0)
599+
{
600+
_ASSERTE(FitsInU1(iMethodDescChunkIndex));
601+
m_MethodDescChunkIndex = static_cast<BYTE>(iMethodDescChunkIndex);
602+
}
603+
604+
if (*(void**)GetBase() == NULL)
605+
*(void**)GetBase() = (BYTE*)pMD - (iMethodDescChunkIndex * MethodDesc::ALIGNMENT);
606+
}
607+
608+
_ASSERTE(GetMethodDesc() == (TADDR)pMD);
609+
610+
if (pLoaderAllocator != NULL)
611+
{
612+
m_pTarget = GetEEFuncEntryPoint(PrecodeFixupThunk);
613+
}
578614
}
579615

580616
#ifdef FEATURE_NATIVE_IMAGE_GENERATION
581617
// Partial initialization. Used to save regrouped chunks.
582618
void FixupPrecode::InitForSave(int iPrecodeChunkIndex)
583619
{
584-
_ASSERTE(!"ARM64:NYI");
620+
STANDARD_VM_CONTRACT;
621+
622+
InitCommon();
623+
624+
_ASSERTE(FitsInU1(iPrecodeChunkIndex));
625+
m_PrecodeChunkIndex = static_cast<BYTE>(iPrecodeChunkIndex);
626+
// The rest is initialized in code:FixupPrecode::Fixup
585627
}
586628

587629
void FixupPrecode::Fixup(DataImage *image, MethodDesc * pMD)
588630
{
589-
_ASSERTE(!"ARM64:NYI");
631+
STANDARD_VM_CONTRACT;
632+
633+
// Note that GetMethodDesc() does not return the correct value because of
634+
// regrouping of MethodDescs into hot and cold blocks. That's why the caller
635+
// has to supply the actual MethodDesc
636+
637+
SSIZE_T mdChunkOffset;
638+
ZapNode * pMDChunkNode = image->GetNodeForStructure(pMD, &mdChunkOffset);
639+
ZapNode * pHelperThunk = image->GetHelperThunk(CORINFO_HELP_EE_PRECODE_FIXUP);
640+
641+
image->FixupFieldToNode(this, offsetof(FixupPrecode, m_pTarget), pHelperThunk);
642+
643+
// Set the actual chunk index
644+
FixupPrecode * pNewPrecode = (FixupPrecode *)image->GetImagePointer(this);
645+
646+
size_t mdOffset = mdChunkOffset - sizeof(MethodDescChunk);
647+
size_t chunkIndex = mdOffset / MethodDesc::ALIGNMENT;
648+
_ASSERTE(FitsInU1(chunkIndex));
649+
pNewPrecode->m_MethodDescChunkIndex = (BYTE)chunkIndex;
650+
651+
// Fixup the base of MethodDescChunk
652+
if (m_PrecodeChunkIndex == 0)
653+
{
654+
image->FixupFieldToNode(this, (BYTE *)GetBase() - (BYTE *)this,
655+
pMDChunkNode, sizeof(MethodDescChunk));
656+
}
590657
}
591658
#endif // FEATURE_NATIVE_IMAGE_GENERATION
592659

@@ -618,7 +685,20 @@ BOOL DoesSlotCallPrestub(PCODE pCode)
618685
{
619686
PTR_DWORD pInstr = dac_cast<PTR_DWORD>(PCODEToPINSTR(pCode));
620687

621-
// ARM64TODO: Check for FixupPrecode
688+
//FixupPrecode
689+
#if defined(HAS_FIXUP_PRECODE)
690+
if (FixupPrecode::IsFixupPrecodeByASM(pCode))
691+
{
692+
PCODE pTarget = dac_cast<PTR_FixupPrecode>(pInstr)->m_pTarget;
693+
694+
if (isJump(pTarget))
695+
{
696+
pTarget = decodeJump(pTarget);
697+
}
698+
699+
return pTarget == (TADDR)PrecodeFixupThunk;
700+
}
701+
#endif
622702

623703
// StubPrecode
624704
if (pInstr[0] == 0x10000089 && // adr x9, #16
@@ -627,7 +707,10 @@ BOOL DoesSlotCallPrestub(PCODE pCode)
627707
{
628708
PCODE pTarget = dac_cast<PTR_StubPrecode>(pInstr)->m_pTarget;
629709

630-
// ARM64TODO: implement for NGen case
710+
if (isJump(pTarget))
711+
{
712+
pTarget = decodeJump(pTarget);
713+
}
631714

632715
return pTarget == GetPreStubEntryPoint();
633716
}

src/coreclr/src/vm/precode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ BOOL Precode::SetTargetInterlocked(PCODE target)
433433
// SetTargetInterlocked does not modify code on ARM so the flush instruction cache is
434434
// not necessary.
435435
//
436-
#if !defined(_TARGET_ARM_)
436+
#if !defined(_TARGET_ARM_) && !defined(_TARGET_ARM64_)
437437
if (ret) {
438438
FlushInstructionCache(GetCurrentProcess(),this,SizeOf());
439439
}

0 commit comments

Comments
 (0)