diff options
Diffstat (limited to 'src/vm/arm64')
-rw-r--r-- | src/vm/arm64/asmconstants.h | 29 | ||||
-rw-r--r-- | src/vm/arm64/asmhelpers.S | 29 | ||||
-rw-r--r-- | src/vm/arm64/asmhelpers.asm | 30 | ||||
-rw-r--r-- | src/vm/arm64/cgencpu.h | 120 | ||||
-rw-r--r-- | src/vm/arm64/stubs.cpp | 123 |
5 files changed, 315 insertions, 16 deletions
diff --git a/src/vm/arm64/asmconstants.h b/src/vm/arm64/asmconstants.h index 3bb4f6494f..84b92fa5a1 100644 --- a/src/vm/arm64/asmconstants.h +++ b/src/vm/arm64/asmconstants.h @@ -176,19 +176,30 @@ ASMCONSTANTS_C_ASSERT(CONTEXT_Pc == offsetof(T_CONTEXT,Pc)) ASMCONSTANTS_C_ASSERT(SIZEOF__FaultingExceptionFrame == sizeof(FaultingExceptionFrame)); ASMCONSTANTS_C_ASSERT(FaultingExceptionFrame__m_fFilterExecuted == offsetof(FaultingExceptionFrame, m_fFilterExecuted)); -#define SIZEOF__FixupPrecode 24 -#define Offset_PrecodeChunkIndex 15 -#define Offset_MethodDescChunkIndex 14 -#define MethodDesc_ALIGNMENT_SHIFT 3 -#define FixupPrecode_ALIGNMENT_SHIFT_1 3 -#define FixupPrecode_ALIGNMENT_SHIFT_2 4 +#define MethodDesc_ALIGNMENT_SHIFT 3 +ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT); + +#define SIZEOF__FixupPrecode 24 +#define Offset_FixupPrecodeChunkIndex 15 +#define Offset_FixupPrecodeMethodDescChunkIndex 14 +#define FixupPrecode_ALIGNMENT_SHIFT_1 3 +#define FixupPrecode_ALIGNMENT_SHIFT_2 4 ASMCONSTANTS_C_ASSERT(SIZEOF__FixupPrecode == sizeof(FixupPrecode)); -ASMCONSTANTS_C_ASSERT(Offset_PrecodeChunkIndex == offsetof(FixupPrecode, m_PrecodeChunkIndex)); -ASMCONSTANTS_C_ASSERT(Offset_MethodDescChunkIndex == offsetof(FixupPrecode, m_MethodDescChunkIndex)); -ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT); +ASMCONSTANTS_C_ASSERT(Offset_FixupPrecodeChunkIndex == offsetof(FixupPrecode, m_PrecodeChunkIndex)); +ASMCONSTANTS_C_ASSERT(Offset_FixupPrecodeMethodDescChunkIndex == offsetof(FixupPrecode, m_MethodDescChunkIndex)); ASMCONSTANTS_C_ASSERT((1<<FixupPrecode_ALIGNMENT_SHIFT_1) + (1<<FixupPrecode_ALIGNMENT_SHIFT_2) == sizeof(FixupPrecode)); +#define SIZEOF__RelativeFixupPrecode 32 +#define Offset_RelativeFixupPrecodeChunkIndex 17 +#define Offset_RelativeFixupPrecodeMethodDescChunkIndex 16 +#define RelativeFixupPrecode_ALIGNMENT_SHIFT 4 + +ASMCONSTANTS_C_ASSERT(SIZEOF__RelativeFixupPrecode == sizeof(RelativeFixupPrecode)); +ASMCONSTANTS_C_ASSERT(Offset_RelativeFixupPrecodeChunkIndex == offsetof(RelativeFixupPrecode, m_PrecodeChunkIndex)); +ASMCONSTANTS_C_ASSERT(Offset_RelativeFixupPrecodeMethodDescChunkIndex == offsetof(RelativeFixupPrecode, m_MethodDescChunkIndex)); +ASMCONSTANTS_C_ASSERT((1<<(RelativeFixupPrecode_ALIGNMENT_SHIFT+1)) == sizeof(RelativeFixupPrecode)); + #ifndef CROSSGEN_COMPILE #define ResolveCacheElem__target 0x10 #define ResolveCacheElem__pNext 0x18 diff --git a/src/vm/arm64/asmhelpers.S b/src/vm/arm64/asmhelpers.S index 91aaa5b054..15ec19219b 100644 --- a/src/vm/arm64/asmhelpers.S +++ b/src/vm/arm64/asmhelpers.S @@ -142,15 +142,15 @@ NESTED_END NDirectImportThunk, _TEXT // ------------------------------------------------------------------ // The call in fixup precode initally points to this function. -// The pupose of this function is to load the MethodDesc and forward the call to prestub. +// The purpose of this function is to load the MethodDesc and forward the call to prestub. NESTED_ENTRY PrecodeFixupThunk, _TEXT, NoHandler // x12 = FixupPrecode * // On Exit // x12 = MethodDesc* // x13, x14 Trashed // Inline computation done by FixupPrecode::GetMethodDesc() - ldrb w13, [x12, #Offset_PrecodeChunkIndex] //m_PrecodeChunkIndex - ldrb w14, [x12, #Offset_MethodDescChunkIndex] // m_MethodDescChunkIndex + ldrb w13, [x12, #Offset_FixupPrecodeChunkIndex] //m_PrecodeChunkIndex + ldrb w14, [x12, #Offset_FixupPrecodeMethodDescChunkIndex] // m_MethodDescChunkIndex add x12, x12, w13, uxtw #FixupPrecode_ALIGNMENT_SHIFT_1 add x13, x12, w13, uxtw #FixupPrecode_ALIGNMENT_SHIFT_2 @@ -161,6 +161,29 @@ NESTED_ENTRY PrecodeFixupThunk, _TEXT, NoHandler NESTED_END PrecodeFixupThunk, _TEXT // ------------------------------------------------------------------ +// ------------------------------------------------------------------ +// The call in fixup precode initally points to this function. +// The purpose of this function is to load the MethodDesc and forward the call to prestub. +NESTED_ENTRY PrecodeRelativeFixupThunk, _TEXT, NoHandler + // x11 = RelativeFixupPrecode * + // On Exit + // x12 = MethodDesc* + // x11, x13 Trashed + // Inline computation done by RelativeFixupPrecode::GetMethodDesc() + ldrb w12, [x11, #Offset_RelativeFixupPrecodeChunkIndex] //m_PrecodeChunkIndex + ldrb w13, [x11, #Offset_RelativeFixupPrecodeMethodDescChunkIndex] // m_MethodDescChunkIndex + + add x11, x11, w12, uxtw #RelativeFixupPrecode_ALIGNMENT_SHIFT + add x11, x11, w12, uxtw #RelativeFixupPrecode_ALIGNMENT_SHIFT + add x12, x11, #SIZEOF__RelativeFixupPrecode // GetBase() + ldr x11, [x12] // base + add x12, x12, x11 + add x12, x12, w13, uxtw #MethodDesc_ALIGNMENT_SHIFT + + b ThePreStub +NESTED_END PrecodeRelativeFixupThunk, _TEXT +// ------------------------------------------------------------------ + NESTED_ENTRY ThePreStub, _TEXT, NoHandler PROLOG_WITH_TRANSITION_BLOCK diff --git a/src/vm/arm64/asmhelpers.asm b/src/vm/arm64/asmhelpers.asm index c1f8429489..27e284c0cd 100644 --- a/src/vm/arm64/asmhelpers.asm +++ b/src/vm/arm64/asmhelpers.asm @@ -210,7 +210,7 @@ Done ; ------------------------------------------------------------------ ; The call in fixup precode initally points to this function. -; The pupose of this function is to load the MethodDesc and forward the call to prestub. +; The purpose of this function is to load the MethodDesc and forward the call to prestub. NESTED_ENTRY PrecodeFixupThunk ; x12 = FixupPrecode * @@ -218,8 +218,8 @@ Done ; x12 = MethodDesc* ; x13, x14 Trashed ; Inline computation done by FixupPrecode::GetMethodDesc() - ldrb w13, [x12, #Offset_PrecodeChunkIndex] ; m_PrecodeChunkIndex - ldrb w14, [x12, #Offset_MethodDescChunkIndex] ; m_MethodDescChunkIndex + ldrb w13, [x12, #Offset_FixupPrecodeChunkIndex] ; m_PrecodeChunkIndex + ldrb w14, [x12, #Offset_FixupPrecodeMethodDescChunkIndex] ; m_MethodDescChunkIndex add x12,x12,w13,uxtw #FixupPrecode_ALIGNMENT_SHIFT_1 add x13,x12,w13,uxtw #FixupPrecode_ALIGNMENT_SHIFT_2 @@ -229,6 +229,30 @@ Done b ThePreStub NESTED_END + +; ------------------------------------------------------------------ +; The call in fixup precode initally points to this function. +; The purpose of this function is to load the MethodDesc and forward the call to prestub. + NESTED_ENTRY PrecodeRelativeFixupThunk + + ; x11 = RelativeFixupPrecode * + ; On Exit + ; x12 = MethodDesc* + ; x11, x13 Trashed + ; Inline computation done by RelativeFixupPrecode::GetMethodDesc() + ldrb w12, [x11, #Offset_RelativeFixupPrecodeChunkIndex] ; m_PrecodeChunkIndex + ldrb w13, [x11, #Offset_RelativeFixupPrecodeMethodDescChunkIndex] ; m_MethodDescChunkIndex + + add x11, x11, w12, uxtw #RelativeFixupPrecode_ALIGNMENT_SHIFT + add x11, x11, w12, uxtw #RelativeFixupPrecode_ALIGNMENT_SHIFT + add x12, x11, #SIZEOF__RelativeFixupPrecode ; GetBase() + ldr x11, [x12] ; base + add x12, x12, x11 + add x12, x12, w13, uxtw #MethodDesc_ALIGNMENT_SHIFT + + b ThePreStub + + NESTED_END ; ------------------------------------------------------------------ NESTED_ENTRY ThePreStub diff --git a/src/vm/arm64/cgencpu.h b/src/vm/arm64/cgencpu.h index b30d5026f3..7d01f9d6ff 100644 --- a/src/vm/arm64/cgencpu.h +++ b/src/vm/arm64/cgencpu.h @@ -44,6 +44,10 @@ extern PCODE GetPreStubEntryPoint(); #define HAS_FIXUP_PRECODE 1 #define HAS_FIXUP_PRECODE_CHUNKS 1 +#if defined(HAS_FIXUP_PRECODE) && defined(HAS_FIXUP_PRECODE_CHUNKS) +#define HAS_RELATIVE_FIXUP_PRECODE 1 +#endif + // ThisPtrRetBufPrecode one is necessary for closed delegates over static methods with return buffer #define HAS_THISPTR_RETBUF_PRECODE 1 @@ -561,6 +565,7 @@ struct HijackArgs }; EXTERN_C VOID STDCALL PrecodeFixupThunk(); +EXTERN_C VOID STDCALL PrecodeRelativeFixupThunk(); // Invalid precode type struct InvalidPrecode { @@ -677,9 +682,9 @@ struct FixupPrecode { // adr x12, #0 // ldr x11, [pc, #12] ; =m_pTarget // br x11 + // 2 byte padding // dcb m_MethodDescChunkIndex // dcb m_PrecodeChunkIndex - // 2 byte padding // dcd m_pTarget @@ -771,6 +776,119 @@ struct FixupPrecode { typedef DPTR(FixupPrecode) PTR_FixupPrecode; +struct RelativeFixupPrecode { + + static const int Type = 0x0B; + + // adr x11, #0 ; registers x11 and x12 are reversed to differentiate from FixupPrecode + // ldr x12, #20 ; =m_pTargetOffset, which is relative to "adr x11, #0" + // add x12, x11, x12 + // br x12 + // dcb m_MethodDescChunkIndex + // dcb m_PrecodeChunkIndex + // 6 byte padding + // dcd m_pTargetOffset + + + UINT32 m_rgCode[4]; + BYTE m_MethodDescChunkIndex; + BYTE m_PrecodeChunkIndex; + BYTE padding[6]; + TADDR m_pTargetOffset; + + void Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int iMethodDescChunkIndex = 0, int iPrecodeChunkIndex = 0); + void InitCommon() + { + WRAPPER_NO_CONTRACT; + int n = 0; + + m_rgCode[n++] = 0x1000000B; // adr x11, #0 + m_rgCode[n++] = 0x580000AC; // ldr x12, #20 ; =m_pTargetOffset, which is relative to "adr x11, #0" + m_rgCode[n++] = 0x8B0C016C; // add x12, x11, x12 + + _ASSERTE((UINT32*)&m_pTargetOffset == &m_rgCode[n + 3]); + + m_rgCode[n++] = 0xD61F0180; // br x12 + + _ASSERTE(n == _countof(m_rgCode)); + } + + TADDR GetBase() + { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + + return dac_cast<TADDR>(this) + (m_PrecodeChunkIndex + 1) * sizeof(RelativeFixupPrecode); + } + + TADDR GetMethodDesc(); + + static TADDR GetTargetOffset() + { + LIMITED_METHOD_DAC_CONTRACT; + return 0; + } + + PCODE GetTarget() + { + LIMITED_METHOD_DAC_CONTRACT; + return dac_cast<TADDR>(this) + GetTargetOffset() + m_pTargetOffset; + } + + void ResetTargetInterlocked() + { + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + EnsureWritableExecutablePages(&m_pTargetOffset); + TADDR addr = (TADDR)GetEEFuncEntryPoint(PrecodeRelativeFixupThunk) - (TADDR)(this) - GetTargetOffset(); + InterlockedExchange64((LONGLONG*)&m_pTargetOffset, addr); + } + + BOOL SetTargetInterlocked(TADDR target, TADDR expected) + { + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + EnsureWritableExecutablePages(&m_pTargetOffset); + TADDR addrExpected = expected - (TADDR)(this) - GetTargetOffset(); + TADDR addrTarget = target - (TADDR)(this) - GetTargetOffset(); + return (TADDR)InterlockedCompareExchange64( + (LONGLONG*)&m_pTargetOffset, addrTarget, addrExpected) == addrExpected; + } + + static BOOL IsRelativeFixupPrecodeByASM(PCODE addr) + { + PTR_DWORD pInstr = dac_cast<PTR_DWORD>(PCODEToPINSTR(addr)); + return + (pInstr[0] == 0x1000000B) && + (pInstr[1] == 0x580000AC) && + (pInstr[2] == 0x8B0C016C) && + (pInstr[3] == 0xD61F0180); + } + +#ifdef FEATURE_PREJIT + // Partial initialization. Used to save regrouped chunks. + void InitForSave(int iPrecodeChunkIndex); + + void Fixup(DataImage *image, MethodDesc * pMD); +#endif + +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); +#endif +}; +typedef DPTR(RelativeFixupPrecode) PTR_RelativeFixupPrecode; + + // Precode to shuffle this and retbuf for closed delegates over static methods with return buffer struct ThisPtrRetBufPrecode { diff --git a/src/vm/arm64/stubs.cpp b/src/vm/arm64/stubs.cpp index 680557984a..b25dc4d531 100644 --- a/src/vm/arm64/stubs.cpp +++ b/src/vm/arm64/stubs.cpp @@ -565,6 +565,18 @@ TADDR FixupPrecode::GetMethodDesc() return base + (m_MethodDescChunkIndex * MethodDesc::ALIGNMENT); } +TADDR RelativeFixupPrecode::GetMethodDesc() +{ + LIMITED_METHOD_DAC_CONTRACT; + + // This lookup is also manually inlined in PrecodeFixupThunk assembly code + TADDR baseAddr = GetBase(); + TADDR base = *PTR_TADDR(baseAddr); + if (base == NULL) + return NULL; + return baseAddr + base + (m_MethodDescChunkIndex * MethodDesc::ALIGNMENT); +} + #ifdef DACCESS_COMPILE void FixupPrecode::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) { @@ -573,6 +585,14 @@ void FixupPrecode::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) DacEnumMemoryRegion(GetBase(), sizeof(TADDR)); } + +void RelativeFixupPrecode::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) +{ + SUPPORTS_DAC; + DacEnumMemoryRegion(dac_cast<TADDR>(this), sizeof(RelativeFixupPrecode)); + + DacEnumMemoryRegion(GetBase(), sizeof(TADDR)); +} #endif // DACCESS_COMPILE #ifndef DACCESS_COMPILE @@ -675,6 +695,39 @@ void FixupPrecode::Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int } } +void RelativeFixupPrecode::Init(MethodDesc* pMD, LoaderAllocator *pLoaderAllocator, int iMethodDescChunkIndex /*=0*/, int iPrecodeChunkIndex /*=0*/) +{ + WRAPPER_NO_CONTRACT; + + InitCommon(); + + // Initialize chunk indices only if they are not initialized yet. This is necessary to make MethodDesc::Reset work. + if (m_PrecodeChunkIndex == 0) + { + _ASSERTE(FitsInU1(iPrecodeChunkIndex)); + m_PrecodeChunkIndex = static_cast<BYTE>(iPrecodeChunkIndex); + } + + if (iMethodDescChunkIndex != -1) + { + if (m_MethodDescChunkIndex == 0) + { + _ASSERTE(FitsInU1(iMethodDescChunkIndex)); + m_MethodDescChunkIndex = static_cast<BYTE>(iMethodDescChunkIndex); + } + + if (*(void**)GetBase() == NULL) + *(void**)GetBase() = (BYTE*)pMD - (iMethodDescChunkIndex * MethodDesc::ALIGNMENT) - GetBase(); + } + + _ASSERTE(GetMethodDesc() == (TADDR)pMD); + + if (pLoaderAllocator != NULL) + { + m_pTargetOffset = GetEEFuncEntryPoint(PrecodeRelativeFixupThunk) - (TADDR)this - RelativeFixupPrecode::GetTargetOffset(); + } +} + #ifdef FEATURE_NATIVE_IMAGE_GENERATION // Partial initialization. Used to save regrouped chunks. void FixupPrecode::InitForSave(int iPrecodeChunkIndex) @@ -688,10 +741,27 @@ void FixupPrecode::InitForSave(int iPrecodeChunkIndex) // The rest is initialized in code:FixupPrecode::Fixup } +// Partial initialization. Used to save regrouped chunks. +void RelativeFixupPrecode::InitForSave(int iPrecodeChunkIndex) +{ + STANDARD_VM_CONTRACT; + + InitCommon(); + + _ASSERTE(FitsInU1(iPrecodeChunkIndex)); + m_PrecodeChunkIndex = static_cast<BYTE>(iPrecodeChunkIndex); + // The rest is initialized in code:RelativeFixupPrecode::Fixup +} + void FixupPrecode::Fixup(DataImage *image, MethodDesc * pMD) { STANDARD_VM_CONTRACT; +#ifdef HAS_RELATIVE_FIXUP_PRECODE + // FixupPrecode is not saved to image in this case + _ASSERTE(!"FixupPrecode is not saved to NGENed image, RelativeFixupPrecode is instead"); +#else // HAS_RELATIVE_FIXUP_PRECODE + // Note that GetMethodDesc() does not return the correct value because of // regrouping of MethodDescs into hot and cold blocks. That's why the caller // has to supply the actual MethodDesc @@ -716,6 +786,44 @@ void FixupPrecode::Fixup(DataImage *image, MethodDesc * pMD) image->FixupFieldToNode(this, (BYTE *)GetBase() - (BYTE *)this, pMDChunkNode, sizeof(MethodDescChunk)); } +#endif // HAS_RELATIVE_FIXUP_PRECODE +} + +void RelativeFixupPrecode::Fixup(DataImage *image, MethodDesc * pMD) +{ + STANDARD_VM_CONTRACT; + + // Note that GetMethodDesc() does not return the correct value because of + // regrouping of MethodDescs into hot and cold blocks. That's why the caller + // has to supply the actual MethodDesc + + SSIZE_T mdChunkOffset; + ZapNode * pMDChunkNode = image->GetNodeForStructure(pMD, &mdChunkOffset); + ZapNode * pHelperThunk = image->GetHelperThunk(CORINFO_HELP_EE_PRECODE_FIXUP); + + image->FixupFieldToNode(this, + offsetof(RelativeFixupPrecode, m_pTargetOffset), + pHelperThunk, + offsetof(RelativeFixupPrecode, m_pTargetOffset) - RelativeFixupPrecode::GetTargetOffset(), + IMAGE_REL_BASED_RELPTR); + + // Set the actual chunk index + RelativeFixupPrecode * pNewPrecode = (RelativeFixupPrecode *)image->GetImagePointer(this); + + size_t mdOffset = mdChunkOffset - sizeof(MethodDescChunk); + size_t chunkIndex = mdOffset / MethodDesc::ALIGNMENT; + _ASSERTE(FitsInU1(chunkIndex)); + pNewPrecode->m_MethodDescChunkIndex = (BYTE)chunkIndex; + + // Fixup the base of MethodDescChunk + if (m_PrecodeChunkIndex == 0) + { + image->FixupFieldToNode(this, + (BYTE *)GetBase() - (BYTE *)this, + pMDChunkNode, + sizeof(MethodDescChunk), + IMAGE_REL_BASED_RELPTR); + } } #endif // FEATURE_NATIVE_IMAGE_GENERATION @@ -762,6 +870,21 @@ BOOL DoesSlotCallPrestub(PCODE pCode) } #endif + //RelativeFixupPrecode +#if defined(HAS_RELATIVE_FIXUP_PRECODE) + if (RelativeFixupPrecode::IsRelativeFixupPrecodeByASM(pCode)) + { + PCODE pTarget = dac_cast<PTR_RelativeFixupPrecode>(pInstr)->GetTarget(); + + if (isJump(pTarget)) + { + pTarget = decodeJump(pTarget); + } + + return pTarget == (TADDR)PrecodeRelativeFixupThunk; + } +#endif // HAS_RELATIVE_FIXUP_PRECODE + // StubPrecode if (pInstr[0] == 0x10000089 && // adr x9, #16 pInstr[1] == 0xA940312A && // ldp x10,x12,[x9] |