diff --git a/src/coreclr/debug/daccess/fntableaccess.cpp b/src/coreclr/debug/daccess/fntableaccess.cpp index 0489bdfb6ca110..cc7a0076cbba60 100644 --- a/src/coreclr/debug/daccess/fntableaccess.cpp +++ b/src/coreclr/debug/daccess/fntableaccess.cpp @@ -139,11 +139,11 @@ static NTSTATUS OutOfProcessFindHeader(ReadMemoryFunction fpReadMemory,PVOID pUs pHeader = tmp; \ } -static NTSTATUS OutOfProcessFunctionTableCallback_JIT(IN ReadMemoryFunction fpReadMemory, - IN PVOID pUserContext, - IN PVOID TableAddress, - OUT PULONG pnEntries, - OUT PT_RUNTIME_FUNCTION* ppFunctions) +extern "C" NTSTATUS OutOfProcessFunctionTableCallbackEx(IN ReadMemoryFunction fpReadMemory, + IN PVOID pUserContext, + IN PVOID TableAddress, + OUT PULONG pnEntries, + OUT PT_RUNTIME_FUNCTION* ppFunctions) { if (NULL == pnEntries) { return STATUS_INVALID_PARAMETER_3; } if (NULL == ppFunctions) { return STATUS_INVALID_PARAMETER_4; } @@ -270,135 +270,6 @@ static NTSTATUS OutOfProcessFunctionTableCallback_JIT(IN ReadMemoryFunction return STATUS_SUCCESS; } - -#ifdef DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - -static NTSTATUS OutOfProcessFunctionTableCallback_Stub(IN ReadMemoryFunction fpReadMemory, - IN PVOID pUserContext, - IN PVOID TableAddress, - OUT PULONG pnEntries, - OUT PT_RUNTIME_FUNCTION* ppFunctions) -{ - if (NULL == pnEntries) { return STATUS_INVALID_PARAMETER_3; } - if (NULL == ppFunctions) { return STATUS_INVALID_PARAMETER_4; } - - *ppFunctions = 0; - *pnEntries = 0; - - PVOID pvContext; - move_field(pvContext, TableAddress, DYNAMIC_FUNCTION_TABLE, Context); - - SIZE_T pStubHeapSegment = ((SIZE_T)pvContext & ~3); - - FakeStubUnwindInfoHeapSegment stubHeapSegment; - move(stubHeapSegment, pStubHeapSegment); - - UINT nEntries = 0; - UINT nEntriesAllocated = 0; - PT_RUNTIME_FUNCTION rgFunctions = NULL; - - for (int pass = 1; pass <= 2; pass++) - { - // Use the same initial header for both passes. The process may still be running, - // and so new entries could be added at the beginning of the list. Using the initial header - // makes sure new entries are not picked up in the second pass. Entries could also be deleted, - // and there is a small time window here where we could read invalid memory. This just means - // that ReadProcessMemory() may fail. As long as we don't crash the host process (e.g. WER) - // we are fine. - SIZE_T pHeader = (SIZE_T)stubHeapSegment.pUnwindHeaderList; - - while (pHeader) - { - FakeStubUnwindInfoHeader unwindInfoHeader; - move(unwindInfoHeader, pHeader); -#if defined(TARGET_AMD64) - // Consistency checks to detect corrupted process state - if (unwindInfoHeader.FunctionEntry.BeginAddress > unwindInfoHeader.FunctionEntry.EndAddress || - unwindInfoHeader.FunctionEntry.EndAddress > stubHeapSegment.cbSegment) - { - _ASSERTE(1 == pass); - return STATUS_UNSUCCESSFUL; - } - - if ((SIZE_T)stubHeapSegment.pbBaseAddress + unwindInfoHeader.FunctionEntry.UnwindData != - pHeader + offsetof(FakeStubUnwindInfoHeader, UnwindInfo)) - { - _ASSERTE(1 == pass); - return STATUS_UNSUCCESSFUL; - } -#elif defined(TARGET_ARM) - - // Skip checking the corrupted process stateon ARM - -#elif defined(TARGET_ARM64) - // Compute the function length - ULONG64 functionLength = 0; - ULONG64 unwindData = unwindInfoHeader.FunctionEntry.UnwindData; - if (( unwindData & 3) != 0) { - // the unwindData contains the function length, retrieve it directly from unwindData - functionLength = (unwindInfoHeader.FunctionEntry.UnwindData >> 2) & 0x7ff; - } else { - // the unwindData is an RVA to the .xdata record which contains the function length - DWORD xdataHeader=0; - if ((SIZE_T)stubHeapSegment.pbBaseAddress + unwindData != pHeader + offsetof(FakeStubUnwindInfoHeader, UnwindInfo)) - { - _ASSERTE(1 == pass); - return STATUS_UNSUCCESSFUL; - } - move(xdataHeader, stubHeapSegment.pbBaseAddress + unwindData); - functionLength = (xdataHeader & 0x3ffff) << 2; - } - if (unwindInfoHeader.FunctionEntry.BeginAddress + functionLength > stubHeapSegment.cbSegment) - { - _ASSERTE(1 == pass); - return STATUS_UNSUCCESSFUL; - } -#else - PORTABILITY_ASSERT("OutOfProcessFunctionTableCallback_Stub"); -#endif - if (nEntriesAllocated) - { - if (nEntries >= nEntriesAllocated) - break; - rgFunctions[nEntries] = unwindInfoHeader.FunctionEntry; - } - nEntries++; - - pHeader = (SIZE_T)unwindInfoHeader.pNext; - } - - if (1 == pass) - { - if (!nEntries) - break; - - _ASSERTE(!nEntriesAllocated); - nEntriesAllocated = nEntries; - - S_SIZE_T blockSize = S_SIZE_T(nEntries) * S_SIZE_T(sizeof(T_RUNTIME_FUNCTION)); - if (blockSize.IsOverflow()) - return STATUS_UNSUCCESSFUL; - - rgFunctions = (PT_RUNTIME_FUNCTION)HeapAlloc(GetProcessHeap(), 0, blockSize.Value()); - if (rgFunctions == NULL) - return STATUS_NO_MEMORY; - nEntries = 0; - } - else - { - _ASSERTE(nEntriesAllocated >= nEntries); - } - } - - *ppFunctions = rgFunctions; - *pnEntries = nEntries; // return the final count - - return STATUS_SUCCESS; -} - -#endif // DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - - BOOL ReadMemory(PVOID pUserContext, LPCVOID lpBaseAddress, PVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead) { HANDLE hProcess = (HANDLE)pUserContext; @@ -413,48 +284,6 @@ extern "C" NTSTATUS OutOfProcessFunctionTableCallback(IN HANDLE return OutOfProcessFunctionTableCallbackEx(&ReadMemory, hProcess, TableAddress, pnEntries, ppFunctions); } -extern "C" NTSTATUS OutOfProcessFunctionTableCallbackEx(IN ReadMemoryFunction fpReadMemory, - IN PVOID pUserContext, - IN PVOID TableAddress, - OUT PULONG pnEntries, - OUT PT_RUNTIME_FUNCTION* ppFunctions) -{ - if (NULL == pnEntries) { return STATUS_INVALID_PARAMETER_3; } - if (NULL == ppFunctions) { return STATUS_INVALID_PARAMETER_4; } - - DYNAMIC_FUNCTION_TABLE * pTable = (DYNAMIC_FUNCTION_TABLE *) TableAddress; - PVOID pvContext; - - move(pvContext, &pTable->Context); - - FakeEEDynamicFunctionTableType type = (FakeEEDynamicFunctionTableType)((SIZE_T)pvContext & 3); - - switch (type) - { - case FAKEDYNFNTABLE_JIT: - return OutOfProcessFunctionTableCallback_JIT( - fpReadMemory, - pUserContext, - TableAddress, - pnEntries, - ppFunctions); - -#ifdef DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - case FAKEDYNFNTABLE_STUB: - return OutOfProcessFunctionTableCallback_Stub( - fpReadMemory, - pUserContext, - TableAddress, - pnEntries, - ppFunctions); -#endif // DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - default: - break; - } - - return STATUS_UNSUCCESSFUL; -} - #else extern "C" NTSTATUS OutOfProcessFunctionTableCallback() diff --git a/src/coreclr/debug/daccess/fntableaccess.h b/src/coreclr/debug/daccess/fntableaccess.h index c4a72a6d93dedb..722f0581e218a0 100644 --- a/src/coreclr/debug/daccess/fntableaccess.h +++ b/src/coreclr/debug/daccess/fntableaccess.h @@ -11,13 +11,6 @@ #define _FN_TABLE_ACCESS_H -#if !defined(TARGET_X86) - -#ifndef TARGET_UNIX -#define DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO -#endif // !TARGET_UNIX -#endif - struct FakeEEJitManager { LPVOID __VFN_table; @@ -71,40 +64,6 @@ typedef struct _FakeHpCodeHdr #define FAKE_STUB_CODE_BLOCK_LAST 0xF -#ifdef DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - -struct FakeStubUnwindInfoHeaderSuffix -{ - UCHAR nUnwindInfoSize; -}; - -// Variable-sized struct that precedes a Stub when the stub requires unwind -// information. Followed by a StubUnwindInfoHeaderSuffix. -struct FakeStubUnwindInfoHeader -{ - FakeStubUnwindInfoHeader *pNext; - T_RUNTIME_FUNCTION FunctionEntry; - UNWIND_INFO UnwindInfo; // variable length -}; - -// List of stub address ranges, in increasing address order. -struct FakeStubUnwindInfoHeapSegment -{ - PBYTE pbBaseAddress; - SIZE_T cbSegment; - FakeStubUnwindInfoHeader *pUnwindHeaderList; - FakeStubUnwindInfoHeapSegment *pNext; -}; - -#endif // DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - - -enum FakeEEDynamicFunctionTableType -{ - FAKEDYNFNTABLE_JIT = 0, - FAKEDYNFNTABLE_STUB = 1, -}; - #ifdef CHECK_DUPLICATED_STRUCT_LAYOUTS @@ -130,29 +89,9 @@ class CheckDuplicatedStructLayouts CHECK_OFFSET(RealCodeHeader, unwindInfos); #endif // !TARGET_X86 -#ifdef DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - CHECK_OFFSET(StubUnwindInfoHeader, pNext); - - CHECK_OFFSET(StubUnwindInfoHeapSegment, pbBaseAddress); - CHECK_OFFSET(StubUnwindInfoHeapSegment, cbSegment); - CHECK_OFFSET(StubUnwindInfoHeapSegment, pUnwindHeaderList); - CHECK_OFFSET(StubUnwindInfoHeapSegment, pNext); - -#endif // DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - #undef CHECK_OFFSET }; -#ifdef DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - -static_assert_no_msg( FAKEDYNFNTABLE_JIT - == DYNFNTABLE_JIT); - -static_assert_no_msg( FAKEDYNFNTABLE_STUB - == DYNFNTABLE_STUB); - -#endif // DEBUGSUPPORT_STUBS_HAVE_UNWIND_INFO - #else // CHECK_DUPLICATED_STRUCT_LAYOUTS BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID pReserved); diff --git a/src/coreclr/inc/CrstTypes.def b/src/coreclr/inc/CrstTypes.def index 0e45e17285ed6b..f51399812a0826 100644 --- a/src/coreclr/inc/CrstTypes.def +++ b/src/coreclr/inc/CrstTypes.def @@ -256,7 +256,7 @@ End Crst Interop AcquiredBefore PinnedHeapHandleTable AvailableParamTypes ClassInit DeadlockDetection GenericDictionaryExpansion HandleTable InstMethodHashTable InteropData LoaderHeap SigConvert - StubDispatchCache StubUnwindInfoHeapSegments SyncBlockCache TypeIDMap UnresolvedClassLock + StubDispatchCache SyncBlockCache TypeIDMap UnresolvedClassLock PendingTypeLoadEntry End @@ -339,7 +339,7 @@ Crst PendingTypeLoadEntry FusionAppCtx GlobalStrLiteralMap HandleTable IbcProfile IJWFixupData IJWHash ISymUnmanagedReader Jit JumpStubCache LoaderHeap Module ModuleLookupTable PEImage - SigConvert SingleUseLock StubDispatchCache StubUnwindInfoHeapSegments + SigConvert SingleUseLock StubDispatchCache SyncBlockCache SystemDomain ThreadIdDispenser ThreadStore TypeIDMap UnresolvedClassLock SameLevelAs PendingTypeLoadEntry End @@ -399,7 +399,7 @@ Crst SingleUseLock End Crst UnwindInfoTableLock - AcquiredAfter StubUnwindInfoHeapSegments SingleUseLock + AcquiredAfter SingleUseLock AcquiredBefore StressLog End @@ -414,10 +414,6 @@ End Crst StubDispatchCache End -Crst StubUnwindInfoHeapSegments - AcquiredAfter StubCache -End - Crst SyncBlockCache AcquiredBefore ThreadIdDispenser End diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index d92858dd5d4a5f..00d9745e177e7f 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -309,7 +309,6 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_JitFramed, W("JitFramed"), 0, "Forces EBP f CONFIG_DWORD_INFO(INTERNAL_JitThrowOnAssertionFailure, W("JitThrowOnAssertionFailure"), 0, "Throw managed exception on assertion failures during JIT instead of failfast") CONFIG_DWORD_INFO(INTERNAL_JitGCStress, W("JitGCStress"), 0, "GC stress mode for jit") CONFIG_DWORD_INFO(INTERNAL_JitHeartbeat, W("JitHeartbeat"), 0, "") -CONFIG_DWORD_INFO(INTERNAL_JitHelperLogging, W("JitHelperLogging"), 0, "") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_JITMinOpts, W("JITMinOpts"), 0, "Forces MinOpts") // *Some* relocs are just opportunistic optimizations and can be non-deterministic - it might produce @@ -853,7 +852,6 @@ CONFIG_DWORD_INFO(INTERNAL_SBDumpOnNewIndex, W("SBDumpOnNewIndex"), 0, "Used for CONFIG_DWORD_INFO(INTERNAL_SBDumpOnResize, W("SBDumpOnResize"), 0, "Used for Syncblock debugging. It's been a while since any of those have been used.") CONFIG_DWORD_INFO(INTERNAL_SBDumpStyle, W("SBDumpStyle"), 0, "Used for Syncblock debugging. It's been a while since any of those have been used.") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_SleepOnExit, W("SleepOnExit"), 0, "Used for lrak detection. I'd say deprecated by umdh.") -CONFIG_DWORD_INFO(INTERNAL_StubLinkerUnwindInfoVerificationOn, W("StubLinkerUnwindInfoVerificationOn"), 0, "") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_SuccessExit, W("SuccessExit"), 0, "") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TestDataConsistency, W("TestDataConsistency"), FALSE, "Allows ensuring the left side is not holding locks (and may thus be in an inconsistent state) when inspection occurs") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ThreadGuardPages, W("ThreadGuardPages"), 0, "") diff --git a/src/coreclr/inc/crsttypes_generated.h b/src/coreclr/inc/crsttypes_generated.h index f14fe2c7a37a66..8fde9aa204abf9 100644 --- a/src/coreclr/inc/crsttypes_generated.h +++ b/src/coreclr/inc/crsttypes_generated.h @@ -102,25 +102,24 @@ enum CrstType CrstStressLog = 84, CrstStubCache = 85, CrstStubDispatchCache = 86, - CrstStubUnwindInfoHeapSegments = 87, - CrstSyncBlockCache = 88, - CrstSyncHashLock = 89, - CrstSystemDomain = 90, - CrstSystemDomainDelayedUnloadList = 91, - CrstThreadIdDispenser = 92, - CrstThreadLocalStorageLock = 93, - CrstThreadStore = 94, - CrstTieredCompilation = 95, - CrstTypeEquivalenceMap = 96, - CrstTypeIDMap = 97, - CrstUMEntryThunkCache = 98, - CrstUMEntryThunkFreeListLock = 99, - CrstUniqueStack = 100, - CrstUnresolvedClassLock = 101, - CrstUnwindInfoTableLock = 102, - CrstVSDIndirectionCellLock = 103, - CrstWrapperTemplate = 104, - kNumberOfCrstTypes = 105 + CrstSyncBlockCache = 87, + CrstSyncHashLock = 88, + CrstSystemDomain = 89, + CrstSystemDomainDelayedUnloadList = 90, + CrstThreadIdDispenser = 91, + CrstThreadLocalStorageLock = 92, + CrstThreadStore = 93, + CrstTieredCompilation = 94, + CrstTypeEquivalenceMap = 95, + CrstTypeIDMap = 96, + CrstUMEntryThunkCache = 97, + CrstUMEntryThunkFreeListLock = 98, + CrstUniqueStack = 99, + CrstUnresolvedClassLock = 100, + CrstUnwindInfoTableLock = 101, + CrstVSDIndirectionCellLock = 102, + CrstWrapperTemplate = 103, + kNumberOfCrstTypes = 104 }; #endif // __CRST_TYPES_INCLUDED @@ -216,9 +215,8 @@ int g_rgCrstLevelMap[] = 3, // CrstSigConvert 4, // CrstSingleUseLock -1, // CrstStressLog - 4, // CrstStubCache + 3, // CrstStubCache 0, // CrstStubDispatchCache - 3, // CrstStubUnwindInfoHeapSegments 2, // CrstSyncBlockCache 0, // CrstSyncHashLock 14, // CrstSystemDomain @@ -328,7 +326,6 @@ LPCSTR g_rgCrstNameMap[] = "CrstStressLog", "CrstStubCache", "CrstStubDispatchCache", - "CrstStubUnwindInfoHeapSegments", "CrstSyncBlockCache", "CrstSyncHashLock", "CrstSystemDomain", diff --git a/src/coreclr/inc/loaderheap.h b/src/coreclr/inc/loaderheap.h index b155d0188b84ea..54ba2595bff1ae 100644 --- a/src/coreclr/inc/loaderheap.h +++ b/src/coreclr/inc/loaderheap.h @@ -279,13 +279,6 @@ class UnlockedLoaderHeap } #endif -#ifdef _DEBUG - // Stubs allocated from a LoaderHeap will have unwind info registered with NT. - // The info must be unregistered when the heap is destroyed. - BOOL m_fPermitStubsWithUnwindInfo; - BOOL m_fStubUnwindInfoUnregistered; -#endif - public: BOOL m_fExplicitControl; // Am I a LoaderHeap or an ExplicitControlLoaderHeap? void (*m_codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); diff --git a/src/coreclr/utilcode/loaderheap.cpp b/src/coreclr/utilcode/loaderheap.cpp index 50f51486d1cbb6..d78292097dfddc 100644 --- a/src/coreclr/utilcode/loaderheap.cpp +++ b/src/coreclr/utilcode/loaderheap.cpp @@ -950,8 +950,6 @@ UnlockedLoaderHeap::UnlockedLoaderHeap(DWORD dwReserveBlockSize, s_dwNumInstancesOfLoaderHeaps++; m_pEventList = NULL; m_dwDebugFlags = LoaderHeapSniffer::InitDebugFlags(); - m_fPermitStubsWithUnwindInfo = FALSE; - m_fStubUnwindInfoUnregistered= FALSE; #endif m_kind = kind; @@ -978,8 +976,6 @@ UnlockedLoaderHeap::~UnlockedLoaderHeap() } CONTRACTL_END - _ASSERTE(!m_fPermitStubsWithUnwindInfo || m_fStubUnwindInfoUnregistered); - if (m_pRangeList != NULL) m_pRangeList->RemoveRanges((void *) this); diff --git a/src/coreclr/vm/amd64/AsmHelpers.asm b/src/coreclr/vm/amd64/AsmHelpers.asm index 1b6fd1c7636820..18435be1b13727 100644 --- a/src/coreclr/vm/amd64/AsmHelpers.asm +++ b/src/coreclr/vm/amd64/AsmHelpers.asm @@ -12,10 +12,6 @@ extern ProfileTailcall:proc extern OnHijackWorker:proc extern JIT_RareDisableHelperWorker:proc -ifdef _DEBUG -extern DebugCheckStubUnwindInfoWorker:proc -endif - ; EXTERN_C int __fastcall HelperMethodFrameRestoreState( ; INDEBUG_COMMA(HelperMethodFrame *pFrame) @@ -192,136 +188,6 @@ getFPReturn4: LEAF_END getFPReturn, _TEXT -ifdef _DEBUG -NESTED_ENTRY DebugCheckStubUnwindInfo, _TEXT - - ; - ; rax is pushed on the stack before being trashed by the "mov rax, - ; target/jmp rax" code generated by X86EmitNearJump. This stack slot - ; will be reused later in the epilogue. This slot is left there to - ; align rsp. - ; - - .allocstack 8 - - mov rax, [rsp] - - ; - ; Create a CONTEXT structure. DebugCheckStubUnwindInfoWorker will - ; fill in the flags. - ; - - alloc_stack 20h + SIZEOF__CONTEXT - - mov r10, rbp - - set_frame rbp, 20h - - mov [rbp + OFFSETOF__CONTEXT__Rbp], r10 - .savereg rbp, OFFSETOF__CONTEXT__Rbp - - save_reg_frame rbx, rbp, OFFSETOF__CONTEXT__Rbx - save_reg_frame rsi, rbp, OFFSETOF__CONTEXT__Rsi - save_reg_frame rdi, rbp, OFFSETOF__CONTEXT__Rdi - save_reg_frame r12, rbp, OFFSETOF__CONTEXT__R12 - save_reg_frame r13, rbp, OFFSETOF__CONTEXT__R13 - save_reg_frame r14, rbp, OFFSETOF__CONTEXT__R14 - save_reg_frame r15, rbp, OFFSETOF__CONTEXT__R15 - save_xmm128_frame xmm6, rbp, OFFSETOF__CONTEXT__Xmm6 - save_xmm128_frame xmm7, rbp, OFFSETOF__CONTEXT__Xmm7 - save_xmm128_frame xmm8, rbp, OFFSETOF__CONTEXT__Xmm8 - save_xmm128_frame xmm9, rbp, OFFSETOF__CONTEXT__Xmm9 - save_xmm128_frame xmm10, rbp, OFFSETOF__CONTEXT__Xmm10 - save_xmm128_frame xmm11, rbp, OFFSETOF__CONTEXT__Xmm11 - save_xmm128_frame xmm12, rbp, OFFSETOF__CONTEXT__Xmm12 - save_xmm128_frame xmm13, rbp, OFFSETOF__CONTEXT__Xmm13 - save_xmm128_frame xmm14, rbp, OFFSETOF__CONTEXT__Xmm14 - save_xmm128_frame xmm15, rbp, OFFSETOF__CONTEXT__Xmm15 - END_PROLOGUE - - mov [rbp + OFFSETOF__CONTEXT__Rax], rax - mov [rbp + OFFSETOF__CONTEXT__Rcx], rcx - mov [rbp + OFFSETOF__CONTEXT__Rdx], rdx - mov [rbp + OFFSETOF__CONTEXT__R8], r8 - mov [rbp + OFFSETOF__CONTEXT__R9], r9 - mov [rbp + OFFSETOF__CONTEXT__R10], r10 - mov [rbp + OFFSETOF__CONTEXT__R11], r11 - movdqa [rbp + OFFSETOF__CONTEXT__Xmm0], xmm0 - movdqa [rbp + OFFSETOF__CONTEXT__Xmm1], xmm1 - movdqa [rbp + OFFSETOF__CONTEXT__Xmm2], xmm2 - movdqa [rbp + OFFSETOF__CONTEXT__Xmm3], xmm3 - movdqa [rbp + OFFSETOF__CONTEXT__Xmm4], xmm4 - movdqa [rbp + OFFSETOF__CONTEXT__Xmm5], xmm5 - - mov rax, [rbp+SIZEOF__CONTEXT+8] - mov [rbp+OFFSETOF__CONTEXT__Rip], rax - - lea rax, [rbp+SIZEOF__CONTEXT+8+8] - mov [rbp+OFFSETOF__CONTEXT__Rsp], rax - - ; - ; Align rsp - ; - and rsp, -16 - - ; - ; Verify that unwinding works from the stub's CONTEXT. - ; - - mov rcx, rbp - call DebugCheckStubUnwindInfoWorker - - ; - ; Restore stub's registers. rbp will be restored using "pop" in the - ; epilogue. - ; - - mov rax, [rbp+OFFSETOF__CONTEXT__Rbp] - mov [rbp+SIZEOF__CONTEXT], rax - - mov rax, [rbp+OFFSETOF__CONTEXT__Rax] - mov rbx, [rbp+OFFSETOF__CONTEXT__Rbx] - mov rcx, [rbp+OFFSETOF__CONTEXT__Rcx] - mov rdx, [rbp+OFFSETOF__CONTEXT__Rdx] - mov rsi, [rbp+OFFSETOF__CONTEXT__Rsi] - mov rdi, [rbp+OFFSETOF__CONTEXT__Rdi] - mov r8, [rbp+OFFSETOF__CONTEXT__R8] - mov r9, [rbp+OFFSETOF__CONTEXT__R9] - mov r10, [rbp+OFFSETOF__CONTEXT__R10] - mov r11, [rbp+OFFSETOF__CONTEXT__R11] - mov r12, [rbp+OFFSETOF__CONTEXT__R12] - mov r13, [rbp+OFFSETOF__CONTEXT__R13] - mov r14, [rbp+OFFSETOF__CONTEXT__R14] - mov r15, [rbp+OFFSETOF__CONTEXT__R15] - movdqa xmm0, [rbp+OFFSETOF__CONTEXT__Xmm0] - movdqa xmm1, [rbp+OFFSETOF__CONTEXT__Xmm1] - movdqa xmm2, [rbp+OFFSETOF__CONTEXT__Xmm2] - movdqa xmm3, [rbp+OFFSETOF__CONTEXT__Xmm3] - movdqa xmm4, [rbp+OFFSETOF__CONTEXT__Xmm4] - movdqa xmm5, [rbp+OFFSETOF__CONTEXT__Xmm5] - movdqa xmm6, [rbp+OFFSETOF__CONTEXT__Xmm6] - movdqa xmm7, [rbp+OFFSETOF__CONTEXT__Xmm7] - movdqa xmm8, [rbp+OFFSETOF__CONTEXT__Xmm8] - movdqa xmm9, [rbp+OFFSETOF__CONTEXT__Xmm9] - movdqa xmm10, [rbp+OFFSETOF__CONTEXT__Xmm10] - movdqa xmm11, [rbp+OFFSETOF__CONTEXT__Xmm11] - movdqa xmm12, [rbp+OFFSETOF__CONTEXT__Xmm12] - movdqa xmm13, [rbp+OFFSETOF__CONTEXT__Xmm13] - movdqa xmm14, [rbp+OFFSETOF__CONTEXT__Xmm14] - movdqa xmm15, [rbp+OFFSETOF__CONTEXT__Xmm15] - - ; - ; epilogue - ; - - lea rsp, [rbp + SIZEOF__CONTEXT] - pop rbp - ret - -NESTED_END DebugCheckStubUnwindInfo, _TEXT -endif ; _DEBUG - - ; A JITted method's return address was hijacked to return to us here. ; VOID OnHijackTripThread() NESTED_ENTRY OnHijackTripThread, _TEXT diff --git a/src/coreclr/vm/arm64/cgencpu.h b/src/coreclr/vm/arm64/cgencpu.h index 66553fed09812c..f83de42fecc368 100644 --- a/src/coreclr/vm/arm64/cgencpu.h +++ b/src/coreclr/vm/arm64/cgencpu.h @@ -494,7 +494,6 @@ class StubLinkerCPU : public StubLinker void EmitJumpRegister(IntReg regTarget); void EmitMovReg(IntReg dest, IntReg source); - void EmitSubImm(IntReg Xd, IntReg Xn, unsigned int value); void EmitAddImm(IntReg Xd, IntReg Xn, unsigned int value); void EmitLoadStoreRegPairImm(DWORD flags, IntReg Xt1, IntReg Xt2, IntReg Xn, int offset=0); @@ -506,12 +505,6 @@ class StubLinkerCPU : public StubLinker void EmitLoadRegReg(IntReg Xt, IntReg Xn, IntReg Xm, DWORD option); void EmitCallRegister(IntReg reg); - void EmitProlog(unsigned short cIntRegArgs, - unsigned short cVecRegArgs, - unsigned short cCalleeSavedRegs, - unsigned short cbStackSpace = 0); - - void EmitEpilog(); void EmitRet(IntReg reg); diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp index 0bc1ac2797606f..6cf5a7ec845896 100644 --- a/src/coreclr/vm/arm64/stubs.cpp +++ b/src/coreclr/vm/arm64/stubs.cpp @@ -1174,143 +1174,6 @@ void StubLinkerCPU::EmitJumpRegister(IntReg regTarget) Emit32((DWORD) (0x3587C0<<10 | regTarget<<5)); } -void StubLinkerCPU::EmitProlog(unsigned short cIntRegArgs, unsigned short cVecRegArgs, unsigned short cCalleeSavedRegs, unsigned short cbStackSpace) -{ - - _ASSERTE(!m_fProlog); - - unsigned short numberOfEntriesOnStack = 2 + cIntRegArgs + cVecRegArgs + cCalleeSavedRegs; // 2 for fp, lr - - // Stack needs to be 16 byte (2 qword) aligned. Compute the required padding before saving it - unsigned short totalPaddedFrameSize = static_cast(ALIGN_UP(cbStackSpace + numberOfEntriesOnStack *sizeof(void*), 2*sizeof(void*))); - // The padding is going to be applied to the local stack - cbStackSpace = totalPaddedFrameSize - numberOfEntriesOnStack *sizeof(void*); - - // Record the parameters of this prolog so that we can generate a matching epilog and unwind info. - DescribeProlog(cIntRegArgs, cVecRegArgs, cCalleeSavedRegs, cbStackSpace); - - - - // N.B Despite the range of a jump with a sub sp is 4KB, we're limiting to 504 to save from emitting right prolog that's - // expressable in unwind codes efficiently. The largest offset in typical unwindinfo encodings that we use is 504. - // so allocations larger than 504 bytes would require setting the SP in multiple strides, which would complicate both - // prolog and epilog generation as well as unwindinfo generation. - _ASSERTE((totalPaddedFrameSize <= 504) && "NYI:ARM64 Implement StubLinker prologs with larger than 504 bytes of frame size"); - if (totalPaddedFrameSize > 504) - COMPlusThrow(kNotSupportedException); - - // Here is how the stack would look like (Stack grows up) - // [Low Address] - // +------------+ - // SP -> | | <-+ - // : : | Stack Frame, (i.e outgoing arguments) including padding - // | | <-+ - // +------------+ - // | FP | - // +------------+ - // | LR | - // +------------+ - // | X19 | <-+ - // +------------+ | - // : : | Callee-saved registers - // +------------+ | - // | X28 | <-+ - // +------------+ - // | V0 | <-+ - // +------------+ | - // : : | Vec Args - // +------------+ | - // | V7 | <-+ - // +------------+ - // | X0 | <-+ - // +------------+ | - // : : | Int Args - // +------------+ | - // | X7 | <-+ - // +------------+ - // Old SP -> |[Stack Args]| - // [High Address] - - - - // Regarding the order of operations in the prolog and epilog; - // If the prolog and the epilog matches each other we can simplify emitting the unwind codes and save a few - // bytes of unwind codes by making prolog and epilog share the same unwind codes. - // In order to do that we need to make the epilog be the reverse of the prolog. - // But we wouldn't want to add restoring of the argument registers as that's completely unnecessary. - // Besides, saving argument registers cannot be expressed by the unwind code encodings. - // So, we'll push saving the argument registers to the very last in the prolog, skip restoring it in epilog, - // and also skip reporting it to the OS. - // - // Another bit that we can save is resetting the frame pointer. - // This is not necessary when the SP doesn't get modified beyond prolog and epilog. (i.e no alloca/localloc) - // And in that case we don't need to report setting up the FP either. - - - - // 1. Relocate SP - EmitSubImm(RegSp, RegSp, totalPaddedFrameSize); - - unsigned cbOffset = 2*sizeof(void*) + cbStackSpace; // 2 is for fp,lr - - // 2. Store callee-saved registers - _ASSERTE(cCalleeSavedRegs <= 10); - for (unsigned short i=0; i<(cCalleeSavedRegs/2)*2; i+=2) - EmitLoadStoreRegPairImm(eSTORE, IntReg(19+i), IntReg(19+i+1), RegSp, cbOffset + i*sizeof(void*)); - if ((cCalleeSavedRegs %2) ==1) - EmitLoadStoreRegImm(eSTORE, IntReg(cCalleeSavedRegs-1), RegSp, cbOffset + (cCalleeSavedRegs-1)*sizeof(void*)); - - // 3. Store FP/LR - EmitLoadStoreRegPairImm(eSTORE, RegFp, RegLr, RegSp, cbStackSpace); - - // 4. Set the frame pointer - EmitMovReg(RegFp, RegSp); - - // 5. Store floating point argument registers - cbOffset += cCalleeSavedRegs*sizeof(void*); - _ASSERTE(cVecRegArgs <= 8); - for (unsigned short i=0; i<(cVecRegArgs/2)*2; i+=2) - EmitLoadStoreRegPairImm(eSTORE, VecReg(i), VecReg(i+1), RegSp, cbOffset + i*sizeof(void*)); - if ((cVecRegArgs % 2) == 1) - EmitLoadStoreRegImm(eSTORE, VecReg(cVecRegArgs-1), RegSp, cbOffset + (cVecRegArgs-1)*sizeof(void*)); - - // 6. Store int argument registers - cbOffset += cVecRegArgs*sizeof(void*); - _ASSERTE(cIntRegArgs <= 8); - for (unsigned short i=0 ; i<(cIntRegArgs/2)*2; i+=2) - EmitLoadStoreRegPairImm(eSTORE, IntReg(i), IntReg(i+1), RegSp, cbOffset + i*sizeof(void*)); - if ((cIntRegArgs % 2) == 1) - EmitLoadStoreRegImm(eSTORE,IntReg(cIntRegArgs-1), RegSp, cbOffset + (cIntRegArgs-1)*sizeof(void*)); -} - -void StubLinkerCPU::EmitEpilog() -{ - _ASSERTE(m_fProlog); - - // 6. Restore int argument registers - // nop: We don't need to. They are scratch registers - - // 5. Restore floating point argument registers - // nop: We don't need to. They are scratch registers - - // 4. Restore the SP from FP - // N.B. We're assuming that the stublinker stubs doesn't do alloca, hence nop - - // 3. Restore FP/LR - EmitLoadStoreRegPairImm(eLOAD, RegFp, RegLr, RegSp, m_cbStackSpace); - - // 2. restore the calleeSavedRegisters - unsigned cbOffset = 2*sizeof(void*) + m_cbStackSpace; // 2 is for fp,lr - if ((m_cCalleeSavedRegs %2) ==1) - EmitLoadStoreRegImm(eLOAD, IntReg(m_cCalleeSavedRegs-1), RegSp, cbOffset + (m_cCalleeSavedRegs-1)*sizeof(void*)); - for (int i=(m_cCalleeSavedRegs/2)*2-2; i>=0; i-=2) - EmitLoadStoreRegPairImm(eLOAD, IntReg(19+i), IntReg(19+i+1), RegSp, cbOffset + i*sizeof(void*)); - - // 1. Restore SP - EmitAddImm(RegSp, RegSp, GetStackFrameSize()); - EmitRet(RegLr); -} - void StubLinkerCPU::EmitRet(IntReg Xn) { // Encoding: 1101011001011111000000| Rn |00000 @@ -1453,19 +1316,6 @@ void StubLinkerCPU::EmitMovReg(IntReg Xd, IntReg Xm) } } -void StubLinkerCPU::EmitSubImm(IntReg Xd, IntReg Xn, unsigned int value) -{ - // sub , , #imm{, } - // Encoding: sf|1|0|1|0|0|0|1|shift(2)|imm(12)|Rn|Rd - // where is encoded as LSL #0 (no shift) when shift=00 and LSL #12 when shift=01. (No shift in this impl) - // imm(12) is an unsigned immediate in the range of 0 to 4095 - // Rn and Rd are both encoded as SP=31 - // sf = 1 for 64-bit variant - _ASSERTE((0 <= value) && (value <= 4095)); - Emit32((DWORD) ((0xD1 << 24) | (value << 10) | (Xd << 5) | Xn)); - -} - void StubLinkerCPU::EmitAddImm(IntReg Xd, IntReg Xn, unsigned int value) { // add SP, SP, #imm{, } diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 38c47a9749684f..79cca2d6c18512 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -811,7 +811,6 @@ void EEStartupHelper() CoreLibBinder::Startup(); - Stub::Init(); StubLinkerCPU::Init(); StubPrecode::StaticInitialize(); FixupPrecode::StaticInitialize(); @@ -1275,7 +1274,6 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading) Interpreter::PrintPostMortemData(); #endif // FEATURE_INTERPRETER VirtualCallStubManager::LogFinalStats(); - WriteJitHelperCountToSTRESSLOG(); #ifdef PROFILING_SUPPORTED // If profiling is enabled, then notify of shutdown first so that the diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 0314a2920f074f..fa89ace071698c 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -423,11 +423,6 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R } } -#ifdef STUBLINKER_GENERATES_UNWIND_INFO -extern StubUnwindInfoHeapSegment *g_StubHeapSegments; -#endif // STUBLINKER_GENERATES_UNWIND_INFO - -extern CrstStatic g_StubUnwindInfoHeapSegmentsCrst; /*****************************************************************************/ // Publish all existing JIT compiled methods by iterating through the code heap // Note that because we need to keep the entries in order we have to hold @@ -468,25 +463,6 @@ extern CrstStatic g_StubUnwindInfoHeapSegmentsCrst; } } } - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - // Enumerate all existing stubs - CrstHolder crst(&g_StubUnwindInfoHeapSegmentsCrst); - for (StubUnwindInfoHeapSegment* pStubHeapSegment = g_StubHeapSegments; pStubHeapSegment; pStubHeapSegment = pStubHeapSegment->pNext) - { - // The stubs are in reverse order, so we reverse them so they are in memory order - CQuickArrayList list; - for (StubUnwindInfoHeader *pHeader = pStubHeapSegment->pUnwindHeaderList; pHeader; pHeader = pHeader->pNext) - list.Push(pHeader); - - for(int i = (int) list.Size()-1; i >= 0; --i) - { - StubUnwindInfoHeader *pHeader = list[i]; - AddToUnwindInfoTable(&pStubHeapSegment->pUnwindInfoTable, &pHeader->FunctionEntry, - (TADDR) pStubHeapSegment->pbBaseAddress, (TADDR) pStubHeapSegment->pbBaseAddress + pStubHeapSegment->cbSegment); - } - } -#endif // STUBLINKER_GENERATES_UNWIND_INFO } /*****************************************************************************/ @@ -2635,8 +2611,7 @@ HeapList* EEJitManager::NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapLi (PVOID)pStartRange, (ULONG)((ULONG64)pEndRange - (ULONG64)pStartRange), GetRuntimeFunctionCallback, - this, - DYNFNTABLE_JIT); + this); } EX_CATCH { diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 24003b9b1c6571..779f7a841fc9d4 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -191,10 +191,6 @@ HRESULT EEConfig::Init() m_fInteropValidatePinnedObjects = false; m_fInteropLogArguments = false; -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - fStubLinkerUnwindInfoVerificationOn = FALSE; -#endif - #if defined(_DEBUG) && defined(FEATURE_EH_FUNCLETS) fSuppressLockViolationsOnReentryFromOS = false; #endif @@ -635,10 +631,6 @@ HRESULT EEConfig::sync() fSuppressLockViolationsOnReentryFromOS = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuppressLockViolationsOnReentryFromOS) != 0); #endif -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - fStubLinkerUnwindInfoVerificationOn = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_StubLinkerUnwindInfoVerificationOn) != 0); -#endif - #if defined(_DEBUG) && defined(TARGET_AMD64) m_cGenerateLongJumpDispatchStubRatio = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GenerateLongJumpDispatchStubRatio, static_cast(m_cGenerateLongJumpDispatchStubRatio)); diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index 279b81ed949008..91d9930c62a327 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -273,10 +273,6 @@ class EEConfig bool SuppressLockViolationsOnReentryFromOS() const {LIMITED_METHOD_CONTRACT; return fSuppressLockViolationsOnReentryFromOS; } #endif -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - bool IsStubLinkerUnwindInfoVerificationOn() const { LIMITED_METHOD_CONTRACT; return fStubLinkerUnwindInfoVerificationOn; } -#endif - #endif // _DEBUG #ifdef FEATURE_COMINTEROP @@ -538,9 +534,6 @@ class EEConfig bool fSuppressLockViolationsOnReentryFromOS; #endif -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - bool fStubLinkerUnwindInfoVerificationOn; -#endif #endif // _DEBUG #ifdef ENABLE_STARTUP_DELAY int iStartupDelayMS; //Adds sleep to startup. diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index e1410da248692f..2c35adfb65bc6e 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -33,19 +33,8 @@ #include "stublink.inl" -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) -#include -#endif - - #ifndef DACCESS_COMPILE -#if defined(TARGET_AMD64) -#if defined(_DEBUG) -extern "C" VOID __cdecl DebugCheckStubUnwindInfo(); -#endif // _DEBUG -#endif // TARGET_AMD64 - #ifdef TARGET_AMD64 @@ -850,7 +839,7 @@ VOID StubLinkerCPU::X86EmitMovRegSP(X86Reg destReg) X86EmitMovRegReg(destReg, kESP); } - +#ifdef TARGET_X86 //--------------------------------------------------------------- // Emits: // PUSH @@ -859,32 +848,10 @@ VOID StubLinkerCPU::X86EmitPushReg(X86Reg reg) { STANDARD_VM_CONTRACT; -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - X86Reg origReg = reg; -#endif - -#ifdef TARGET_AMD64 - if (reg >= kR8) - { - Emit8(REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT | REX_OPCODE_REG_EXT); - reg = X86RegFromAMD64Reg(reg); - } -#endif Emit8(static_cast(0x50 + reg)); - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - if (IsPreservedReg(origReg)) - { - UnwindPushedReg(origReg); - } - else -#endif - { - Push(sizeof(void*)); - } + Push(sizeof(void*)); } - //--------------------------------------------------------------- // Emits: // POP @@ -893,14 +860,6 @@ VOID StubLinkerCPU::X86EmitPopReg(X86Reg reg) { STANDARD_VM_CONTRACT; -#ifdef TARGET_AMD64 - if (reg >= kR8) - { - Emit8(REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT | REX_OPCODE_REG_EXT); - reg = X86RegFromAMD64Reg(reg); - } -#endif // TARGET_AMD64 - Emit8(static_cast(0x58 + reg)); Pop(sizeof(void*)); } @@ -953,13 +912,9 @@ VOID StubLinkerCPU::X86EmitPushImmPtr(LPVOID value BIT64_ARG(X86Reg tmpReg /*=kR { STANDARD_VM_CONTRACT; -#ifdef TARGET_AMD64 - X86EmitRegLoad(tmpReg, (UINT_PTR) value); - X86EmitPushReg(tmpReg); -#else X86EmitPushImm32((UINT_PTR) value); -#endif } +#endif // TARGET_X86 //--------------------------------------------------------------- // Emits: @@ -1099,56 +1054,6 @@ VOID StubLinkerCPU:: X86EmitCmpRegIndexImm32(X86Reg reg, INT32 offs, INT32 imm32 Emit32(imm32); } -//--------------------------------------------------------------- -// Emits: -#if defined(TARGET_AMD64) -// mov rax, -// add rsp, imm32 -// jmp rax -#else -// add rsp, imm32 -// jmp -#endif -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitTailcallWithESPAdjust(CodeLabel *pTarget, INT32 imm32) -{ - STANDARD_VM_CONTRACT; - -#if defined(TARGET_AMD64) - EmitLabelRef(pTarget, reinterpret_cast(gX64NearJumpSetup), 0); - X86EmitAddEsp(imm32); - EmitLabelRef(pTarget, reinterpret_cast(gX64NearJumpExecute), 0); -#else - X86EmitAddEsp(imm32); - X86EmitNearJump(pTarget); -#endif -} - -//--------------------------------------------------------------- -// Emits: -#if defined(TARGET_AMD64) -// mov rax, -// pop reg -// jmp rax -#else -// pop reg -// jmp -#endif -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitTailcallWithSinglePop(CodeLabel *pTarget, X86Reg reg) -{ - STANDARD_VM_CONTRACT; - -#if defined(TARGET_AMD64) - EmitLabelRef(pTarget, reinterpret_cast(gX64NearJumpSetup), 0); - X86EmitPopReg(reg); - EmitLabelRef(pTarget, reinterpret_cast(gX64NearJumpExecute), 0); -#else - X86EmitPopReg(reg); - X86EmitNearJump(pTarget); -#endif -} - //--------------------------------------------------------------- // Emits: // JMP or @@ -1216,24 +1121,12 @@ VOID StubLinkerCPU::X86EmitReturn(WORD wArgBytes) Emit16(wArgBytes); } +#ifdef TARGET_X86 Pop(wArgBytes); +#endif } -#ifdef TARGET_AMD64 -//--------------------------------------------------------------- -// Emits: -// JMP or -// JMP (gX64LeaRIP), reg); -} -#endif // TARGET_AMD64 - - - +#ifdef TARGET_X86 VOID StubLinkerCPU::X86EmitPushRegs(unsigned regSet) { STANDARD_VM_CONTRACT; @@ -1254,6 +1147,7 @@ VOID StubLinkerCPU::X86EmitPopRegs(unsigned regSet) if (regSet & (1U<], -// -// It marks the instruction has 64bit so that the processor -// performs a 8byte data move to a RSP based stack location. -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitIndexRegStoreRSP(int32_t ofs, - X86Reg srcreg) -{ - STANDARD_VM_CONTRACT; - - X86EmitOp(0x89, srcreg, (X86Reg)kESP_Unsafe, ofs, (X86Reg)0, 0, k64BitOp); -} - -//--------------------------------------------------------------- -// Emits: -// mov [R12 + ], -// -// It marks the instruction has 64bit so that the processor -// performs a 8byte data move to a R12 based stack location. -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitIndexRegStoreR12(int32_t ofs, - X86Reg srcreg) -{ - STANDARD_VM_CONTRACT; - - X86EmitOp(0x89, srcreg, (X86Reg)kR12, ofs, (X86Reg)0, 0, k64BitOp); -} -#endif // defined(TARGET_AMD64) - +#ifdef TARGET_X86 //--------------------------------------------------------------- // Emits: // push dword ptr [ + ] @@ -1400,32 +1263,6 @@ VOID StubLinkerCPU::X86EmitIndexPop(X86Reg srcreg, int32_t ofs) Pop(sizeof(void*)); } -//--------------------------------------------------------------- -// Emits: -// lea , [ + -//--------------------------------------------------------------- -VOID StubLinkerCPU::X86EmitIndexLea(X86Reg dstreg, X86Reg srcreg, int32_t ofs) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION((int) dstreg < NumX86Regs); - PRECONDITION((int) srcreg < NumX86Regs); - } - CONTRACTL_END; - - X86EmitOffsetModRM(0x8d, dstreg, srcreg, ofs); -} - -#if defined(TARGET_AMD64) -VOID StubLinkerCPU::X86EmitIndexLeaRSP(X86Reg dstreg, X86Reg srcreg, int32_t ofs) -{ - STANDARD_VM_CONTRACT; - - X86EmitOp(0x8d, dstreg, (X86Reg)kESP_Unsafe, ofs, (X86Reg)0, 0, k64BitOp); -} -#endif // defined(TARGET_AMD64) - //--------------------------------------------------------------- // Emits: // sub esp, IMM @@ -1534,6 +1371,7 @@ VOID StubLinkerCPU::X86EmitAddEsp(INT32 imm32) } Pop(imm32); } +#endif // TARGET_X86 VOID StubLinkerCPU::X86EmitAddReg(X86Reg reg, INT32 imm32) { @@ -2244,18 +2082,6 @@ VOID StubLinkerCPU::X86EmitEspOffset(BYTE opcode, } -//--------------------------------------------------------------- - -VOID StubLinkerCPU::X86EmitPushEBPframe() -{ - STANDARD_VM_CONTRACT; - - // push ebp - X86EmitPushReg(kEBP); - // mov ebp,esp - X86EmitMovRegSP(kEBP); -} - #ifdef _DEBUG //--------------------------------------------------------------- // Emits: @@ -2312,47 +2138,7 @@ static const X86Reg c_argRegs[] = { }; #endif - - -#if defined(_DEBUG) && !defined(TARGET_UNIX) -void StubLinkerCPU::EmitJITHelperLoggingThunk(PCODE pJitHelper, LPVOID helperFuncCount) -{ - STANDARD_VM_CONTRACT; - - VMHELPCOUNTDEF* pHelperFuncCount = (VMHELPCOUNTDEF*)helperFuncCount; -/* - push rcx - mov rcx, &(pHelperFuncCount->count) - lock inc [rcx] - pop rcx -#ifdef TARGET_AMD64 - mov rax, - jmp rax -#else - jmp -#endif -*/ - - // push rcx - // mov rcx, &(pHelperFuncCount->count) - X86EmitPushReg(kECX); - X86EmitRegLoad(kECX, (UINT_PTR)(&(pHelperFuncCount->count))); - - // lock inc [rcx] - BYTE lock_inc_RCX[] = { 0xf0, 0xff, 0x01 }; - EmitBytes(lock_inc_RCX, sizeof(lock_inc_RCX)); - -#if defined(TARGET_AMD64) - // mov rax, - // pop rcx - // jmp rax -#else - // pop rcx - // jmp -#endif - X86EmitTailcallWithSinglePop(NewExternalCodeLabel(pJitHelper), kECX); -} -#endif // _DEBUG && !TARGET_UNIX +#ifdef TARGET_X86 VOID StubLinkerCPU::X86EmitCurrentThreadFetch(X86Reg dstreg, unsigned preservedRegSet) { @@ -2391,13 +2177,9 @@ VOID StubLinkerCPU::X86EmitCurrentThreadFetch(X86Reg dstreg, unsigned preservedR #else // TARGET_UNIX -#ifdef TARGET_AMD64 - BYTE code[] = { 0x65,0x48,0x8b,0x04,0x25 }; // mov dstreg, qword ptr gs:[IMM32] - static const int regByteIndex = 3; -#elif defined(TARGET_X86) BYTE code[] = { 0x64,0x8b,0x05 }; // mov dstreg, dword ptr fs:[IMM32] static const int regByteIndex = 2; -#endif + code[regByteIndex] |= (dstreg << 3); EmitBytes(code, sizeof(code)); @@ -2457,13 +2239,9 @@ VOID StubLinkerCPU::X86EmitCurrentThreadAllocContextFetch(X86Reg dstreg, unsigne #else // TARGET_UNIX -#ifdef TARGET_AMD64 - BYTE code[] = { 0x65,0x48,0x8b,0x04,0x25 }; // mov dstreg, qword ptr gs:[IMM32] - static const int regByteIndex = 3; -#elif defined(TARGET_X86) BYTE code[] = { 0x64,0x8b,0x05 }; // mov dstreg, dword ptr fs:[IMM32] static const int regByteIndex = 2; -#endif + code[regByteIndex] |= (dstreg << 3); EmitBytes(code, sizeof(code)); @@ -2477,7 +2255,6 @@ VOID StubLinkerCPU::X86EmitCurrentThreadAllocContextFetch(X86Reg dstreg, unsigne #endif // TARGET_UNIX } -#ifdef TARGET_X86 // This method unboxes the THIS pointer and then calls pRealMD // If it's shared code for a method in a generic value class, then also extract the vtable pointer // and pass it as an extra argument. Thus this stub generator really covers both @@ -2685,165 +2462,6 @@ VOID StubLinkerCPU::EmitInstantiatingMethodStub(MethodDesc* pMD, void* extra) } #endif // defined(FEATURE_SHARE_GENERIC_CODE) && !defined(FEATURE_INSTANTIATINGSTUB_AS_IL) && defined(TARGET_X86) - -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - -typedef BOOL GetModuleInformationProc( - HANDLE hProcess, - HMODULE hModule, - LPMODULEINFO lpmodinfo, - DWORD cb -); - -GetModuleInformationProc *g_pfnGetModuleInformation = NULL; - -extern "C" VOID __cdecl DebugCheckStubUnwindInfoWorker (CONTEXT *pStubContext) -{ - LOG((LF_STUBS, LL_INFO1000000, "checking stub unwind info:\n")); - - // - // Make a copy of the CONTEXT. RtlVirtualUnwind will modify this copy. - // DebugCheckStubUnwindInfo will need to restore registers from the - // original CONTEXT. - // - CONTEXT ctx = *pStubContext; - ctx.ContextFlags = (CONTEXT_CONTROL | CONTEXT_INTEGER); - - // - // Find the upper bound of the stack and address range of KERNEL32. This - // is where we expect the unwind to stop. - // - void *pvStackTop = GetThread()->GetCachedStackBase(); - - if (!g_pfnGetModuleInformation) - { - HMODULE hmodPSAPI = GetModuleHandle(W("PSAPI.DLL")); - - if (!hmodPSAPI) - { - hmodPSAPI = WszLoadLibrary(W("PSAPI.DLL")); - if (!hmodPSAPI) - { - _ASSERTE(!"unable to load PSAPI.DLL"); - goto ErrExit; - } - } - - g_pfnGetModuleInformation = (GetModuleInformationProc*)GetProcAddress(hmodPSAPI, "GetModuleInformation"); - if (!g_pfnGetModuleInformation) - { - _ASSERTE(!"can't find PSAPI!GetModuleInformation"); - goto ErrExit; - } - - // Intentionally leak hmodPSAPI. We don't want to - // LoadLibrary/FreeLibrary every time, this is slow + produces lots of - // debugger spew. This is just debugging code after all... - } - - HMODULE hmodKERNEL32 = GetModuleHandle(W("KERNEL32")); - _ASSERTE(hmodKERNEL32); - - MODULEINFO modinfoKERNEL32; - if (!g_pfnGetModuleInformation(GetCurrentProcess(), hmodKERNEL32, &modinfoKERNEL32, sizeof(modinfoKERNEL32))) - { - _ASSERTE(!"unable to get bounds of KERNEL32"); - goto ErrExit; - } - - // - // Unwind until IP is 0, sp is at the stack top, and callee IP is in kernel32. - // - - for (;;) - { - ULONG64 ControlPc = (ULONG64)GetIP(&ctx); - - LOG((LF_STUBS, LL_INFO1000000, "pc %p, sp %p\n", ControlPc, GetSP(&ctx))); - - ULONG64 ImageBase; - T_RUNTIME_FUNCTION *pFunctionEntry = RtlLookupFunctionEntry( - ControlPc, - &ImageBase, - NULL); - if (pFunctionEntry) - { - PVOID HandlerData; - ULONG64 EstablisherFrame; - - RtlVirtualUnwind( - 0, - ImageBase, - ControlPc, - pFunctionEntry, - &ctx, - &HandlerData, - &EstablisherFrame, - NULL); - - ULONG64 NewControlPc = (ULONG64)GetIP(&ctx); - - LOG((LF_STUBS, LL_INFO1000000, "function %p, image %p, new pc %p, new sp %p\n", pFunctionEntry, ImageBase, NewControlPc, GetSP(&ctx))); - - if (!NewControlPc) - { - if (dac_cast(GetSP(&ctx)) < (BYTE*)pvStackTop - 0x100) - { - _ASSERTE(!"SP did not end up at top of stack"); - goto ErrExit; - } - - if (!( ControlPc > (ULONG64)modinfoKERNEL32.lpBaseOfDll - && ControlPc < (ULONG64)modinfoKERNEL32.lpBaseOfDll + modinfoKERNEL32.SizeOfImage)) - { - _ASSERTE(!"PC did not end up in KERNEL32"); - goto ErrExit; - } - - break; - } - } - else - { - // Nested functions that do not use any stack space or nonvolatile - // registers are not required to have unwind info (ex. - // USER32!ZwUserCreateWindowEx). - ctx.Rip = *(ULONG64*)(ctx.Rsp); - ctx.Rsp += sizeof(ULONG64); - } - } -ErrExit: - return; -} - -//virtual -VOID StubLinkerCPU::EmitUnwindInfoCheckWorker (CodeLabel *pCheckLabel) -{ - STANDARD_VM_CONTRACT; - X86EmitCall(pCheckLabel, 0); -} - -//virtual -VOID StubLinkerCPU::EmitUnwindInfoCheckSubfunction() -{ - STANDARD_VM_CONTRACT; - -#ifdef TARGET_AMD64 - // X86EmitCall will generate "mov rax, target/jmp rax", so we have to save - // rax on the stack. DO NOT use X86EmitPushReg. That will induce infinite - // recursion, since the push may require more unwind info. This "push rax" - // will be accounted for by DebugCheckStubUnwindInfo's unwind info - // (considered part of its locals), so there doesn't have to be unwind - // info for it. - Emit8(0x50); -#endif - - X86EmitNearJump(NewExternalCodeLabel(DebugCheckStubUnwindInfo)); -} - -#endif // defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - - VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) { STANDARD_VM_CONTRACT; diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index dd627aafe0ce9d..0978dee0976f93 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -204,16 +204,10 @@ class StubLinkerCPU : public StubLinker VOID X86EmitOffsetModRM(BYTE opcode, X86Reg altreg, X86Reg indexreg, int32_t ofs); VOID X86EmitOffsetModRmSIB(BYTE opcode, X86Reg opcodeOrReg, X86Reg baseReg, X86Reg indexReg, int32_t scale, int32_t ofs); - VOID X86EmitTailcallWithESPAdjust(CodeLabel *pTarget, INT32 imm32); - VOID X86EmitTailcallWithSinglePop(CodeLabel *pTarget, X86Reg reg); - VOID X86EmitNearJump(CodeLabel *pTarget); VOID X86EmitCondJump(CodeLabel *pTarget, X86CondCode::cc condcode); VOID X86EmitCall(CodeLabel *target, int iArgBytes); VOID X86EmitReturn(WORD wArgBytes); -#ifdef TARGET_AMD64 - VOID X86EmitLeaRIP(CodeLabel *target, X86Reg reg); -#endif VOID X86EmitCurrentThreadFetch(X86Reg dstreg, unsigned preservedRegSet); @@ -221,18 +215,10 @@ class StubLinkerCPU : public StubLinker VOID X86EmitIndexRegLoad(X86Reg dstreg, X86Reg srcreg, int32_t ofs = 0); VOID X86EmitIndexRegStore(X86Reg dstreg, int32_t ofs, X86Reg srcreg); -#if defined(TARGET_AMD64) - VOID X86EmitIndexRegStoreRSP(int32_t ofs, X86Reg srcreg); - VOID X86EmitIndexRegStoreR12(int32_t ofs, X86Reg srcreg); -#endif // defined(TARGET_AMD64) VOID X86EmitIndexPush(X86Reg srcreg, int32_t ofs); VOID X86EmitBaseIndexPush(X86Reg baseReg, X86Reg indexReg, int32_t scale, int32_t ofs); VOID X86EmitIndexPop(X86Reg srcreg, int32_t ofs); - VOID X86EmitIndexLea(X86Reg dstreg, X86Reg srcreg, int32_t ofs); -#if defined(TARGET_AMD64) - VOID X86EmitIndexLeaRSP(X86Reg dstreg, X86Reg srcreg, int32_t ofs); -#endif // defined(TARGET_AMD64) VOID X86EmitSPIndexPush(int32_t ofs); VOID X86EmitSubEsp(INT32 imm32); @@ -242,7 +228,6 @@ class StubLinkerCPU : public StubLinker int32_t ofs AMD64_ARG(X86OperandSize OperandSize = k64BitOp) ); - VOID X86EmitPushEBPframe(); // Emits the most efficient form of the operation: // @@ -307,14 +292,6 @@ class StubLinkerCPU : public StubLinker VOID X86EmitRegLoad(X86Reg reg, UINT_PTR imm); - VOID X86EmitRegSave(X86Reg altreg, int32_t ofs) - { - LIMITED_METHOD_CONTRACT; - X86EmitEspOffset(0x89, altreg, ofs); - // X86Reg values never are outside a byte. - UnwindSavedReg(static_cast(altreg), ofs); - } - VOID X86_64BitOperands () { WRAPPER_NO_CONTRACT; @@ -340,22 +317,10 @@ class StubLinkerCPU : public StubLinker // Emits code to adjust for a static delegate target. VOID EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray); - -#if defined(_DEBUG) && !defined(TARGET_UNIX) - //=========================================================================== - // Emits code to log JITHelper access - void EmitJITHelperLoggingThunk(PCODE pJitHelper, LPVOID helperFuncCount); -#endif - #ifdef _DEBUG VOID X86EmitDebugTrashReg(X86Reg reg); #endif -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - virtual VOID EmitUnwindInfoCheckWorker (CodeLabel *pCheckLabel); - virtual VOID EmitUnwindInfoCheckSubfunction(); -#endif - private: VOID X86EmitSubEspWorker(INT32 imm32); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 5b617b8e1d0130..e5586d74db0e39 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -4645,17 +4645,6 @@ static const BinderMethodID hlpDynamicToBinderMap[DYNAMIC_CORINFO_HELP_COUNT] = #include "jithelpers.h" }; -#if defined(_DEBUG) && (defined(TARGET_AMD64) || defined(TARGET_X86)) && !defined(TARGET_UNIX) -#define HELPERCOUNTDEF(lpv) { (LPVOID)(lpv), NULL, 0 }, - -VMHELPCOUNTDEF hlpFuncCountTable[CORINFO_HELP_COUNT+1] = -{ -#define JITHELPER(code, pfnHelper, binderId) HELPERCOUNTDEF(pfnHelper) -#define DYNAMICJITHELPER(code, pfnHelper, binderId) HELPERCOUNTDEF(1 + DYNAMIC_##code) -#include "jithelpers.h" -}; -#endif - // Set the JIT helper function in the helper table // Handles the case where the function does not reside in mscorwks.dll @@ -4726,258 +4715,4 @@ void InitJITHelpers2() #if defined(TARGET_X86) || defined(TARGET_ARM) SetJitHelperFunction(CORINFO_HELP_INIT_PINVOKE_FRAME, (void *)GenerateInitPInvokeFrameHelper()->GetEntryPoint()); #endif // TARGET_X86 || TARGET_ARM - - InitJitHelperLogging(); -} - -//======================================================================== -// -// JIT HELPERS LOGGING -// -//======================================================================== - -#if defined(_DEBUG) && (defined(TARGET_AMD64) || defined(TARGET_X86)) && !defined(TARGET_UNIX) -// ***************************************************************************** -// JitHelperLogging usage: -// 1) Ngen using: -// DOTNET_HardPrejitEnabled=0 -// -// This allows us to instrument even ngen'd image calls to JIT helpers. -// Remember to clear the key after ngen-ing and before actually running -// the app you want to log. -// -// 2) Then set: -// DOTNET_JitHelperLogging=1 -// DOTNET_LogEnable=1 -// DOTNET_LogLevel=1 -// DOTNET_LogToFile=1 -// -// 3) Run the app that you want to log; Results will be in COMPLUS.LOG(.X) -// -// 4) JitHelperLogging=2 and JitHelperLogging=3 result in different output -// as per code in WriteJitHelperCountToSTRESSLOG() below. -// ***************************************************************************** -void WriteJitHelperCountToSTRESSLOG() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - int jitHelperLoggingLevel = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHelperLogging); - if (jitHelperLoggingLevel != 0) - { - DWORD logFacility, logLevel; - - logFacility = LF_ALL; //LF_ALL/LL_ALWAYS is okay here only because this logging would normally - logLevel = LL_ALWAYS; // would never be turned on at all (used only for performance measurements) - - const int countPos = 60; - - STRESS_LOG0(logFacility, logLevel, "Writing Jit Helper COUNT table to log\n"); - - VMHELPCOUNTDEF* hlpFuncCount = hlpFuncCountTable; - while(hlpFuncCount < (hlpFuncCountTable + CORINFO_HELP_COUNT)) - { - const char* name; - LONG count; - - name = hlpFuncCount->helperName; - count = hlpFuncCount->count; - - int nameLen = 0; - switch (jitHelperLoggingLevel) - { - case 1: - // This will print a comma separated list: - // CORINFO_XXX_HELPER, 10 - // CORINFO_YYYY_HELPER, 11 - STRESS_LOG2(logFacility, logLevel, "%s, %d\n", name, count); - break; - - case 2: - // This will print a table like: - // CORINFO_XXX_HELPER 10 - // CORINFO_YYYY_HELPER 11 - if (hlpFuncCount->helperName != NULL) - nameLen = (int)strlen(name); - else - nameLen = (int)strlen("(null)"); - - if (nameLen < countPos) - { - char* buffer = new char[(countPos - nameLen) + 1]; - memset(buffer, (int)' ', (countPos-nameLen)); - buffer[(countPos - nameLen)] = '\0'; - STRESS_LOG3(logFacility, logLevel, "%s%s %d\n", name, buffer, count); - } - else - { - STRESS_LOG2(logFacility, logLevel, "%s %d\n", name, count); - } - break; - - case 3: - // This will print out the counts and the address range of the helper (if we know it) - // CORINFO_XXX_HELPER, 10, (0x12345678 -> 0x12345778) - // CORINFO_YYYY_HELPER, 11, (0x00011234 -> 0x00012234) - STRESS_LOG4(logFacility, logLevel, "%s, %d, (0x%p -> 0x%p)\n", name, count, hlpFuncCount->pfnRealHelper, ((LPBYTE)hlpFuncCount->pfnRealHelper + hlpFuncCount->helperSize)); - break; - - default: - STRESS_LOG1(logFacility, logLevel, "Unsupported JitHelperLogging mode (%d)\n", jitHelperLoggingLevel); - break; - } - - hlpFuncCount++; - } - } -} -// This will do the work to instrument the JIT helper table. -void InitJitHelperLogging() -{ - STANDARD_VM_CONTRACT; - - if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHelperLogging) != 0)) - { - -#ifdef TARGET_X86 - IMAGE_DOS_HEADER *pDOS = (IMAGE_DOS_HEADER *)GetClrModuleBase(); - _ASSERTE(pDOS->e_magic == VAL16(IMAGE_DOS_SIGNATURE) && pDOS->e_lfanew != 0); - - IMAGE_NT_HEADERS *pNT = (IMAGE_NT_HEADERS*)((LPBYTE)GetClrModuleBase() + VAL32(pDOS->e_lfanew)); -#ifdef HOST_64BIT - _ASSERTE(pNT->Signature == VAL32(IMAGE_NT_SIGNATURE) - && pNT->FileHeader.SizeOfOptionalHeader == VAL16(sizeof(IMAGE_OPTIONAL_HEADER64)) - && pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC) ); -#else - _ASSERTE(pNT->Signature == VAL32(IMAGE_NT_SIGNATURE) - && pNT->FileHeader.SizeOfOptionalHeader == VAL16(sizeof(IMAGE_OPTIONAL_HEADER32)) - && pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC) ); -#endif -#endif // TARGET_X86 - - // Make the static hlpFuncTable read/write for purposes of writing the logging thunks - DWORD dwOldProtect; - if (!ClrVirtualProtect((LPVOID)hlpFuncTable, (sizeof(VMHELPDEF) * CORINFO_HELP_COUNT), PAGE_EXECUTE_READWRITE, &dwOldProtect)) - { - ThrowLastError(); - } - - LoaderHeap* pHeap = SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap(); - - // iterate through the jit helper tables replacing helpers with logging thunks - // - // NOTE: if NGEN'd images were NGEN'd with hard binding on then static helper - // calls will NOT be instrumented. - VMHELPDEF* hlpFunc = const_cast(hlpFuncTable); - VMHELPCOUNTDEF* hlpFuncCount = hlpFuncCountTable; - while(hlpFunc < (hlpFuncTable + CORINFO_HELP_COUNT)) - { - if (hlpFunc->pfnHelper != NULL) - { - CPUSTUBLINKER sl; - CPUSTUBLINKER* pSl = &sl; - - if (((size_t)hlpFunc->pfnHelper - 1) > DYNAMIC_CORINFO_HELP_COUNT) - { - // While we're here initialize the table of VMHELPCOUNTDEF - // guys with info about this helper - hlpFuncCount->pfnRealHelper = hlpFunc->pfnHelper; - hlpFuncCount->helperName = hlpFunc->name; - hlpFuncCount->count = 0; -#ifdef TARGET_AMD64 - ULONGLONG uImageBase; - PT_RUNTIME_FUNCTION pFunctionEntry; - pFunctionEntry = RtlLookupFunctionEntry((ULONGLONG)hlpFunc->pfnHelper, &uImageBase, NULL); - - if (pFunctionEntry != NULL) - { - _ASSERTE((uImageBase + pFunctionEntry->BeginAddress) == (ULONGLONG)hlpFunc->pfnHelper); - hlpFuncCount->helperSize = pFunctionEntry->EndAddress - pFunctionEntry->BeginAddress; - } - else - { - hlpFuncCount->helperSize = 0; - } -#else // TARGET_X86 - // How do I get this for x86? - hlpFuncCount->helperSize = 0; -#endif // TARGET_AMD64 - - pSl->EmitJITHelperLoggingThunk(GetEEFuncEntryPoint(hlpFunc->pfnHelper), (LPVOID)hlpFuncCount); - Stub* pStub = pSl->Link(pHeap); - hlpFunc->pfnHelper = (void*)pStub->GetEntryPoint(); - } - else - { - _ASSERTE(((size_t)hlpFunc->pfnHelper - 1) >= 0 && - ((size_t)hlpFunc->pfnHelper - 1) < ARRAY_SIZE(hlpDynamicFuncTable)); - VMHELPDEF* dynamicHlpFunc = &hlpDynamicFuncTable[((size_t)hlpFunc->pfnHelper - 1)]; - - // While we're here initialize the table of VMHELPCOUNTDEF - // guys with info about this helper. There is only one table - // for the count dudes that contains info about both dynamic - // and static helpers. - -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:26001) // "Bounds checked above" -#endif /*_PREFAST_ */ - hlpFuncCount->pfnRealHelper = dynamicHlpFunc->pfnHelper; - hlpFuncCount->helperName = dynamicHlpFunc->name; - hlpFuncCount->count = 0; -#ifdef _PREFAST_ -#pragma warning(pop) -#endif /*_PREFAST_*/ - -#ifdef TARGET_AMD64 - ULONGLONG uImageBase; - PT_RUNTIME_FUNCTION pFunctionEntry; - pFunctionEntry = RtlLookupFunctionEntry((ULONGLONG)hlpFunc->pfnHelper, &uImageBase, NULL); - - if (pFunctionEntry != NULL) - { - _ASSERTE((uImageBase + pFunctionEntry->BeginAddress) == (ULONGLONG)hlpFunc->pfnHelper); - hlpFuncCount->helperSize = pFunctionEntry->EndAddress - pFunctionEntry->BeginAddress; - } - else - { - // if we can't get a function entry for this we'll just pretend the size is 0 - hlpFuncCount->helperSize = 0; - } -#else // TARGET_X86 - // Is the address in mscoree.dll at all? (All helpers are in - // mscoree.dll) - if (dynamicHlpFunc->pfnHelper >= (LPBYTE*)GetClrModuleBase() && dynamicHlpFunc->pfnHelper < (LPBYTE*)GetClrModuleBase() + VAL32(pNT->OptionalHeader.SizeOfImage)) - { - // See note above. How do I get the size on x86 for a static method? - hlpFuncCount->helperSize = 0; - } - else - { - Stub::RecoverStubAndSize((TADDR)dynamicHlpFunc->pfnHelper, (DWORD*)&hlpFuncCount->helperSize); - hlpFuncCount->helperSize -= sizeof(Stub); - } - -#endif // TARGET_AMD64 - - pSl->EmitJITHelperLoggingThunk(GetEEFuncEntryPoint(dynamicHlpFunc->pfnHelper), (LPVOID)hlpFuncCount); - Stub* pStub = pSl->Link(pHeap); - dynamicHlpFunc->pfnHelper = (void*)pStub->GetEntryPoint(); - } - } - - hlpFunc++; - hlpFuncCount++; - } - - // Restore original access rights to the static hlpFuncTable - ClrVirtualProtect((LPVOID)hlpFuncTable, (sizeof(VMHELPDEF) * CORINFO_HELP_COUNT), dwOldProtect, &dwOldProtect); - } - - return; } -#endif // _DEBUG && (TARGET_AMD64 || TARGET_X86) diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index f0c9e69e159e64..fba8a923b394d1 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -1022,23 +1022,6 @@ extern "C" const VMHELPDEF hlpFuncTable[CORINFO_HELP_COUNT]; #endif -#if defined(_DEBUG) && (defined(TARGET_AMD64) || defined(TARGET_X86)) && !defined(TARGET_UNIX) -typedef struct { - void* pfnRealHelper; - const char* helperName; - LONG count; - LONG helperSize; -} VMHELPCOUNTDEF; - -extern "C" VMHELPCOUNTDEF hlpFuncCountTable[CORINFO_HELP_COUNT+1]; - -void InitJitHelperLogging(); -void WriteJitHelperCountToSTRESSLOG(); -#else -inline void InitJitHelperLogging() { } -inline void WriteJitHelperCountToSTRESSLOG() { } -#endif - // enum for dynamically assigned helper calls enum DynamicCorInfoHelpFunc { #define JITHELPER(code, pfnHelper, binderId) diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index e4463d734e0640..09bcdbbf2b6332 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -1174,10 +1174,6 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) if (IsCollectible()) m_pLowFrequencyHeap = m_pHighFrequencyHeap; -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - m_pHighFrequencyHeap->m_fPermitStubsWithUnwindInfo = TRUE; -#endif - if (dwStaticsHeapReserveSize != 0) { m_pStaticsHeap = new (&m_StaticsHeapInstance) LoaderHeap(STATIC_FIELD_HEAP_RESERVE_SIZE, @@ -1201,10 +1197,6 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) initReservedMem += dwStubHeapReserveSize; -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - m_pStubHeap->m_fPermitStubsWithUnwindInfo = TRUE; -#endif - m_pPrecodeHeap = new (&m_PrecodeHeapInstance) CodeFragmentHeap(this, STUB_CODE_BLOCK_PRECODE); m_pNewStubPrecodeHeap = new (&m_NewStubPrecodeHeapInstance) LoaderHeap(2 * GetStubCodePageSize(), @@ -1387,20 +1379,12 @@ void LoaderAllocator::Terminate() if (m_pHighFrequencyHeap != NULL) { -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - UnregisterUnwindInfoInLoaderHeap(m_pHighFrequencyHeap); -#endif - m_pHighFrequencyHeap->~LoaderHeap(); m_pHighFrequencyHeap = NULL; } if (m_pStubHeap != NULL) { -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - UnregisterUnwindInfoInLoaderHeap(m_pStubHeap); -#endif - m_pStubHeap->~LoaderHeap(); m_pStubHeap = NULL; } diff --git a/src/coreclr/vm/loongarch64/cgencpu.h b/src/coreclr/vm/loongarch64/cgencpu.h index fd88ed65abffdb..10172f53583129 100644 --- a/src/coreclr/vm/loongarch64/cgencpu.h +++ b/src/coreclr/vm/loongarch64/cgencpu.h @@ -416,9 +416,7 @@ class StubLinkerCPU : public StubLinker void EmitMovConstant(IntReg Rd, UINT64 constant); void EmitJumpRegister(IntReg regTarget); void EmitMovReg(IntReg dest, IntReg source); - void EmitMovFloatReg(FloatReg Fd, FloatReg Fs); - void EmitSubImm(IntReg Rd, IntReg Rn, unsigned int value); void EmitAddImm(IntReg Rd, IntReg Rn, unsigned int value); void EmitLoadStoreRegPairImm(DWORD flags, IntReg Rt1, IntReg Rt2, IntReg Rn, int offset=0); @@ -426,11 +424,6 @@ class StubLinkerCPU : public StubLinker void EmitLoadStoreRegImm(DWORD flags, IntReg Rt, IntReg Rn, int offset=0, int log2Size = 3); -#if defined(TARGET_LOONGARCH64) - void EmitFloatLoadStoreRegImm(DWORD flags, FloatReg Ft, IntReg Xn, int offset=0); -#else - void EmitLoadStoreRegImm(DWORD flags, VecReg Vt, IntReg Xn, int offset=0); -#endif void EmitLoadFloatRegImm(FloatReg ft, IntReg base, int offset); }; diff --git a/src/coreclr/vm/loongarch64/stubs.cpp b/src/coreclr/vm/loongarch64/stubs.cpp index 17457d8c33d06c..8cb0892c801a0c 100644 --- a/src/coreclr/vm/loongarch64/stubs.cpp +++ b/src/coreclr/vm/loongarch64/stubs.cpp @@ -1225,18 +1225,6 @@ void StubLinkerCPU::EmitLoadStoreRegImm(DWORD flags, IntReg Rt, IntReg Rn, int o EmitLoadStoreRegImm(flags, (int)Rt, Rn, offset, FALSE, log2Size); } -void StubLinkerCPU::EmitFloatLoadStoreRegImm(DWORD flags, FloatReg Ft, IntReg Rn, int offset) -{ - BOOL isLoad = flags & 1; - if (isLoad) { - // fld.d(Ft, Rn, offset); - Emit32(emitIns_O_R_R_I(0xae, (int)Ft & 0x1f, Rn, offset)); - } else { - // fst.d(Ft, Rn, offset); - Emit32(emitIns_O_R_R_I(0xaf, (int)Ft & 0x1f, Rn, offset)); - } -} - void StubLinkerCPU::EmitLoadStoreRegImm(DWORD flags, int regNum, IntReg Rn, int offset, BOOL isVec, int log2Size) { _ASSERTE((log2Size & ~0x3ULL) == 0); @@ -1265,20 +1253,6 @@ void StubLinkerCPU::EmitMovReg(IntReg Rd, IntReg Rm) Emit32(0x03800000 | (Rm.reg << 5) | Rd.reg); } -void StubLinkerCPU::EmitMovFloatReg(FloatReg Fd, FloatReg Fs) -{ - // fmov.d fd, fs - Emit32(0x01149800 | Fd.reg | (Fs.reg << 5)); -} - -void StubLinkerCPU::EmitSubImm(IntReg Rd, IntReg Rn, unsigned int value) -{ - _ASSERTE(value <= 2047); - int tmp_value = -(int)value; - // addi.d(Rd, Rn, -value); - Emit32(0x02c00000 | (Rn.reg << 5) | Rd.reg | ((tmp_value & 0xfff)<<10)); -} - void StubLinkerCPU::EmitAddImm(IntReg Rd, IntReg Rn, unsigned int value) { _ASSERTE(value <= 2047); diff --git a/src/coreclr/vm/riscv64/cgencpu.h b/src/coreclr/vm/riscv64/cgencpu.h index c08f6a144f5562..1d7dec10ce889b 100644 --- a/src/coreclr/vm/riscv64/cgencpu.h +++ b/src/coreclr/vm/riscv64/cgencpu.h @@ -345,21 +345,6 @@ struct IntReg WORD Mask() const { return 1 << reg; } }; -struct FloatReg -{ - int reg; - FloatReg(int reg):reg(reg) - { - _ASSERTE(0 <= reg && reg < 32); - } - - operator int () { return reg; } - operator int () const { return reg; } - int operator == (FloatReg other) { return reg == other.reg; } - int operator != (FloatReg other) { return reg != other.reg; } - WORD Mask() const { return 1 << reg; } -}; - const IntReg RegSp = IntReg(2); const IntReg RegFp = IntReg(8); const IntReg RegRa = IntReg(1); @@ -392,19 +377,13 @@ class StubLinkerCPU : public StubLinker void EmitJumpRegister(IntReg regTarget); void EmitMovReg(IntReg dest, IntReg source); - void EmitSubImm(IntReg Xd, IntReg Xn, int value); void EmitAddImm(IntReg Xd, IntReg Xn, int value); void EmitSllImm(IntReg Xd, IntReg Xn, unsigned int value); void EmitLuImm(IntReg Xd, unsigned int value); void EmitLoad(IntReg dest, IntReg srcAddr, int offset = 0); - void EmitLoad(FloatReg dest, IntReg srcAddr, int offset = 0); void EmitStore(IntReg src, IntReg destAddr, int offset = 0); - void EmitStore(FloatReg src, IntReg destAddr, int offset = 0); - - void EmitProlog(unsigned short cIntRegArgs, unsigned short cFpRegArgs, unsigned short cbStackSpace = 0); - void EmitEpilog(); }; diff --git a/src/coreclr/vm/riscv64/stubs.cpp b/src/coreclr/vm/riscv64/stubs.cpp index 2d947b231eb9ca..ca242f9a101756 100644 --- a/src/coreclr/vm/riscv64/stubs.cpp +++ b/src/coreclr/vm/riscv64/stubs.cpp @@ -1104,117 +1104,6 @@ void StubLinkerCPU::EmitMovConstant(IntReg reg, UINT64 imm) } -void StubLinkerCPU::EmitProlog(unsigned short cIntRegArgs, unsigned short cFpRegArgs, unsigned short cbStackSpace) -{ - _ASSERTE(!m_fProlog); - - unsigned short numberOfEntriesOnStack = 2 + cIntRegArgs + cFpRegArgs; // 2 for fp, ra - - // Stack needs to be 16 byte aligned. Compute the required padding before saving it - unsigned short totalPaddedFrameSize = static_cast(ALIGN_UP(cbStackSpace + numberOfEntriesOnStack * sizeof(void*), 2 * sizeof(void*))); - // The padding is going to be applied to the local stack - cbStackSpace = totalPaddedFrameSize - numberOfEntriesOnStack * sizeof(void*); - - // Record the parameters of this prolog so that we can generate a matching epilog and unwind info. - DescribeProlog(cIntRegArgs, cFpRegArgs, cbStackSpace); - - - // N.B Despite the range of a jump with a sub sp is 4KB, we're limiting to 504 to save from emitting right prolog that's - // expressable in unwind codes efficiently. The largest offset in typical unwindinfo encodings that we use is 504. - // so allocations larger than 504 bytes would require setting the SP in multiple strides, which would complicate both - // prolog and epilog generation as well as unwindinfo generation. - _ASSERTE((totalPaddedFrameSize <= 504) && "NYI:RISCV64 Implement StubLinker prologs with larger than 504 bytes of frame size"); - if (totalPaddedFrameSize > 504) - COMPlusThrow(kNotSupportedException); - - // Here is how the stack would look like (Stack grows up) - // [Low Address] - // +------------+ - // SP -> | | <-+ - // : : | Stack Frame, (i.e outgoing arguments) including padding - // | | <-+ - // +------------+ - // | FP | - // +------------+ - // | RA | - // +------------+ - // | F10 | <-+ - // +------------+ | - // : : | Fp Args - // +------------+ | - // | F17 | <-+ - // +------------+ - // | X10 | <-+ - // +------------+ | - // : : | Int Args - // +------------+ | - // | X17 | <-+ - // +------------+ - // Old SP -> |[Stack Args]| - // [High Address] - - // Regarding the order of operations in the prolog and epilog; - // If the prolog and the epilog matches each other we can simplify emitting the unwind codes and save a few - // bytes of unwind codes by making prolog and epilog share the same unwind codes. - // In order to do that we need to make the epilog be the reverse of the prolog. - // But we wouldn't want to add restoring of the argument registers as that's completely unnecessary. - // Besides, saving argument registers cannot be expressed by the unwind code encodings. - // So, we'll push saving the argument registers to the very last in the prolog, skip restoring it in epilog, - // and also skip reporting it to the OS. - // - // Another bit that we can save is resetting the frame pointer. - // This is not necessary when the SP doesn't get modified beyond prolog and epilog. (i.e no alloca/localloc) - // And in that case we don't need to report setting up the FP either. - - // 1. Relocate SP - EmitSubImm(RegSp, RegSp, totalPaddedFrameSize); - - unsigned cbOffset = 2 * sizeof(void*) + cbStackSpace; // 2 is for fp, ra - - // 2. Store FP/RA - EmitStore(RegFp, RegSp, cbStackSpace); - EmitStore(RegRa, RegSp, cbStackSpace + sizeof(void*)); - - // 3. Set the frame pointer to the Canonical Frame Address or CFA, which is the stack pointer value on entry to the - // current procedure - EmitAddImm(RegFp, RegSp, totalPaddedFrameSize); - - // 4. Store floating point argument registers - _ASSERTE(cFpRegArgs <= 8); - for (unsigned short i = 0; i < cFpRegArgs; i++) - EmitStore(FloatReg(i + 10), RegSp, cbOffset + i * sizeof(void*)); - - // 5. Store int argument registers - cbOffset += cFpRegArgs * sizeof(void*); - _ASSERTE(cIntRegArgs <= 8); - for (unsigned short i = 0 ; i < cIntRegArgs; i++) - EmitStore(IntReg(i + 10), RegSp, cbOffset + i * sizeof(void*)); -} - -void StubLinkerCPU::EmitEpilog() -{ - _ASSERTE(m_fProlog); - - // 5. Restore int argument registers - // nop: We don't need to. They are scratch registers - - // 4. Restore floating point argument registers - // nop: We don't need to. They are scratch registers - - // 3. Restore the SP from FP - // N.B. We're assuming that the stublinker stubs doesn't do alloca, hence nop - - // 2. Restore FP/RA - EmitLoad(RegFp, RegSp, m_cbStackSpace); - EmitLoad(RegRa, RegSp, m_cbStackSpace + sizeof(void*)); - - // 1. Restore SP - EmitAddImm(RegSp, RegSp, GetStackFrameSize()); - - // jalr x0, 0(ra) - EmitJumpRegister(RegRa); -} - // Instruction types as per RISC-V Spec, Chapter 24 RV32/64G Instruction Set Listings static unsigned ITypeInstr(unsigned opcode, unsigned funct3, unsigned rd, unsigned rs1, int imm12) { @@ -1300,31 +1189,17 @@ void StubLinkerCPU::EmitLoad(IntReg dest, IntReg srcAddr, int offset) Emit32(ITypeInstr(0x3, 0x3, dest, srcAddr, offset)); // ld LOG((LF_STUBS, LL_EVERYTHING, "ld %s, %i(%s)\n", intRegAbiNames[dest], offset, intRegAbiNames[srcAddr])); } -void StubLinkerCPU::EmitLoad(FloatReg dest, IntReg srcAddr, int offset) -{ - Emit32(ITypeInstr(0x7, 0x3, dest, srcAddr, offset)); // fld - LOG((LF_STUBS, LL_EVERYTHING, "fld %s, %i(%s)\n", fpRegAbiNames[dest], offset, intRegAbiNames[srcAddr])); -} void StubLinkerCPU:: EmitStore(IntReg src, IntReg destAddr, int offset) { Emit32(STypeInstr(0x23, 0x3, destAddr, src, offset)); // sd LOG((LF_STUBS, LL_EVERYTHING, "sd %s, %i(%s)\n", intRegAbiNames[src], offset, intRegAbiNames[destAddr])); } -void StubLinkerCPU::EmitStore(FloatReg src, IntReg destAddr, int offset) -{ - Emit32(STypeInstr(0x27, 0x3, destAddr, src, offset)); // fsd - LOG((LF_STUBS, LL_EVERYTHING, "fsd %s, %i(%s)\n", fpRegAbiNames[src], offset, intRegAbiNames[destAddr])); -} void StubLinkerCPU::EmitMovReg(IntReg Xd, IntReg Xm) { EmitAddImm(Xd, Xm, 0); } -void StubLinkerCPU::EmitSubImm(IntReg Xd, IntReg Xn, int value) -{ - EmitAddImm(Xd, Xn, -value); -} void StubLinkerCPU::EmitAddImm(IntReg Xd, IntReg Xn, int value) { Emit32(ITypeInstr(0x13, 0, Xd, Xn, value)); // addi diff --git a/src/coreclr/vm/rtlfunctions.cpp b/src/coreclr/vm/rtlfunctions.cpp index 0e77e31a02d162..65642ee3c891c7 100644 --- a/src/coreclr/vm/rtlfunctions.cpp +++ b/src/coreclr/vm/rtlfunctions.cpp @@ -57,13 +57,14 @@ HRESULT EnsureRtlFunctions() #ifndef HOST_X86 +#define DYNAMIC_FUNCTION_TABLE_MAX_RANGE INT32_MAX + VOID InstallEEFunctionTable ( PVOID pvTableID, PVOID pvStartRange, ULONG cbRange, PGET_RUNTIME_FUNCTION_CALLBACK pfnGetRuntimeFunctionCallback, - PVOID pvContext, - EEDynamicFunctionTableType TableType) + PVOID pvContext) { CONTRACTL { @@ -120,7 +121,7 @@ VOID InstallEEFunctionTable ( (ULONG_PTR)pvStartRange, cbRange, pfnGetRuntimeFunctionCallback, - EncodeDynamicFunctionTableContext(pvContext, TableType), + pvContext, wszModuleName)) { COMPlusThrowOM(); diff --git a/src/coreclr/vm/rtlfunctions.h b/src/coreclr/vm/rtlfunctions.h index ef0f64cba9dbdf..7a981248d8fc70 100644 --- a/src/coreclr/vm/rtlfunctions.h +++ b/src/coreclr/vm/rtlfunctions.h @@ -6,48 +6,6 @@ #ifndef __RTLFUNCTIONS_H__ #define __RTLFUNCTIONS_H__ -#ifdef FEATURE_EH_FUNCLETS - -enum EEDynamicFunctionTableType -{ - DYNFNTABLE_JIT = 0, - DYNFNTABLE_STUB = 1, - DYNFNTABLE_INVALID = -1, - - DYNFNTABLE_FIRST = DYNFNTABLE_JIT, - DYNFNTABLE_LAST = DYNFNTABLE_STUB, -}; - -// Used by OutOfProcessFunctionTableCallback in DLLS\mscordbg\DebugSupport.cpp -// to figure out how to parse a dynamic function table that was registered -// with a callback. -inline -EEDynamicFunctionTableType IdentifyDynamicFunctionTableTypeFromContext (PVOID pvContext) -{ - EEDynamicFunctionTableType type = (EEDynamicFunctionTableType)((SIZE_T)pvContext & 3); - if (type < DYNFNTABLE_FIRST || type > DYNFNTABLE_LAST) - type = DYNFNTABLE_INVALID; - return type; -} - -inline -PVOID EncodeDynamicFunctionTableContext (PVOID pvContext, EEDynamicFunctionTableType type) -{ - _ASSERTE(type >= DYNFNTABLE_FIRST && type <= DYNFNTABLE_LAST); - return (PVOID)((SIZE_T)pvContext | type); -} - -inline -PVOID DecodeDynamicFunctionTableContext (PVOID pvContext) -{ - return (PVOID)((SIZE_T)pvContext & ~3); -} - - -#define DYNAMIC_FUNCTION_TABLE_MAX_RANGE INT32_MAX - -#endif // FEATURE_EH_FUNCLETS - #if !defined(DACCESS_COMPILE) && defined(HOST_WINDOWS) && !defined(HOST_X86) @@ -57,8 +15,7 @@ VOID InstallEEFunctionTable( PVOID pvStartRange, ULONG cbRange, PGET_RUNTIME_FUNCTION_CALLBACK pfnGetRuntimeFunctionCallback, - PVOID pvContext, - EEDynamicFunctionTableType TableType); + PVOID pvContext); inline VOID DeleteEEFunctionTable( @@ -69,7 +26,7 @@ VOID DeleteEEFunctionTable( #else -#define InstallEEFunctionTable(pvTableID, pvStartRange, cbRange, pfnGetRuntimeFunctionCallback, pvContext, TableType) do { } while (0) +#define InstallEEFunctionTable(pvTableID, pvStartRange, cbRange, pfnGetRuntimeFunctionCallback, pvContext) do { } while (0) #define DeleteEEFunctionTable(pvTableID) do { } while (0) #endif diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index 317fe2c592d1c3..f1207eb6975691 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -86,250 +86,15 @@ struct LabelRef : public CodeElement LabelRef *m_nextLabelRef; }; - -//************************************************************************ -// IntermediateUnwindInfo -//************************************************************************ - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - - -#ifdef TARGET_AMD64 -// List of unwind operations, queued in StubLinker::m_pUnwindInfoList. -struct IntermediateUnwindInfo -{ - IntermediateUnwindInfo *pNext; - CodeRun *pCodeRun; - UINT LocalOffset; - UNWIND_CODE rgUnwindCode[1]; // variable length, depends on first entry's UnwindOp -}; -#endif // TARGET_AMD64 - - -StubUnwindInfoHeapSegment *g_StubHeapSegments; -CrstStatic g_StubUnwindInfoHeapSegmentsCrst; -#ifdef _DEBUG // for unit test -void *__DEBUG__g_StubHeapSegments = &g_StubHeapSegments; -#endif - - -// -// Callback registered via RtlInstallFunctionTableCallback. Called by -// RtlpLookupDynamicFunctionEntry to locate RUNTIME_FUNCTION entry for a PC -// found within a portion of a heap that contains stub code. -// -T_RUNTIME_FUNCTION* -FindStubFunctionEntry ( - BIT64_ONLY(IN ULONG64 ControlPc) - NOT_BIT64(IN ULONG ControlPc), - IN PVOID Context - ) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - FORBID_FAULT; - } - CONTRACTL_END - - CONSISTENCY_CHECK(DYNFNTABLE_STUB == IdentifyDynamicFunctionTableTypeFromContext(Context)); - - StubUnwindInfoHeapSegment *pStubHeapSegment = (StubUnwindInfoHeapSegment*)DecodeDynamicFunctionTableContext(Context); - - // - // The RUNTIME_FUNCTION entry contains ULONG offsets relative to the - // segment base. Stub::EmitUnwindInfo ensures that this cast is valid. - // - ULONG RelativeAddress = (ULONG)((BYTE*)ControlPc - pStubHeapSegment->pbBaseAddress); - - LOG((LF_STUBS, LL_INFO100000, "ControlPc %p, RelativeAddress 0x%x, pStubHeapSegment %p, pStubHeapSegment->pbBaseAddress %p\n", - ControlPc, - RelativeAddress, - pStubHeapSegment, - pStubHeapSegment->pbBaseAddress)); - - // - // Search this segment's list of stubs for an entry that includes the - // segment-relative offset. - // - for (StubUnwindInfoHeader *pHeader = pStubHeapSegment->pUnwindHeaderList; - pHeader; - pHeader = pHeader->pNext) - { - // The entry points are in increasing address order. - if (RelativeAddress >= RUNTIME_FUNCTION__BeginAddress(&pHeader->FunctionEntry)) - { - T_RUNTIME_FUNCTION *pCurFunction = &pHeader->FunctionEntry; - T_RUNTIME_FUNCTION *pPrevFunction = NULL; - - LOG((LF_STUBS, LL_INFO100000, "pCurFunction %p, pCurFunction->BeginAddress 0x%x, pCurFunction->EndAddress 0x%x\n", - pCurFunction, - RUNTIME_FUNCTION__BeginAddress(pCurFunction), - RUNTIME_FUNCTION__EndAddress(pCurFunction, (TADDR)pStubHeapSegment->pbBaseAddress))); - - CONSISTENCY_CHECK((RUNTIME_FUNCTION__EndAddress(pCurFunction, (TADDR)pStubHeapSegment->pbBaseAddress) > RUNTIME_FUNCTION__BeginAddress(pCurFunction))); - CONSISTENCY_CHECK((!pPrevFunction || RUNTIME_FUNCTION__EndAddress(pPrevFunction, (TADDR)pStubHeapSegment->pbBaseAddress) <= RUNTIME_FUNCTION__BeginAddress(pCurFunction))); - - // The entry points are in increasing address order. They're - // also contiguous, so after we're sure it's after the start of - // the first function (checked above), we only need to test - // the end address. - if (RelativeAddress < RUNTIME_FUNCTION__EndAddress(pCurFunction, (TADDR)pStubHeapSegment->pbBaseAddress)) - { - CONSISTENCY_CHECK((RelativeAddress >= RUNTIME_FUNCTION__BeginAddress(pCurFunction))); - - return pCurFunction; - } - } - } - - // - // Return NULL to indicate that there is no RUNTIME_FUNCTION/unwind - // information for this offset. - // - return NULL; -} - - -bool UnregisterUnwindInfoInLoaderHeapCallback (PVOID pvArgs, PVOID pvAllocationBase, SIZE_T cbReserved) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - - // - // There may be multiple StubUnwindInfoHeapSegment's associated with a region. - // - - LOG((LF_STUBS, LL_INFO1000, "Looking for stub unwind info for LoaderHeap segment %p size %p\n", pvAllocationBase, cbReserved)); - - CrstHolder crst(&g_StubUnwindInfoHeapSegmentsCrst); - - StubUnwindInfoHeapSegment *pStubHeapSegment; - for (StubUnwindInfoHeapSegment **ppPrevStubHeapSegment = &g_StubHeapSegments; - (pStubHeapSegment = *ppPrevStubHeapSegment); ) - { - LOG((LF_STUBS, LL_INFO10000, " have unwind info for address %p size %p\n", pStubHeapSegment->pbBaseAddress, pStubHeapSegment->cbSegment)); - - // If heap region ends before stub segment - if ((BYTE*)pvAllocationBase + cbReserved <= pStubHeapSegment->pbBaseAddress) - { - // The list is ordered, so address range is between segments - break; - } - - // The given heap segment base address may fall within a prereserved - // region that was given to the heap when the heap was constructed, so - // pvAllocationBase may be > pbBaseAddress. Also, there could be - // multiple segments for each heap region, so pvAllocationBase may be - // < pbBaseAddress. So...there is no meaningful relationship between - // pvAllocationBase and pbBaseAddress. - - // If heap region starts before end of stub segment - if ((BYTE*)pvAllocationBase < pStubHeapSegment->pbBaseAddress + pStubHeapSegment->cbSegment) - { - _ASSERTE((BYTE*)pvAllocationBase + cbReserved <= pStubHeapSegment->pbBaseAddress + pStubHeapSegment->cbSegment); - - DeleteEEFunctionTable(pStubHeapSegment); -#ifdef TARGET_AMD64 - if (pStubHeapSegment->pUnwindInfoTable != 0) - delete pStubHeapSegment->pUnwindInfoTable; -#endif - *ppPrevStubHeapSegment = pStubHeapSegment->pNext; - - delete pStubHeapSegment; - } - else - { - ppPrevStubHeapSegment = &pStubHeapSegment->pNext; - } - } - - return false; // Keep enumerating -} - - -VOID UnregisterUnwindInfoInLoaderHeap (UnlockedLoaderHeap *pHeap) +#ifdef TARGET_ARM +void StubLinker::DescribeProlog(UINT cCalleeSavedRegs, UINT cbStackFrame, BOOL fPushArgRegs) { - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - PRECONDITION(pHeap->m_fPermitStubsWithUnwindInfo); - } - CONTRACTL_END; - - pHeap->EnumPageRegions(&UnregisterUnwindInfoInLoaderHeapCallback, NULL /* pvArgs */); - -#ifdef _DEBUG - pHeap->m_fStubUnwindInfoUnregistered = TRUE; -#endif // _DEBUG + m_fProlog = TRUE; + m_cCalleeSavedRegs = cCalleeSavedRegs; + m_cbStackFrame = cbStackFrame; + m_fPushArgRegs = fPushArgRegs; } - - -class StubUnwindInfoSegmentBoundaryReservationList -{ - struct ReservationList - { - ReservationList *pNext; - - static ReservationList *FromStub (Stub *pStub) - { - return (ReservationList*)(pStub+1); - } - - Stub *GetStub () - { - return (Stub*)this - 1; - } - }; - - ReservationList *m_pList; - -public: - - StubUnwindInfoSegmentBoundaryReservationList () - { - LIMITED_METHOD_CONTRACT; - - m_pList = NULL; - } - - ~StubUnwindInfoSegmentBoundaryReservationList () - { - LIMITED_METHOD_CONTRACT; - - ReservationList *pList = m_pList; - while (pList) - { - ReservationList *pNext = pList->pNext; - - ExecutableWriterHolder stubWriterHolder(pList->GetStub(), sizeof(Stub)); - stubWriterHolder.GetRW()->DecRef(); - - pList = pNext; - } - } - - void AddStub (Stub *pStub) - { - LIMITED_METHOD_CONTRACT; - - ReservationList *pList = ReservationList::FromStub(pStub); - - ExecutableWriterHolder listWriterHolder(pList, sizeof(ReservationList)); - listWriterHolder.GetRW()->pNext = m_pList; - m_pList = pList; - } -}; - - -#endif // STUBLINKER_GENERATES_UNWIND_INFO - +#endif // TARGET_ARM //************************************************************************ // StubLinker @@ -359,29 +124,6 @@ StubLinker::StubLinker() m_cbStackFrame = 0; m_fPushArgRegs = FALSE; #endif -#ifdef TARGET_RISCV64 - m_fProlog = FALSE; - m_cIntRegArgs = 0; - m_cFpRegArgs = 0; - m_cbStackSpace = 0; -#endif -#ifdef STUBLINKER_GENERATES_UNWIND_INFO -#ifdef _DEBUG - m_pUnwindInfoCheckLabel = NULL; -#endif -#ifdef TARGET_AMD64 - m_pUnwindInfoList = NULL; - m_nUnwindSlots = 0; - m_fHaveFramePointer = FALSE; -#endif -#ifdef TARGET_ARM64 - m_fProlog = FALSE; - m_cIntRegArgs = 0; - m_cVecRegArgs = 0; - m_cCalleeSavedRegs = 0; - m_cbStackSpace = 0; -#endif -#endif // STUBLINKER_GENERATES_UNWIND_INFO } @@ -825,40 +567,13 @@ Stub *StubLinker::Link(LoaderHeap *pHeap, DWORD flags) _ASSERTE(!pHeap || pHeap->IsExecutable()); - StubHolder pStub; - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - StubUnwindInfoSegmentBoundaryReservationList ReservedStubs; - - for (;;) -#endif - { - pStub = Stub::NewStub( + StubHolder pStub = Stub::NewStub( pHeap, size, - flags -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - , UnwindInfoSize(globalsize) -#endif - ); - ASSERT(pStub != NULL); - - bool fSuccess = EmitStub(pStub, globalsize, size, pHeap); + flags); + ASSERT(pStub != NULL); -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - if (fSuccess) - { - break; - } - else - { - ReservedStubs.AddStub(pStub); - pStub.SuppressRelease(); - } -#else - CONSISTENCY_CHECK_MSG(fSuccess, ("EmitStub should always return true")); -#endif - } + EmitStub(pStub, globalsize, size, pHeap); return pStub.Extract(); } @@ -874,15 +589,6 @@ int StubLinker::CalculateSize(int* pGlobalSize) _ASSERTE(pGlobalSize); -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - if (m_pUnwindInfoCheckLabel) - { - EmitLabel(m_pUnwindInfoCheckLabel); - EmitUnwindInfoCheckSubfunction(); - m_pUnwindInfoCheckLabel = NULL; - } -#endif - #ifdef _DEBUG // Don't want any undefined labels for (CodeLabel *pCodeLabel = m_pFirstCodeLabel; @@ -1004,7 +710,7 @@ int StubLinker::CalculateSize(int* pGlobalSize) return globalsize + datasize; } -bool StubLinker::EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap) +void StubLinker::EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap) { STANDARD_VM_CONTRACT; @@ -1088,805 +794,13 @@ bool StubLinker::EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap pStub->GetInstantiatedMethodDesc())); } -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - if (pStub->HasUnwindInfo()) - { - if (!EmitUnwindInfo(pStub, pStubRW, globalsize, pHeap)) - return false; - } -#endif // STUBLINKER_GENERATES_UNWIND_INFO - if (!m_fDataOnly) { FlushInstructionCache(GetCurrentProcess(), pCode, globalsize); } _ASSERTE(m_fDataOnly || DbgIsExecutable(pCode, globalsize)); - - return true; -} - - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO -#if defined(TARGET_AMD64) - -// See RtlVirtualUnwind in base\ntos\rtl\amd64\exdsptch.c - -static_assert_no_msg(kRAX == (offsetof(CONTEXT, Rax) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kRCX == (offsetof(CONTEXT, Rcx) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kRDX == (offsetof(CONTEXT, Rdx) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kRBX == (offsetof(CONTEXT, Rbx) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kRBP == (offsetof(CONTEXT, Rbp) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kRSI == (offsetof(CONTEXT, Rsi) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kRDI == (offsetof(CONTEXT, Rdi) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kR8 == (offsetof(CONTEXT, R8 ) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kR9 == (offsetof(CONTEXT, R9 ) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kR10 == (offsetof(CONTEXT, R10) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kR11 == (offsetof(CONTEXT, R11) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kR12 == (offsetof(CONTEXT, R12) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kR13 == (offsetof(CONTEXT, R13) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kR14 == (offsetof(CONTEXT, R14) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); -static_assert_no_msg(kR15 == (offsetof(CONTEXT, R15) - offsetof(CONTEXT, Rax)) / sizeof(ULONG64)); - -VOID StubLinker::UnwindSavedReg (UCHAR reg, ULONG SPRelativeOffset) -{ - USHORT FrameOffset = (USHORT)(SPRelativeOffset / 8); - - if ((ULONG)FrameOffset == SPRelativeOffset) - { - UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_SAVE_NONVOL); - pUnwindCode->OpInfo = reg; - pUnwindCode[1].FrameOffset = FrameOffset; - } - else - { - UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_SAVE_NONVOL_FAR); - pUnwindCode->OpInfo = reg; - pUnwindCode[1].FrameOffset = (USHORT)SPRelativeOffset; - pUnwindCode[2].FrameOffset = (USHORT)(SPRelativeOffset >> 16); - } -} - -VOID StubLinker::UnwindPushedReg (UCHAR reg) -{ - m_stackSize += sizeof(void*); - - if (m_fHaveFramePointer) - return; - - UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_PUSH_NONVOL); - pUnwindCode->OpInfo = reg; -} - -VOID StubLinker::UnwindAllocStack (SHORT FrameSizeIncrement) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - if (! ClrSafeInt::addition(m_stackSize, FrameSizeIncrement, m_stackSize)) - COMPlusThrowArithmetic(); - - if (m_fHaveFramePointer) - return; - - UCHAR OpInfo = (UCHAR)((FrameSizeIncrement - 8) / 8); - - if (OpInfo*8 + 8 == FrameSizeIncrement) - { - UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_ALLOC_SMALL); - pUnwindCode->OpInfo = OpInfo; - } - else - { - USHORT FrameOffset = (USHORT)FrameSizeIncrement; - bool fNeedExtraSlot = ((ULONG)FrameOffset != (ULONG)FrameSizeIncrement); - - UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_ALLOC_LARGE, fNeedExtraSlot ? 1 : 0); - - pUnwindCode->OpInfo = fNeedExtraSlot ? 1 : 0; - - pUnwindCode[1].FrameOffset = FrameOffset; - - if (fNeedExtraSlot) - pUnwindCode[2].FrameOffset = (USHORT)(FrameSizeIncrement >> 16); - } -} - -VOID StubLinker::UnwindSetFramePointer (UCHAR reg) -{ - _ASSERTE(!m_fHaveFramePointer); - - UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_SET_FPREG); - pUnwindCode->OpInfo = reg; - - m_fHaveFramePointer = TRUE; -} - -UNWIND_CODE *StubLinker::AllocUnwindInfo (UCHAR Op, UCHAR nExtraSlots /*= 0*/) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - _ASSERTE(Op < sizeof(UnwindOpExtraSlotTable)); - - UCHAR nSlotsAlloc = UnwindOpExtraSlotTable[Op] + nExtraSlots; - - IntermediateUnwindInfo *pUnwindInfo = (IntermediateUnwindInfo*)m_quickHeap.Alloc( sizeof(IntermediateUnwindInfo) - + nSlotsAlloc * sizeof(UNWIND_CODE)); - m_nUnwindSlots += 1 + nSlotsAlloc; - - pUnwindInfo->pNext = m_pUnwindInfoList; - m_pUnwindInfoList = pUnwindInfo; - - UNWIND_CODE *pUnwindCode = &pUnwindInfo->rgUnwindCode[0]; - - pUnwindCode->UnwindOp = Op; - - CodeRun *pCodeRun = GetLastCodeRunIfAny(); - _ASSERTE(pCodeRun != NULL); - - pUnwindInfo->pCodeRun = pCodeRun; - pUnwindInfo->LocalOffset = pCodeRun->m_numcodebytes; - - EmitUnwindInfoCheck(); - - return pUnwindCode; } -#endif // defined(TARGET_AMD64) - -struct FindBlockArgs -{ - BYTE *pCode; - BYTE *pBlockBase; - SIZE_T cbBlockSize; -}; - -bool FindBlockCallback (PTR_VOID pvArgs, PTR_VOID pvAllocationBase, SIZE_T cbReserved) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - - FindBlockArgs* pArgs = (FindBlockArgs*)pvArgs; - if (pArgs->pCode >= pvAllocationBase && (pArgs->pCode < ((BYTE *)pvAllocationBase + cbReserved))) - { - pArgs->pBlockBase = (BYTE*)pvAllocationBase; - pArgs->cbBlockSize = cbReserved; - return true; - } - - return false; -} - -bool StubLinker::EmitUnwindInfo(Stub* pStubRX, Stub* pStubRW, int globalsize, LoaderHeap* pHeap) -{ - STANDARD_VM_CONTRACT; - - BYTE *pCode = (BYTE*)(pStubRX->GetEntryPoint()); - - // - // Determine the lower bound of the address space containing the stub. - // - - FindBlockArgs findBlockArgs; - findBlockArgs.pCode = pCode; - findBlockArgs.pBlockBase = NULL; - - pHeap->EnumPageRegions(&FindBlockCallback, &findBlockArgs); - - if (findBlockArgs.pBlockBase == NULL) - { - // REVISIT_TODO better exception - COMPlusThrowOM(); - } - - BYTE *pbRegionBaseAddress = findBlockArgs.pBlockBase; - -#ifdef _DEBUG - static SIZE_T MaxSegmentSize = -1; - if (MaxSegmentSize == (SIZE_T)-1) - MaxSegmentSize = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MaxStubUnwindInfoSegmentSize, DYNAMIC_FUNCTION_TABLE_MAX_RANGE); -#else - const SIZE_T MaxSegmentSize = DYNAMIC_FUNCTION_TABLE_MAX_RANGE; -#endif - - // - // The RUNTIME_FUNCTION offsets are ULONGs. If the region size is > - // UINT32_MAX, then we'll shift the base address to the next 4gb and - // register a separate function table. - // - // But...RtlInstallFunctionTableCallback has a 2gb restriction...so - // make that INT32_MAX. - // - - StubUnwindInfoHeader *pHeaderRW = pStubRW->GetUnwindInfoHeader(); - StubUnwindInfoHeader *pHeaderRX = pStubRX->GetUnwindInfoHeader(); - _ASSERTE(IS_ALIGNED(pHeaderRW, sizeof(void*))); - - BYTE *pbBaseAddressRX = pbRegionBaseAddress; - BYTE *pbBaseAddressRW = (BYTE*)((uint64_t)pbRegionBaseAddress + (uint64_t)pHeaderRW - (uint64_t)pHeaderRX); - - while ((size_t)((BYTE*)pHeaderRX - pbBaseAddressRX) > MaxSegmentSize) - { - pbBaseAddressRX += MaxSegmentSize; - pbBaseAddressRW += MaxSegmentSize; - } - - // - // If the unwind info/code straddle a 2gb boundary, then we're stuck. - // Rather than add a lot more bit twiddling code to deal with this - // exceptionally rare case, we'll signal the caller to keep this allocation - // temporarily and allocate another. This repeats until we eventually get - // an allocation that doesn't straddle a 2gb boundary. Afterwards the old - // allocations are freed. - // - - if ((size_t)(pCode + globalsize - pbBaseAddressRX) > MaxSegmentSize) - { - return false; - } - - // Ensure that the first RUNTIME_FUNCTION struct ends up pointer aligned, - // so that the StubUnwindInfoHeader struct is aligned. UNWIND_INFO - // includes one UNWIND_CODE. - _ASSERTE(IS_ALIGNED(pStubRX, sizeof(void*))); - _ASSERTE(0 == (offsetof(StubUnwindInfoHeader, FunctionEntry) % sizeof(void*))); - - StubUnwindInfoHeader * pUnwindInfoHeader = pStubRW->GetUnwindInfoHeader(); - -#ifdef TARGET_AMD64 - - UNWIND_CODE *pDestUnwindCode = &pUnwindInfoHeader->UnwindInfo.UnwindCode[0]; -#ifdef _DEBUG - UNWIND_CODE *pDestUnwindCodeLimit = (UNWIND_CODE*)pStubRW->GetUnwindInfoHeaderSuffix(); -#endif - - UINT FrameRegister = 0; - - // - // Resolve the unwind operation offsets, and fill in the UNWIND_INFO and - // RUNTIME_FUNCTION structs preceding the stub. The unwind codes are recorded - // in decreasing address order. - // - - for (IntermediateUnwindInfo *pUnwindInfoList = m_pUnwindInfoList; pUnwindInfoList != NULL; pUnwindInfoList = pUnwindInfoList->pNext) - { - UNWIND_CODE *pUnwindCode = &pUnwindInfoList->rgUnwindCode[0]; - UCHAR op = pUnwindCode[0].UnwindOp; - - if (UWOP_SET_FPREG == op) - { - FrameRegister = pUnwindCode[0].OpInfo; - } - - // - // Compute number of slots used by this encoding. - // - - UINT nSlots; - - if (UWOP_ALLOC_LARGE == op) - { - nSlots = 2 + pUnwindCode[0].OpInfo; - } - else - { - _ASSERTE(UnwindOpExtraSlotTable[op] != (UCHAR)-1); - nSlots = 1 + UnwindOpExtraSlotTable[op]; - } - - // - // Compute offset and ensure that it will fit in the encoding. - // - - SIZE_T CodeOffset = pUnwindInfoList->pCodeRun->m_globaloffset - + pUnwindInfoList->LocalOffset; - - if (CodeOffset != (SIZE_T)(UCHAR)CodeOffset) - { - // REVISIT_TODO better exception - COMPlusThrowOM(); - } - - // - // Copy the encoding data, overwrite the new offset, and advance - // to the next encoding. - // - - _ASSERTE(pDestUnwindCode + nSlots <= pDestUnwindCodeLimit); - - CopyMemory(pDestUnwindCode, pUnwindCode, nSlots * sizeof(UNWIND_CODE)); - - pDestUnwindCode->CodeOffset = (UCHAR)CodeOffset; - - pDestUnwindCode += nSlots; - } - - // - // Fill in the UNWIND_INFO struct - // - UNWIND_INFO *pUnwindInfo = &pUnwindInfoHeader->UnwindInfo; - _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG))); - - // PrologueSize may be 0 if all unwind directives at offset 0. - SIZE_T PrologueSize = m_pUnwindInfoList->pCodeRun->m_globaloffset - + m_pUnwindInfoList->LocalOffset; - - UINT nEntryPointSlots = m_nUnwindSlots; - - if ( PrologueSize != (SIZE_T)(UCHAR)PrologueSize - || nEntryPointSlots > UCHAR_MAX) - { - // REVISIT_TODO better exception - COMPlusThrowOM(); - } - - _ASSERTE(nEntryPointSlots); - - pUnwindInfo->Version = 1; - pUnwindInfo->Flags = 0; - pUnwindInfo->SizeOfProlog = (UCHAR)PrologueSize; - pUnwindInfo->CountOfUnwindCodes = (UCHAR)nEntryPointSlots; - pUnwindInfo->FrameRegister = FrameRegister; - pUnwindInfo->FrameOffset = 0; - - // - // Fill in the RUNTIME_FUNCTION struct for this prologue. - // - PT_RUNTIME_FUNCTION pCurFunction = &pUnwindInfoHeader->FunctionEntry; - _ASSERTE(IS_ALIGNED(pCurFunction, sizeof(ULONG))); - - S_UINT32 sBeginAddress = S_BYTEPTR(pCode) - S_BYTEPTR(pbBaseAddressRX); - if (sBeginAddress.IsOverflow()) - COMPlusThrowArithmetic(); - pCurFunction->BeginAddress = sBeginAddress.Value(); - - S_UINT32 sEndAddress = S_BYTEPTR(pCode) + S_BYTEPTR(globalsize) - S_BYTEPTR(pbBaseAddressRX); - if (sEndAddress.IsOverflow()) - COMPlusThrowArithmetic(); - pCurFunction->EndAddress = sEndAddress.Value(); - - S_UINT32 sTemp = S_BYTEPTR(pUnwindInfo) - S_BYTEPTR(pbBaseAddressRW); - if (sTemp.IsOverflow()) - COMPlusThrowArithmetic(); - RUNTIME_FUNCTION__SetUnwindInfoAddress(pCurFunction, sTemp.Value()); -#elif defined(TARGET_ARM) - // - // Fill in the RUNTIME_FUNCTION struct for this prologue. - // - UNWIND_INFO *pUnwindInfo = &pUnwindInfoHeader->UnwindInfo; - - PT_RUNTIME_FUNCTION pCurFunction = &pUnwindInfoHeader->FunctionEntry; - _ASSERTE(IS_ALIGNED(pCurFunction, sizeof(ULONG))); - - S_UINT32 sBeginAddress = S_BYTEPTR(pCode) - S_BYTEPTR(pbBaseAddressRX); - if (sBeginAddress.IsOverflow()) - COMPlusThrowArithmetic(); - RUNTIME_FUNCTION__SetBeginAddress(pCurFunction, sBeginAddress.Value()); - - S_UINT32 sTemp = S_BYTEPTR(pUnwindInfo) - S_BYTEPTR(pbBaseAddressRW); - if (sTemp.IsOverflow()) - COMPlusThrowArithmetic(); - RUNTIME_FUNCTION__SetUnwindInfoAddress(pCurFunction, sTemp.Value()); - - //Get the exact function Length. Cannot use globalsize as it is explicitly made to be - // 4 byte aligned - CodeRun *pLastCodeElem = GetLastCodeRunIfAny(); - _ASSERTE(pLastCodeElem != NULL); - - int functionLength = pLastCodeElem->m_numcodebytes + pLastCodeElem->m_globaloffset; - - // cannot encode functionLength greater than (2 * 0xFFFFF) - if (functionLength > 2 * 0xFFFFF) - COMPlusThrowArithmetic(); - - _ASSERTE(functionLength <= globalsize); - - BYTE * pUnwindCodes = (BYTE *)pUnwindInfo + sizeof(DWORD); - - // Not emitting compact unwind info as there are very few (4) dynamic stubs with unwind info. - // Benefit of the optimization does not outweigh the cost of adding the code for it. - - //UnwindInfo for prolog - if (m_cbStackFrame != 0) - { - if(m_cbStackFrame < 512) - { - *pUnwindCodes++ = (BYTE)0xF8; // 16-bit sub/add sp,#x - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 18); - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 10); - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 2); - } - else - { - *pUnwindCodes++ = (BYTE)0xFA; // 32-bit sub/add sp,#x - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 18); - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 10); - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 2); - } - - if(m_cbStackFrame >= 4096) - { - // r4 register is used as param to checkStack function and must have been saved in prolog - _ASSERTE(m_cCalleeSavedRegs > 0); - *pUnwindCodes++ = (BYTE)0xFB; // nop 16 bit for bl r12 - *pUnwindCodes++ = (BYTE)0xFC; // nop 32 bit for movt r12, checkStack - *pUnwindCodes++ = (BYTE)0xFC; // nop 32 bit for movw r12, checkStack - - // Ensure that mov r4, m_cbStackFrame fits in a 32-bit instruction - if(m_cbStackFrame > 65535) - COMPlusThrow(kNotSupportedException); - *pUnwindCodes++ = (BYTE)0xFC; // nop 32 bit for mov r4, m_cbStackFrame - } - } - - // Unwind info generated will be incorrect when m_cCalleeSavedRegs = 0. - // The unwind code will say that the size of push/pop instruction - // size is 16bits when actually the opcode generated by - // ThumbEmitPop & ThumbEMitPush will be 32bits. - // Currently no stubs has m_cCalleeSavedRegs as 0 - // therefore just adding the assert. - _ASSERTE(m_cCalleeSavedRegs > 0); - - if (m_cCalleeSavedRegs <= 4) - { - *pUnwindCodes++ = (BYTE)(0xD4 + (m_cCalleeSavedRegs - 1)); // push/pop {r4-rX} - } - else - { - _ASSERTE(m_cCalleeSavedRegs <= 8); - *pUnwindCodes++ = (BYTE)(0xDC + (m_cCalleeSavedRegs - 5)); // push/pop {r4-rX} - } - - if (m_fPushArgRegs) - { - *pUnwindCodes++ = (BYTE)0x04; // push {r0-r3} / add sp,#16 - *pUnwindCodes++ = (BYTE)0xFD; // bx lr - } - else - { - *pUnwindCodes++ = (BYTE)0xFF; // end - } - - ptrdiff_t epilogUnwindCodeIndex = 0; - - //epilog differs from prolog - if(m_cbStackFrame >= 4096) - { - //Index of the first unwind code of the epilog - epilogUnwindCodeIndex = pUnwindCodes - (BYTE *)pUnwindInfo - sizeof(DWORD); - - *pUnwindCodes++ = (BYTE)0xF8; // sub/add sp,#x - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 18); - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 10); - *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 2); - - if (m_cCalleeSavedRegs <= 4) - { - *pUnwindCodes++ = (BYTE)(0xD4 + (m_cCalleeSavedRegs - 1)); // push/pop {r4-rX} - } - else - { - *pUnwindCodes++ = (BYTE)(0xDC + (m_cCalleeSavedRegs - 5)); // push/pop {r4-rX} - } - - if (m_fPushArgRegs) - { - *pUnwindCodes++ = (BYTE)0x04; // push {r0-r3} / add sp,#16 - *pUnwindCodes++ = (BYTE)0xFD; // bx lr - } - else - { - *pUnwindCodes++ = (BYTE)0xFF; // end - } - - } - - // Number of 32-bit unwind codes - size_t codeWordsCount = (ALIGN_UP((size_t)pUnwindCodes, sizeof(void*)) - (size_t)pUnwindInfo - sizeof(DWORD))/4; - - _ASSERTE(epilogUnwindCodeIndex < 32); - - //Check that MAX_UNWIND_CODE_WORDS is sufficient to store all unwind Codes - _ASSERTE(codeWordsCount <= MAX_UNWIND_CODE_WORDS); - - *(DWORD *)pUnwindInfo = - ((functionLength) / 2) | - (1 << 21) | - ((int)epilogUnwindCodeIndex << 23)| - ((int)codeWordsCount << 28); - -#elif defined(TARGET_ARM64) - if (!m_fProlog) - { - // If EmitProlog isn't called. This is a leaf function which doesn't need any unwindInfo - T_RUNTIME_FUNCTION *pCurFunction = NULL; - } - else - { - - // - // Fill in the RUNTIME_FUNCTION struct for this prologue. - // - UNWIND_INFO *pUnwindInfo = &(pUnwindInfoHeader->UnwindInfo); - - T_RUNTIME_FUNCTION *pCurFunction = &(pUnwindInfoHeader->FunctionEntry); - - _ASSERTE(IS_ALIGNED(pCurFunction, sizeof(void*))); - - S_UINT32 sBeginAddress = S_BYTEPTR(pCode) - S_BYTEPTR(pbBaseAddressRX); - if (sBeginAddress.IsOverflow()) - COMPlusThrowArithmetic(); - - S_UINT32 sTemp = S_BYTEPTR(pUnwindInfo) - S_BYTEPTR(pbBaseAddressRW); - if (sTemp.IsOverflow()) - COMPlusThrowArithmetic(); - - RUNTIME_FUNCTION__SetBeginAddress(pCurFunction, sBeginAddress.Value()); - RUNTIME_FUNCTION__SetUnwindInfoAddress(pCurFunction, sTemp.Value()); - - CodeRun *pLastCodeElem = GetLastCodeRunIfAny(); - _ASSERTE(pLastCodeElem != NULL); - - int functionLength = pLastCodeElem->m_numcodebytes + pLastCodeElem->m_globaloffset; - - // .xdata has 18 bits for function length and it is to store the total length of the function in bytes, divided by 4 - // If the function is larger than 1M, then multiple pdata and xdata records must be used, which we don't support right now. - if (functionLength > 4 * 0x3FFFF) - COMPlusThrowArithmetic(); - - _ASSERTE(functionLength <= globalsize); - - // No support for extended code words and/or extended epilog. - // ASSERTION: first 10 bits of the pUnwindInfo, which holds the #codewords and #epilogcount, cannot be 0 - // And no space for exception scope data also means that no support for exceptions for the stubs - // generated with this stublinker. - BYTE * pUnwindCodes = (BYTE *)pUnwindInfo + sizeof(DWORD); - - - // Emitting the unwind codes: - // The unwind codes are emitted in Epilog order. - // - // 6. Integer argument registers - // Although we might be saving the argument registers in the prolog we don't need - // to report them to the OS. (they are not expressible anyways) - - // 5. Floating point argument registers: - // Similar to Integer argument registers, no reporting - // - - // 4. Set the frame pointer - // ASSUMPTION: none of the Stubs generated with this stublinker change SP value outside of epilog and prolog - // when that is the case we can skip reporting setting up the frame pointer - - // With skiping Step #4, #5 and #6 Prolog and Epilog becomes reversible. so they can share the unwind codes - int epilogUnwindCodeIndex = 0; - - unsigned cStackFrameSizeInQWORDs = GetStackFrameSize()/16; - // 3. Store FP/LR - // save_fplr - *pUnwindCodes++ = (BYTE)(0x40 | (m_cbStackSpace>>3)); - - // 2. Callee-saved registers - // - if (m_cCalleeSavedRegs > 0) - { - unsigned offset = 2 + m_cbStackSpace/8; // 2 is for fp,lr - if ((m_cCalleeSavedRegs %2) ==1) - { - // save_reg - *pUnwindCodes++ = (BYTE) (0xD0 | ((m_cCalleeSavedRegs-1)>>2)); - *pUnwindCodes++ = (BYTE) ((BYTE)((m_cCalleeSavedRegs-1) << 6) | ((offset + m_cCalleeSavedRegs - 1) & 0x3F)); - } - for (int i=(m_cCalleeSavedRegs/2)*2-2; i>=0; i-=2) - { - if (i!=0) - { - // save_next - *pUnwindCodes++ = 0xE6; - } - else - { - // save_regp - *pUnwindCodes++ = 0xC8; - *pUnwindCodes++ = (BYTE)(offset & 0x3F); - } - } - } - - // 1. SP Relocation - // - // EmitProlog is supposed to reject frames larger than 504 bytes. - // Assert that here. - _ASSERTE(cStackFrameSizeInQWORDs <= 0x3F); - if (cStackFrameSizeInQWORDs <= 0x1F) - { - // alloc_s - *pUnwindCodes++ = (BYTE)(cStackFrameSizeInQWORDs); - } - else - { - // alloc_m - *pUnwindCodes++ = (BYTE)(0xC0 | (cStackFrameSizeInQWORDs >> 8)); - *pUnwindCodes++ = (BYTE)(cStackFrameSizeInQWORDs); - } - - // End - *pUnwindCodes++ = 0xE4; - - // Number of 32-bit unwind codes - int codeWordsCount = (int)(ALIGN_UP((size_t)pUnwindCodes, sizeof(DWORD)) - (size_t)pUnwindInfo - sizeof(DWORD))/4; - - //Check that MAX_UNWIND_CODE_WORDS is sufficient to store all unwind Codes - _ASSERTE(codeWordsCount <= MAX_UNWIND_CODE_WORDS); - - *(DWORD *)pUnwindInfo = - ((functionLength) / 4) | - (1 << 21) | // E bit - (epilogUnwindCodeIndex << 22)| - (codeWordsCount << 27); - } // end else (!m_fProlog) -#else - PORTABILITY_ASSERT("StubLinker::EmitUnwindInfo"); - T_RUNTIME_FUNCTION *pCurFunction = NULL; -#endif - - // - // Get a StubUnwindInfoHeapSegment for this base address - // - - CrstHolder crst(&g_StubUnwindInfoHeapSegmentsCrst); - - StubUnwindInfoHeapSegment *pStubHeapSegment; - StubUnwindInfoHeapSegment **ppPrevStubHeapSegment; - for (ppPrevStubHeapSegment = &g_StubHeapSegments; - (pStubHeapSegment = *ppPrevStubHeapSegment); - (ppPrevStubHeapSegment = &pStubHeapSegment->pNext)) - { - if (pbBaseAddressRX < pStubHeapSegment->pbBaseAddress) - { - // The list is ordered, so address is between segments - pStubHeapSegment = NULL; - break; - } - - if (pbBaseAddressRX == pStubHeapSegment->pbBaseAddress) - { - // Found an existing segment - break; - } - } - - if (!pStubHeapSegment) - { - // - // RtlInstallFunctionTableCallback will only accept a ULONG for the - // region size. We've already checked above that the RUNTIME_FUNCTION - // offsets will work relative to pbBaseAddressRX. - // - - SIZE_T cbSegment = findBlockArgs.cbBlockSize; - - if (cbSegment > MaxSegmentSize) - cbSegment = MaxSegmentSize; - - NewHolder pNewStubHeapSegment = new StubUnwindInfoHeapSegment(); - - - pNewStubHeapSegment->pbBaseAddress = pbBaseAddressRX; - pNewStubHeapSegment->cbSegment = cbSegment; - pNewStubHeapSegment->pUnwindHeaderList = NULL; -#ifdef TARGET_AMD64 - pNewStubHeapSegment->pUnwindInfoTable = NULL; -#endif - - // Insert the new stub into list - pNewStubHeapSegment->pNext = *ppPrevStubHeapSegment; - *ppPrevStubHeapSegment = pNewStubHeapSegment; - pNewStubHeapSegment.SuppressRelease(); - - // Use new segment for the stub - pStubHeapSegment = pNewStubHeapSegment; - - InstallEEFunctionTable( - pNewStubHeapSegment, - pbBaseAddressRX, - (ULONG)cbSegment, - &FindStubFunctionEntry, - pNewStubHeapSegment, - DYNFNTABLE_STUB); - } - - // - // Link the new stub into the segment. - // - - pHeaderRW->pNext = pStubHeapSegment->pUnwindHeaderList; - pStubHeapSegment->pUnwindHeaderList = pHeaderRW; - -#ifdef TARGET_AMD64 - // Publish Unwind info to ETW stack crawler - UnwindInfoTable::AddToUnwindInfoTable( - &pStubHeapSegment->pUnwindInfoTable, pCurFunction, - (TADDR) pStubHeapSegment->pbBaseAddress, - (TADDR) pStubHeapSegment->pbBaseAddress + pStubHeapSegment->cbSegment); -#endif - -#ifdef _DEBUG - _ASSERTE(pHeaderRW->IsRegistered()); - _ASSERTE( &pHeaderRW->FunctionEntry - == FindStubFunctionEntry((ULONG64)pCode, EncodeDynamicFunctionTableContext(pStubHeapSegment, DYNFNTABLE_STUB))); -#endif - - return true; -} -#endif // STUBLINKER_GENERATES_UNWIND_INFO - -#ifdef TARGET_ARM -void StubLinker::DescribeProlog(UINT cCalleeSavedRegs, UINT cbStackFrame, BOOL fPushArgRegs) -{ - m_fProlog = TRUE; - m_cCalleeSavedRegs = cCalleeSavedRegs; - m_cbStackFrame = cbStackFrame; - m_fPushArgRegs = fPushArgRegs; -} -#elif defined(TARGET_ARM64) -void StubLinker::DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cCalleeSavedRegs, UINT cbStackSpace) -{ - m_fProlog = TRUE; - m_cIntRegArgs = cIntRegArgs; - m_cVecRegArgs = cVecRegArgs; - m_cCalleeSavedRegs = cCalleeSavedRegs; - m_cbStackSpace = cbStackSpace; -} - -UINT StubLinker::GetSavedRegArgsOffset() -{ - _ASSERTE(m_fProlog); - // This is the offset from SP - // We're assuming that the stublinker will push the arg registers to the bottom of the stack frame - return m_cbStackSpace + (2+ m_cCalleeSavedRegs)*sizeof(void*); // 2 is for FP and LR -} - -UINT StubLinker::GetStackFrameSize() -{ - _ASSERTE(m_fProlog); - return m_cbStackSpace + (2 + m_cCalleeSavedRegs + m_cIntRegArgs + m_cVecRegArgs)*sizeof(void*); -} - -#elif defined(TARGET_RISCV64) -void StubLinker::DescribeProlog(UINT cIntRegArgs, UINT cFpRegArgs, UINT cbStackSpace) -{ - m_fProlog = TRUE; - m_cIntRegArgs = cIntRegArgs; - m_cFpRegArgs = cFpRegArgs; - m_cbStackSpace = cbStackSpace; -} - -UINT StubLinker::GetSavedRegArgsOffset() -{ - _ASSERTE(m_fProlog); - // This is the offset from SP - // We're assuming that the stublinker will push the arg registers to the bottom of the stack frame - return m_cbStackSpace + 2 * sizeof(void*); // 2 is for FP and LR -} - -UINT StubLinker::GetStackFrameSize() -{ - _ASSERTE(m_fProlog); - return m_cbStackSpace + (2 + m_cIntRegArgs + m_cFpRegArgs) * sizeof(void*); -} - -#endif // ifdef TARGET_ARM, elif defined(TARGET_ARM64), elif defined(TARGET_RISCV64) #endif // #ifndef DACCESS_COMPILE @@ -1945,89 +859,6 @@ VOID Stub::DeleteStub() } CONTRACTL_END; -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - if (HasUnwindInfo()) - { - StubUnwindInfoHeader *pHeader = GetUnwindInfoHeader(); - - // - // Check if the stub has been linked into a StubUnwindInfoHeapSegment. - // - if (pHeader->IsRegistered()) - { - CrstHolder crst(&g_StubUnwindInfoHeapSegmentsCrst); - - // - // Find the segment containing the stub. - // - StubUnwindInfoHeapSegment **ppPrevSegment = &g_StubHeapSegments; - StubUnwindInfoHeapSegment *pSegment = *ppPrevSegment; - - if (pSegment) - { - PBYTE pbCode = (PBYTE)GetEntryPointInternal(); -#ifdef TARGET_AMD64 - UnwindInfoTable::RemoveFromUnwindInfoTable(&pSegment->pUnwindInfoTable, - (TADDR) pSegment->pbBaseAddress, (TADDR) pbCode); -#endif - for (StubUnwindInfoHeapSegment *pNextSegment = pSegment->pNext; - pNextSegment; - ppPrevSegment = &pSegment->pNext, pSegment = pNextSegment, pNextSegment = pSegment->pNext) - { - // The segments are sorted by pbBaseAddress. - if (pbCode < pNextSegment->pbBaseAddress) - break; - } - } - - // The stub was marked as registered, so a segment should exist. - _ASSERTE(pSegment); - - if (pSegment) - { - - // - // Find this stub's location in the segment's list. - // - StubUnwindInfoHeader *pCurHeader; - StubUnwindInfoHeader **ppPrevHeaderList; - for (ppPrevHeaderList = &pSegment->pUnwindHeaderList; - (pCurHeader = *ppPrevHeaderList); - (ppPrevHeaderList = &pCurHeader->pNext)) - { - if (pHeader == pCurHeader) - break; - } - - // The stub was marked as registered, so we should find it in the segment's list. - _ASSERTE(pCurHeader); - - if (pCurHeader) - { - // - // Remove the stub from the segment's list. - // - *ppPrevHeaderList = pHeader->pNext; - - // - // If the segment's list is now empty, delete the segment. - // - if (!pSegment->pUnwindHeaderList) - { - DeleteEEFunctionTable(pSegment); -#ifdef TARGET_AMD64 - if (pSegment->pUnwindInfoTable != 0) - delete pSegment->pUnwindInfoTable; -#endif - *ppPrevSegment = pSegment->pNext; - delete pSegment; - } - } - } - } - } -#endif - if ((m_numCodeBytesAndFlags & LOADER_HEAP_BIT) == 0) { #ifdef _DEBUG @@ -2052,17 +883,6 @@ TADDR Stub::GetAllocationBase() TADDR info = dac_cast(this); SIZE_T cbPrefix = 0; -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - if (HasUnwindInfo()) - { - StubUnwindInfoHeaderSuffix *pSuffix = - PTR_StubUnwindInfoHeaderSuffix(info - cbPrefix - - sizeof(*pSuffix)); - - cbPrefix += StubUnwindInfoHeader::ComputeAlignedSize(pSuffix->nUnwindInfoSize); - } -#endif // STUBLINKER_GENERATES_UNWIND_INFO - if (!HasExternalEntryPoint()) { cbPrefix = ALIGN_UP(cbPrefix + sizeof(Stub), CODE_SIZE_ALIGN) - sizeof(Stub); @@ -2096,11 +916,7 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) /*static*/ Stub* Stub::NewStub( LoaderHeap *pHeap, UINT numCodeBytes, - DWORD flags -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - , UINT nUnwindInfoSize -#endif - ) + DWORD flags) { CONTRACTL { @@ -2119,17 +935,6 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) size_t stubPayloadOffset = 0; S_SIZE_T size = S_SIZE_T(sizeof(Stub)); -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - _ASSERTE(!nUnwindInfoSize || !pHeap || pHeap->m_fPermitStubsWithUnwindInfo); - - if (nUnwindInfoSize != 0) - { - // The Unwind info precedes the Stub itself. - stubPayloadOffset = StubUnwindInfoHeader::ComputeAlignedSize(nUnwindInfoSize); - size += stubPayloadOffset; - } -#endif // STUBLINKER_GENERATES_UNWIND_INFO - if (flags & NEWSTUB_FL_EXTERNAL) { _ASSERTE(pHeap == NULL); @@ -2175,22 +980,14 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) } pStubRW->SetupStub( numCodeBytes, - flags -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - , nUnwindInfoSize -#endif - ); + flags); _ASSERTE((BYTE *)pStubRX->GetAllocationBase() == pBlock); return pStubRX; } -void Stub::SetupStub(int numCodeBytes, DWORD flags -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - , UINT nUnwindInfoSize -#endif - ) +void Stub::SetupStub(int numCodeBytes, DWORD flags) { CONTRACTL { @@ -2227,36 +1024,6 @@ void Stub::SetupStub(int numCodeBytes, DWORD flags if ((flags & NEWSTUB_FL_SHUFFLE_THUNK) != 0) m_numCodeBytesAndFlags |= SHUFFLE_THUNK_BIT; } - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - if (nUnwindInfoSize) - { - m_numCodeBytesAndFlags |= UNWIND_INFO_BIT; - - StubUnwindInfoHeaderSuffix * pSuffix = GetUnwindInfoHeaderSuffix(); - pSuffix->nUnwindInfoSize = (BYTE)nUnwindInfoSize; - - StubUnwindInfoHeader * pHeader = GetUnwindInfoHeader(); - pHeader->Init(); - } -#endif -} - -//------------------------------------------------------------------- -// One-time init -//------------------------------------------------------------------- -/*static*/ void Stub::Init() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END; - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - g_StubUnwindInfoHeapSegmentsCrst.Init(CrstStubUnwindInfoHeapSegments); -#endif } #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/stublink.h b/src/coreclr/vm/stublink.h index 47ca7d0726641b..2fcbad8e700c38 100644 --- a/src/coreclr/vm/stublink.h +++ b/src/coreclr/vm/stublink.h @@ -66,55 +66,6 @@ struct CodeLabel; struct CodeRun; struct LabelRef; struct CodeElement; -struct IntermediateUnwindInfo; - -#if !defined(TARGET_X86) && !defined(TARGET_UNIX) -#define STUBLINKER_GENERATES_UNWIND_INFO -#endif // !TARGET_X86 && !TARGET_UNIX - - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - -typedef DPTR(struct StubUnwindInfoHeaderSuffix) PTR_StubUnwindInfoHeaderSuffix; -struct StubUnwindInfoHeaderSuffix -{ - UCHAR nUnwindInfoSize; // Size of unwind info in bytes -}; - -// Variable-sized struct that precedes a Stub when the stub requires unwind -// information. Followed by a StubUnwindInfoHeaderSuffix. -typedef DPTR(struct StubUnwindInfoHeader) PTR_StubUnwindInfoHeader; -struct StubUnwindInfoHeader -{ - PTR_StubUnwindInfoHeader pNext; - T_RUNTIME_FUNCTION FunctionEntry; - UNWIND_INFO UnwindInfo; // variable length - - // Computes the size needed for this variable-sized struct. - static SIZE_T ComputeAlignedSize(UINT nUnwindInfoSize); - - void Init (); - - bool IsRegistered (); -}; - -// List of stub address ranges, in increasing address order. -struct StubUnwindInfoHeapSegment -{ - PBYTE pbBaseAddress; - SIZE_T cbSegment; - StubUnwindInfoHeader *pUnwindHeaderList; - StubUnwindInfoHeapSegment *pNext; - -#ifdef HOST_64BIT - class UnwindInfoTable* pUnwindInfoTable; // Used to publish unwind info to ETW stack crawler -#endif -}; - -VOID UnregisterUnwindInfoInLoaderHeap (UnlockedLoaderHeap *pHeap); - -#endif // STUBLINKER_GENERATES_UNWIND_INFO - //------------------------------------------------------------------------- // A non-multithreaded object that fixes up and emits one executable stub. @@ -219,47 +170,9 @@ class StubLinker #ifdef TARGET_ARM void DescribeProlog(UINT cCalleeSavedRegs, UINT cbStackFrame, BOOL fPushArgRegs); -#elif defined(TARGET_ARM64) - void DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cCalleeSavedRegs, UINT cbStackFrame); - UINT GetSavedRegArgsOffset(); - UINT GetStackFrameSize(); -#elif defined(TARGET_RISCV64) - void DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cbStackFrame); - UINT GetSavedRegArgsOffset(); - UINT GetStackFrameSize(); -#endif - - //=========================================================================== - // Unwind information - - // Records location of preserved or parameter register - VOID UnwindSavedReg (UCHAR reg, ULONG SPRelativeOffset); - VOID UnwindPushedReg (UCHAR reg); - - // Records "sub rsp, xxx" - VOID UnwindAllocStack (SHORT FrameSizeIncrement); - - // Records frame pointer register - VOID UnwindSetFramePointer (UCHAR reg); - - // In DEBUG, emits a call to m_pUnwindInfoCheckLabel (via - // EmitUnwindInfoCheckWorker). Code at that label will call to a - // helper that will attempt to RtlVirtualUnwind through the stub. The - // helper will preserve ALL registers. - VOID EmitUnwindInfoCheck(); - -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) -protected: - - // Injects a call to the given label. - virtual VOID EmitUnwindInfoCheckWorker (CodeLabel *pCheckLabel) { _ASSERTE(!"override me"); } - - // Emits a call to a helper that will attempt to RtlVirtualUnwind - // through the stub. The helper will preserve ALL registers. - virtual VOID EmitUnwindInfoCheckSubfunction() { _ASSERTE(!"override me"); } #endif -public: + public: //--------------------------------------------------------------- // Generate the actual stub. The returned stub has a refcount of 1. @@ -282,7 +195,7 @@ class StubLinker BOOL m_fDataOnly; // the stub contains only data - does not need FlushInstructionCache #ifdef TARGET_ARM -protected: + protected: BOOL m_fProlog; // True if DescribeProlog has been called UINT m_cCalleeSavedRegs; // Count of callee saved registers (0 == none, 1 == r4, 2 == // r4-r5 etc. up to 8 == r4-r11) @@ -290,84 +203,7 @@ class StubLinker BOOL m_fPushArgRegs; // If true, r0-r3 are saved before callee saved regs #endif // TARGET_ARM -#ifdef TARGET_ARM64 -protected: - BOOL m_fProlog; // True if DescribeProlog has been called - UINT m_cIntRegArgs; // Count of int register arguments (x0 - x7) - UINT m_cVecRegArgs; // Count of FP register arguments (v0 - v7) - UINT m_cCalleeSavedRegs; // Count of callee saved registers (x19 - x28) - UINT m_cbStackSpace; // Additional stack space for return buffer and stack alignment -#endif // TARGET_ARM64 - -#ifdef TARGET_RISCV64 -protected: - BOOL m_fProlog; // True if DescribeProlog has been called - UINT m_cIntRegArgs; // Count of int register arguments (x10 - x17) - UINT m_cFpRegArgs; // Count of FP register arguments (f10 - f17) - UINT m_cbStackSpace; // Additional stack space for return buffer and stack alignment -#endif // TARGET_RISCV64 - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - -#ifdef _DEBUG - CodeLabel *m_pUnwindInfoCheckLabel; // subfunction to call to unwind info check helper. - // On AMD64, the prologue is restricted to 256 - // bytes, so this reduces the size of the injected - // code from 14 to 5 bytes. -#endif - -#ifdef TARGET_AMD64 - IntermediateUnwindInfo *m_pUnwindInfoList; - UINT m_nUnwindSlots; // number of slots to allocate at end, == UNWIND_INFO::CountOfCodes - BOOL m_fHaveFramePointer; // indicates stack operations no longer need to be recorded - - // - // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry - // - UINT UnwindInfoSize(UINT codeSize) - { - if (m_nUnwindSlots == 0) return 0; - - return sizeof(T_RUNTIME_FUNCTION) + offsetof(UNWIND_INFO, UnwindCode) + m_nUnwindSlots * sizeof(UNWIND_CODE); - } -#endif // TARGET_AMD64 - -#ifdef TARGET_ARM -#define MAX_UNWIND_CODE_WORDS 5 /* maximum number of 32-bit words to store unwind codes */ - // Cache information about the stack frame set up in the prolog and use it in the generation of the - // epilog. -private: - // Reserve fixed size block that's big enough to fit any unwind info we can have - static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4; - - // - // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry - // - UINT UnwindInfoSize(UINT codeSize) - { - if (!m_fProlog) return 0; - - return c_nUnwindInfoSize; - } -#endif // TARGET_ARM - -#ifdef TARGET_ARM64 -#define MAX_UNWIND_CODE_WORDS 5 /* maximum number of 32-bit words to store unwind codes */ - -private: - // Reserve fixed size block that's big enough to fit any unwind info we can have - static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4; - UINT UnwindInfoSize(UINT codeSize) - { - if (!m_fProlog) return 0; - - return c_nUnwindInfoSize; - } - -#endif // TARGET_ARM64 - -#endif // STUBLINKER_GENERATES_UNWIND_INFO - + private: CodeRun *AppendNewEmptyCodeRun(); @@ -390,15 +226,9 @@ class StubLinker // Writes out the code element into memory following the // stub object. - bool EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap); + void EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap); CodeRun *GetLastCodeRunIfAny(); - - bool EmitUnwindInfo(Stub* pStubRX, Stub* pStubRW, int globalsize, LoaderHeap* pHeap); - -#if defined(TARGET_AMD64) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - UNWIND_CODE *AllocUnwindInfo (UCHAR Op, UCHAR nExtraSlots = 0); -#endif // defined(TARGET_AMD64) && defined(STUBLINKER_GENERATES_UNWIND_INFO) }; //************************************************************************ @@ -465,8 +295,7 @@ class Stub EXTERNAL_ENTRY_BIT = 0x80000000, LOADER_HEAP_BIT = 0x40000000, INSTANTIATING_STUB_BIT = 0x20000000, - UNWIND_INFO_BIT = 0x10000000, - SHUFFLE_THUNK_BIT = 0x08000000, + SHUFFLE_THUNK_BIT = 0x10000000, CODEBYTES_MASK = SHUFFLE_THUNK_BIT - 1, MAX_CODEBYTES = CODEBYTES_MASK + 1, @@ -540,58 +369,6 @@ class Stub return m_data.InstantiatedMethod; } - //------------------------------------------------------------------- - // Unwind information. - //------------------------------------------------------------------- - -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - - BOOL HasUnwindInfo() - { - LIMITED_METHOD_CONTRACT; - return (m_numCodeBytesAndFlags & UNWIND_INFO_BIT) != 0; - } - - StubUnwindInfoHeaderSuffix *GetUnwindInfoHeaderSuffix() - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - FORBID_FAULT; - } - CONTRACTL_END - - _ASSERTE(HasUnwindInfo()); - - TADDR info = dac_cast(this); - - return PTR_StubUnwindInfoHeaderSuffix - (info - sizeof(StubUnwindInfoHeaderSuffix)); - } - - StubUnwindInfoHeader *GetUnwindInfoHeader() - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - FORBID_FAULT; - } - CONTRACTL_END - - _ASSERTE(HasUnwindInfo()); - - StubUnwindInfoHeaderSuffix *pSuffix = GetUnwindInfoHeaderSuffix(); - - TADDR suffixEnd = dac_cast(pSuffix) + sizeof(*pSuffix); - - return PTR_StubUnwindInfoHeader(suffixEnd - - StubUnwindInfoHeader::ComputeAlignedSize(pSuffix->nUnwindInfoSize)); - } - -#endif // STUBLINKER_GENERATES_UNWIND_INFO - //------------------------------------------------------------------- // Returns pointer to the start of the allocation containing this Stub. //------------------------------------------------------------------- @@ -726,11 +503,7 @@ class Stub // This creates stubs. //------------------------------------------------------------------- static Stub* NewStub(LoaderHeap *pLoaderHeap, UINT numCodeBytes, - DWORD flags = NEWSTUB_FL_NONE -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - , UINT nUnwindInfoSize = 0 -#endif - ); + DWORD flags = NEWSTUB_FL_NONE); static Stub* NewStub(PTR_VOID pCode, DWORD flags = NEWSTUB_FL_NONE); static Stub* NewStub(PCODE pCode, DWORD flags = NEWSTUB_FL_NONE) @@ -738,18 +511,8 @@ class Stub return NewStub((PTR_VOID)pCode, flags); } - //------------------------------------------------------------------- - // One-time init - //------------------------------------------------------------------- - static void Init(); - protected: - // fMC: Set to true if the stub is a multicast delegate, false otherwise - void SetupStub(int numCodeBytes, DWORD flags -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - , UINT nUnwindInfoSlots -#endif - ); + void SetupStub(int numCodeBytes, DWORD flags); void DeleteStub(); //------------------------------------------------------------------- diff --git a/src/coreclr/vm/stublink.inl b/src/coreclr/vm/stublink.inl index aaaab7b82eeada..a48064007dad52 100644 --- a/src/coreclr/vm/stublink.inl +++ b/src/coreclr/vm/stublink.inl @@ -15,44 +15,7 @@ #include "safemath.h" -#ifdef STUBLINKER_GENERATES_UNWIND_INFO - -inline //static -SIZE_T StubUnwindInfoHeader::ComputeAlignedSize(UINT nUnwindInfoSize) -{ - LIMITED_METHOD_CONTRACT; - - return ALIGN_UP( FIELD_OFFSET(StubUnwindInfoHeader, FunctionEntry) - + nUnwindInfoSize - + sizeof(StubUnwindInfoHeaderSuffix) - , sizeof(void*)); -} - - -#ifndef DACCESS_COMPILE - -inline -void StubUnwindInfoHeader::Init () -{ - LIMITED_METHOD_CONTRACT; - - pNext = (StubUnwindInfoHeader*)(SIZE_T)1; -} - - -inline -bool StubUnwindInfoHeader::IsRegistered () -{ - LIMITED_METHOD_CONTRACT; - - return pNext != (StubUnwindInfoHeader*)(SIZE_T)1; -} - -#endif // #ifndef DACCESS_COMPILE - -#endif // STUBLINKER_GENERATES_UNWIND_INFO - - +#ifdef TARGET_X86 inline void StubLinker::Push(UINT size) { @@ -64,10 +27,8 @@ void StubLinker::Push(UINT size) stackSize += sSize; _ASSERTE(!stackSize.IsOverflow()); m_stackSize = stackSize.Value(); - UnwindAllocStack(sSize); } - inline void StubLinker::Pop(UINT size) { @@ -79,37 +40,7 @@ void StubLinker::Pop(UINT size) _ASSERTE(!stackSize.IsOverflow()); m_stackSize = stackSize.Value(); } - - -inline -VOID StubLinker::EmitUnwindInfoCheck() -{ -#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) - if (g_pConfig->IsStubLinkerUnwindInfoVerificationOn()) - { - if (!m_pUnwindInfoCheckLabel) - m_pUnwindInfoCheckLabel = NewCodeLabel(); - EmitUnwindInfoCheckWorker(m_pUnwindInfoCheckLabel); - } -#endif -} - - -#ifndef STUBLINKER_GENERATES_UNWIND_INFO - -inline VOID StubLinker::UnwindSavedReg (UCHAR reg, ULONG SPRelativeOffset) {LIMITED_METHOD_CONTRACT;} -inline VOID StubLinker::UnwindAllocStack (SHORT FrameSizeIncrement) {LIMITED_METHOD_CONTRACT;} -inline VOID StubLinker::UnwindSetFramePointer (UCHAR reg) {LIMITED_METHOD_CONTRACT;} - -inline VOID StubLinker::UnwindPushedReg (UCHAR reg) -{ - LIMITED_METHOD_CONTRACT; - - m_stackSize += sizeof(void*); -} - -#endif // !STUBLINKER_GENERATES_UNWIND_INFO - +#endif // TARGET_X86 #endif // !__STUBLINK_INL__