From 7e51ef578a663da239968012f5683b873d6f1470 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Sat, 22 Feb 2025 00:30:49 +0100 Subject: [PATCH 01/15] Separate code manager for the interpreter This change adds a separate code manager for the interpreted code. Here is an overview of the changes: * A base class EECodeGenManager is extracted from the EEJitManager * A new class InterpreterJitManager derived from the EECodeGenManager is added and implemented. * Similarly, a base class CEECodeGenInfo is extracted from the CEEJitInfo * A new class CInterpreterJitInfo derived from the CEECodeGenInfo is added and implemented * The CodeHeader and RealCodeHeader became base classes and JitCodeHeader, RealJitCodeHeader, InterpreterCodeHeader and RealInterpreterCodeHeader were added. The CodeHeader derivates don't add any extra data, the JitCodeHeader just provides the methods that are needed to access Jit specific members of the RealJitCodeHeader. * The UnsafeJitFunction is refactored so that the interpreter (if enabled) is invoked first and then the AltJit / Jit ones are called. * A new DOTNET_Interpreter, DOTNET_InterpreterPath and DOTNET_InterpreterName env vars are added to match the existing AltJit ones. --- src/coreclr/debug/daccess/fntableaccess.cpp | 4 +- src/coreclr/debug/daccess/fntableaccess.h | 10 +- src/coreclr/inc/clrconfigvalues.h | 6 + src/coreclr/inc/corjit.h | 1 + src/coreclr/inc/dacvars.h | 3 + src/coreclr/inc/vptr_list.h | 3 + src/coreclr/interpreter/eeinterp.cpp | 11 +- src/coreclr/vm/codeman.cpp | 383 ++++++++--- src/coreclr/vm/codeman.h | 521 ++++++++++----- src/coreclr/vm/dynamicmethod.cpp | 37 +- src/coreclr/vm/dynamicmethod.h | 10 +- src/coreclr/vm/jitinterface.cpp | 602 ++++++++++-------- src/coreclr/vm/jitinterface.h | 348 ++++++---- src/coreclr/vm/loaderallocator.cpp | 1 + src/coreclr/vm/loaderallocator.hpp | 2 + .../JIT/interpreter/InterpreterTester.cs | 6 +- 16 files changed, 1256 insertions(+), 692 deletions(-) diff --git a/src/coreclr/debug/daccess/fntableaccess.cpp b/src/coreclr/debug/daccess/fntableaccess.cpp index 023a82e268c8ed..cc6a3eb50f8df8 100644 --- a/src/coreclr/debug/daccess/fntableaccess.cpp +++ b/src/coreclr/debug/daccess/fntableaccess.cpp @@ -137,7 +137,7 @@ static NTSTATUS OutOfProcessFindHeader(ReadMemoryFunction fpReadMemory,PVOID pUs return STATUS_SUCCESS; } -#define CODE_HEADER FakeRealCodeHeader +#define CODE_HEADER FakeJitRealCodeHeader #define ResolveCodeHeader(pHeader) \ if (pHeader) \ { \ @@ -169,7 +169,7 @@ extern "C" NTSTATUS OutOfProcessFunctionTableCallbackEx(IN ReadMemoryFunction *ppFunctions = 0; *pnEntries = 0; - DWORD_PTR pHp = JitMan + (DWORD_PTR)offsetof(FakeEEJitManager, m_pCodeHeap); + DWORD_PTR pHp = JitMan + (DWORD_PTR)offsetof(FakeEECodeGenManager, m_pCodeHeap); move(pHp, pHp); diff --git a/src/coreclr/debug/daccess/fntableaccess.h b/src/coreclr/debug/daccess/fntableaccess.h index 722f0581e218a0..f1ec10dd549aae 100644 --- a/src/coreclr/debug/daccess/fntableaccess.h +++ b/src/coreclr/debug/daccess/fntableaccess.h @@ -11,7 +11,7 @@ #define _FN_TABLE_ACCESS_H -struct FakeEEJitManager +struct FakeEECodeGenManager { LPVOID __VFN_table; LPVOID m_runtimeSupport; @@ -55,7 +55,7 @@ typedef struct _FakeHpRealCodeHdr LPVOID hdrMDesc; // changed from MethodDesc* DWORD nUnwindInfos; T_RUNTIME_FUNCTION unwindInfos[0]; -} FakeRealCodeHeader; +} FakeJitRealCodeHeader; typedef struct _FakeHpCodeHdr { @@ -76,7 +76,7 @@ class CheckDuplicatedStructLayouts { #define CHECK_OFFSET(cls, fld) CPP_ASSERT(cls##fld, offsetof(Fake##cls, fld) == offsetof(cls, fld)) - CHECK_OFFSET(EEJitManager, m_pCodeHeap); + CHECK_OFFSET(EECodeGenManager, m_pCodeHeap); CHECK_OFFSET(HeapList, hpNext); CHECK_OFFSET(HeapList, startAddress); @@ -85,8 +85,8 @@ class CheckDuplicatedStructLayouts CHECK_OFFSET(HeapList, pHdrMap); #if !defined(TARGET_X86) - CHECK_OFFSET(RealCodeHeader, nUnwindInfos); - CHECK_OFFSET(RealCodeHeader, unwindInfos); + CHECK_OFFSET(JitRealCodeHeader, nUnwindInfos); + CHECK_OFFSET(JitRealCodeHeader, unwindInfos); #endif // !TARGET_X86 #undef CHECK_OFFSET diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index bf28ce3fc3e757..446ad119ebdf7a 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -325,6 +325,12 @@ RETAIL_CONFIG_STRING_INFO(EXTERNAL_AltJitOs, W("AltJitOS"), "Sets target OS for RETAIL_CONFIG_STRING_INFO(EXTERNAL_AltJitExcludeAssemblies, W("AltJitExcludeAssemblies"), "Do not use AltJit on this semicolon-delimited list of assemblies.") #endif // defined(ALLOW_SXS_JIT) +#ifdef FEATURE_INTERPRETER +RETAIL_CONFIG_STRING_INFO(EXTERNAL_InterpreterName, W("InterpreterName"), "Primary interpreter to use") +CONFIG_STRING_INFO(INTERNAL_InterpreterPath, W("InterpreterPath"), "Full path to the interpreter to use") +RETAIL_CONFIG_STRING_INFO(EXTERNAL_Interpreter, W("Interpreter"), "Enables Interpreter and selectively limits it to the specified methods.") +#endif // FEATURE_INTERPRETER + RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitHostMaxSlabCache, W("JitHostMaxSlabCache"), 0x1000000, "Sets jit host max slab cache size, 16MB default") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitOptimizeType, W("JitOptimizeType"), 0 /* OPT_DEFAULT */, "") diff --git a/src/coreclr/inc/corjit.h b/src/coreclr/inc/corjit.h index d8e6a774784f52..77ee42d46343ab 100644 --- a/src/coreclr/inc/corjit.h +++ b/src/coreclr/inc/corjit.h @@ -52,6 +52,7 @@ enum CorJitAllocMemFlag CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN = 0x00000004, // The code will be 32-byte aligned CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN = 0x00000008, // The read-only data will be 32-byte aligned CORJIT_ALLOCMEM_FLG_RODATA_64BYTE_ALIGN = 0x00000010, // The read-only data will be 64-byte aligned + CORJIT_ALLOCMEM_FLG_INTERPRETED = 0x00000020, // The code is interpreted byte code }; inline CorJitAllocMemFlag operator |(CorJitAllocMemFlag a, CorJitAllocMemFlag b) diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index 7df74b3c480732..585f700f7e1c7a 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -84,6 +84,9 @@ DEFINE_DACVAR(PTR_EEJitManager, ExecutionManager__m_pEEJitManager, ExecutionMana #ifdef FEATURE_READYTORUN DEFINE_DACVAR(PTR_ReadyToRunJitManager, ExecutionManager__m_pReadyToRunJitManager, ExecutionManager::m_pReadyToRunJitManager) #endif +#ifdef FEATURE_INTERPRETER +DEFINE_DACVAR(PTR_InterpreterJitManager, ExecutionManager__m_pInterpreterJitManager, ExecutionManager::m_pInterpreterJitManager) +#endif DEFINE_DACVAR_NO_DUMP(VMHELPDEF *, dac__hlpFuncTable, ::hlpFuncTable) DEFINE_DACVAR(VMHELPDEF *, dac__hlpDynamicFuncTable, ::hlpDynamicFuncTable) diff --git a/src/coreclr/inc/vptr_list.h b/src/coreclr/inc/vptr_list.h index fa61a7b81aa9ba..761d79b1fa59ec 100644 --- a/src/coreclr/inc/vptr_list.h +++ b/src/coreclr/inc/vptr_list.h @@ -9,6 +9,9 @@ VPTR_CLASS(EEJitManager) #ifdef FEATURE_READYTORUN VPTR_CLASS(ReadyToRunJitManager) #endif +#ifdef FEATURE_INTERPRETER +VPTR_CLASS(InterpreterJitManager) +#endif VPTR_CLASS(EECodeManager) VPTR_CLASS(RangeList) diff --git a/src/coreclr/interpreter/eeinterp.cpp b/src/coreclr/interpreter/eeinterp.cpp index 7d7960e5ebc88a..09bdedd79ea9bf 100644 --- a/src/coreclr/interpreter/eeinterp.cpp +++ b/src/coreclr/interpreter/eeinterp.cpp @@ -66,7 +66,7 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd, // TODO: replace this by something like the JIT does to support multiple methods being specified and we don't // keep fetching it on each call to compileMethod - const char *methodToInterpret = g_interpHost->getStringConfigValue("AltJit"); + const char *methodToInterpret = g_interpHost->getStringConfigValue("Interpreter"); doInterpret = (methodName != NULL && strcmp(methodName, methodToInterpret) == 0); g_interpHost->freeStringConfigValue(methodToInterpret); if (doInterpret) @@ -90,23 +90,18 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd, uint32_t sizeOfCode = sizeof(InterpMethod*) + IRCodeSize * sizeof(int32_t); uint8_t unwindInfo[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - // TODO: get rid of the need to allocate fake unwind info. - compHnd->reserveUnwindInfo(false /* isFunclet */, false /* isColdCode */ , sizeof(unwindInfo) /* unwindSize */); - AllocMemArgs args; + AllocMemArgs args {}; args.hotCodeSize = sizeOfCode; args.coldCodeSize = 0; args.roDataSize = 0; args.xcptnsCount = 0; - args.flag = CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN; + args.flag = CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN | CORJIT_ALLOCMEM_FLG_INTERPRETED; compHnd->allocMem(&args); // We store first the InterpMethod pointer as the code header, followed by the actual code *(InterpMethod**)args.hotCodeBlockRW = pMethod; memcpy ((uint8_t*)args.hotCodeBlockRW + sizeof(InterpMethod*), pIRCode, IRCodeSize * sizeof(int32_t)); - // TODO: get rid of the need to allocate fake unwind info - compHnd->allocUnwindInfo((uint8_t*)args.hotCodeBlock, (uint8_t*)args.coldCodeBlock, 0, 1, sizeof(unwindInfo), unwindInfo, CORJIT_FUNC_ROOT); - *entryAddress = (uint8_t*)args.hotCodeBlock; *nativeSizeOfCode = sizeOfCode; diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 12b02c90a39ba4..7185c6e805761f 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -52,6 +52,10 @@ SPTR_IMPL(EEJitManager, ExecutionManager, m_pEEJitManager); SPTR_IMPL(ReadyToRunJitManager, ExecutionManager, m_pReadyToRunJitManager); #endif +#ifdef FEATURE_INTERPRETER +SPTR_IMPL(InterpreterJitManager, ExecutionManager, m_pInterpreterJitManager); +#endif + SVAL_IMPL(RangeSectionMapData, ExecutionManager, g_codeRangeMap); VOLATILE_SVAL_IMPL_INIT(LONG, ExecutionManager, m_dwReaderCount, 0); VOLATILE_SVAL_IMPL_INIT(LONG, ExecutionManager, m_dwWriterLock, 0); @@ -416,7 +420,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R { // This cast is justified because only EEJitManager's have the code type above. EEJitManager* pJitMgr = (EEJitManager*)(pRS->_pjit); - CodeHeader * pHeader = pJitMgr->GetCodeHeaderFromStartAddress(entryPoint); + JitCodeHeader * pHeader = dac_cast(pJitMgr->GetCodeHeaderFromStartAddress(entryPoint)); for(ULONG i = 0; i < pHeader->GetNumberOfUnwindInfos(); i++) RemoveFromUnwindInfoTable(&pRS->_pUnwindInfoTable, pRS->_range.RangeStart(), pRS->_range.RangeStart() + pHeader->GetUnwindInfo(i)->BeginAddress); } @@ -434,7 +438,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R STANDARD_VM_CONTRACT; { // CodeHeapIterator holds the m_CodeHeapCritSec, which ensures code heaps don't get deallocated while being walked - EEJitManager::CodeHeapIterator heapIterator(NULL); + EECodeGenManager::CodeHeapIterator heapIterator(NULL); // Currently m_CodeHeapCritSec is given the CRST_UNSAFE_ANYMODE flag which allows it to be taken in a GC_NOTRIGGER // region but also disallows GC_TRIGGERS. We need GC_TRIGGERS because we take another lock. Ideally we would @@ -455,7 +459,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R { // This cast is justified because only EEJitManager's have the code type above. EEJitManager* pJitMgr = (EEJitManager*)(pRS->_pjit); - CodeHeader * pHeader = pJitMgr->GetCodeHeaderFromStartAddress(methodEntry); + JitCodeHeader * pHeader = dac_cast(pJitMgr->GetCodeHeaderFromStartAddress(methodEntry)); int unwindInfoCount = pHeader->GetNumberOfUnwindInfos(); for(int i = 0; i < unwindInfoCount; i++) AddToUnwindInfoTable(&pRS->_pUnwindInfoTable, pHeader->GetUnwindInfo(i), pRS->_range.RangeStart(), pRS->_range.RangeEndOpen()); @@ -537,7 +541,7 @@ DeleteJitHeapCache #if !defined(DACCESS_COMPILE) -EEJitManager::CodeHeapIterator::CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter) +EECodeGenManager::CodeHeapIterator::CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter) : m_lockHolder(&(ExecutionManager::GetEEJitManager()->m_CodeHeapCritSec)), m_Iterator(NULL, 0, NULL, 0) { CONTRACTL @@ -555,7 +559,7 @@ EEJitManager::CodeHeapIterator::CodeHeapIterator(LoaderAllocator *pLoaderAllocat new (&m_Iterator) MethodSectionIterator((const void *)m_pHeapList->mapBase, (COUNT_T)m_pHeapList->maxCodeHeapSize, m_pHeapList->pHdrMap, (COUNT_T)HEAP2MAPSIZE(ROUND_UP_TO_PAGE(m_pHeapList->maxCodeHeapSize))); }; -EEJitManager::CodeHeapIterator::~CodeHeapIterator() +EECodeGenManager::CodeHeapIterator::~CodeHeapIterator() { CONTRACTL { @@ -566,7 +570,7 @@ EEJitManager::CodeHeapIterator::~CodeHeapIterator() CONTRACTL_END; } -BOOL EEJitManager::CodeHeapIterator::Next() +BOOL EECodeGenManager::CodeHeapIterator::Next() { CONTRACTL { @@ -1181,12 +1185,19 @@ PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFuncti // EEJitManager //********************************************************************************** -EEJitManager::EEJitManager() +EECodeGenManager::EECodeGenManager() : + m_pCodeHeap(NULL), + m_cleanupList(NULL), // CRST_DEBUGGER_THREAD - We take this lock on debugger thread during EnC add method, among other things // CRST_TAKEN_DURING_SHUTDOWN - We take this lock during shutdown if ETW is on (to do rundown) - m_CodeHeapCritSec( CrstSingleUseLock, - CrstFlags(CRST_UNSAFE_ANYMODE|CRST_DEBUGGER_THREAD|CRST_TAKEN_DURING_SHUTDOWN)), + m_CodeHeapCritSec( CrstSingleUseLock, CrstFlags(CRST_UNSAFE_ANYMODE|CRST_DEBUGGER_THREAD|CRST_TAKEN_DURING_SHUTDOWN)), + m_storeRichDebugInfo(false) +{ +} + +EEJitManager::EEJitManager() + : m_CPUCompileFlags(), m_JitLoadCritSec( CrstSingleUseLock ) { @@ -1195,7 +1206,6 @@ EEJitManager::EEJitManager() GC_NOTRIGGER; } CONTRACTL_END; - m_pCodeHeap = NULL; m_jit = NULL; m_JITCompiler = NULL; #ifdef TARGET_AMD64 @@ -1211,9 +1221,6 @@ EEJitManager::EEJitManager() m_AltJITRequired = false; #endif - m_storeRichDebugInfo = false; - m_cleanupList = NULL; - SetCpuInfo(); } @@ -1668,6 +1675,10 @@ struct JIT_LOAD_DATA // Here's the global data for JIT load and initialization state. JIT_LOAD_DATA g_JitLoadData; +#ifdef FEATURE_INTERPRETER +JIT_LOAD_DATA g_interpreterLoadData; +#endif // FEATURE_INTERPRETER + CORINFO_OS getClrVmOs(); #define LogJITInitializationError(...) \ @@ -2168,9 +2179,9 @@ void CodeFragmentHeap::RealBackoutMem(void *pMem //************************************************************************** -LoaderCodeHeap::LoaderCodeHeap() +LoaderCodeHeap::LoaderCodeHeap(BOOL fMakeExecutable) : m_LoaderHeap(NULL, // RangeList *pRangeList - TRUE), // BOOL fMakeExecutable + fMakeExecutable), m_cbMinNextPad(0) { WRAPPER_NO_CONTRACT; @@ -2359,11 +2370,11 @@ HeapList* LoaderCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap } LOG((LF_JIT, LL_INFO100, - "Request new LoaderCodeHeap::CreateCodeHeap(%08x, %08x, for loader allocator" FMT_ADDR "in" FMT_ADDR ".." FMT_ADDR ")\n", - (DWORD) reserveSize, (DWORD) initialRequestSize, DBG_ADDR(pInfo->m_pAllocator), DBG_ADDR(loAddr), DBG_ADDR(hiAddr) + "Request new LoaderCodeHeap::CreateCodeHeap(%08x, %08x, %sexecutable, for loader allocator" FMT_ADDR "in" FMT_ADDR ".." FMT_ADDR ")\n", + (DWORD) reserveSize, (DWORD) initialRequestSize, pInfo->IsInterpreted() ? "non-" : "", DBG_ADDR(pInfo->m_pAllocator), DBG_ADDR(loAddr), DBG_ADDR(hiAddr) )); - NewHolder pCodeHeap(new LoaderCodeHeap()); + NewHolder pCodeHeap(new LoaderCodeHeap(!pInfo->IsInterpreted() /* fMakeExecutable */)); BYTE * pBaseAddr = NULL; DWORD dwSizeAcquiredFromInitialBlock = 0; @@ -2371,7 +2382,10 @@ HeapList* LoaderCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap size_t allocationSize = pCodeHeap->m_LoaderHeap.AllocMem_TotalSize(initialRequestSize); #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - allocationSize += pCodeHeap->m_LoaderHeap.AllocMem_TotalSize(JUMP_ALLOCATE_SIZE); + if (!pInfo->IsInterpreted()) + { + allocationSize += pCodeHeap->m_LoaderHeap.AllocMem_TotalSize(JUMP_ALLOCATE_SIZE); + } #endif pBaseAddr = (BYTE *)pInfo->m_pAllocator->GetCodeHeapInitialBlock(loAddr, hiAddr, (DWORD)allocationSize, &dwSizeAcquiredFromInitialBlock); if (pBaseAddr != NULL) @@ -2428,7 +2442,15 @@ HeapList* LoaderCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap HeapList *pHp = new HeapList; #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - pHp->CLRPersonalityRoutine = (BYTE *)pCodeHeap->m_LoaderHeap.AllocMem(JUMP_ALLOCATE_SIZE); + if (pInfo->IsInterpreted()) + { + pHp->CLRPersonalityRoutine = NULL; + pCodeHeap->m_LoaderHeap.ReservePages(1); + } + else + { + pHp->CLRPersonalityRoutine = (BYTE *)pCodeHeap->m_LoaderHeap.AllocMem(JUMP_ALLOCATE_SIZE); + } #else // Ensure that the heap has a reserved block of memory and so the GetReservedBytesFree() // and GetAllocPtr() calls below return nonzero values. @@ -2438,13 +2460,19 @@ HeapList* LoaderCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap pHp->pHeap = pCodeHeap; size_t heapSize = pCodeHeap->m_LoaderHeap.GetReservedBytesFree(); - size_t nibbleMapSize = HEAP2MAPSIZE(ROUND_UP_TO_PAGE(heapSize)); pHp->startAddress = (TADDR)pCodeHeap->m_LoaderHeap.GetAllocPtr(); pHp->endAddress = pHp->startAddress; pHp->maxCodeHeapSize = heapSize; - pHp->reserveForJumpStubs = fAllocatedFromEmergencyJumpStubReserve ? pHp->maxCodeHeapSize : GetDefaultReserveForJumpStubs(pHp->maxCodeHeapSize); + if (pInfo->IsInterpreted()) + { + pHp->reserveForJumpStubs = 0; + } + else + { + pHp->reserveForJumpStubs = fAllocatedFromEmergencyJumpStubReserve ? pHp->maxCodeHeapSize : GetDefaultReserveForJumpStubs(pHp->maxCodeHeapSize); + } _ASSERTE(heapSize >= initialRequestSize); @@ -2452,7 +2480,15 @@ HeapList* LoaderCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap // Furthermore, if we avoid writing to it, these pages don't come into our working set pHp->mapBase = ROUND_DOWN_TO_PAGE(pHp->startAddress); // round down to next lower page align + size_t nibbleMapSize = HEAP2MAPSIZE(ROUND_UP_TO_PAGE(heapSize)); pHp->pHdrMap = (DWORD*)(void*)pJitMetaHeap->AllocMem(S_SIZE_T(nibbleMapSize)); +#ifdef TARGET_64BIT + if (pHp->CLRPersonalityRoutine != NULL) + { + ExecutableWriterHolder personalityRoutineWriterHolder(pHp->CLRPersonalityRoutine, 12); + emitJump(pHp->CLRPersonalityRoutine, personalityRoutineWriterHolder.GetRW(), (void *)ProcessCLRException); + } +#endif // TARGET_64BIT pHp->pLoaderAllocator = pInfo->m_pAllocator; @@ -2461,11 +2497,6 @@ HeapList* LoaderCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap DBG_ADDR(pHp->startAddress), DBG_ADDR(pHp->startAddress+pHp->maxCodeHeapSize) )); -#ifdef TARGET_64BIT - ExecutableWriterHolder personalityRoutineWriterHolder(pHp->CLRPersonalityRoutine, 12); - emitJump(pHp->CLRPersonalityRoutine, personalityRoutineWriterHolder.GetRW(), (void *)ProcessCLRException); -#endif // TARGET_64BIT - pCodeHeap.SuppressRelease(); RETURN pHp; } @@ -2551,7 +2582,7 @@ extern "C" PT_RUNTIME_FUNCTION GetRuntimeFunctionCallback(IN ULONG ControlPc } #endif // FEATURE_EH_FUNCLETS -HeapList* EEJitManager::NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapList *pADHeapList) +HeapList* EECodeGenManager::NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapList *pADHeapList) { CONTRACT(HeapList *) { THROWS; @@ -2583,7 +2614,10 @@ HeapList* EEJitManager::NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapLi size_t reserveSize = initialRequestSize; #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - reserveSize += JUMP_ALLOCATE_SIZE; + if (!pInfo->IsInterpreted()) + { + reserveSize += JUMP_ALLOCATE_SIZE; + } #endif if (reserveSize < minReserveSize) @@ -2596,6 +2630,11 @@ HeapList* EEJitManager::NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapLi DWORD flags = RangeSection::RANGE_SECTION_CODEHEAP; + if (pInfo->IsInterpreted()) + { + flags |= RangeSection::RANGE_SECTION_INTERPRETER; + } + if (pInfo->IsDynamicDomain()) { flags |= RangeSection::RANGE_SECTION_COLLECTIBLE; @@ -2631,15 +2670,19 @@ HeapList* EEJitManager::NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapLi this, (RangeSection::RangeSectionFlags)flags, pHp); - // - // add a table to cover each range in the range list - // - InstallEEFunctionTable( - (PVOID)pStartRange, // this is just an ID that gets passed to RtlDeleteFunctionTable; - (PVOID)pStartRange, - (ULONG)((ULONG64)pEndRange - (ULONG64)pStartRange), - GetRuntimeFunctionCallback, - this); + + if (!pInfo->IsInterpreted()) + { + // + // add a table to cover each range in the range list + // + InstallEEFunctionTable( + (PVOID)pStartRange, // this is just an ID that gets passed to RtlDeleteFunctionTable; + (PVOID)pStartRange, + (ULONG)((ULONG64)pEndRange - (ULONG64)pStartRange), + GetRuntimeFunctionCallback, + this); + } } EX_CATCH { @@ -2666,9 +2709,9 @@ HeapList* EEJitManager::NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapLi RETURN(pHp); } -void* EEJitManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, - size_t header, size_t blockSize, unsigned align, - HeapList ** ppCodeHeap) +void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, + size_t header, size_t blockSize, unsigned align, + HeapList ** ppCodeHeap) { CONTRACT(void *) { THROWS; @@ -2686,13 +2729,30 @@ void* EEJitManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, // Avoid going through the full list in the common case - try to use the most recently used codeheap if (pInfo->IsDynamicDomain()) { - pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap; - pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = NULL; + if (pInfo->IsInterpreted()) + { + pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap; + pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap = NULL; + } + else + { + // Interpreter-TODO: interpreter and dynamic domain at the same time + pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap; + pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = NULL; + } } else { - pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedCodeHeap; - pInfo->m_pAllocator->m_pLastUsedCodeHeap = NULL; + if (pInfo->IsInterpreted()) + { + pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap; + pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap = NULL; + } + else + { + pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedCodeHeap; + pInfo->m_pAllocator->m_pLastUsedCodeHeap = NULL; + } } // If we will use a cached code heap, ensure that the code heap meets the constraints @@ -2747,11 +2807,25 @@ void* EEJitManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, if (pInfo->IsDynamicDomain()) { - pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = pCodeHeap; + if (pInfo->IsInterpreted()) + { + pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap = pCodeHeap; + } + else + { + pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = pCodeHeap; + } } else { - pInfo->m_pAllocator->m_pLastUsedCodeHeap = pCodeHeap; + if (pInfo->IsInterpreted()) + { + pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap = pCodeHeap; + } + else + { + pInfo->m_pAllocator->m_pLastUsedCodeHeap = pCodeHeap; + } } // Record the pCodeHeap value into ppCodeHeap @@ -2768,13 +2842,13 @@ void* EEJitManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, RETURN(mem); } -void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, CodeHeader** ppCodeHeader, CodeHeader** ppCodeHeaderRW, - size_t* pAllocatedSize, HeapList** ppCodeHeap - , BYTE** ppRealHeader +void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, CodeHeader** ppCodeHeader, CodeHeader** ppCodeHeaderRW, + size_t* pAllocatedSize, HeapList** ppCodeHeap + , BYTE** ppRealHeader #ifdef FEATURE_EH_FUNCLETS - , UINT nUnwindInfos + , UINT nUnwindInfos #endif - ) + ) { CONTRACTL { THROWS; @@ -2821,13 +2895,30 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo requestInfo.SetDynamicDomain(); } #endif - requestInfo.setReserveForJumpStubs(reserveForJumpStubs); + + if (flag & CORJIT_ALLOCMEM_FLG_INTERPRETED) + { + _ASSERTE(nUnwindInfos == 0); + _ASSERTE(reserveForJumpStubs == 0); + + requestInfo.SetInterpreted(); + } + + SIZE_T realHeaderSize; + if (requestInfo.IsInterpreted()) + { + realHeaderSize = sizeof(InterpreterRealCodeHeader); + } + else + { + requestInfo.setReserveForJumpStubs(reserveForJumpStubs); #ifdef FEATURE_EH_FUNCLETS - SIZE_T realHeaderSize = offsetof(RealCodeHeader, unwindInfos[0]) + (sizeof(T_RUNTIME_FUNCTION) * nUnwindInfos); + realHeaderSize = offsetof(JitRealCodeHeader, unwindInfos[0]) + (sizeof(T_RUNTIME_FUNCTION) * nUnwindInfos); #else - SIZE_T realHeaderSize = sizeof(RealCodeHeader); + realHeaderSize = sizeof(JitRealCodeHeader); #endif + } // if this is a LCG method then we will be allocating the RealCodeHeader // following the code so that the code block can be removed easily by @@ -2853,13 +2944,13 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo _ASSERTE(IS_ALIGNED(pCode, alignment)); - pCodeHdr = ((CodeHeader *)pCode) - 1; + pCodeHdr = ((JitCodeHeader *)pCode) - 1; - *pAllocatedSize = sizeof(CodeHeader) + totalSize; + *pAllocatedSize = sizeof(JitCodeHeader) + totalSize; - if (ExecutableAllocator::IsWXORXEnabled()) + if (ExecutableAllocator::IsWXORXEnabled() && !requestInfo.IsInterpreted()) { - pCodeHdrRW = (CodeHeader *)new BYTE[*pAllocatedSize]; + pCodeHdrRW = (JitCodeHeader *)new BYTE[*pAllocatedSize]; } else { @@ -2885,7 +2976,10 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo pCodeHdrRW->SetGCInfo(NULL); pCodeHdrRW->SetMethodDesc(pMD); #ifdef FEATURE_EH_FUNCLETS - pCodeHdrRW->SetNumberOfUnwindInfos(nUnwindInfos); + if (!requestInfo.IsInterpreted()) + { + ((JitCodeHeader*)pCodeHdrRW)->SetNumberOfUnwindInfos(nUnwindInfos); + } #endif if (requestInfo.IsDynamicDomain()) @@ -2902,7 +2996,7 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo *ppCodeHeaderRW = pCodeHdrRW; } -EEJitManager::DomainCodeHeapList *EEJitManager::GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly) +EEJitManager::DomainCodeHeapList *EECodeGenManager::GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly) { CONTRACTL { NOTHROW; @@ -2943,7 +3037,7 @@ EEJitManager::DomainCodeHeapList *EEJitManager::GetCodeHeapList(CodeHeapRequestI return pList; } -bool EEJitManager::CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHeap) +bool EECodeGenManager::CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHeap) { CONTRACTL { NOTHROW; @@ -3037,7 +3131,7 @@ bool EEJitManager::CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHea return retVal; } -EEJitManager::DomainCodeHeapList * EEJitManager::CreateCodeHeapList(CodeHeapRequestInfo *pInfo) +EEJitManager::DomainCodeHeapList * EECodeGenManager::CreateCodeHeapList(CodeHeapRequestInfo *pInfo) { CONTRACTL { THROWS; @@ -3058,7 +3152,7 @@ EEJitManager::DomainCodeHeapList * EEJitManager::CreateCodeHeapList(CodeHeapRequ return pNewList.Extract(); } -LoaderHeap *EEJitManager::GetJitMetaHeap(MethodDesc *pMD) +LoaderHeap *EECodeGenManager::GetJitMetaHeap(MethodDesc *pMD) { CONTRACTL { NOTHROW; @@ -3071,7 +3165,7 @@ LoaderHeap *EEJitManager::GetJitMetaHeap(MethodDesc *pMD) return pAllocator->GetLowFrequencyHeap(); } -BYTE* EEJitManager::allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) +BYTE* EECodeGenManager::allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) { CONTRACTL { THROWS; @@ -3096,7 +3190,7 @@ BYTE* EEJitManager::allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t return(pCodeHeader->GetGCInfo()); } -void* EEJitManager::allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) +void* EECodeGenManager::allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) { CONTRACTL { THROWS; @@ -3124,7 +3218,7 @@ void* EEJitManager::allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, siz } -EE_ILEXCEPTION* EEJitManager::allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) +EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) { CONTRACTL { THROWS; @@ -3250,7 +3344,7 @@ void * EEJitManager::allocCodeFragmentBlock(size_t blockSize, unsigned alignment #endif // !DACCESS_COMPILE -GCInfoToken EEJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken) +GCInfoToken EECodeGenManager::GetGCInfoToken(const METHODTOKEN& MethodToken) { CONTRACTL { NOTHROW; @@ -3263,7 +3357,7 @@ GCInfoToken EEJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken) } // creates an enumeration and returns the number of EH clauses -unsigned EEJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState) +unsigned EECodeGenManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState) { LIMITED_METHOD_CONTRACT; EE_ILEXCEPTION * EHInfo = GetCodeHeader(MethodToken)->GetEHInfo(); @@ -3278,7 +3372,7 @@ unsigned EEJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, E return *(dac_cast(dac_cast(EHInfo) - sizeof(size_t))); } -PTR_EXCEPTION_CLAUSE_TOKEN EEJitManager::GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, +PTR_EXCEPTION_CLAUSE_TOKEN EECodeGenManager::GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, EE_ILEXCEPTION_CLAUSE* pEHClauseOut) { CONTRACTL { @@ -3295,7 +3389,7 @@ PTR_EXCEPTION_CLAUSE_TOKEN EEJitManager::GetNextEHClause(EH_CLAUSE_ENUMERATOR* p } #ifndef DACCESS_COMPILE -TypeHandle EEJitManager::ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, +TypeHandle EECodeGenManager::ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, CrawlFrame *pCf) { // We don't want to use a runtime contract here since this codepath is used during @@ -3331,7 +3425,14 @@ TypeHandle EEJitManager::ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, ClassLoader::ReturnNullIfNotFound); } -void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len) +void EEJitManager::UnpublishUnwindInfoForMethod(TADDR codeStart) +{ +#if defined(TARGET_AMD64) + UnwindInfoTable::UnpublishUnwindInfoForMethod((TADDR)codeStart); +#endif // defined(TARGET_AMD64) +} + +void EECodeGenManager::RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len) { CONTRACTL { NOTHROW; @@ -3355,10 +3456,8 @@ void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t pResolver->m_recordCodePointer = NULL; } -#if defined(TARGET_AMD64) // Remove the unwind information (if applicable) - UnwindInfoTable::UnpublishUnwindInfoForMethod((TADDR)codeStart); -#endif // defined(TARGET_AMD64) + UnpublishUnwindInfoForMethod((TADDR)codeStart); HostCodeHeap* pHeap = HostCodeHeap::GetCodeHeap((TADDR)codeStart); FreeCodeMemory(pHeap, codeStart); @@ -3429,7 +3528,7 @@ void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t // count is 0, we can safely delete, otherwise we must add to the cleanup list to be deleted later. We know // there can only be one unload at a time, so we can use a single var to hold the unlinked, but not deleted, // elements. -void EEJitManager::Unload(LoaderAllocator *pAllocator) +void EECodeGenManager::Unload(LoaderAllocator *pAllocator) { CONTRACTL { NOTHROW; @@ -3496,7 +3595,7 @@ EEJitManager::DomainCodeHeapList::~DomainCodeHeapList() LIMITED_METHOD_CONTRACT; } -void EEJitManager::RemoveCodeHeapFromDomainList(CodeHeap *pHeap, LoaderAllocator *pAllocator) +void EECodeGenManager::RemoveCodeHeapFromDomainList(CodeHeap *pHeap, LoaderAllocator *pAllocator) { CONTRACTL { NOTHROW; @@ -3532,7 +3631,51 @@ void EEJitManager::RemoveCodeHeapFromDomainList(CodeHeap *pHeap, LoaderAllocator } } -void EEJitManager::FreeCodeMemory(HostCodeHeap *pCodeHeap, void * codeStart) +#ifdef FEATURE_INTERPRETER + +InterpreterJitManager::InterpreterJitManager() : + m_interpreter(NULL), + m_interpreterHandle(NULL), + m_interpreterLoadCritSec(CrstSingleUseLock) +{ + LIMITED_METHOD_CONTRACT; +} + +BOOL InterpreterJitManager::LoadInterpreter() +{ + STANDARD_VM_CONTRACT; + + // If the JIT is already loaded, don't take the lock. + if (IsInterpreterLoaded()) + return TRUE; + + // Use m_interpreterLoadCritSec to ensure that the interpreter is loaded on one thread only + CrstHolder chRead(&m_interpreterLoadCritSec); + + // Did someone load the JIT before we got the lock? + if (IsInterpreterLoaded()) + return TRUE; + + m_storeRichDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_RichDebugInfo) != 0; + + ICorJitCompiler* newInterpreter = NULL; + m_interpreter = NULL; + + g_interpreterLoadData.jld_id = JIT_LOAD_MAIN; + LPWSTR interpreterPath = NULL; +#ifdef _DEBUG + IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_InterpreterPath, &interpreterPath)); +#endif + LoadAndInitializeJIT(ExecutionManager::GetInterpreterName() DEBUGARG(interpreterPath), &m_interpreterHandle, &newInterpreter, &g_interpreterLoadData, getClrVmOs()); + + // Publish the interpreter. + m_interpreter = newInterpreter; + + return IsInterpreterLoaded(); +} +#endif // FEATURE_INTERPRETER + +void EECodeGenManager::FreeCodeMemory(HostCodeHeap *pCodeHeap, void * codeStart) { CONTRACTL { @@ -3566,9 +3709,12 @@ void ExecutionManager::CleanupCodeHeaps() _ASSERTE (IsAtProcessExit() || (GCHeapUtilities::IsGCInProgress() && ::IsGCThread())); GetEEJitManager()->CleanupCodeHeaps(); +#ifdef FEATURE_INTERPRETER + GetInterpreterJitManager()->CleanupCodeHeaps(); +#endif // FEATURE_INTERPRETER } -void EEJitManager::CleanupCodeHeaps() +void EECodeGenManager::CleanupCodeHeaps() { CONTRACTL { @@ -3616,7 +3762,7 @@ void EEJitManager::CleanupCodeHeaps() } } -void EEJitManager::RemoveFromCleanupList(HostCodeHeap *pCodeHeap) +void EECodeGenManager::RemoveFromCleanupList(HostCodeHeap *pCodeHeap) { CONTRACTL { NOTHROW; @@ -3646,7 +3792,7 @@ void EEJitManager::RemoveFromCleanupList(HostCodeHeap *pCodeHeap) } } -void EEJitManager::AddToCleanupList(HostCodeHeap *pCodeHeap) +void EECodeGenManager::AddToCleanupList(HostCodeHeap *pCodeHeap) { CONTRACTL { NOTHROW; @@ -3676,7 +3822,7 @@ void EEJitManager::AddToCleanupList(HostCodeHeap *pCodeHeap) } } -void EEJitManager::DeleteCodeHeap(HeapList *pHeapList) +void EECodeGenManager::DeleteCodeHeap(HeapList *pHeapList) { CONTRACTL { NOTHROW; @@ -3735,7 +3881,7 @@ static CodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & r //----------------------------------------------------------------------------- // Get vars from Jit Store //----------------------------------------------------------------------------- -BOOL EEJitManager::GetBoundariesAndVars( +BOOL EECodeGenManager::GetBoundariesAndVars( const DebugInfoRequest & request, IN FP_IDS_NEW fpNew, IN void * pNewData, OUT ULONG32 * pcMap, @@ -3781,7 +3927,7 @@ BOOL EEJitManager::GetBoundariesAndVars( return TRUE; } -BOOL EEJitManager::GetRichDebugInfo( +BOOL EECodeGenManager::GetRichDebugInfo( const DebugInfoRequest& request, IN FP_IDS_NEW fpNew, IN void* pNewData, OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, @@ -3848,7 +3994,7 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ //----------------------------------------------------------------------------- // Enumerate for minidumps. //----------------------------------------------------------------------------- -void EEJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) { CONTRACTL { @@ -3868,7 +4014,7 @@ void EEJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags fl } #endif // DACCESS_COMPILE -PCODE EEJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) +PCODE EECodeGenManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) { WRAPPER_NO_CONTRACT; @@ -3876,7 +4022,7 @@ PCODE EEJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, D return pHeader->GetCodeStartAddress() + relOffset; } -BOOL EEJitManager::JitCodeToMethodInfo( +BOOL EECodeGenManager::JitCodeToMethodInfo( RangeSection * pRangeSection, PCODE currentPC, MethodDesc ** ppMethodDesc, @@ -3893,7 +4039,7 @@ BOOL EEJitManager::JitCodeToMethodInfo( if (pRangeSection->_flags & RangeSection::RANGE_SECTION_RANGELIST) return FALSE; - TADDR start = dac_cast(pRangeSection->_pjit)->FindMethodCode(pRangeSection, currentPC); + TADDR start = dac_cast(pRangeSection->_pjit)->FindMethodCode(pRangeSection, currentPC); if (start == (TADDR)0) return FALSE; @@ -3925,7 +4071,7 @@ BOOL EEJitManager::JitCodeToMethodInfo( return TRUE; } -StubCodeBlockKind EEJitManager::GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) +StubCodeBlockKind EECodeGenManager::GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) { CONTRACTL { NOTHROW; @@ -3938,7 +4084,7 @@ StubCodeBlockKind EEJitManager::GetStubCodeBlockKind(RangeSection * pRangeSectio return pRangeSection->_pRangeList->GetCodeBlockKind(); } - TADDR start = dac_cast(pRangeSection->_pjit)->FindMethodCode(pRangeSection, currentPC); + TADDR start = dac_cast(pRangeSection->_pjit)->FindMethodCode(pRangeSection, currentPC); if (start == (TADDR)0) return STUB_CODE_BLOCK_NOCODE; CodeHeader * pCHdr = PTR_CodeHeader(start - sizeof(CodeHeader)); @@ -3946,7 +4092,7 @@ StubCodeBlockKind EEJitManager::GetStubCodeBlockKind(RangeSection * pRangeSectio } -TADDR EEJitManager::FindMethodCode(PCODE currentPC) +TADDR EECodeGenManager::FindMethodCode(PCODE currentPC) { CONTRACTL { NOTHROW; @@ -3957,13 +4103,13 @@ TADDR EEJitManager::FindMethodCode(PCODE currentPC) RangeSection * pRS = ExecutionManager::FindCodeRange(currentPC, ExecutionManager::GetScanFlags()); if (pRS == NULL || (pRS->_flags & RangeSection::RANGE_SECTION_CODEHEAP) == 0) return STUB_CODE_BLOCK_NOCODE; - return dac_cast(pRS->_pjit)->FindMethodCode(pRS, currentPC); + return dac_cast(pRS->_pjit)->FindMethodCode(pRS, currentPC); } // Finds the header corresponding to the code at offset "delta". // Returns NULL if there is no header for the given "delta" // For implementation details, see comment in nibblemapmacros.h -TADDR EEJitManager::FindMethodCode(RangeSection * pRangeSection, PCODE currentPC) +TADDR EECodeGenManager::FindMethodCode(RangeSection * pRangeSection, PCODE currentPC) { using namespace NibbleMap; @@ -4067,7 +4213,7 @@ TADDR EEJitManager::FindMethodCode(RangeSection * pRangeSection, PCODE currentPC #if !defined(DACCESS_COMPILE) -void EEJitManager::NibbleMapSet(HeapList * pHp, TADDR pCode, size_t codeSize) +void EECodeGenManager::NibbleMapSet(HeapList * pHp, TADDR pCode, size_t codeSize) { CONTRACTL { NOTHROW; @@ -4079,7 +4225,7 @@ void EEJitManager::NibbleMapSet(HeapList * pHp, TADDR pCode, size_t codeSize) } // For implementation details, see comment in nibblemapmacros.h -void EEJitManager::NibbleMapSetUnlocked(HeapList * pHp, TADDR pCode, size_t codeSize) +void EECodeGenManager::NibbleMapSetUnlocked(HeapList * pHp, TADDR pCode, size_t codeSize) { using namespace NibbleMap; @@ -4131,7 +4277,7 @@ void EEJitManager::NibbleMapSetUnlocked(HeapList * pHp, TADDR pCode, size_t code } // For implementation details, see comment in nibblemapmacros.h -void EEJitManager::NibbleMapDelete(HeapList* pHp, TADDR pCode) +void EECodeGenManager::NibbleMapDelete(HeapList* pHp, TADDR pCode) { CONTRACTL { NOTHROW; @@ -4142,7 +4288,7 @@ void EEJitManager::NibbleMapDelete(HeapList* pHp, TADDR pCode) NibbleMapDeleteUnlocked(pHp, pCode); } -void EEJitManager::NibbleMapDeleteUnlocked(HeapList* pHp, TADDR pCode) +void EECodeGenManager::NibbleMapDeleteUnlocked(HeapList* pHp, TADDR pCode) { using namespace NibbleMap; @@ -4205,7 +4351,7 @@ PTR_RUNTIME_FUNCTION EEJitManager::LazyGetFunctionEntry(EECodeInfo * pCodeInfo) return NULL; } - CodeHeader * pHeader = GetCodeHeader(pCodeInfo->GetMethodToken()); + JitCodeHeader * pHeader = dac_cast(GetCodeHeader(pCodeInfo->GetMethodToken())); DWORD address = RUNTIME_FUNCTION__BeginAddress(pHeader->GetUnwindInfo(0)) + pCodeInfo->GetRelOffset(); @@ -4236,7 +4382,7 @@ DWORD EEJitManager::GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD } CONTRACTL_END; - CodeHeader * pCH = GetCodeHeader(MethodToken); + JitCodeHeader * pCH = dac_cast(GetCodeHeader(MethodToken)); TADDR moduleBase = JitTokenToModuleBase(MethodToken); _ASSERTE(pCH->GetNumberOfUnwindInfos() >= 1); @@ -4413,7 +4559,7 @@ extern "C" void GetRuntimeStackWalkInfo(IN ULONG64 ControlPc, #ifdef DACCESS_COMPILE -void EEJitManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) +void EECodeGenManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) { IJitManager::EnumMemoryRegions(flags); @@ -4473,6 +4619,10 @@ void ExecutionManager::Init() #ifdef FEATURE_READYTORUN m_pReadyToRunJitManager = new ReadyToRunJitManager(); #endif + +#ifdef FEATURE_INTERPRETER + m_pInterpreterJitManager = new InterpreterJitManager(); +#endif } #endif // #ifndef DACCESS_COMPILE @@ -4629,7 +4779,7 @@ BOOL ExecutionManager::IsManagedCodeWorker(PCODE currentPC, RangeSectionLockStat // Typically if we find a Jit Manager we are inside a managed method // but on we could also be in a stub, so we check for that // as well and we don't consider stub to be real managed code. - TADDR start = dac_cast(pRS->_pjit)->FindMethodCode(pRS, currentPC); + TADDR start = dac_cast(pRS->_pjit)->FindMethodCode(pRS, currentPC); if (start == (TADDR)0) return FALSE; CodeHeader * pCHdr = PTR_CodeHeader(start - sizeof(CodeHeader)); @@ -4644,6 +4794,14 @@ BOOL ExecutionManager::IsManagedCodeWorker(PCODE currentPC, RangeSectionLockStat return TRUE; } #endif +#ifdef FEATURE_INTERPRETER + else + if (pRS->_flags & RangeSection::RANGE_SECTION_INTERPRETER) + { + if (dac_cast(pRS->_pjit)->JitCodeToMethodInfo(pRS, currentPC, NULL, NULL)) + return TRUE; + } +#endif return FALSE; } @@ -4712,8 +4870,31 @@ LPCWSTR ExecutionManager::GetJitName() return pwzJitName; } + #endif // !FEATURE_MERGE_JIT_AND_ENGINE +#ifdef FEATURE_INTERPRETER + +// This static method returns the name of the interpreter dll +// +LPCWSTR ExecutionManager::GetInterpreterName() +{ + STANDARD_VM_CONTRACT; + + LPCWSTR pwzInterpreterName = NULL; + + // Try to obtain a name for the jit library from the env. variable + IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InterpreterName, const_cast(&pwzInterpreterName))); + + if (NULL == pwzInterpreterName) + { + pwzInterpreterName = MAKEDLLNAME_W(W("clrinterpreter")); + } + + return pwzInterpreterName; +} +#endif // FEATURE_INTERPRETER + RangeSection* ExecutionManager::GetRangeSection(TADDR addr, RangeSectionLockState *pLockState) { CONTRACTL { diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 35c149355fae27..880e45c3d2e783 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -118,10 +118,10 @@ enum StubCodeBlockKind : int // Today CodeHeader is used by the EEJitManager. // The GCInfo version is always current GCINFO_VERSION in this header. -typedef DPTR(struct _hpRealCodeHdr) PTR_RealCodeHeader; -typedef DPTR(struct _hpCodeHdr) PTR_CodeHeader; +typedef DPTR(struct RealCodeHeader) PTR_RealCodeHeader; +typedef DPTR(struct CodeHeader) PTR_CodeHeader; -typedef struct _hpRealCodeHdr +struct RealCodeHeader { public: PTR_BYTE phdrDebugInfo; @@ -137,6 +137,12 @@ typedef struct _hpRealCodeHdr PTR_MethodDesc phdrMDesc; +public: +// if we're using the indirect codeheaders then all enumeration is done by the code header +}; + +struct JitRealCodeHeader : public RealCodeHeader +{ #ifdef FEATURE_EH_FUNCLETS DWORD nUnwindInfos; T_RUNTIME_FUNCTION unwindInfos[0]; @@ -144,9 +150,15 @@ typedef struct _hpRealCodeHdr public: // if we're using the indirect codeheaders then all enumeration is done by the code header -} RealCodeHeader; +}; + +struct InterpreterRealCodeHeader : public RealCodeHeader +{ +public: +// if we're using the indirect codeheaders then all enumeration is done by the code header +}; -typedef struct _hpCodeHdr +struct CodeHeader { PTR_RealCodeHeader pRealCodeHeader; @@ -227,32 +239,53 @@ typedef struct _hpCodeHdr pRealCodeHeader = (PTR_RealCodeHeader)kind; } +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); +#endif // DACCESS_COMPILE + +}; + +typedef DPTR(JitRealCodeHeader) PTR_JitRealCodeHeader; +typedef DPTR(InterpreterRealCodeHeader) PTR_InterpreterRealCodeHeader; + +struct JitCodeHeader : public CodeHeader +{ #if defined(FEATURE_EH_FUNCLETS) UINT GetNumberOfUnwindInfos() { SUPPORTS_DAC; - return pRealCodeHeader->nUnwindInfos; + return ((PTR_JitRealCodeHeader)pRealCodeHeader)->nUnwindInfos; } void SetNumberOfUnwindInfos(UINT nUnwindInfos) { LIMITED_METHOD_CONTRACT; - pRealCodeHeader->nUnwindInfos = nUnwindInfos; + ((PTR_JitRealCodeHeader)pRealCodeHeader)->nUnwindInfos = nUnwindInfos; } PTR_RUNTIME_FUNCTION GetUnwindInfo(UINT iUnwindInfo) { SUPPORTS_DAC; _ASSERTE(iUnwindInfo < GetNumberOfUnwindInfos()); return dac_cast( - PTR_TO_MEMBER_TADDR(RealCodeHeader, pRealCodeHeader, unwindInfos) + iUnwindInfo * sizeof(T_RUNTIME_FUNCTION)); + PTR_TO_MEMBER_TADDR(JitRealCodeHeader, (PTR_JitRealCodeHeader)pRealCodeHeader, unwindInfos) + iUnwindInfo * sizeof(T_RUNTIME_FUNCTION)); } #endif // FEATURE_EH_FUNCLETS +}; -#ifdef DACCESS_COMPILE - void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); -#endif // DACCESS_COMPILE +typedef DPTR(JitCodeHeader) PTR_JitCodeHeader; -} CodeHeader; +// The code headers must have the same size, they only point to a different type of the real code header +static_assert(sizeof(JitCodeHeader) == sizeof(CodeHeader), "JitCodeHeader and CodeHeader must have the same size"); +#ifdef FEATURE_INTERPRETER +struct InterpreterCodeHeader : public CodeHeader +{ +}; + +typedef DPTR(InterpreterCodeHeader) PTR_InterpreterCodeHeader; + +static_assert(sizeof(InterpreterCodeHeader) == sizeof(CodeHeader), "InterpreterCodeHeader and CodeHeader must have the same size"); + +#endif // FEATURE_INTERPRETER //----------------------------------------------------------------------------- // This is a structure used to consolidate the information that we @@ -271,6 +304,7 @@ struct CodeHeapRequestInfo size_t m_reserveForJumpStubs; // Amount to reserve for jump stubs (won't be allocated) bool m_isDynamicDomain; bool m_isCollectible; + bool m_isInterpreted; bool m_throwOnOutOfMemoryWithinRange; bool IsDynamicDomain() { return m_isDynamicDomain; } @@ -278,6 +312,9 @@ struct CodeHeapRequestInfo bool IsCollectible() { return m_isCollectible; } + bool IsInterpreted() { return m_isInterpreted; } + void SetInterpreted() { m_isInterpreted = true; } + size_t getRequestSize() { return m_requestSize; } void setRequestSize(size_t requestSize) { m_requestSize = requestSize; } @@ -296,6 +333,7 @@ struct CodeHeapRequestInfo : m_pMD(pMD), m_pAllocator(0), m_loAddr(0), m_hiAddr(0), m_requestSize(0), m_reserveSize(0), m_reserveForJumpStubs(0) + , m_isInterpreted(false) { WRAPPER_NO_CONTRACT; Init(); } CodeHeapRequestInfo(MethodDesc *pMD, LoaderAllocator* pAllocator, @@ -303,6 +341,7 @@ struct CodeHeapRequestInfo : m_pMD(pMD), m_pAllocator(pAllocator), m_loAddr(loAddr), m_hiAddr(hiAddr), m_requestSize(0), m_reserveSize(0), m_reserveForJumpStubs(0) + , m_isInterpreted(false) { WRAPPER_NO_CONTRACT; Init(); } }; @@ -318,7 +357,7 @@ struct CodeHeapRequestInfo // critical section - m_pCodeHeapCritSec - so if the implementation of the heap // is only for the code manager, no locking needs to occur. // It's important however that a delete operation on the CodeHeap (if any) happens -// via EEJitManager::FreeCodeMemory(HostCodeHeap*, void*) +// via EECodeGenManager::FreeCodeMemory(HostCodeHeap*, void*) // // The heap to be created depends on the MethodDesc that is being compiled. // Standard code uses the LoaderCodeHeap, a heap based on the LoaderHeap. @@ -382,14 +421,14 @@ struct HeapList PTR_LoaderAllocator pLoaderAllocator; // LoaderAllocator of HeapList #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - BYTE* CLRPersonalityRoutine; // jump thunk to personality routine + BYTE* CLRPersonalityRoutine; // jump thunk to personality routine, NULL if there is no personality routine (e.g. interpreter code heap) #endif TADDR GetModuleBase() { #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - return (TADDR)CLRPersonalityRoutine; - #else + return (CLRPersonalityRoutine != NULL) ? (TADDR)CLRPersonalityRoutine : (TADDR)mapBase; +#else return (TADDR)mapBase; #endif } @@ -421,7 +460,7 @@ class LoaderCodeHeap : CodeHeap ExplicitControlLoaderHeap m_LoaderHeap; SSIZE_T m_cbMinNextPad; - LoaderCodeHeap(); + LoaderCodeHeap(BOOL fMakeExecutable); public: static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap *pJitMetaHeap); @@ -566,6 +605,7 @@ struct RangeSection RANGE_SECTION_COLLECTIBLE = 0x1, RANGE_SECTION_CODEHEAP = 0x2, RANGE_SECTION_RANGELIST = 0x4, + RANGE_SECTION_INTERPRETER = 0x8, }; #ifdef FEATURE_READYTORUN @@ -1651,13 +1691,173 @@ class IJitManager PTR_ICodeManager m_runtimeSupport; }; -//----------------------------------------------------------------------------- - class HostCodeHeap; typedef VPTR(class HostCodeHeap) PTR_HostCodeHeap; +class EECodeGenManager : public IJitManager +{ +#ifdef DACCESS_COMPILE + friend class ClrDataAccess; + friend class DacDbiInterfaceImpl; +#endif + friend class CheckDuplicatedStructLayouts; + + VPTR_ABSTRACT_VTABLE_CLASS(EECodeGenManager, IJitManager) + + struct DomainCodeHeapList { + LoaderAllocator *m_pAllocator; + CDynArray m_CodeHeapList; + DomainCodeHeapList(); + ~DomainCodeHeapList(); + }; + +public: + + EECodeGenManager(); + + virtual ICorJitCompiler* GetCompiler() = 0; + virtual ICorJitCompiler* GetAltCompiler() = 0; + + // Used to read debug info. + virtual BOOL GetBoundariesAndVars( + const DebugInfoRequest & request, + IN FP_IDS_NEW fpNew, IN void * pNewData, + OUT ULONG32 * pcMap, + OUT ICorDebugInfo::OffsetMapping **ppMap, + OUT ULONG32 * pcVars, + OUT ICorDebugInfo::NativeVarInfo **ppVars); + + virtual BOOL GetRichDebugInfo( + const DebugInfoRequest& request, + IN FP_IDS_NEW fpNew, IN void* pNewData, + OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, + OUT ULONG32* pNumInlineTree, + OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, + OUT ULONG32* pNumRichMappings); + + virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset); + + virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo); + + virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken); + + virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState); + virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, + EE_ILEXCEPTION_CLAUSE* pEHclause); + + GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); + + static CodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); + static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); + + virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC); + + static TADDR FindMethodCode(RangeSection * pRangeSection, PCODE currentPC); + static TADDR FindMethodCode(PCODE currentPC); + + bool IsStoringRichDebugInfo() + { + LIMITED_METHOD_CONTRACT; + return m_storeRichDebugInfo; + } + +#ifndef DACCESS_COMPILE + virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, + CrawlFrame *pCf); + + void RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); + void Unload(LoaderAllocator* pAllocator); + void CleanupCodeHeaps(); + + void allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, CodeHeader** ppCodeHeader, CodeHeader** ppCodeHeaderRW, + size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader +#ifdef FEATURE_EH_FUNCLETS + , UINT nUnwindInfos +#endif + ); + BYTE *allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); + EE_ILEXCEPTION* allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); + + // Heap Management functions + void NibbleMapSet(HeapList * pHp, TADDR pCode, size_t codeSize); + void NibbleMapSetUnlocked(HeapList * pHp, TADDR pCode, size_t codeSize); + void NibbleMapDelete(HeapList* pHp, TADDR pCode); + void NibbleMapDeleteUnlocked(HeapList* pHp, TADDR pCode); + + void FreeCodeMemory(HostCodeHeap *pCodeHeap, void * codeStart); + void RemoveFromCleanupList(HostCodeHeap *pCodeHeap); + void AddToCleanupList(HostCodeHeap *pCodeHeap); + void DeleteCodeHeap(HeapList *pHeapList); + void RemoveCodeHeapFromDomainList(CodeHeap *pHeap, LoaderAllocator *pAllocator); + + HeapList* NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapList *pADHeapList); + bool CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHeap); + +protected: + void* allocCodeRaw(CodeHeapRequestInfo *pInfo, size_t header, size_t blockSize, unsigned align, HeapList ** ppCodeHeap); + void* allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); + virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) = 0; + + DomainCodeHeapList *GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly = FALSE); + DomainCodeHeapList* CreateCodeHeapList(CodeHeapRequestInfo *pInfo); + LoaderHeap* GetJitMetaHeap(MethodDesc *pMD); + + HeapList * GetCodeHeapList() + { + return m_pCodeHeap; + } + +public: + class CodeHeapIterator + { + CrstHolder m_lockHolder; + HeapList *m_pHeapList; + LoaderAllocator *m_pLoaderAllocator; + MethodSectionIterator m_Iterator; + MethodDesc *m_pCurrent; + + public: + CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter = NULL); + ~CodeHeapIterator(); + BOOL Next(); + + MethodDesc *GetMethod() + { + LIMITED_METHOD_CONTRACT; + return m_pCurrent; + } + + TADDR GetMethodCode() + { + LIMITED_METHOD_CONTRACT; + return (TADDR)m_Iterator.GetMethodCode(); + } + }; +#else // !DACCESS_COMPILE + virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); +#endif // !DACCESS_COMPILE + +private: + PTR_HeapList m_pCodeHeap; + PTR_HostCodeHeap m_cleanupList; + // must hold critical section to access this structure. + CUnorderedArray m_DomainCodeHeaps; + CUnorderedArray m_DynamicDomainCodeHeaps; +protected: + Crst m_CodeHeapCritSec; + bool m_storeRichDebugInfo; +}; + +//----------------------------------------------------------------------------- + typedef VPTR(class EEJitManager) PTR_EEJitManager; +typedef VPTR(class EECodeGenManager) PTR_EECodeGenManager; typedef VPTR(class ReadyToRunJitManager) PTR_ReadyToRunJitManager; +typedef VPTR(class InterpreterJitManager) PTR_InterpreterJitManager; struct JumpStubBlockHeader { @@ -1702,7 +1902,7 @@ struct JumpStubBlockHeader /*****************************************************************************/ -class EEJitManager : public IJitManager +class EEJitManager : public EECodeGenManager { #ifdef DACCESS_COMPILE friend class ClrDataAccess; @@ -1711,10 +1911,20 @@ class EEJitManager : public IJitManager friend class CheckDuplicatedStructLayouts; friend class CodeHeapIterator; - VPTR_VTABLE_CLASS(EEJitManager, IJitManager) + VPTR_VTABLE_CLASS(EEJitManager, EECodeGenManager) public: + virtual ICorJitCompiler* GetCompiler() override + { + return m_jit; + } + + virtual ICorJitCompiler* GetAltCompiler() override + { + return m_alternateJit; + } + // Failing to load the main JIT is a failure. // If the user requested an altjit and we failed to load an altjit, that is also a failure. BOOL IsJitLoaded() @@ -1758,67 +1968,19 @@ class EEJitManager : public IJitManager return (miManaged | miIL); } - // Used to read debug info. - virtual BOOL GetBoundariesAndVars( - const DebugInfoRequest & request, - IN FP_IDS_NEW fpNew, IN void * pNewData, - OUT ULONG32 * pcMap, - OUT ICorDebugInfo::OffsetMapping **ppMap, - OUT ULONG32 * pcVars, - OUT ICorDebugInfo::NativeVarInfo **ppVars); - - virtual BOOL GetRichDebugInfo( - const DebugInfoRequest& request, - IN FP_IDS_NEW fpNew, IN void* pNewData, - OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, - OUT ULONG32* pNumInlineTree, - OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, - OUT ULONG32* pNumRichMappings); - - virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset); - - virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection, - PCODE currentPC, - MethodDesc ** ppMethodDesc, - EECodeInfo * pCodeInfo); - - virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken); virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo *methodRegionInfo); - virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState); - virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, - EE_ILEXCEPTION_CLAUSE* pEHclause); -#ifndef DACCESS_COMPILE - virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, - CrawlFrame *pCf); -#endif // !DACCESS_COMPILE - GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); #if !defined DACCESS_COMPILE - void RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); - void Unload(LoaderAllocator* pAllocator); - void CleanupCodeHeaps(); - BOOL LoadJIT(); - void allocCode(MethodDesc* pFD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, CodeHeader** ppCodeHeader, CodeHeader** ppCodeHeaderRW, - size_t* pAllocatedSize, HeapList** ppCodeHeap - , BYTE** ppRealHeader -#ifdef FEATURE_EH_FUNCLETS - , UINT nUnwindInfos -#endif - ); - BYTE * allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); - EE_ILEXCEPTION* allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); JumpStubBlockHeader* allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps, BYTE * loAddr, BYTE * hiAddr, LoaderAllocator *pLoaderAllocator, bool throwOnOutOfMemoryWithinRange); void * allocCodeFragmentBlock(size_t blockSize, unsigned alignment, LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind); -#endif // !DACCESS_COMPILE - static CodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); - static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); +#endif // !DACCESS_COMPILE #if defined(FEATURE_EH_FUNCLETS) // Compute function entry lazily. Do not call directly. Use EECodeInfo::GetFunctionEntry instead. @@ -1827,12 +1989,6 @@ class EEJitManager : public IJitManager virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength); #endif // FEATURE_EH_FUNCLETS - virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC); - -#if defined(DACCESS_COMPILE) - virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); - virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); -#endif // DACCESS_COMPILE #if defined(FEATURE_EH_FUNCLETS) // Enumerate the memory necessary to retrieve the unwind info for a specific method virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) @@ -1845,86 +2001,8 @@ class EEJitManager : public IJitManager } #endif // FEATURE_EH_FUNCLETS -#ifndef DACCESS_COMPILE - // Heap Management functions - void NibbleMapSet(HeapList * pHp, TADDR pCode, size_t codeSize); - void NibbleMapSetUnlocked(HeapList * pHp, TADDR pCode, size_t codeSize); - void NibbleMapDelete(HeapList* pHp, TADDR pCode); - void NibbleMapDeleteUnlocked(HeapList* pHp, TADDR pCode); -#endif // !DACCESS_COMPILE - - static TADDR FindMethodCode(RangeSection * pRangeSection, PCODE currentPC); - static TADDR FindMethodCode(PCODE currentPC); - #if !defined DACCESS_COMPILE - void FreeCodeMemory(HostCodeHeap *pCodeHeap, void * codeStart); - void RemoveFromCleanupList(HostCodeHeap *pCodeHeap); - void AddToCleanupList(HostCodeHeap *pCodeHeap); - void DeleteCodeHeap(HeapList *pHeapList); - void RemoveCodeHeapFromDomainList(CodeHeap *pHeap, LoaderAllocator *pAllocator); -#endif // !DACCESS_COMPILE - -private : - struct DomainCodeHeapList { - LoaderAllocator *m_pAllocator; - CDynArray m_CodeHeapList; - DomainCodeHeapList(); - ~DomainCodeHeapList(); - }; - -#ifndef DACCESS_COMPILE - HeapList* NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapList *pADHeapList); - bool CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHeap); - void* allocCodeRaw(CodeHeapRequestInfo *pInfo, - size_t header, size_t blockSize, unsigned align, - HeapList ** ppCodeHeap); - - DomainCodeHeapList *GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly = FALSE); - DomainCodeHeapList *CreateCodeHeapList(CodeHeapRequestInfo *pInfo); - LoaderHeap* GetJitMetaHeap(MethodDesc *pMD); - - HeapList * GetCodeHeapList() - { - return m_pCodeHeap; - } - -protected: - void * allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); -private: -#endif // !DACCESS_COMPILE - - PTR_HeapList m_pCodeHeap; - -protected : - Crst m_CodeHeapCritSec; - -#if !defined(DACCESS_COMPILE) -public: - class CodeHeapIterator - { - CrstHolder m_lockHolder; - HeapList *m_pHeapList; - LoaderAllocator *m_pLoaderAllocator; - MethodSectionIterator m_Iterator; - MethodDesc *m_pCurrent; - - public: - CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter = NULL); - ~CodeHeapIterator(); - BOOL Next(); - - MethodDesc *GetMethod() - { - LIMITED_METHOD_CONTRACT; - return m_pCurrent; - } - - TADDR GetMethodCode() - { - LIMITED_METHOD_CONTRACT; - return (TADDR)m_Iterator.GetMethodCode(); - } - }; + virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) override; #endif // !DACCESS_COMPILE private: @@ -1941,25 +2019,10 @@ protected : return m_CPUCompileFlags; } -private: - bool m_storeRichDebugInfo; - -public: - bool IsStoringRichDebugInfo() - { - LIMITED_METHOD_CONTRACT; - return m_storeRichDebugInfo; - } - private : - PTR_HostCodeHeap m_cleanupList; //When EH Clauses are resolved we need to atomically update the TypeHandle Crst m_JitLoadCritSec; - // must hold critical section to access this structure. - CUnorderedArray m_DomainCodeHeaps; - CUnorderedArray m_DynamicDomainCodeHeaps; - #ifdef TARGET_AMD64 private: // @@ -2092,8 +2155,20 @@ class ExecutionManager } #endif +#ifdef FEATURE_INTERPRETER + static InterpreterJitManager * GetInterpreterJitManager() + { + LIMITED_METHOD_DAC_CONTRACT; + return m_pInterpreterJitManager; + } +#endif + static LPCWSTR GetJitName(); +#ifdef FEATURE_INTERPRETER + static LPCWSTR GetInterpreterName(); +#endif // FEATURE_INTERPRETER + static void Unload(LoaderAllocator *pLoaderAllocator); static void AddCodeRange(TADDR StartRange, TADDR EndRange, @@ -2153,6 +2228,9 @@ class ExecutionManager #ifdef FEATURE_READYTORUN SPTR_DECL(ReadyToRunJitManager, m_pReadyToRunJitManager); #endif +#ifdef FEATURE_READYTORUN + SPTR_DECL(InterpreterJitManager, m_pInterpreterJitManager); +#endif static CrstStatic m_JumpStubCrst; static CrstStatic m_RangeCrst; // Acquire before writing into m_CodeRangeList and m_DataRangeList @@ -2287,14 +2365,14 @@ struct cdac_data }; #endif -inline CodeHeader * EEJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) +inline CodeHeader * EECodeGenManager::GetCodeHeader(const METHODTOKEN& MethodToken) { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(!MethodToken.IsNull()); return dac_cast(MethodToken.m_pCodeHeader); } -inline CodeHeader * EEJitManager::GetCodeHeaderFromStartAddress(TADDR methodStartAddress) +inline CodeHeader * EECodeGenManager::GetCodeHeaderFromStartAddress(TADDR methodStartAddress) { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(methodStartAddress != (TADDR)NULL); @@ -2302,7 +2380,7 @@ inline CodeHeader * EEJitManager::GetCodeHeaderFromStartAddress(TADDR methodStar return dac_cast(methodStartAddress - sizeof(CodeHeader)); } -inline TADDR EEJitManager::JitTokenToStartAddress(const METHODTOKEN& MethodToken) +inline TADDR EECodeGenManager::JitTokenToStartAddress(const METHODTOKEN& MethodToken) { CONTRACTL { NOTHROW; @@ -2449,6 +2527,103 @@ class ReadyToRunJitManager final: public IJitManager #endif +#ifdef FEATURE_INTERPRETER + +class InterpreterJitManager : public EECodeGenManager +{ + VPTR_VTABLE_CLASS(InterpreterJitManager, EECodeGenManager) +public: + ICorJitCompiler * m_interpreter; + HINSTANCE m_interpreterHandle; + + InterpreterJitManager(); + + virtual ICorJitCompiler* GetCompiler() override + { + return m_interpreter; + } + + virtual ICorJitCompiler* GetAltCompiler() override + { + return NULL; + } + + BOOL LoadInterpreter(); + + BOOL IsInterpreterLoaded() + { + LIMITED_METHOD_CONTRACT; + return m_interpreter != NULL; + } + + virtual DWORD GetCodeType() override + { + LIMITED_METHOD_DAC_CONTRACT; + return (miManaged | miIL); + } + + virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo * methodRegionInfo) override + { + // Not used for the interpreter + _ASSERTE(FALSE); + } + +#if defined(FEATURE_EH_FUNCLETS) + virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo) override + { + // Not used for the interpreter + _ASSERTE(FALSE); + return NULL; + } + + virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo) override + { + // Not used for the interpreter + _ASSERTE(FALSE); + return NULL; + } + + virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength) override + { + // Not used for the interpreter + _ASSERTE(FALSE); + return 0; + } + +#if !defined DACCESS_COMPILE +protected: + virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) override + { + // Nothing to do for the interpreter + } + +public: +#endif // !DACCESS_COMPILE + +#endif // FEATURE_EH_FUNCLETS + + virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) override + { + return STUB_CODE_BLOCK_UNKNOWN; + } + +#if defined(DACCESS_COMPILE) + +#if defined(FEATURE_EH_FUNCLETS) + virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) override + { + // Not used for the interpreter + _ASSERTE(FALSE); + } + +#endif // FEATURE_EH_FUNCLETS +#endif // DACCESS_COMPILE +private : + Crst m_interpreterLoadCritSec; +}; + +#endif // FEATURE_INTERPRETER + //***************************************************************************** // EECodeInfo provides information about code at particular address: // - Start of the method and relative offset diff --git a/src/coreclr/vm/dynamicmethod.cpp b/src/coreclr/vm/dynamicmethod.cpp index 5285bc76e7af1c..c4408c3b081c41 100644 --- a/src/coreclr/vm/dynamicmethod.cpp +++ b/src/coreclr/vm/dynamicmethod.cpp @@ -323,7 +323,7 @@ void DynamicMethodTable::LinkMethod(DynamicMethodDesc *pMethod) // // CodeHeap implementation // -HeapList* HostCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, EEJitManager *pJitManager) +HeapList* HostCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, EECodeGenManager *pJitManager) { CONTRACT (HeapList*) { @@ -353,7 +353,7 @@ HeapList* HostCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, EEJitManager RETURN pHp; } -HostCodeHeap::HostCodeHeap(EEJitManager *pJitManager) +HostCodeHeap::HostCodeHeap(EECodeGenManager *pJitManager) { CONTRACTL { @@ -439,19 +439,27 @@ HeapList* HostCodeHeap::InitializeHeapList(CodeHeapRequestInfo *pInfo) TrackAllocation *pTracker = NULL; -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - - pTracker = AllocMemory_NoThrow(0, JUMP_ALLOCATE_SIZE, sizeof(void*), 0); - if (pTracker == NULL) + if (pInfo->IsInterpreted()) { - // This should only ever happen with fault injection - _ASSERTE(g_pConfig->ShouldInjectFault(INJECTFAULT_DYNAMICCODEHEAP)); - delete pHp; - ThrowOutOfMemory(); + pHp->CLRPersonalityRoutine = NULL; } + else + { +#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + + pTracker = AllocMemory_NoThrow(0, JUMP_ALLOCATE_SIZE, sizeof(void*), 0); + if (pTracker == NULL) + { + // This should only ever happen with fault injection + _ASSERTE(g_pConfig->ShouldInjectFault(INJECTFAULT_DYNAMICCODEHEAP)); + delete pHp; + ThrowOutOfMemory(); + } + + pHp->CLRPersonalityRoutine = (BYTE *)(pTracker + 1); - pHp->CLRPersonalityRoutine = (BYTE *)(pTracker + 1); #endif + } pHp->hpNext = NULL; pHp->pHeap = (PTR_CodeHeap)this; @@ -471,8 +479,11 @@ HeapList* HostCodeHeap::InitializeHeapList(CodeHeapRequestInfo *pInfo) pHp->reserveForJumpStubs = 0; #ifdef HOST_64BIT - ExecutableWriterHolder personalityRoutineWriterHolder(pHp->CLRPersonalityRoutine, 12); - emitJump(pHp->CLRPersonalityRoutine, personalityRoutineWriterHolder.GetRW(), (void *)ProcessCLRException); + if (pHp->CLRPersonalityRoutine != NULL) + { + ExecutableWriterHolder personalityRoutineWriterHolder(pHp->CLRPersonalityRoutine, 12); + emitJump(pHp->CLRPersonalityRoutine, personalityRoutineWriterHolder.GetRW(), (void *)ProcessCLRException); + } #endif size_t nibbleMapSize = HEAP2MAPSIZE(ROUND_UP_TO_PAGE(pHp->maxCodeHeapSize)); diff --git a/src/coreclr/vm/dynamicmethod.h b/src/coreclr/vm/dynamicmethod.h index 894bd178856ae6..6ea8662ca41180 100644 --- a/src/coreclr/vm/dynamicmethod.h +++ b/src/coreclr/vm/dynamicmethod.h @@ -131,7 +131,9 @@ class LCGMethodResolver : public DynamicResolver friend class DynamicMethodTable; // review this to see whether the EEJitManageris the only thing to worry about friend class ExecutionManager; + friend class EECodeGenManager; friend class EEJitManager; + friend class InterpreterJitManager; friend class HostCodeHeap; friend struct ExecutionManager::JumpStubCache; @@ -268,7 +270,9 @@ class HostCodeHeap : CodeHeap #ifdef DACCESS_COMPILE friend class ClrDataAccess; #else + friend class EECodeGenManager; friend class EEJitManager; + friend class InterpreterJitManager; #endif VPTR_VTABLE_CLASS(HostCodeHeap, CodeHeap) @@ -276,7 +280,7 @@ class HostCodeHeap : CodeHeap private: // pointer back to jit manager info PTR_HeapList m_pHeapList; - PTR_EEJitManager m_pJitManager; + PTR_EECodeGenManager m_pJitManager; // basic allocation data PTR_BYTE m_pBaseAddr; PTR_BYTE m_pLastAvailableCommittedAddr; @@ -302,10 +306,10 @@ class HostCodeHeap : CodeHeap LoaderAllocator*m_pAllocator; public: - static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, EEJitManager *pJitManager); + static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, EECodeGenManager *pJitManager); private: - HostCodeHeap(EEJitManager *pJitManager); + HostCodeHeap(EECodeGenManager *pJitManager); HeapList* InitializeHeapList(CodeHeapRequestInfo *pInfo); TrackAllocation* AllocFromFreeList(size_t header, size_t size, DWORD alignment, size_t reserveForJumpStubs); void AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocation *pBlockToInsertRW); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 2e58e15933427d..c7316899196fec 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10897,7 +10897,7 @@ void CEEJitInfo::GetProfilingHandle(bool *pbHookFunction, } /*********************************************************************/ -void CEEJitInfo::WriteCodeBytes() +void CEECodeGenInfo::WriteCodeBytes() { LIMITED_METHOD_CONTRACT; @@ -10916,7 +10916,7 @@ void CEEJitInfo::WriteCodeBytes() } /*********************************************************************/ -void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr) +void CEECodeGenInfo::BackoutJitData(EECodeGenManager * jitMgr) { CONTRACTL { NOTHROW; @@ -10933,32 +10933,41 @@ void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr) } /*********************************************************************/ -void CEEJitInfo::WriteCode(EEJitManager * jitMgr) +void CEEJitInfo::WriteCode(EECodeGenManager * jitMgr) { CONTRACTL { THROWS; GC_TRIGGERS; } CONTRACTL_END; - WriteCodeBytes(); - - // Now that the code header was written to the final location, publish the code via the nibble map - // m_codeWriteBufferSize is the size of the code region + code header. The nibble map should only use - // the code region, therefore we subtract the size of the CodeHeader. - jitMgr->NibbleMapSet(m_pCodeHeap, m_CodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(CodeHeader)); + CEECodeGenInfo::WriteCode(jitMgr); #if defined(TARGET_AMD64) // Publish the new unwind information in a way that the ETW stack crawler can find _ASSERTE(m_usedUnwindInfos == m_totalUnwindInfos); - UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos); + UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, ((JitCodeHeader*)m_CodeHeader)->GetUnwindInfo(0), m_totalUnwindInfos); #endif // defined(TARGET_AMD64) +} + +void CEECodeGenInfo::WriteCode(EECodeGenManager * jitMgr) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + } CONTRACTL_END; + + WriteCodeBytes(); + // Now that the code header was written to the final location, publish the code via the nibble map + // m_codeWriteBufferSize is the size of the code region + code header. The nibble map should only use + // the code region, therefore we subtract the size of the CodeHeader. + jitMgr->NibbleMapSet(m_pCodeHeap, m_CodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(CodeHeader)); } /*********************************************************************/ // Route jit information to the Jit Debug store. -void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, uint32_t cMap, +void CEECodeGenInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, uint32_t cMap, ICorDebugInfo::OffsetMapping *pMap) { CONTRACTL { @@ -10977,7 +10986,7 @@ void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, uint32_t cMap, EE_TO_JIT_TRANSITION(); } -void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, uint32_t cVars, ICorDebugInfo::NativeVarInfo *vars) +void CEECodeGenInfo::setVars(CORINFO_METHOD_HANDLE ftn, uint32_t cVars, ICorDebugInfo::NativeVarInfo *vars) { CONTRACTL { THROWS; @@ -10995,7 +11004,7 @@ void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, uint32_t cVars, ICorDebugInf EE_TO_JIT_TRANSITION(); } -void CEEJitInfo::reportRichMappings( +void CEECodeGenInfo::reportRichMappings( ICorDebugInfo::InlineTreeNode* inlineTreeNodes, uint32_t numInlineTreeNodes, ICorDebugInfo::RichOffsetMapping* mappings, @@ -11009,7 +11018,7 @@ void CEEJitInfo::reportRichMappings( JIT_TO_EE_TRANSITION(); - if (m_jitManager->IsStoringRichDebugInfo()) + if (((EEJitManager*)m_jitManager)->IsStoringRichDebugInfo()) { m_inlineTreeNodes = inlineTreeNodes; m_numInlineTreeNodes = numInlineTreeNodes; @@ -11025,7 +11034,7 @@ void CEEJitInfo::reportRichMappings( EE_TO_JIT_TRANSITION(); } -void CEEJitInfo::reportMetadata( +void CEECodeGenInfo::reportMetadata( const char* key, const void* value, size_t length) @@ -11085,7 +11094,7 @@ PatchpointInfo* CEEJitInfo::getOSRInfo(unsigned* ilOffset) return result; } -void CEEJitInfo::CompressDebugInfo() +void CEECodeGenInfo::CompressDebugInfo() { CONTRACTL { THROWS; @@ -11093,11 +11102,7 @@ void CEEJitInfo::CompressDebugInfo() MODE_PREEMPTIVE; } CONTRACTL_END; -#ifdef FEATURE_ON_STACK_REPLACEMENT - PatchpointInfo* patchpointInfo = m_pPatchpointInfoFromJit; -#else - PatchpointInfo* patchpointInfo = NULL; -#endif + PatchpointInfo* patchpointInfo = GetPatchpointInfo(); // Don't track JIT info for DynamicMethods. if (m_pMethodBeingCompiled->IsDynamicMethod() && !g_pConfig->GetTrackDynamicMethodDebugInfo()) @@ -11117,7 +11122,7 @@ void CEEJitInfo::CompressDebugInfo() #ifdef FEATURE_ON_STACK_REPLACEMENT writeFlagByte = TRUE; #endif - if (m_jitManager->IsStoringRichDebugInfo()) + if (((EEJitManager*)m_jitManager)->IsStoringRichDebugInfo()) writeFlagByte = TRUE; PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars( @@ -11285,7 +11290,7 @@ void CEEJitInfo::allocUnwindInfo ( _ASSERTE(m_usedUnwindInfos > 0); } - PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeaderRW->GetUnwindInfo(m_usedUnwindInfos); + PT_RUNTIME_FUNCTION pRuntimeFunction = ((JitCodeHeader*)m_CodeHeaderRW)->GetUnwindInfo(m_usedUnwindInfos); m_usedUnwindInfos++; @@ -11355,7 +11360,7 @@ void CEEJitInfo::allocUnwindInfo ( for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++) { - PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeaderRW->GetUnwindInfo(iUnwindInfo); + PT_RUNTIME_FUNCTION pOtherFunction = ((JitCodeHeader*)m_CodeHeaderRW)->GetUnwindInfo(iUnwindInfo); _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress + writeableOffset) || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress + writeableOffset) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction))); } @@ -12207,6 +12212,50 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) JIT_TO_EE_TRANSITION(); + CEECodeGenInfo::allocMem(pArgs, GetReserveForJumpStubs() +#ifdef FEATURE_EH_FUNCLETS + , m_totalUnwindInfos, m_totalUnwindSize, &m_theUnwindBlock +#endif + ); + +#ifdef FEATURE_EH_FUNCLETS + m_moduleBase = m_pCodeHeap->GetModuleBase(); +#endif + + EE_TO_JIT_TRANSITION(); +} + +void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION(); + + CEECodeGenInfo::allocMem(pArgs, 0 /* reserveForJumpStubs */ +#ifdef FEATURE_EH_FUNCLETS + , 0 /* unwindInfoCount */, 0 /* unwindSize */, NULL /* ppUnwindBlock */ +#endif + ); + + EE_TO_JIT_TRANSITION(); +} + +void CEECodeGenInfo::allocMem(AllocMemArgs *pArgs, size_t reserveForJumpStubs +#ifdef FEATURE_EH_FUNCLETS + , ULONG unwindInfoCount, ULONG unwindSize, BYTE** ppUnwindBlock +#endif +) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + _ASSERTE(pArgs->coldCodeSize == 0); if (pArgs->coldCodeBlock) { @@ -12258,8 +12307,11 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) } #ifdef FEATURE_EH_FUNCLETS - totalSize.AlignUp(sizeof(DWORD)); - totalSize += m_totalUnwindSize; + if (unwindSize > 0) + { + totalSize.AlignUp(sizeof(DWORD)); + totalSize += unwindSize; + } #endif _ASSERTE(m_CodeHeader == 0 && @@ -12291,17 +12343,13 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) pArgs->hotCodeSize + pArgs->coldCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId()); } - m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap + m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), reserveForJumpStubs, pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap , &m_pRealCodeHeader #ifdef FEATURE_EH_FUNCLETS - , m_totalUnwindInfos + , unwindInfoCount #endif ); -#ifdef FEATURE_EH_FUNCLETS - m_moduleBase = m_pCodeHeap->GetModuleBase(); -#endif - BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress(); size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader; @@ -12324,9 +12372,11 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) #ifdef FEATURE_EH_FUNCLETS current = (BYTE *)ALIGN_UP(current, sizeof(DWORD)); - - m_theUnwindBlock = current; - current += m_totalUnwindSize; + if (unwindSize > 0) + { + *ppUnwindBlock = current; + current += unwindSize; + } #endif _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value()); @@ -12334,8 +12384,6 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) #ifdef _DEBUG m_codeSize = codeSize; #endif // _DEBUG - - EE_TO_JIT_TRANSITION(); } /*********************************************************************/ @@ -12475,15 +12523,12 @@ void CEEJitInfo::getEHinfo( EE_TO_JIT_TRANSITION(); } -// -// Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE. -// -CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr, - CEEInfo *comp, - struct CORINFO_METHOD_INFO *info, - CORJIT_FLAGS jitFlags, - BYTE **nativeEntry, - uint32_t *nativeSizeOfCode) +CorJitResult invokeCompileMethodHelper(EECodeGenManager *jitMgr, + CEECodeGenInfo *comp, + struct CORINFO_METHOD_INFO *info, + CORJIT_FLAGS jitFlags, + BYTE **nativeEntry, + uint32_t *nativeSizeOfCode) { STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_TRIGGERS; @@ -12491,36 +12536,48 @@ CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr, CorJitResult ret = CORJIT_SKIPPED; // Note that CORJIT_SKIPPED is an error exit status code + comp->setJitFlags(jitFlags); + #if defined(ALLOW_SXS_JIT) - if (FAILED(ret) && jitMgr->m_alternateJit) + ICorJitCompiler *jitCompiler = jitMgr->GetAltCompiler(); + if (jitCompiler != NULL) { CORJIT_FLAGS altJitFlags = jitFlags; altJitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALT_JIT); comp->setJitFlags(altJitFlags); - ret = jitMgr->m_alternateJit->compileMethod( comp, - info, - CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS, - nativeEntry, - nativeSizeOfCode); - // If we failed to jit, then fall back to the primary Jit. + ret = jitCompiler->compileMethod(comp, + info, + CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS, + nativeEntry, + nativeSizeOfCode); + if (FAILED(ret)) { - ((CEEJitInfo*)comp)->BackoutJitData(jitMgr); - ((CEEJitInfo*)comp)->ResetForJitRetry(); + comp->BackoutJitData(jitMgr); + comp->ResetForJitRetry(); ret = CORJIT_SKIPPED; } } #endif // defined(ALLOW_SXS_JIT) + comp->setJitFlags(jitFlags); + // CORJIT_SKIPPED also evaluates as "FAILED" if (FAILED(ret)) { - ret = jitMgr->m_jit->compileMethod( comp, - info, - CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS, - nativeEntry, - nativeSizeOfCode); + jitCompiler = jitMgr->GetCompiler(); + ret = jitCompiler->compileMethod(comp, + info, + CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS, + nativeEntry, + nativeSizeOfCode); + if (FAILED(ret)) + { + comp->BackoutJitData(jitMgr); + comp->ResetForJitRetry(); + ret = CORJIT_SKIPPED; + } } // Cleanup any internal data structures allocated @@ -12528,31 +12585,19 @@ CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr, // If the JIT fails we keep the IL around and will // try reJIT the same IL. VSW 525059 // - if (SUCCEEDED(ret) && !((CEEJitInfo*)comp)->JitAgain()) + if (SUCCEEDED(ret) && !comp->JitAgain()) { - ((CEEJitInfo*)comp)->CompressDebugInfo(); - + comp->CompressDebugInfo(); comp->MethodCompileComplete(info->ftn); } - -#if defined(FEATURE_GDBJIT) - bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL; - - if (isJittedEntry) - { - CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1; - pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods()); - } -#endif - return ret; } /*********************************************************************/ -CorJitResult invokeCompileMethod(EEJitManager *jitMgr, - CEEInfo *comp, +CorJitResult invokeCompileMethod(EECodeGenManager *jitMgr, + CEECodeGenInfo *comp, struct CORINFO_METHOD_INFO *info, CORJIT_FLAGS jitFlags, BYTE **nativeEntry, @@ -12816,6 +12861,167 @@ BOOL g_fAllowRel32 = TRUE; #endif +PCODE UnsafeJitFunctionWorker(EECodeGenManager *pJitMgr, CEECodeGenInfo *pJitInfo, CORJIT_FLAGS* pJitFlags, CORINFO_METHOD_INFO methodInfo, MethodInfoHelperContext *pCxt, NativeCodeVersion nativeCodeVersion) +{ + STANDARD_VM_CONTRACT; + if (pCxt->HasTransientMethodDetails()) + pJitInfo->AddTransientMethodDetails(pCxt->CreateTransientMethodDetails()); + + MethodDesc * pMethodForSecurity = pJitInfo->GetMethodForSecurity(methodInfo.ftn); + MethodDesc * ftn = nativeCodeVersion.GetMethodDesc(); + +#ifdef _DEBUG + LPCUTF8 cls = ftn->GetMethodTable()->GetDebugClassName(); + LPCUTF8 name = ftn->GetName(); +#endif + + //Since the check could trigger a demand, we have to do this every time. + //This is actually an overly complicated way to make sure that a method can access all its arguments + //and its return type. + AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks; + TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable()); + BOOL doAccessCheck = TRUE; + if (pMethodForSecurity->IsDynamicMethod()) + { + doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(), + &ownerTypeForSecurity, + &accessCheckType); + } + if (doAccessCheck) + { + AccessCheckOptions accessCheckOptions(accessCheckType, + NULL, + TRUE /*Throw on error*/, + pMethodForSecurity); + + AccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable()); + + // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to + // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters. + + // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod + // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will + // just do an access check from a NULL context which means only public types are accessible. + if (!ClassLoader::CanAccess(&accessContext, + ownerTypeForSecurity.GetMethodTable(), + ownerTypeForSecurity.GetAssembly(), + pMethodForSecurity->GetAttrs(), + pMethodForSecurity, + NULL, + accessCheckOptions)) + { + EX_THROW(EEMethodException, (pMethodForSecurity)); + } + } + + CorJitResult res = CORJIT_SKIPPED; + PBYTE nativeEntry = NULL; + uint32_t sizeOfCode = 0; + + { + GCX_COOP(); + + /* There is a double indirection to call compileMethod - can we + improve this with the new structure? */ + +#ifdef PERF_TRACK_METHOD_JITTIMES + //Because we're not calling QPC enough. I'm not going to track times if we're just importing. + LARGE_INTEGER methodJitTimeStart = {0}; + QueryPerformanceCounter (&methodJitTimeStart); + +#endif + LOG((LF_CORDB, LL_EVERYTHING, "Calling invokeCompileMethod...\n")); + + res = invokeCompileMethod(pJitMgr, + pJitInfo, + &methodInfo, + *pJitFlags, + &nativeEntry, + &sizeOfCode); + +#if FEATURE_PERFMAP + // Save the code size so that it can be reported to the perfmap. + if (pSizeOfCode != NULL) + { + *pSizeOfCode = sizeOfCode; + } +#endif + +#ifdef PERF_TRACK_METHOD_JITTIMES + //store the time in the string buffer. Module name and token are unique enough. Also, do not + //capture importing time, just actual compilation time. + { + LARGE_INTEGER methodJitTimeStop; + QueryPerformanceCounter(&methodJitTimeStop); + + SString moduleName; + ftn->GetModule()->GetDomainAssembly()->GetPEAssembly()->GetPathOrCodeBase(moduleName); + + SString codeBase; + codeBase.AppendPrintf("%s,0x%x,%d,%d\n", + moduleName.GetUTF8(), //module name + ftn->GetMemberDef(), //method token + (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count + methodInfo.ILCodeSize //il size + ); + OutputDebugStringUtf8(codeBase.GetUTF8()); + } +#endif // PERF_TRACK_METHOD_JITTIMES + + } + + LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature)); + + if (res == CORJIT_SKIPPED) + { + // We are done + return NULL; + } + + if (SUCCEEDED(res)) + { + pJitInfo->WriteCode(pJitMgr); +#if defined(DEBUGGING_SUPPORTED) + // + // Notify the debugger that we have successfully jitted the function + // + if (g_pDebugInterface) + { + g_pDebugInterface->JITComplete(nativeCodeVersion, (TADDR)nativeEntry); + } +#endif // DEBUGGING_SUPPORTED + } + else + { + pJitInfo->BackoutJitData(pJitMgr); + ThrowExceptionForJit(res); + } + + if (!nativeEntry) + COMPlusThrow(kInvalidProgramException); + + LOG((LF_JIT, LL_INFO10000, + "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry), + ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature)); + +#ifdef _DEBUG + LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName; + LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName; + LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature; +#elif 0 + LPCUTF8 pszNamespace; + LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace); + LPCUTF8 pszDebugMethodName = ftn->GetName(); + LPCUTF8 pszDebugMethodSignature = ""; +#endif + + // For dynamic method, the code memory may be reused, thus we are passing in the hasCodeExecutedBefore set to true + ClrFlushInstructionCache(nativeEntry, sizeOfCode, /* hasCodeExecutedBefore */ true); + + // We are done + return (PCODE)nativeEntry; +} + // ******************************************************************** // README!! // ******************************************************************** @@ -12849,6 +13055,18 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, timer.Start(); +#ifdef FEATURE_INTERPRETER + InterpreterJitManager *interpreterMgr = ExecutionManager::GetInterpreterJitManager(); + + LPWSTR interpreterConfig; + IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Interpreter, &interpreterConfig)); + + if ((interpreterConfig != NULL) && !interpreterMgr->LoadInterpreter()) + { + EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load interpreter")); + } +#endif // FEATURE_INTERPRETER + EEJitManager *jitMgr = ExecutionManager::GetEEJitManager(); if (!jitMgr->LoadJIT()) { @@ -12925,216 +13143,82 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, #endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) - while (true) +#ifdef FEATURE_INTERPRETER + bool useInterpreter = interpreterMgr->IsInterpreterLoaded(); + + if (useInterpreter) + { + CInterpreterJitInfo jitInfo(ftn, ILHeader, interpreterMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING)); + ret = UnsafeJitFunctionWorker(interpreterMgr, &jitInfo, pJitFlags, methodInfo, &cxt, nativeCodeVersion); + } +#endif // FEATURE_INTERPRETER + + if (ret == NULL) { - CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING)); + while (true) + { + CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING)); #if defined(TARGET_AMD64) || defined(TARGET_ARM64) #if defined(TARGET_AMD64) - if (fForceJumpStubOverflow) - jitInfo.SetJumpStubOverflow(fAllowRel32); - jitInfo.SetAllowRel32(fAllowRel32); + if (fForceJumpStubOverflow) + jitInfo.SetJumpStubOverflow(fAllowRel32); + jitInfo.SetAllowRel32(fAllowRel32); #else - if (fForceJumpStubOverflow) - jitInfo.SetJumpStubOverflow(fForceJumpStubOverflow); + if (fForceJumpStubOverflow) + jitInfo.SetJumpStubOverflow(fForceJumpStubOverflow); #endif - jitInfo.SetReserveForJumpStubs(reserveForJumpStubs); + jitInfo.SetReserveForJumpStubs(reserveForJumpStubs); #endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) #ifdef FEATURE_ON_STACK_REPLACEMENT - // If this is an OSR jit request, grab the OSR info so we can pass it to the jit - if (pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_OSR)) - { - unsigned ilOffset = 0; - PatchpointInfo* patchpointInfo = nativeCodeVersion.GetOSRInfo(&ilOffset); - jitInfo.SetOSRInfo(patchpointInfo, ilOffset); - } -#endif // FEATURE_ON_STACK_REPLACEMENT - - if (cxt.HasTransientMethodDetails()) - jitInfo.AddTransientMethodDetails(cxt.CreateTransientMethodDetails()); - - MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(methodInfo.ftn); - - //Since the check could trigger a demand, we have to do this every time. - //This is actually an overly complicated way to make sure that a method can access all its arguments - //and its return type. - AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks; - TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable()); - BOOL doAccessCheck = TRUE; - if (pMethodForSecurity->IsDynamicMethod()) - { - doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(), - &ownerTypeForSecurity, - &accessCheckType); - } - if (doAccessCheck) - { - AccessCheckOptions accessCheckOptions(accessCheckType, - NULL, - TRUE /*Throw on error*/, - pMethodForSecurity); - - AccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable()); - - // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to - // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters. - - // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod - // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will - // just do an access check from a NULL context which means only public types are accessible. - if (!ClassLoader::CanAccess(&accessContext, - ownerTypeForSecurity.GetMethodTable(), - ownerTypeForSecurity.GetAssembly(), - pMethodForSecurity->GetAttrs(), - pMethodForSecurity, - NULL, - accessCheckOptions)) - { - EX_THROW(EEMethodException, (pMethodForSecurity)); - } - } - - CorJitResult res; - PBYTE nativeEntry; - uint32_t sizeOfCode; - - { - GCX_COOP(); - - /* There is a double indirection to call compileMethod - can we - improve this with the new structure? */ - -#ifdef PERF_TRACK_METHOD_JITTIMES - //Because we're not calling QPC enough. I'm not going to track times if we're just importing. - LARGE_INTEGER methodJitTimeStart = {0}; - QueryPerformanceCounter (&methodJitTimeStart); - -#endif - LOG((LF_CORDB, LL_EVERYTHING, "Calling invokeCompileMethod...\n")); - - res = invokeCompileMethod(jitMgr, - &jitInfo, - &methodInfo, - *pJitFlags, - &nativeEntry, - &sizeOfCode); - - LOG((LF_CORDB, LL_EVERYTHING, "Got through invokeCompileMethod\n")); - -#if FEATURE_PERFMAP - // Save the code size so that it can be reported to the perfmap. - if (pSizeOfCode != NULL) - { - *pSizeOfCode = sizeOfCode; - } -#endif - -#ifdef PERF_TRACK_METHOD_JITTIMES - //store the time in the string buffer. Module name and token are unique enough. Also, do not - //capture importing time, just actual compilation time. + // If this is an OSR jit request, grab the OSR info so we can pass it to the jit + if (pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_OSR)) { - LARGE_INTEGER methodJitTimeStop; - QueryPerformanceCounter(&methodJitTimeStop); - - SString moduleName; - ftn->GetModule()->GetDomainAssembly()->GetPEAssembly()->GetPathOrCodeBase(moduleName); - - SString codeBase; - codeBase.AppendPrintf("%s,0x%x,%d,%d\n", - moduleName.GetUTF8(), //module name - ftn->GetMemberDef(), //method token - (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count - methodInfo.ILCodeSize //il size - ); - OutputDebugStringUtf8(codeBase.GetUTF8()); + unsigned ilOffset = 0; + PatchpointInfo* patchpointInfo = nativeCodeVersion.GetOSRInfo(&ilOffset); + jitInfo.SetOSRInfo(patchpointInfo, ilOffset); } -#endif // PERF_TRACK_METHOD_JITTIMES - - } - - LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature)); - - if (SUCCEEDED(res)) - { - jitInfo.WriteCode(jitMgr); -#if defined(DEBUGGING_SUPPORTED) - // - // Notify the debugger that we have successfully jitted the function - // - if (g_pDebugInterface) - { - if (!jitInfo.JitAgain()) - { - g_pDebugInterface->JITComplete(nativeCodeVersion, (TADDR)nativeEntry); - } - } -#endif // DEBUGGING_SUPPORTED - } - else - { - jitInfo.BackoutJitData(jitMgr); - ThrowExceptionForJit(res); - } +#endif // FEATURE_ON_STACK_REPLACEMENT - if (!nativeEntry) - COMPlusThrow(kInvalidProgramException); + ret = UnsafeJitFunctionWorker(jitMgr, &jitInfo, pJitFlags, methodInfo, &cxt, nativeCodeVersion); + if (!ret) + COMPlusThrow(kInvalidProgramException); #if (defined(TARGET_AMD64) || defined(TARGET_ARM64)) - if (jitInfo.IsJumpStubOverflow()) - { - // Backout and try again with fAllowRel32 == FALSE. - jitInfo.BackoutJitData(jitMgr); + if (jitInfo.IsJumpStubOverflow()) + { + // Backout and try again with fAllowRel32 == FALSE. + jitInfo.BackoutJitData(jitMgr); #ifdef TARGET_AMD64 - // Disallow rel32 relocs in future. - g_fAllowRel32 = FALSE; + // Disallow rel32 relocs in future. + g_fAllowRel32 = FALSE; - fAllowRel32 = FALSE; + fAllowRel32 = FALSE; #endif // TARGET_AMD64 #ifdef TARGET_ARM64 - fForceJumpStubOverflow = FALSE; + fForceJumpStubOverflow = FALSE; #endif // TARGET_ARM64 - reserveForJumpStubs = jitInfo.GetReserveForJumpStubs(); + reserveForJumpStubs = jitInfo.GetReserveForJumpStubs(); - // Get any transient method details and take ownership - // from the JITInfo instance. We are going to be recreating - // a new JITInfo and will reuse these details there. - TransientMethodDetails details = jitInfo.RemoveTransientMethodDetails(ftn); - cxt.TakeOwnership(std::move(details)); - continue; - } + // Get any transient method details and take ownership + // from the JITInfo instance. We are going to be recreating + // a new JITInfo and will reuse these details there. + TransientMethodDetails details = jitInfo.RemoveTransientMethodDetails(ftn); + cxt.TakeOwnership(std::move(details)); + continue; + } #endif // (TARGET_AMD64 || TARGET_ARM64) - LOG((LF_JIT, LL_INFO10000, - "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry), - ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature)); - -#ifdef _DEBUG - LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName; - LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName; - LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature; -#elif 0 - LPCUTF8 pszNamespace; - LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace); - LPCUTF8 pszDebugMethodName = ftn->GetName(); - LPCUTF8 pszDebugMethodSignature = ""; -#endif - - //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry), - // pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode); - - // For dynamic method, the code memory may be reused, thus we are passing in the hasCodeExecutedBefore set to true - ClrFlushInstructionCache(nativeEntry, sizeOfCode, /* hasCodeExecutedBefore */ true); - ret = (PCODE)nativeEntry; - #ifdef TARGET_ARM - ret |= THUMB_CODE; + ret |= THUMB_CODE; #endif - // We are done - break; + // We are done + break; + } } #ifdef _DEBUG diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 4b647b25430cdb..82b0208e04a9e6 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -565,13 +565,190 @@ class CEEInfo : public ICorJitInfo /*********************************************************************/ class EEJitManager; +class InterpreterJitManager; +class EECodeGenManager; struct HeapList; -struct _hpCodeHdr; -typedef struct _hpCodeHdr CodeHeader; +struct CodeHeader; + +class CEECodeGenInfo : public CEEInfo +{ +public: + // ICorJitInfo stuff + CEECodeGenInfo(MethodDesc* fd, COR_ILMETHOD_DECODER* header, EECodeGenManager* jm, bool allowInlining = true) + : CEEInfo(fd, allowInlining), + m_jitManager(jm), + m_CodeHeader(NULL), + m_CodeHeaderRW(NULL), + m_codeWriteBufferSize(0), + m_pRealCodeHeader(NULL), + m_pCodeHeap(NULL), + m_ILHeader(header), + m_GCinfo_len(0), + m_EHinfo_len(0), + m_iOffsetMapping(0), + m_pOffsetMapping(NULL), + m_iNativeVarInfo(0), + m_pNativeVarInfo(NULL), + m_inlineTreeNodes(NULL), + m_numInlineTreeNodes(0), + m_richOffsetMappings(NULL), + m_numRichOffsetMappings(0), + m_gphCache() + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } CONTRACTL_END; + } + + ~CEECodeGenInfo() + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } CONTRACTL_END; + + if (m_CodeHeaderRW != m_CodeHeader) + freeArrayInternal(m_CodeHeaderRW); + + if (m_pOffsetMapping != NULL) + freeArrayInternal(m_pOffsetMapping); + + if (m_pNativeVarInfo != NULL) + freeArrayInternal(m_pNativeVarInfo); + } + + void BackoutJitData(EECodeGenManager * jitMgr); + + void ResetForJitRetry() + { + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + if (m_CodeHeaderRW != m_CodeHeader) + freeArrayInternal(m_CodeHeaderRW); + + m_CodeHeader = NULL; + m_CodeHeaderRW = NULL; + + m_codeWriteBufferSize = 0; + m_pRealCodeHeader = NULL; + m_pCodeHeap = NULL; + + if (m_pOffsetMapping != NULL) + freeArrayInternal(m_pOffsetMapping); + + if (m_pNativeVarInfo != NULL) + freeArrayInternal(m_pNativeVarInfo); + + m_iOffsetMapping = 0; + m_pOffsetMapping = NULL; + m_iNativeVarInfo = 0; + m_pNativeVarInfo = NULL; + + if (m_inlineTreeNodes != NULL) + freeArrayInternal(m_inlineTreeNodes); + if (m_richOffsetMappings != NULL) + freeArrayInternal(m_richOffsetMappings); + + m_inlineTreeNodes = NULL; + m_numInlineTreeNodes = 0; + m_richOffsetMappings = NULL; + m_numRichOffsetMappings = 0; + } + + // ICorDebugInfo stuff. + void setBoundaries(CORINFO_METHOD_HANDLE ftn, + ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap) override final; + void setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, + ICorDebugInfo::NativeVarInfo *vars) override final; + void CompressDebugInfo(); + + virtual PatchpointInfo* GetPatchpointInfo() + { + return NULL; + } + + virtual BOOL JitAgain() + { + return FALSE; + } + + void reportRichMappings( + ICorDebugInfo::InlineTreeNode* inlineTreeNodes, + uint32_t numInlineTreeNodes, + ICorDebugInfo::RichOffsetMapping* mappings, + uint32_t numMappings) override final; + + void reportMetadata(const char* key, const void* value, size_t length) override final; + + virtual void WriteCode(EECodeGenManager * jitMgr); + +protected: + + void allocMem (AllocMemArgs *pArgs, size_t reserveForJumpStubs +#ifdef FEATURE_EH_FUNCLETS + , ULONG unwindInfoSize, ULONG unwindSize, BYTE** ppUnwindBlock +#endif + ); + + void WriteCodeBytes(); + + EECodeGenManager* m_jitManager; // responsible for allocating memory + CodeHeader* m_CodeHeader; // descriptor for JITTED code - read/execute address + CodeHeader* m_CodeHeaderRW; // descriptor for JITTED code - code write scratch buffer address + size_t m_codeWriteBufferSize; + BYTE* m_pRealCodeHeader; + HeapList* m_pCodeHeap; + COR_ILMETHOD_DECODER * m_ILHeader; // the code header as exist in the file + +#if defined(_DEBUG) + ULONG m_codeSize; // Code size requested via allocMem +#endif + + size_t m_GCinfo_len; // Cached copy of GCinfo_len so we can backout in BackoutJitData() + size_t m_EHinfo_len; // Cached copy of EHinfo_len so we can backout in BackoutJitData() + + ULONG32 m_iOffsetMapping; + ICorDebugInfo::OffsetMapping * m_pOffsetMapping; + + ULONG32 m_iNativeVarInfo; + ICorDebugInfo::NativeVarInfo * m_pNativeVarInfo; + + ICorDebugInfo::InlineTreeNode *m_inlineTreeNodes; + ULONG32 m_numInlineTreeNodes; + ICorDebugInfo::RichOffsetMapping *m_richOffsetMappings; + ULONG32 m_numRichOffsetMappings; + + // The first time a call is made to CEEJitInfo::GetProfilingHandle() from this thread + // for this method, these values are filled in. Thereafter, these values are used + // in lieu of calling into the base CEEInfo::GetProfilingHandle() again. This protects the + // profiler from duplicate calls to its FunctionIDMapper() callback. + struct GetProfilingHandleCache + { + GetProfilingHandleCache() : + m_bGphIsCacheValid(false), + m_bGphHookFunction(false), + m_pvGphProfilerHandle(NULL) + { + LIMITED_METHOD_CONTRACT; + } + + bool m_bGphIsCacheValid : 1; // Tells us whether below values are valid + bool m_bGphHookFunction : 1; + void* m_pvGphProfilerHandle; + } m_gphCache; +}; // CEEJitInfo is the concrete implementation of callbacks that the EE must provide for the JIT to do its // work. See code:ICorJitInfo#JitToEEInterface for more on this interface. -class CEEJitInfo : public CEEInfo +class CEEJitInfo : public CEECodeGenInfo { public: // ICorJitInfo stuff @@ -644,36 +821,7 @@ class CEEJitInfo : public CEEInfo GC_NOTRIGGER; } CONTRACTL_END; - if (m_CodeHeaderRW != m_CodeHeader) - freeArrayInternal(m_CodeHeaderRW); - - m_CodeHeader = NULL; - m_CodeHeaderRW = NULL; - - m_codeWriteBufferSize = 0; - m_pRealCodeHeader = NULL; - m_pCodeHeap = NULL; - - if (m_pOffsetMapping != NULL) - freeArrayInternal(m_pOffsetMapping); - - if (m_pNativeVarInfo != NULL) - freeArrayInternal(m_pNativeVarInfo); - - m_iOffsetMapping = 0; - m_pOffsetMapping = NULL; - m_iNativeVarInfo = 0; - m_pNativeVarInfo = NULL; - - if (m_inlineTreeNodes != NULL) - freeArrayInternal(m_inlineTreeNodes); - if (m_richOffsetMappings != NULL) - freeArrayInternal(m_richOffsetMappings); - - m_inlineTreeNodes = NULL; - m_numInlineTreeNodes = 0; - m_richOffsetMappings = NULL; - m_numRichOffsetMappings = 0; + CEECodeGenInfo::ResetForJitRetry(); #ifdef FEATURE_ON_STACK_REPLACEMENT if (m_pPatchpointInfoFromJit != NULL) @@ -713,7 +861,7 @@ class CEEJitInfo : public CEEInfo return m_fJumpStubOverflow; } - BOOL JitAgain() + virtual BOOL JitAgain() override { LIMITED_METHOD_CONTRACT; return m_fJumpStubOverflow; @@ -730,8 +878,18 @@ class CEEJitInfo : public CEEInfo LIMITED_METHOD_CONTRACT; m_reserveForJumpStubs = value; } + + virtual PatchpointInfo* GetPatchpointInfo() + { +#ifdef FEATURE_ON_STACK_REPLACEMENT + return m_pPatchpointInfoFromJit; +#else + return NULL; +#endif + } + #else - BOOL JitAgain() + virtual BOOL JitAgain() override { LIMITED_METHOD_CONTRACT; return FALSE; @@ -756,15 +914,8 @@ class CEEJitInfo : public CEEInfo #endif CEEJitInfo(MethodDesc* fd, COR_ILMETHOD_DECODER* header, - EEJitManager* jm, bool allowInlining = true) - : CEEInfo(fd, allowInlining), - m_jitManager(jm), - m_CodeHeader(NULL), - m_CodeHeaderRW(NULL), - m_codeWriteBufferSize(0), - m_pRealCodeHeader(NULL), - m_pCodeHeap(NULL), - m_ILHeader(header), + EECodeGenManager* jm, bool allowInlining = true) + : CEECodeGenInfo(fd, header, jm, allowInlining), #ifdef FEATURE_EH_FUNCLETS m_moduleBase(0), m_totalUnwindSize(0), @@ -780,22 +931,11 @@ class CEEJitInfo : public CEEInfo m_fJumpStubOverflow(FALSE), m_reserveForJumpStubs(0), #endif - m_GCinfo_len(0), - m_EHinfo_len(0), - m_iOffsetMapping(0), - m_pOffsetMapping(NULL), - m_iNativeVarInfo(0), - m_pNativeVarInfo(NULL), - m_inlineTreeNodes(NULL), - m_numInlineTreeNodes(0), - m_richOffsetMappings(NULL), - m_numRichOffsetMappings(0), #ifdef FEATURE_ON_STACK_REPLACEMENT m_pPatchpointInfoFromJit(NULL), m_pPatchpointInfoFromRuntime(NULL), - m_ilOffset(0), + m_ilOffset(0) #endif - m_gphCache() { CONTRACTL { @@ -814,15 +954,6 @@ class CEEJitInfo : public CEEInfo MODE_ANY; } CONTRACTL_END; - if (m_CodeHeaderRW != m_CodeHeader) - freeArrayInternal(m_CodeHeaderRW); - - if (m_pOffsetMapping != NULL) - freeArrayInternal(m_pOffsetMapping); - - if (m_pNativeVarInfo != NULL) - freeArrayInternal(m_pNativeVarInfo); - #ifdef FEATURE_ON_STACK_REPLACEMENT if (m_pPatchpointInfoFromJit != NULL) freeArrayInternal(m_pPatchpointInfoFromJit); @@ -841,21 +972,6 @@ class CEEJitInfo : public CEEInfo #endif } - // ICorDebugInfo stuff. - void setBoundaries(CORINFO_METHOD_HANDLE ftn, - ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap) override final; - void setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, - ICorDebugInfo::NativeVarInfo *vars) override final; - void CompressDebugInfo(); - - void reportRichMappings( - ICorDebugInfo::InlineTreeNode* inlineTreeNodes, - uint32_t numInlineTreeNodes, - ICorDebugInfo::RichOffsetMapping* mappings, - uint32_t numMappings) override final; - - void reportMetadata(const char* key, const void* value, size_t length) override final; - void* getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ void ** ppIndirection) override final; /* OUT */ static PCODE getHelperFtnStatic(CorInfoHelpFunc ftnNum); @@ -876,17 +992,13 @@ class CEEJitInfo : public CEEInfo CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override final; void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override final; - void BackoutJitData(EEJitManager * jitMgr); - - void WriteCode(EEJitManager * jitMgr); + virtual void WriteCode(EECodeGenManager * jitMgr) override; void setPatchpointInfo(PatchpointInfo* patchpointInfo) override final; PatchpointInfo* getOSRInfo(unsigned* ilOffset) override final; protected : - void WriteCodeBytes(); - #ifdef FEATURE_PGO // PGO data struct ComputedPgoData @@ -906,13 +1018,6 @@ protected : #endif - EEJitManager* m_jitManager; // responsible for allocating memory - CodeHeader* m_CodeHeader; // descriptor for JITTED code - read/execute address - CodeHeader* m_CodeHeaderRW; // descriptor for JITTED code - code write scratch buffer address - size_t m_codeWriteBufferSize; - BYTE* m_pRealCodeHeader; - HeapList* m_pCodeHeap; - COR_ILMETHOD_DECODER * m_ILHeader; // the code header as exist in the file #ifdef FEATURE_EH_FUNCLETS TADDR m_moduleBase; // Base for unwind Infos ULONG m_totalUnwindSize; // Total reserved unwind space @@ -931,49 +1036,42 @@ protected : size_t m_reserveForJumpStubs; // Space to reserve for jump stubs when allocating code #endif -#if defined(_DEBUG) - ULONG m_codeSize; // Code size requested via allocMem -#endif - - size_t m_GCinfo_len; // Cached copy of GCinfo_len so we can backout in BackoutJitData() - size_t m_EHinfo_len; // Cached copy of EHinfo_len so we can backout in BackoutJitData() - - ULONG32 m_iOffsetMapping; - ICorDebugInfo::OffsetMapping * m_pOffsetMapping; - - ULONG32 m_iNativeVarInfo; - ICorDebugInfo::NativeVarInfo * m_pNativeVarInfo; - - ICorDebugInfo::InlineTreeNode *m_inlineTreeNodes; - ULONG32 m_numInlineTreeNodes; - ICorDebugInfo::RichOffsetMapping *m_richOffsetMappings; - ULONG32 m_numRichOffsetMappings; - #ifdef FEATURE_ON_STACK_REPLACEMENT PatchpointInfo * m_pPatchpointInfoFromJit; PatchpointInfo * m_pPatchpointInfoFromRuntime; unsigned m_ilOffset; #endif - // The first time a call is made to CEEJitInfo::GetProfilingHandle() from this thread - // for this method, these values are filled in. Thereafter, these values are used - // in lieu of calling into the base CEEInfo::GetProfilingHandle() again. This protects the - // profiler from duplicate calls to its FunctionIDMapper() callback. - struct GetProfilingHandleCache +}; + +class CInterpreterJitInfo : public CEECodeGenInfo +{ +public: + // ICorJitInfo stuff + + CInterpreterJitInfo(MethodDesc* fd, COR_ILMETHOD_DECODER* header, + EECodeGenManager* jm, bool allowInlining = true) + : CEECodeGenInfo(fd, header, jm, allowInlining) { - GetProfilingHandleCache() : - m_bGphIsCacheValid(false), - m_bGphHookFunction(false), - m_pvGphProfilerHandle(NULL) + CONTRACTL { - LIMITED_METHOD_CONTRACT; - } + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } CONTRACTL_END; + } - bool m_bGphIsCacheValid : 1; // Tells us whether below values are valid - bool m_bGphHookFunction : 1; - void* m_pvGphProfilerHandle; - } m_gphCache; + void allocMem (AllocMemArgs *pArgs) override final; + void ResetForJitRetry() + { + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + CEECodeGenInfo::ResetForJitRetry(); + } }; /*********************************************************************/ diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 5257358d4758e5..83001346d2bc46 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -70,6 +70,7 @@ LoaderAllocator::LoaderAllocator(bool collectible) : m_pVSDHeapInitialAlloc = NULL; m_pLastUsedCodeHeap = NULL; m_pLastUsedDynamicCodeHeap = NULL; + m_pLastUsedInterpreterCodeHeap = NULL; m_pJumpStubCache = NULL; m_IsCollectible = collectible; diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 9880a627636720..606dc53b8fd20d 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -371,6 +371,8 @@ class LoaderAllocator // ExecutionManager caches void * m_pLastUsedCodeHeap; void * m_pLastUsedDynamicCodeHeap; + void * m_pLastUsedInterpreterCodeHeap; + void * m_pLastUsedInterpreterDynamicCodeHeap; void * m_pJumpStubCache; // LoaderAllocator GC Structures diff --git a/src/tests/JIT/interpreter/InterpreterTester.cs b/src/tests/JIT/interpreter/InterpreterTester.cs index 9895bc2608082e..fafbc331ba2178 100644 --- a/src/tests/JIT/interpreter/InterpreterTester.cs +++ b/src/tests/JIT/interpreter/InterpreterTester.cs @@ -22,9 +22,9 @@ public static void RunTests() string interpreterApp = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Interpreter.dll"); var startInfo = new ProcessStartInfo(Path.Combine(coreRoot, corerun), interpreterApp); - startInfo.EnvironmentVariables["DOTNET_AltJitName"] = libInterp; - startInfo.EnvironmentVariables["DOTNET_AltJitPath"] = Path.Combine(coreRoot, libInterp); - startInfo.EnvironmentVariables["DOTNET_AltJit"] = "RunInterpreterTests"; + startInfo.EnvironmentVariables["DOTNET_InterpreterName"] = libInterp; + startInfo.EnvironmentVariables["DOTNET_InterpreterPath"] = Path.Combine(coreRoot, libInterp); + startInfo.EnvironmentVariables["DOTNET_Interpreter"] = "RunInterpreterTests"; using (Process p = Process.Start(startInfo)) { From 02eda0502f6ad95e037ca0cbd24550332db0e33f Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 27 Feb 2025 22:20:29 +0100 Subject: [PATCH 02/15] Make the code headers independent Make the jit and interpreter code headers independent --- src/coreclr/debug/daccess/enummem.cpp | 6 +- src/coreclr/debug/daccess/fntableaccess.cpp | 2 +- src/coreclr/debug/daccess/fntableaccess.h | 6 +- src/coreclr/vm/codeman.cpp | 152 +++++++--- src/coreclr/vm/codeman.h | 316 ++++++++++++++++---- src/coreclr/vm/dynamicmethod.cpp | 2 + src/coreclr/vm/eventtrace.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 124 +++++--- src/coreclr/vm/jitinterface.h | 61 ++-- src/coreclr/vm/perfmap.cpp | 2 +- src/coreclr/vm/profilingenumerators.cpp | 2 +- 11 files changed, 487 insertions(+), 188 deletions(-) diff --git a/src/coreclr/debug/daccess/enummem.cpp b/src/coreclr/debug/daccess/enummem.cpp index 7840bb29070cd0..9e46344b97c7f5 100644 --- a/src/coreclr/debug/daccess/enummem.cpp +++ b/src/coreclr/debug/daccess/enummem.cpp @@ -318,8 +318,12 @@ HRESULT ClrDataAccess::EnumMemDumpJitManagerInfo(IN CLRDataEnumMemoryFlags flags if (flags == CLRDATA_ENUM_MEM_HEAP2) { - EEJitManager* managerPtr = ExecutionManager::GetEEJitManager(); + EECodeGenManager* managerPtr = ExecutionManager::GetEEJitManager(); managerPtr->EnumMemoryRegions(flags); +#ifdef FEATURE_INTERPRETER + managerPtr = ExecutionManager::GetInterpreterJitManager(); + managerPtr->EnumMemoryRegions(flags); +#endif // FEATURE_INTERPRETER } return status; diff --git a/src/coreclr/debug/daccess/fntableaccess.cpp b/src/coreclr/debug/daccess/fntableaccess.cpp index cc6a3eb50f8df8..c342ad31bc09ae 100644 --- a/src/coreclr/debug/daccess/fntableaccess.cpp +++ b/src/coreclr/debug/daccess/fntableaccess.cpp @@ -137,7 +137,7 @@ static NTSTATUS OutOfProcessFindHeader(ReadMemoryFunction fpReadMemory,PVOID pUs return STATUS_SUCCESS; } -#define CODE_HEADER FakeJitRealCodeHeader +#define CODE_HEADER FakeRealCodeHeader #define ResolveCodeHeader(pHeader) \ if (pHeader) \ { \ diff --git a/src/coreclr/debug/daccess/fntableaccess.h b/src/coreclr/debug/daccess/fntableaccess.h index f1ec10dd549aae..a0617422edb51a 100644 --- a/src/coreclr/debug/daccess/fntableaccess.h +++ b/src/coreclr/debug/daccess/fntableaccess.h @@ -55,7 +55,7 @@ typedef struct _FakeHpRealCodeHdr LPVOID hdrMDesc; // changed from MethodDesc* DWORD nUnwindInfos; T_RUNTIME_FUNCTION unwindInfos[0]; -} FakeJitRealCodeHeader; +} FakeRealCodeHeader; typedef struct _FakeHpCodeHdr { @@ -85,8 +85,8 @@ class CheckDuplicatedStructLayouts CHECK_OFFSET(HeapList, pHdrMap); #if !defined(TARGET_X86) - CHECK_OFFSET(JitRealCodeHeader, nUnwindInfos); - CHECK_OFFSET(JitRealCodeHeader, unwindInfos); + CHECK_OFFSET(RealCodeHeader, nUnwindInfos); + CHECK_OFFSET(RealCodeHeader, unwindInfos); #endif // !TARGET_X86 #undef CHECK_OFFSET diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 7185c6e805761f..fe09874aa73a3c 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -420,7 +420,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R { // This cast is justified because only EEJitManager's have the code type above. EEJitManager* pJitMgr = (EEJitManager*)(pRS->_pjit); - JitCodeHeader * pHeader = dac_cast(pJitMgr->GetCodeHeaderFromStartAddress(entryPoint)); + CodeHeader * pHeader = dac_cast(pJitMgr->GetCodeHeaderFromStartAddress(entryPoint)); for(ULONG i = 0; i < pHeader->GetNumberOfUnwindInfos(); i++) RemoveFromUnwindInfoTable(&pRS->_pUnwindInfoTable, pRS->_range.RangeStart(), pRS->_range.RangeStart() + pHeader->GetUnwindInfo(i)->BeginAddress); } @@ -438,7 +438,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R STANDARD_VM_CONTRACT; { // CodeHeapIterator holds the m_CodeHeapCritSec, which ensures code heaps don't get deallocated while being walked - EECodeGenManager::CodeHeapIterator heapIterator(NULL); + EECodeGenManager::CodeHeapIterator heapIterator(ExecutionManager::GetEEJitManager(), NULL); // Currently m_CodeHeapCritSec is given the CRST_UNSAFE_ANYMODE flag which allows it to be taken in a GC_NOTRIGGER // region but also disallows GC_TRIGGERS. We need GC_TRIGGERS because we take another lock. Ideally we would @@ -459,7 +459,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R { // This cast is justified because only EEJitManager's have the code type above. EEJitManager* pJitMgr = (EEJitManager*)(pRS->_pjit); - JitCodeHeader * pHeader = dac_cast(pJitMgr->GetCodeHeaderFromStartAddress(methodEntry)); + CodeHeader * pHeader = dac_cast(pJitMgr->GetCodeHeaderFromStartAddress(methodEntry)); int unwindInfoCount = pHeader->GetNumberOfUnwindInfos(); for(int i = 0; i < unwindInfoCount; i++) AddToUnwindInfoTable(&pRS->_pUnwindInfoTable, pHeader->GetUnwindInfo(i), pRS->_range.RangeStart(), pRS->_range.RangeEndOpen()); @@ -511,10 +511,10 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R /*----------------------------------------------------------------------------- This is a listing of which methods uses which synchronization mechanism - in the EEJitManager. + in the EECodeGenManager. //----------------------------------------------------------------------------- -Setters of EEJitManager::m_CodeHeapCritSec +Setters of EECodeGenManager::m_CodeHeapCritSec ----------------------------------------------- allocCode allocGCInfo @@ -527,7 +527,7 @@ ReleaseReferenceToHeap JitCodeToMethodInfo -Need EEJitManager::m_CodeHeapCritSec to be set +Need EECodeGenManager::m_CodeHeapCritSec to be set ----------------------------------------------- NewCodeHeap allocCodeRaw @@ -541,8 +541,8 @@ DeleteJitHeapCache #if !defined(DACCESS_COMPILE) -EECodeGenManager::CodeHeapIterator::CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter) - : m_lockHolder(&(ExecutionManager::GetEEJitManager()->m_CodeHeapCritSec)), m_Iterator(NULL, 0, NULL, 0) +EECodeGenManager::CodeHeapIterator::CodeHeapIterator(EECodeGenManager *pJitMgr, LoaderAllocator *pLoaderAllocatorFilter) + : m_lockHolder(&(pJitMgr->m_CodeHeapCritSec)), m_Iterator(NULL, 0, NULL, 0) { CONTRACTL { @@ -554,7 +554,7 @@ EECodeGenManager::CodeHeapIterator::CodeHeapIterator(LoaderAllocator *pLoaderAll m_pHeapList = NULL; m_pLoaderAllocator = pLoaderAllocatorFilter; - m_pHeapList = ExecutionManager::GetEEJitManager()->GetCodeHeapList(); + m_pHeapList = pJitMgr->GetCodeHeapList(); if(m_pHeapList) new (&m_Iterator) MethodSectionIterator((const void *)m_pHeapList->mapBase, (COUNT_T)m_pHeapList->maxCodeHeapSize, m_pHeapList->pHdrMap, (COUNT_T)HEAP2MAPSIZE(ROUND_UP_TO_PAGE(m_pHeapList->maxCodeHeapSize))); }; @@ -2179,7 +2179,7 @@ void CodeFragmentHeap::RealBackoutMem(void *pMem //************************************************************************** -LoaderCodeHeap::LoaderCodeHeap(BOOL fMakeExecutable) +LoaderCodeHeap::LoaderCodeHeap(bool fMakeExecutable) : m_LoaderHeap(NULL, // RangeList *pRangeList fMakeExecutable), m_cbMinNextPad(0) @@ -2736,7 +2736,6 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, } else { - // Interpreter-TODO: interpreter and dynamic domain at the same time pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap; pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = NULL; } @@ -2842,7 +2841,7 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, RETURN(mem); } -void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, CodeHeader** ppCodeHeader, CodeHeader** ppCodeHeaderRW, +void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader #ifdef FEATURE_EH_FUNCLETS @@ -2898,7 +2897,9 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser if (flag & CORJIT_ALLOCMEM_FLG_INTERPRETED) { +#ifdef FEATURE_EH_FUNCLETS _ASSERTE(nUnwindInfos == 0); +#endif _ASSERTE(reserveForJumpStubs == 0); requestInfo.SetInterpreted(); @@ -2914,9 +2915,9 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser requestInfo.setReserveForJumpStubs(reserveForJumpStubs); #ifdef FEATURE_EH_FUNCLETS - realHeaderSize = offsetof(JitRealCodeHeader, unwindInfos[0]) + (sizeof(T_RUNTIME_FUNCTION) * nUnwindInfos); + realHeaderSize = offsetof(RealCodeHeader, unwindInfos[0]) + (sizeof(T_RUNTIME_FUNCTION) * nUnwindInfos); #else - realHeaderSize = sizeof(JitRealCodeHeader); + realHeaderSize = sizeof(RealCodeHeader); #endif } @@ -2944,13 +2945,13 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser _ASSERTE(IS_ALIGNED(pCode, alignment)); - pCodeHdr = ((JitCodeHeader *)pCode) - 1; + pCodeHdr = ((CodeHeader *)pCode) - 1; - *pAllocatedSize = sizeof(JitCodeHeader) + totalSize; + *pAllocatedSize = sizeof(CodeHeader) + totalSize; if (ExecutableAllocator::IsWXORXEnabled() && !requestInfo.IsInterpreted()) { - pCodeHdrRW = (JitCodeHeader *)new BYTE[*pAllocatedSize]; + pCodeHdrRW = (CodeHeader *)new BYTE[*pAllocatedSize]; } else { @@ -2978,7 +2979,7 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser #ifdef FEATURE_EH_FUNCLETS if (!requestInfo.IsInterpreted()) { - ((JitCodeHeader*)pCodeHdrRW)->SetNumberOfUnwindInfos(nUnwindInfos); + ((CodeHeader*)pCodeHdrRW)->SetNumberOfUnwindInfos(nUnwindInfos); } #endif @@ -3165,39 +3166,39 @@ LoaderHeap *EECodeGenManager::GetJitMetaHeap(MethodDesc *pMD) return pAllocator->GetLowFrequencyHeap(); } -BYTE* EECodeGenManager::allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) +BYTE* EECodeGenManager::allocGCInfo(void* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) { CONTRACTL { THROWS; GC_NOTRIGGER; } CONTRACTL_END; - MethodDesc* pMD = pCodeHeader->GetMethodDesc(); + MethodDesc* pMD = GetMethodDesc(pCodeHeader); // sadly for light code gen I need the check in here. We should change GetJitMetaHeap if (pMD->IsLCGMethod()) { CrstHolder ch(&m_CodeHeapCritSec); - pCodeHeader->SetGCInfo((BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize)); + SetGCInfo(pCodeHeader, (BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize)); } else { - pCodeHeader->SetGCInfo((BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize))); + SetGCInfo(pCodeHeader, (BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize))); } - _ASSERTE(pCodeHeader->GetGCInfo()); // AllocMem throws if there's not enough memory + _ASSERTE(GetGCInfo(pCodeHeader)); // AllocMem throws if there's not enough memory * pAllocationSize = blockSize; // Store the allocation size so we can backout later. - return(pCodeHeader->GetGCInfo()); + return(GetGCInfo(pCodeHeader)); } -void* EECodeGenManager::allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) +void* EECodeGenManager::allocEHInfoRaw(void* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) { CONTRACTL { THROWS; GC_NOTRIGGER; } CONTRACTL_END; - MethodDesc* pMD = pCodeHeader->GetMethodDesc(); + MethodDesc* pMD = GetMethodDesc(pCodeHeader); void * mem = NULL; // sadly for light code gen I need the check in here. We should change GetJitMetaHeap @@ -3218,7 +3219,7 @@ void* EECodeGenManager::allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, } -EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) +EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(void* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) { CONTRACTL { THROWS; @@ -3234,10 +3235,10 @@ EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(CodeHeader* pCodeHeader, unsigned BYTE *EHInfo = (BYTE*)allocEHInfoRaw(pCodeHeader, blockSize, pAllocationSize); - pCodeHeader->SetEHInfo((EE_ILEXCEPTION*) (EHInfo + sizeof(size_t))); - pCodeHeader->GetEHInfo()->Init(numClauses); + SetEHInfo(pCodeHeader, (EE_ILEXCEPTION*) (EHInfo + sizeof(size_t))); + GetEHInfo(pCodeHeader)->Init(numClauses); *((size_t *)EHInfo) = numClauses; - return(pCodeHeader->GetEHInfo()); + return(GetEHInfo(pCodeHeader)); } JumpStubBlockHeader * EEJitManager::allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps, @@ -3353,14 +3354,14 @@ GCInfoToken EECodeGenManager::GetGCInfoToken(const METHODTOKEN& MethodToken) } CONTRACTL_END; // The JIT-ed code always has the current version of GCInfo - return{ GetCodeHeader(MethodToken)->GetGCInfo(), GCINFO_VERSION }; + return{ GetGCInfo(GetCodeHeader(MethodToken)), GCINFO_VERSION }; } // creates an enumeration and returns the number of EH clauses unsigned EECodeGenManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState) { LIMITED_METHOD_CONTRACT; - EE_ILEXCEPTION * EHInfo = GetCodeHeader(MethodToken)->GetEHInfo(); + EE_ILEXCEPTION * EHInfo = GetEHInfo(GetCodeHeader(MethodToken)); pEnumState->iCurrentPos = 0; // since the EH info is not compressed, the clause number is used to do the enumeration pEnumState->pExceptionClauseArray = 0; @@ -3432,19 +3433,19 @@ void EEJitManager::UnpublishUnwindInfoForMethod(TADDR codeStart) #endif // defined(TARGET_AMD64) } -void EECodeGenManager::RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len) +void EECodeGenManager::RemoveJitData(void * pCHdr, size_t GCinfo_len, size_t EHinfo_len) { CONTRACTL { NOTHROW; GC_TRIGGERS; } CONTRACTL_END; - MethodDesc* pMD = pCHdr->GetMethodDesc(); + MethodDesc* pMD = GetMethodDesc(pCHdr); - if (pMD->IsLCGMethod()) { - - void * codeStart = (pCHdr + 1); + void * codeStart = (void*)GetCodeStartAddress(pCHdr); + if (pMD->IsLCGMethod()) + { { CrstHolder ch(&m_CodeHeapCritSec); @@ -3473,7 +3474,7 @@ void EECodeGenManager::RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size HeapList *pHp = GetCodeHeapList(); while (pHp && ((pHp->startAddress > (TADDR)pCHdr) || - (pHp->endAddress < (TADDR)pCHdr + sizeof(CodeHeader)))) + (pHp->endAddress < (TADDR)codeStart))) { pHp = pHp->GetNext(); } @@ -3484,16 +3485,16 @@ void EECodeGenManager::RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size if (pHp == NULL) return; - NibbleMapDeleteUnlocked(pHp, (TADDR)(pCHdr + 1)); + NibbleMapDeleteUnlocked(pHp, (TADDR)codeStart); } // Backout the GCInfo if (GCinfo_len > 0) { - GetJitMetaHeap(pMD)->BackoutMem(pCHdr->GetGCInfo(), GCinfo_len); + GetJitMetaHeap(pMD)->BackoutMem(GetGCInfo(pCHdr), GCinfo_len); } // Backout the EHInfo - BYTE *EHInfo = (BYTE *)pCHdr->GetEHInfo(); + BYTE *EHInfo = (BYTE *)GetEHInfo(pCHdr); if (EHInfo) { EHInfo -= sizeof(size_t); @@ -3709,9 +3710,9 @@ void ExecutionManager::CleanupCodeHeaps() _ASSERTE (IsAtProcessExit() || (GCHeapUtilities::IsGCInProgress() && ::IsGCThread())); GetEEJitManager()->CleanupCodeHeaps(); -#ifdef FEATURE_INTERPRETER +#ifdef FEATURE_INTERPRETER GetInterpreterJitManager()->CleanupCodeHeaps(); -#endif // FEATURE_INTERPRETER +#endif // FEATURE_INTERPRETER } void EECodeGenManager::CleanupCodeHeaps() @@ -3991,6 +3992,60 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ } } +void EEJitManager::EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } + CONTRACTL_END; + + DAC_ENUM_DTHIS(); + + PTR_CodeHeader pCH = dac_cast(pCodeHeader); + pCH->EnumMemoryRegions(flags, pJitMan); +} + +#ifdef FEATURE_INTERPRETER +void InterpreterCodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } + CONTRACTL_END; + + DAC_ENUM_DTHIS(); + + this->pRealCodeHeader.EnumMem(); + + if (this->GetDebugInfo() != NULL) + { + CompressDebugInfo::EnumMemoryRegions(flags, this->GetDebugInfo(), FALSE /* hasFlagByte */); + } +} + +void InterpreterJitManager::EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } + CONTRACTL_END; + + DAC_ENUM_DTHIS(); + + PTR_InterpreterCodeHeader pCH = dac_cast(pCodeHeader); + pCH->EnumMemoryRegions(flags, pJitMan); +} +#endif // FEATURE_INTERPRETER + //----------------------------------------------------------------------------- // Enumerate for minidumps. //----------------------------------------------------------------------------- @@ -4018,8 +4073,8 @@ PCODE EECodeGenManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToke { WRAPPER_NO_CONTRACT; - CodeHeader * pHeader = GetCodeHeader(MethodToken); - return pHeader->GetCodeStartAddress() + relOffset; + void * pHeader = GetCodeHeader(MethodToken); + return GetCodeStartAddress(pHeader) + relOffset; } BOOL EECodeGenManager::JitCodeToMethodInfo( @@ -4351,7 +4406,7 @@ PTR_RUNTIME_FUNCTION EEJitManager::LazyGetFunctionEntry(EECodeInfo * pCodeInfo) return NULL; } - JitCodeHeader * pHeader = dac_cast(GetCodeHeader(pCodeInfo->GetMethodToken())); + CodeHeader * pHeader = dac_cast(GetCodeHeader(pCodeInfo->GetMethodToken())); DWORD address = RUNTIME_FUNCTION__BeginAddress(pHeader->GetUnwindInfo(0)) + pCodeInfo->GetRelOffset(); @@ -4382,7 +4437,7 @@ DWORD EEJitManager::GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD } CONTRACTL_END; - JitCodeHeader * pCH = dac_cast(GetCodeHeader(MethodToken)); + CodeHeader * pCH = dac_cast(GetCodeHeader(MethodToken)); TADDR moduleBase = JitTokenToModuleBase(MethodToken); _ASSERTE(pCH->GetNumberOfUnwindInfos() >= 1); @@ -5152,6 +5207,9 @@ void ExecutionManager::Unload(LoaderAllocator *pLoaderAllocator) } GetEEJitManager()->Unload(pLoaderAllocator); +#ifdef FEATURE_INTERPRETER + GetInterpreterJitManager()->Unload(pLoaderAllocator); +#endif // FEATURE_INTERPRETER } // This method is used by the JIT and the runtime for PreStubs. It will return diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 880e45c3d2e783..ca769a024d16c0 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -137,12 +137,6 @@ struct RealCodeHeader PTR_MethodDesc phdrMDesc; -public: -// if we're using the indirect codeheaders then all enumeration is done by the code header -}; - -struct JitRealCodeHeader : public RealCodeHeader -{ #ifdef FEATURE_EH_FUNCLETS DWORD nUnwindInfos; T_RUNTIME_FUNCTION unwindInfos[0]; @@ -152,8 +146,22 @@ struct JitRealCodeHeader : public RealCodeHeader // if we're using the indirect codeheaders then all enumeration is done by the code header }; -struct InterpreterRealCodeHeader : public RealCodeHeader +struct InterpreterRealCodeHeader { +public: + PTR_BYTE phdrDebugInfo; + + // Note - *(&(pCodeHeader->phdrJitEHInfo) - sizeof(size_t)) + // contains the number of EH clauses, See EEJitManager::allocEHInfo + PTR_EE_ILEXCEPTION phdrJitEHInfo; + PTR_BYTE phdrJitGCInfo; + +#if defined(FEATURE_GDBJIT) + VOID* pCalledMethods; +#endif + + PTR_MethodDesc phdrMDesc; + public: // if we're using the indirect codeheaders then all enumeration is done by the code header }; @@ -239,48 +247,105 @@ struct CodeHeader pRealCodeHeader = (PTR_RealCodeHeader)kind; } -#ifdef DACCESS_COMPILE - void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); -#endif // DACCESS_COMPILE - -}; - -typedef DPTR(JitRealCodeHeader) PTR_JitRealCodeHeader; -typedef DPTR(InterpreterRealCodeHeader) PTR_InterpreterRealCodeHeader; - -struct JitCodeHeader : public CodeHeader -{ #if defined(FEATURE_EH_FUNCLETS) UINT GetNumberOfUnwindInfos() { SUPPORTS_DAC; - return ((PTR_JitRealCodeHeader)pRealCodeHeader)->nUnwindInfos; + return pRealCodeHeader->nUnwindInfos; } void SetNumberOfUnwindInfos(UINT nUnwindInfos) { LIMITED_METHOD_CONTRACT; - ((PTR_JitRealCodeHeader)pRealCodeHeader)->nUnwindInfos = nUnwindInfos; + pRealCodeHeader->nUnwindInfos = nUnwindInfos; } PTR_RUNTIME_FUNCTION GetUnwindInfo(UINT iUnwindInfo) { SUPPORTS_DAC; _ASSERTE(iUnwindInfo < GetNumberOfUnwindInfos()); return dac_cast( - PTR_TO_MEMBER_TADDR(JitRealCodeHeader, (PTR_JitRealCodeHeader)pRealCodeHeader, unwindInfos) + iUnwindInfo * sizeof(T_RUNTIME_FUNCTION)); + PTR_TO_MEMBER_TADDR(RealCodeHeader, pRealCodeHeader, unwindInfos) + iUnwindInfo * sizeof(T_RUNTIME_FUNCTION)); } #endif // FEATURE_EH_FUNCLETS -}; -typedef DPTR(JitCodeHeader) PTR_JitCodeHeader; -// The code headers must have the same size, they only point to a different type of the real code header -static_assert(sizeof(JitCodeHeader) == sizeof(CodeHeader), "JitCodeHeader and CodeHeader must have the same size"); +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); +#endif // DACCESS_COMPILE + +}; + +typedef DPTR(RealCodeHeader) PTR_RealCodeHeader; +typedef DPTR(InterpreterRealCodeHeader) PTR_InterpreterRealCodeHeader; #ifdef FEATURE_INTERPRETER -struct InterpreterCodeHeader : public CodeHeader + +struct InterpreterCodeHeader { + PTR_InterpreterRealCodeHeader pRealCodeHeader; + +public: + PTR_BYTE GetDebugInfo() + { + SUPPORTS_DAC; + return pRealCodeHeader->phdrDebugInfo; + } + PTR_EE_ILEXCEPTION GetEHInfo() + { + return pRealCodeHeader->phdrJitEHInfo; + } + PTR_BYTE GetGCInfo() + { + SUPPORTS_DAC; + return pRealCodeHeader->phdrJitGCInfo; + + } + PTR_MethodDesc GetMethodDesc() + { + SUPPORTS_DAC; + return pRealCodeHeader->phdrMDesc; + } +#if defined(FEATURE_GDBJIT) + VOID* GetCalledMethods() + { + SUPPORTS_DAC; + return pRealCodeHeader->pCalledMethods; + } +#endif + TADDR GetCodeStartAddress() + { + SUPPORTS_DAC; + return dac_cast(dac_cast(this) + 1); + } + + void SetRealCodeHeader(BYTE* pRCH) + { + pRealCodeHeader = PTR_InterpreterRealCodeHeader((InterpreterRealCodeHeader*)pRCH); + } + + void SetDebugInfo(PTR_BYTE pDI) + { + pRealCodeHeader->phdrDebugInfo = pDI; + } + void SetEHInfo(PTR_EE_ILEXCEPTION pEH) + { + pRealCodeHeader->phdrJitEHInfo = pEH; + } + void SetGCInfo(PTR_BYTE pGC) + { + pRealCodeHeader->phdrJitGCInfo = pGC; + } + void SetMethodDesc(PTR_MethodDesc pMD) + { + pRealCodeHeader->phdrMDesc = pMD; + } + +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); +#endif // DACCESS_COMPILE + }; + typedef DPTR(InterpreterCodeHeader) PTR_InterpreterCodeHeader; static_assert(sizeof(InterpreterCodeHeader) == sizeof(CodeHeader), "InterpreterCodeHeader and CodeHeader must have the same size"); @@ -460,7 +525,9 @@ class LoaderCodeHeap : CodeHeap ExplicitControlLoaderHeap m_LoaderHeap; SSIZE_T m_cbMinNextPad; - LoaderCodeHeap(BOOL fMakeExecutable); +#ifndef DACCESS_COMPILE + LoaderCodeHeap(bool fMakeExecutable); +#endif public: static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap *pJitMetaHeap); @@ -1750,8 +1817,7 @@ class EECodeGenManager : public IJitManager GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); - static CodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); - static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); + virtual void * GetCodeHeader(const METHODTOKEN& MethodToken) = 0; virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC); @@ -1764,22 +1830,42 @@ class EECodeGenManager : public IJitManager return m_storeRichDebugInfo; } + // CodeHeader accessors + virtual PTR_BYTE GetDebugInfo(void* pCodeHeader) = 0; + virtual PTR_EE_ILEXCEPTION GetEHInfo(void* pCodeHeader) = 0; + virtual PTR_BYTE GetGCInfo(void* pCodeHeader) = 0; + virtual PTR_MethodDesc GetMethodDesc(void* pCodeHeader) = 0; +#if defined(FEATURE_GDBJIT) + virtual VOID* GetCalledMethods(void* pCodeHeader) = 0; +#endif + virtual TADDR GetCodeStartAddress(void* pCodeHeader) = 0; + virtual void SetRealCodeHeader(void* pCodeHeader, BYTE* pRCH) = 0; + virtual void SetDebugInfo(void* pCodeHeader, PTR_BYTE pDI) = 0; + virtual void SetEHInfo(void* pCodeHeader, PTR_EE_ILEXCEPTION pEH) = 0; + virtual void SetGCInfo(void* pCodeHeader, PTR_BYTE pGC) = 0; + virtual void SetMethodDesc(void* pCodeHeader, PTR_MethodDesc pMD) = 0; + +#ifdef DACCESS_COMPILE + virtual void EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) = 0; +#endif // DACCESS_COMPILE + + #ifndef DACCESS_COMPILE virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, CrawlFrame *pCf); - void RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); + void RemoveJitData(void * pCHdr, size_t GCinfo_len, size_t EHinfo_len); void Unload(LoaderAllocator* pAllocator); void CleanupCodeHeaps(); - void allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, CodeHeader** ppCodeHeader, CodeHeader** ppCodeHeaderRW, + void allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader #ifdef FEATURE_EH_FUNCLETS , UINT nUnwindInfos #endif ); - BYTE *allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); - EE_ILEXCEPTION* allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); + BYTE *allocGCInfo(void* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); + EE_ILEXCEPTION* allocEHInfo(void* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); // Heap Management functions void NibbleMapSet(HeapList * pHp, TADDR pCode, size_t codeSize); @@ -1798,7 +1884,7 @@ class EECodeGenManager : public IJitManager protected: void* allocCodeRaw(CodeHeapRequestInfo *pInfo, size_t header, size_t blockSize, unsigned align, HeapList ** ppCodeHeap); - void* allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); + void* allocEHInfoRaw(void* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) = 0; DomainCodeHeapList *GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly = FALSE); @@ -1820,7 +1906,7 @@ class EECodeGenManager : public IJitManager MethodDesc *m_pCurrent; public: - CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter = NULL); + CodeHeapIterator(EECodeGenManager *pJitMgr, LoaderAllocator *pLoaderAllocatorFilter = NULL); ~CodeHeapIterator(); BOOL Next(); @@ -1902,7 +1988,7 @@ struct JumpStubBlockHeader /*****************************************************************************/ -class EEJitManager : public EECodeGenManager +class EEJitManager final : public EECodeGenManager { #ifdef DACCESS_COMPILE friend class ClrDataAccess; @@ -1915,12 +2001,12 @@ class EEJitManager : public EECodeGenManager public: - virtual ICorJitCompiler* GetCompiler() override + virtual ICorJitCompiler* GetCompiler() { return m_jit; } - virtual ICorJitCompiler* GetAltCompiler() override + virtual ICorJitCompiler* GetAltCompiler() { return m_alternateJit; } @@ -1970,6 +2056,63 @@ class EEJitManager : public EECodeGenManager virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo *methodRegionInfo); + // CodeHeader accessors + // TODO: void* or TADDR? + virtual PTR_BYTE GetDebugInfo(void* pCodeHeader) + { + return ((CodeHeader*)pCodeHeader)->GetDebugInfo(); + } + virtual PTR_EE_ILEXCEPTION GetEHInfo(void* pCodeHeader) + { + return ((CodeHeader*)pCodeHeader)->GetEHInfo(); + } + virtual PTR_BYTE GetGCInfo(void* pCodeHeader) + { + return ((CodeHeader*)pCodeHeader)->GetGCInfo(); + } + virtual PTR_MethodDesc GetMethodDesc(void* pCodeHeader) + { + return ((CodeHeader*)pCodeHeader)->GetMethodDesc(); + } +#if defined(FEATURE_GDBJIT) + virtual VOID* GetCalledMethods(void* pCodeHeader) + { + return ((CodeHeader*)pCodeHeader)->GetCalledMethods(); + } +#endif + virtual TADDR GetCodeStartAddress(void* pCodeHeader) + { + return ((CodeHeader*)pCodeHeader)->GetCodeStartAddress(); + } + virtual void SetRealCodeHeader(void* pCodeHeader, BYTE* pRCH) + { + ((CodeHeader*)pCodeHeader)->SetRealCodeHeader(pRCH); + } + virtual void SetDebugInfo(void* pCodeHeader, PTR_BYTE pDI) + { + ((CodeHeader*)pCodeHeader)->SetDebugInfo(pDI); + } + virtual void SetEHInfo(void* pCodeHeader, PTR_EE_ILEXCEPTION pEH) + { + ((CodeHeader*)pCodeHeader)->SetEHInfo(pEH); + } + virtual void SetGCInfo(void* pCodeHeader, PTR_BYTE pGC) + { + ((CodeHeader*)pCodeHeader)->SetGCInfo(pGC); + } + + virtual void SetMethodDesc(void* pCodeHeader, PTR_MethodDesc pMD) + { + ((CodeHeader*)pCodeHeader)->SetMethodDesc(pMD); + } + +#ifdef DACCESS_COMPILE + virtual void EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); +#endif // DACCESS_COMPILE + + static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); + virtual void * GetCodeHeader(const METHODTOKEN& MethodToken); + #if !defined DACCESS_COMPILE BOOL LoadJIT(); @@ -2002,7 +2145,7 @@ class EEJitManager : public EECodeGenManager #endif // FEATURE_EH_FUNCLETS #if !defined DACCESS_COMPILE - virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) override; + virtual void UnpublishUnwindInfoForMethod(TADDR codeStart); #endif // !DACCESS_COMPILE private: @@ -2365,14 +2508,14 @@ struct cdac_data }; #endif -inline CodeHeader * EECodeGenManager::GetCodeHeader(const METHODTOKEN& MethodToken) +inline void * EEJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(!MethodToken.IsNull()); return dac_cast(MethodToken.m_pCodeHeader); } -inline CodeHeader * EECodeGenManager::GetCodeHeaderFromStartAddress(TADDR methodStartAddress) +inline CodeHeader * EEJitManager::GetCodeHeaderFromStartAddress(TADDR methodStartAddress) { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(methodStartAddress != (TADDR)NULL); @@ -2388,8 +2531,8 @@ inline TADDR EECodeGenManager::JitTokenToStartAddress(const METHODTOKEN& MethodT SUPPORTS_DAC; } CONTRACTL_END; - CodeHeader * pCH = GetCodeHeader(MethodToken); - return pCH->GetCodeStartAddress(); + void * pCH = GetCodeHeader(MethodToken); + return GetCodeStartAddress(pCH); } inline void EEJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, @@ -2529,7 +2672,7 @@ class ReadyToRunJitManager final: public IJitManager #ifdef FEATURE_INTERPRETER -class InterpreterJitManager : public EECodeGenManager +class InterpreterJitManager final : public EECodeGenManager { VPTR_VTABLE_CLASS(InterpreterJitManager, EECodeGenManager) public: @@ -2538,12 +2681,12 @@ class InterpreterJitManager : public EECodeGenManager InterpreterJitManager(); - virtual ICorJitCompiler* GetCompiler() override + virtual ICorJitCompiler* GetCompiler() { return m_interpreter; } - virtual ICorJitCompiler* GetAltCompiler() override + virtual ICorJitCompiler* GetAltCompiler() { return NULL; } @@ -2556,34 +2699,90 @@ class InterpreterJitManager : public EECodeGenManager return m_interpreter != NULL; } - virtual DWORD GetCodeType() override + virtual DWORD GetCodeType() { LIMITED_METHOD_DAC_CONTRACT; return (miManaged | miIL); } - virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo * methodRegionInfo) override + virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo * methodRegionInfo) { // Not used for the interpreter _ASSERTE(FALSE); } + // CodeHeader accessors + // TODO: void* or TADDR? + virtual PTR_BYTE GetDebugInfo(void* pCodeHeader) + { + return ((InterpreterCodeHeader*)pCodeHeader)->GetDebugInfo(); + } + virtual PTR_EE_ILEXCEPTION GetEHInfo(void* pCodeHeader) + { + return ((InterpreterCodeHeader*)pCodeHeader)->GetEHInfo(); + } + virtual PTR_BYTE GetGCInfo(void* pCodeHeader) + { + return ((InterpreterCodeHeader*)pCodeHeader)->GetGCInfo(); + } + virtual PTR_MethodDesc GetMethodDesc(void* pCodeHeader) + { + return ((InterpreterCodeHeader*)pCodeHeader)->GetMethodDesc(); + } +#if defined(FEATURE_GDBJIT) + virtual VOID* GetCalledMethods(void* pCodeHeader) + { + return ((InterpreterCodeHeader*)pCodeHeader)->GetCalledMethods(); + } +#endif + virtual TADDR GetCodeStartAddress(void* pCodeHeader) + { + return ((InterpreterCodeHeader*)pCodeHeader)->GetCodeStartAddress(); + } + virtual void SetRealCodeHeader(void* pCodeHeader, BYTE* pRCH) + { + ((InterpreterCodeHeader*)pCodeHeader)->SetRealCodeHeader(pRCH); + } + virtual void SetDebugInfo(void* pCodeHeader, PTR_BYTE pDI) + { + ((InterpreterCodeHeader*)pCodeHeader)->SetDebugInfo(pDI); + } + virtual void SetEHInfo(void* pCodeHeader, PTR_EE_ILEXCEPTION pEH) + { + ((InterpreterCodeHeader*)pCodeHeader)->SetEHInfo(pEH); + } + virtual void SetGCInfo(void* pCodeHeader, PTR_BYTE pGC) + { + ((InterpreterCodeHeader*)pCodeHeader)->SetGCInfo(pGC); + } + + virtual void SetMethodDesc(void* pCodeHeader, PTR_MethodDesc pMD) + { + ((InterpreterCodeHeader*)pCodeHeader)->SetMethodDesc(pMD); + } + +#ifdef DACCESS_COMPILE + virtual void EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); +#endif // DACCESS_COMPILE + + virtual void * GetCodeHeader(const METHODTOKEN& MethodToken); + #if defined(FEATURE_EH_FUNCLETS) - virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo) override + virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo) { // Not used for the interpreter _ASSERTE(FALSE); return NULL; } - virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo) override + virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo) { // Not used for the interpreter _ASSERTE(FALSE); return NULL; } - virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength) override + virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength) { // Not used for the interpreter _ASSERTE(FALSE); @@ -2592,7 +2791,7 @@ class InterpreterJitManager : public EECodeGenManager #if !defined DACCESS_COMPILE protected: - virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) override + virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) { // Nothing to do for the interpreter } @@ -2602,7 +2801,7 @@ class InterpreterJitManager : public EECodeGenManager #endif // FEATURE_EH_FUNCLETS - virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) override + virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) { return STUB_CODE_BLOCK_UNKNOWN; } @@ -2610,7 +2809,7 @@ class InterpreterJitManager : public EECodeGenManager #if defined(DACCESS_COMPILE) #if defined(FEATURE_EH_FUNCLETS) - virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) override + virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { // Not used for the interpreter _ASSERTE(FALSE); @@ -2635,7 +2834,7 @@ private : // class EECodeInfo { - friend BOOL EEJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo); + friend BOOL EECodeGenManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo); #ifdef FEATURE_READYTORUN friend BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo); #endif @@ -2769,6 +2968,13 @@ ULONG GetFixedStackSize(); }; +inline void * InterpreterJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) +{ + LIMITED_METHOD_DAC_CONTRACT; + _ASSERTE(!MethodToken.IsNull()); + return dac_cast(MethodToken.m_pCodeHeader); +} + #include "codeman.inl" void ThrowOutOfMemoryWithinRange(); diff --git a/src/coreclr/vm/dynamicmethod.cpp b/src/coreclr/vm/dynamicmethod.cpp index c4408c3b081c41..fe899f4d5238d2 100644 --- a/src/coreclr/vm/dynamicmethod.cpp +++ b/src/coreclr/vm/dynamicmethod.cpp @@ -439,11 +439,13 @@ HeapList* HostCodeHeap::InitializeHeapList(CodeHeapRequestInfo *pInfo) TrackAllocation *pTracker = NULL; +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pHp->CLRPersonalityRoutine = NULL; } else +#endif // FEATURE_INTERPRETER { #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index 19c35aa9452ed7..363395e752deaa 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -5221,7 +5221,7 @@ VOID ETW::MethodLog::SendEventsForJitMethodsHelper(LoaderAllocator *pLoaderAlloc MethodDescSet sentMethodDetailsSet; MethodDescSet* pSentMethodDetailsSet = fSendRichDebugInfoEvent ? &sentMethodDetailsSet : NULL; - EEJitManager::CodeHeapIterator heapIterator(pLoaderAllocatorFilter); + EECodeGenManager::CodeHeapIterator heapIterator(ExecutionManager::GetEEJitManager(), pLoaderAllocatorFilter); while (heapIterator.Next()) { MethodDesc * pMD = heapIterator.GetMethod(); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c7316899196fec..6352ad95e53be2 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10904,7 +10904,7 @@ void CEECodeGenInfo::WriteCodeBytes() if (m_pRealCodeHeader != NULL) { // Restore the read only version of the real code header - m_CodeHeaderRW->SetRealCodeHeader(m_pRealCodeHeader); + m_jitManager->SetRealCodeHeader(m_CodeHeaderRW, m_pRealCodeHeader); m_pRealCodeHeader = NULL; } @@ -10927,7 +10927,7 @@ void CEECodeGenInfo::BackoutJitData(EECodeGenManager * jitMgr) // the code bytes to the target memory location. WriteCodeBytes(); - CodeHeader* pCodeHeader = m_CodeHeader; + void* pCodeHeader = m_CodeHeader; if (pCodeHeader) jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len); } @@ -10940,16 +10940,25 @@ void CEEJitInfo::WriteCode(EECodeGenManager * jitMgr) GC_TRIGGERS; } CONTRACTL_END; - CEECodeGenInfo::WriteCode(jitMgr); + WriteCodeBytes(); + + CodeHeader* pCodeHeader = (CodeHeader*)m_CodeHeader; + + // Now that the code header was written to the final location, publish the code via the nibble map + // m_codeWriteBufferSize is the size of the code region + code header. The nibble map should only use + // the code region, therefore we subtract the size of the CodeHeader. + jitMgr->NibbleMapSet(m_pCodeHeap, pCodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(CodeHeader)); #if defined(TARGET_AMD64) // Publish the new unwind information in a way that the ETW stack crawler can find _ASSERTE(m_usedUnwindInfos == m_totalUnwindInfos); - UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, ((JitCodeHeader*)m_CodeHeader)->GetUnwindInfo(0), m_totalUnwindInfos); + UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, pCodeHeader->GetUnwindInfo(0), m_totalUnwindInfos); #endif // defined(TARGET_AMD64) } -void CEECodeGenInfo::WriteCode(EECodeGenManager * jitMgr) +#ifdef FEATURE_INTERPRETER +/*********************************************************************/ +void CInterpreterJitInfo::WriteCode(EECodeGenManager * jitMgr) { CONTRACTL { THROWS; @@ -10958,12 +10967,14 @@ void CEECodeGenInfo::WriteCode(EECodeGenManager * jitMgr) WriteCodeBytes(); + InterpreterCodeHeader* pCodeHeader = (InterpreterCodeHeader*)m_CodeHeader; + // Now that the code header was written to the final location, publish the code via the nibble map // m_codeWriteBufferSize is the size of the code region + code header. The nibble map should only use // the code region, therefore we subtract the size of the CodeHeader. - jitMgr->NibbleMapSet(m_pCodeHeap, m_CodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(CodeHeader)); + jitMgr->NibbleMapSet(m_pCodeHeap, pCodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(InterpreterCodeHeader)); } - +#endif // FEATURE_INTERPRETER /*********************************************************************/ // Route jit information to the Jit Debug store. @@ -11122,7 +11133,7 @@ void CEECodeGenInfo::CompressDebugInfo() #ifdef FEATURE_ON_STACK_REPLACEMENT writeFlagByte = TRUE; #endif - if (((EEJitManager*)m_jitManager)->IsStoringRichDebugInfo()) + if (m_jitManager->IsStoringRichDebugInfo()) writeFlagByte = TRUE; PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars( @@ -11134,7 +11145,7 @@ void CEECodeGenInfo::CompressDebugInfo() writeFlagByte, m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap()); - m_CodeHeaderRW->SetDebugInfo(pDebugInfo); + m_jitManager->SetDebugInfo(m_CodeHeaderRW, pDebugInfo); } EX_CATCH { @@ -11290,7 +11301,9 @@ void CEEJitInfo::allocUnwindInfo ( _ASSERTE(m_usedUnwindInfos > 0); } - PT_RUNTIME_FUNCTION pRuntimeFunction = ((JitCodeHeader*)m_CodeHeaderRW)->GetUnwindInfo(m_usedUnwindInfos); + CodeHeader *pCodeHeaderRW = (CodeHeader *)m_CodeHeaderRW; + + PT_RUNTIME_FUNCTION pRuntimeFunction = pCodeHeaderRW->GetUnwindInfo(m_usedUnwindInfos); m_usedUnwindInfos++; @@ -11360,7 +11373,7 @@ void CEEJitInfo::allocUnwindInfo ( for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++) { - PT_RUNTIME_FUNCTION pOtherFunction = ((JitCodeHeader*)m_CodeHeaderRW)->GetUnwindInfo(iUnwindInfo); + PT_RUNTIME_FUNCTION pOtherFunction = pCodeHeaderRW->GetUnwindInfo(iUnwindInfo); _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress + writeableOffset) || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress + writeableOffset) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction))); } @@ -11716,6 +11729,15 @@ void CEEInfo::JitProcessShutdownWork() jitMgr->m_alternateJit->ProcessShutdownWork(this); } #endif // ALLOW_SXS_JIT + +#ifdef FEATURE_INTERPRETER + InterpreterJitManager* interpreterMgr = ExecutionManager::GetInterpreterJitManager(); + + if (interpreterMgr->m_interpreter != NULL) + { + interpreterMgr->m_interpreter->ProcessShutdownWork(this); + } +#endif // FEATURE_INTERPRETER } /*********************************************************************/ @@ -12212,9 +12234,9 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) JIT_TO_EE_TRANSITION(); - CEECodeGenInfo::allocMem(pArgs, GetReserveForJumpStubs() + allocMemWorker(pArgs, GetReserveForJumpStubs() #ifdef FEATURE_EH_FUNCLETS - , m_totalUnwindInfos, m_totalUnwindSize, &m_theUnwindBlock + , m_totalUnwindInfos, m_totalUnwindSize, &m_theUnwindBlock #endif ); @@ -12235,18 +12257,18 @@ void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs) JIT_TO_EE_TRANSITION(); - CEECodeGenInfo::allocMem(pArgs, 0 /* reserveForJumpStubs */ + allocMemWorker(pArgs, 0 /* reserveForJumpStubs */ #ifdef FEATURE_EH_FUNCLETS - , 0 /* unwindInfoCount */, 0 /* unwindSize */, NULL /* ppUnwindBlock */ + , 0 /* unwindInfoCount */, 0 /* unwindSize */, NULL /* ppUnwindBlock */ #endif ); EE_TO_JIT_TRANSITION(); } -void CEECodeGenInfo::allocMem(AllocMemArgs *pArgs, size_t reserveForJumpStubs +void CEECodeGenInfo::allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpStubs #ifdef FEATURE_EH_FUNCLETS - , ULONG unwindInfoCount, ULONG unwindSize, BYTE** ppUnwindBlock + , ULONG unwindInfoCount, ULONG unwindSize, BYTE** ppUnwindBlock #endif ) { @@ -12350,7 +12372,7 @@ void CEECodeGenInfo::allocMem(AllocMemArgs *pArgs, size_t reserveForJumpStubs #endif ); - BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress(); + BYTE* current = (BYTE *)m_jitManager->GetCodeStartAddress(m_CodeHeader); size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader; *codeBlock = current; @@ -12379,7 +12401,7 @@ void CEECodeGenInfo::allocMem(AllocMemArgs *pArgs, size_t reserveForJumpStubs } #endif - _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value()); + _ASSERTE((SIZE_T)(current - (BYTE *)m_jitManager->GetCodeStartAddress(m_CodeHeader)) <= totalSize.Value()); #ifdef _DEBUG m_codeSize = codeSize; @@ -12387,7 +12409,7 @@ void CEECodeGenInfo::allocMem(AllocMemArgs *pArgs, size_t reserveForJumpStubs } /*********************************************************************/ -void * CEEJitInfo::allocGCInfo (size_t size) +void * CEECodeGenInfo::allocGCInfo (size_t size) { CONTRACTL { THROWS; @@ -12400,7 +12422,7 @@ void * CEEJitInfo::allocGCInfo (size_t size) JIT_TO_EE_TRANSITION(); _ASSERTE(m_CodeHeaderRW != 0); - _ASSERTE(m_CodeHeaderRW->GetGCInfo() == 0); + _ASSERTE(m_jitManager->GetGCInfo(m_CodeHeaderRW) == 0); #ifdef HOST_64BIT if (size & 0xFFFFFFFF80000000LL) @@ -12415,7 +12437,7 @@ void * CEEJitInfo::allocGCInfo (size_t size) COMPlusThrowHR(CORJIT_OUTOFMEM); } - _ASSERTE(m_CodeHeaderRW->GetGCInfo() != 0 && block == m_CodeHeaderRW->GetGCInfo()); + _ASSERTE(m_jitManager->GetGCInfo(m_CodeHeaderRW) != 0 && block == m_jitManager->GetGCInfo(m_CodeHeaderRW)); EE_TO_JIT_TRANSITION(); @@ -12423,7 +12445,7 @@ void * CEEJitInfo::allocGCInfo (size_t size) } /*********************************************************************/ -void CEEJitInfo::setEHcount ( +void CEECodeGenInfo::setEHcount ( unsigned cEH) { CONTRACTL { @@ -12436,19 +12458,20 @@ void CEEJitInfo::setEHcount ( _ASSERTE(cEH != 0); _ASSERTE(m_CodeHeaderRW != 0); - _ASSERTE(m_CodeHeaderRW->GetEHInfo() == 0); + _ASSERTE(m_jitManager->GetEHInfo(m_CodeHeaderRW) == 0); EE_ILEXCEPTION* ret; ret = m_jitManager->allocEHInfo(m_CodeHeaderRW,cEH, &m_EHinfo_len); _ASSERTE(ret); // allocEHInfo throws if there's not enough memory - _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && m_CodeHeaderRW->GetEHInfo()->EHCount() == cEH); + _ASSERTE(m_jitManager->GetEHInfo(m_CodeHeaderRW) != 0 && m_jitManager->GetEHInfo(m_CodeHeaderRW)->EHCount() == cEH); EE_TO_JIT_TRANSITION(); } /*********************************************************************/ -void CEEJitInfo::setEHinfo ( + +void CEECodeGenInfo::setEHinfo ( unsigned EHnumber, const CORINFO_EH_CLAUSE* clause) { @@ -12461,9 +12484,10 @@ void CEEJitInfo::setEHinfo ( JIT_TO_EE_TRANSITION(); // Fix make the Code Manager EH clauses EH_INFO+ - _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && EHnumber < m_CodeHeaderRW->GetEHInfo()->EHCount()); + EE_ILEXCEPTION *pEHInfo = m_jitManager->GetEHInfo(m_CodeHeaderRW); + _ASSERTE(pEHInfo != 0 && EHnumber < pEHInfo->EHCount()); - EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeaderRW->GetEHInfo()->EHClause(EHnumber); + EE_ILEXCEPTION_CLAUSE* pEHClause = pEHInfo->EHClause(EHnumber); pEHClause->TryStartPC = clause->TryOffset; pEHClause->TryEndPC = clause->TryLength; @@ -12495,9 +12519,10 @@ void CEEJitInfo::setEHinfo ( EE_TO_JIT_TRANSITION(); } + /*********************************************************************/ // get individual exception handler -void CEEJitInfo::getEHinfo( +void CEECodeGenInfo::getEHinfo( CORINFO_METHOD_HANDLE ftn, /* IN */ unsigned EHnumber, /* IN */ CORINFO_EH_CLAUSE* clause) /* OUT */ @@ -12861,7 +12886,8 @@ BOOL g_fAllowRel32 = TRUE; #endif -PCODE UnsafeJitFunctionWorker(EECodeGenManager *pJitMgr, CEECodeGenInfo *pJitInfo, CORJIT_FLAGS* pJitFlags, CORINFO_METHOD_INFO methodInfo, MethodInfoHelperContext *pCxt, NativeCodeVersion nativeCodeVersion) +PCODE UnsafeJitFunctionWorker(EECodeGenManager *pJitMgr, CEECodeGenInfo *pJitInfo, CORJIT_FLAGS* pJitFlags, CORINFO_METHOD_INFO methodInfo, + MethodInfoHelperContext *pCxt, NativeCodeVersion nativeCodeVersion, ULONG* pSizeOfCode) { STANDARD_VM_CONTRACT; if (pCxt->HasTransientMethodDetails()) @@ -13126,35 +13152,35 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, *pJitFlags = GetCompileFlags(config, ftn, &methodInfo); -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) - BOOL fForceJumpStubOverflow = FALSE; - -#ifdef _DEBUG - // Always exercise the overflow codepath with force relocs - if (PEDecoder::GetForceRelocs()) - fForceJumpStubOverflow = TRUE; -#endif - -#if defined(TARGET_AMD64) - BOOL fAllowRel32 = (g_fAllowRel32 | fForceJumpStubOverflow) && g_pConfig->JitEnableOptionalRelocs(); -#endif - - size_t reserveForJumpStubs = 0; - -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) - #ifdef FEATURE_INTERPRETER bool useInterpreter = interpreterMgr->IsInterpreterLoaded(); if (useInterpreter) { CInterpreterJitInfo jitInfo(ftn, ILHeader, interpreterMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING)); - ret = UnsafeJitFunctionWorker(interpreterMgr, &jitInfo, pJitFlags, methodInfo, &cxt, nativeCodeVersion); + ret = UnsafeJitFunctionWorker(interpreterMgr, &jitInfo, pJitFlags, methodInfo, &cxt, nativeCodeVersion, pSizeOfCode); } #endif // FEATURE_INTERPRETER if (ret == NULL) { +#if defined(TARGET_AMD64) || defined(TARGET_ARM64) + BOOL fForceJumpStubOverflow = FALSE; + +#ifdef _DEBUG + // Always exercise the overflow codepath with force relocs + if (PEDecoder::GetForceRelocs()) + fForceJumpStubOverflow = TRUE; +#endif + +#if defined(TARGET_AMD64) + BOOL fAllowRel32 = (g_fAllowRel32 | fForceJumpStubOverflow) && g_pConfig->JitEnableOptionalRelocs(); +#endif + + size_t reserveForJumpStubs = 0; + +#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) + while (true) { CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING)); @@ -13181,7 +13207,7 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, } #endif // FEATURE_ON_STACK_REPLACEMENT - ret = UnsafeJitFunctionWorker(jitMgr, &jitInfo, pJitFlags, methodInfo, &cxt, nativeCodeVersion); + ret = UnsafeJitFunctionWorker(jitMgr, &jitInfo, pJitFlags, methodInfo, &cxt, nativeCodeVersion, pSizeOfCode); if (!ret) COMPlusThrow(kInvalidProgramException); diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 82b0208e04a9e6..af75ef0db6dad5 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -688,21 +688,36 @@ class CEECodeGenInfo : public CEEInfo void reportMetadata(const char* key, const void* value, size_t length) override final; - virtual void WriteCode(EECodeGenManager * jitMgr); + virtual void WriteCode(EECodeGenManager * jitMgr) = 0; protected: - void allocMem (AllocMemArgs *pArgs, size_t reserveForJumpStubs + void allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpStubs #ifdef FEATURE_EH_FUNCLETS - , ULONG unwindInfoSize, ULONG unwindSize, BYTE** ppUnwindBlock + , ULONG unwindInfoSize, ULONG unwindSize, BYTE** ppUnwindBlock #endif ); void WriteCodeBytes(); + virtual void getEHinfo( + CORINFO_METHOD_HANDLE ftn, /* IN */ + unsigned EHnumber, /* IN */ + CORINFO_EH_CLAUSE* clause /* OUT */ + ) override final; + + virtual void * allocGCInfo (size_t size) override final; + + virtual void setEHcount (unsigned cEH) override final; + + virtual void setEHinfo ( + unsigned EHnumber, + const CORINFO_EH_CLAUSE* clause + ) override final; + EECodeGenManager* m_jitManager; // responsible for allocating memory - CodeHeader* m_CodeHeader; // descriptor for JITTED code - read/execute address - CodeHeader* m_CodeHeaderRW; // descriptor for JITTED code - code write scratch buffer address + void* m_CodeHeader; // descriptor for JITTED code - read/execute address + void* m_CodeHeaderRW; // descriptor for JITTED code - code write scratch buffer address size_t m_codeWriteBufferSize; BYTE* m_pRealCodeHeader; HeapList* m_pCodeHeap; @@ -755,6 +770,8 @@ class CEEJitInfo : public CEECodeGenInfo void allocMem (AllocMemArgs *pArgs) override final; + void WriteCode(EECodeGenManager * jitMgr) override final; + void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unwindSize) override final; void allocUnwindInfo ( @@ -767,20 +784,6 @@ class CEEJitInfo : public CEECodeGenInfo CorJitFuncKind funcKind /* IN */ ) override final; - void * allocGCInfo (size_t size) override final; - - void setEHcount (unsigned cEH) override final; - - void setEHinfo ( - unsigned EHnumber, - const CORINFO_EH_CLAUSE* clause) override final; - - void getEHinfo( - CORINFO_METHOD_HANDLE ftn, /* IN */ - unsigned EHnumber, /* IN */ - CORINFO_EH_CLAUSE* clause /* OUT */ - ) override final; - HRESULT allocPgoInstrumentationBySchema( CORINFO_METHOD_HANDLE ftnHnd, /* IN */ PgoInstrumentationSchema* pSchema, /* IN/OUT */ @@ -879,7 +882,7 @@ class CEEJitInfo : public CEECodeGenInfo m_reserveForJumpStubs = value; } - virtual PatchpointInfo* GetPatchpointInfo() + virtual PatchpointInfo* GetPatchpointInfo() override final { #ifdef FEATURE_ON_STACK_REPLACEMENT return m_pPatchpointInfoFromJit; @@ -915,24 +918,24 @@ class CEEJitInfo : public CEECodeGenInfo CEEJitInfo(MethodDesc* fd, COR_ILMETHOD_DECODER* header, EECodeGenManager* jm, bool allowInlining = true) - : CEECodeGenInfo(fd, header, jm, allowInlining), + : CEECodeGenInfo(fd, header, jm, allowInlining) #ifdef FEATURE_EH_FUNCLETS - m_moduleBase(0), + , m_moduleBase(0), m_totalUnwindSize(0), m_usedUnwindSize(0), m_theUnwindBlock(NULL), m_totalUnwindInfos(0), - m_usedUnwindInfos(0), + m_usedUnwindInfos(0) #endif #ifdef TARGET_AMD64 - m_fAllowRel32(FALSE), + , m_fAllowRel32(FALSE) #endif #if defined(TARGET_AMD64) || defined(TARGET_ARM64) - m_fJumpStubOverflow(FALSE), - m_reserveForJumpStubs(0), + , m_fJumpStubOverflow(FALSE), + m_reserveForJumpStubs(0) #endif #ifdef FEATURE_ON_STACK_REPLACEMENT - m_pPatchpointInfoFromJit(NULL), + , m_pPatchpointInfoFromJit(NULL), m_pPatchpointInfoFromRuntime(NULL), m_ilOffset(0) #endif @@ -992,8 +995,6 @@ class CEEJitInfo : public CEECodeGenInfo CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override final; void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override final; - virtual void WriteCode(EECodeGenManager * jitMgr) override; - void setPatchpointInfo(PatchpointInfo* patchpointInfo) override final; PatchpointInfo* getOSRInfo(unsigned* ilOffset) override final; @@ -1063,6 +1064,8 @@ class CInterpreterJitInfo : public CEECodeGenInfo void allocMem (AllocMemArgs *pArgs) override final; + void WriteCode(EECodeGenManager * jitMgr) override final; + void ResetForJitRetry() { CONTRACTL { diff --git a/src/coreclr/vm/perfmap.cpp b/src/coreclr/vm/perfmap.cpp index e3892bd1018f6c..b51667ef11d3b0 100644 --- a/src/coreclr/vm/perfmap.cpp +++ b/src/coreclr/vm/perfmap.cpp @@ -135,7 +135,7 @@ void PerfMap::Enable(PerfMapType type, bool sendExisting) { CodeVersionManager::LockHolder codeVersioningLockHolder; - EEJitManager::CodeHeapIterator heapIterator(nullptr); + EECodeGenManager::CodeHeapIterator heapIterator(ExecutionManager::GetEEJitManager(), nullptr); while (heapIterator.Next()) { MethodDesc * pMethod = heapIterator.GetMethod(); diff --git a/src/coreclr/vm/profilingenumerators.cpp b/src/coreclr/vm/profilingenumerators.cpp index 50883da5ea8822..ef7b8d9c2f1818 100644 --- a/src/coreclr/vm/profilingenumerators.cpp +++ b/src/coreclr/vm/profilingenumerators.cpp @@ -47,7 +47,7 @@ BOOL ProfilerFunctionEnum::Init(BOOL fWithReJITIDs) } CONTRACTL_END; - EEJitManager::CodeHeapIterator heapIterator; + EECodeGenManager::CodeHeapIterator heapIterator(ExecutionManager::GetEEJitManager()); while(heapIterator.Next()) { MethodDesc *pMD = heapIterator.GetMethod(); From 29cd3beefad425e6d5e07f56fbcecfb6e83dacbc Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 28 Feb 2025 17:44:32 +0100 Subject: [PATCH 03/15] Added missing #ifdef --- src/coreclr/vm/codeman.h | 2 ++ src/coreclr/vm/jitinterface.cpp | 2 ++ src/coreclr/vm/jitinterface.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index ca769a024d16c0..95d939d396bf5d 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -2968,12 +2968,14 @@ ULONG GetFixedStackSize(); }; +#ifdef FEATURE_INTERPRETER inline void * InterpreterJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(!MethodToken.IsNull()); return dac_cast(MethodToken.m_pCodeHeader); } +#endif // FEATURE_INTERPRETER #include "codeman.inl" diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 6352ad95e53be2..dc1ef7d12d1ca7 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -12247,6 +12247,7 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) EE_TO_JIT_TRANSITION(); } +#ifdef FEATURE_INTERPRETER void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs) { CONTRACTL { @@ -12265,6 +12266,7 @@ void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs) EE_TO_JIT_TRANSITION(); } +#endif // FEATURE_INTERPRETER void CEECodeGenInfo::allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpStubs #ifdef FEATURE_EH_FUNCLETS diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index af75ef0db6dad5..a58ac815651c4f 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -1045,6 +1045,7 @@ protected : }; +#ifdef FEATURE_INTERPRETER class CInterpreterJitInfo : public CEECodeGenInfo { public: @@ -1076,6 +1077,7 @@ class CInterpreterJitInfo : public CEECodeGenInfo CEECodeGenInfo::ResetForJitRetry(); } }; +#endif // FEATURE_INTERPRETER /*********************************************************************/ /*********************************************************************/ From e88bfed2edcb882b63f91396bd33455fa0f83c5a Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 28 Feb 2025 20:25:07 +0100 Subject: [PATCH 04/15] Fix MUSL build break --- src/coreclr/vm/codeman.h | 4 ++-- src/coreclr/vm/jitinterface.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 95d939d396bf5d..c86885dcf9d751 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -2772,14 +2772,14 @@ class InterpreterJitManager final : public EECodeGenManager { // Not used for the interpreter _ASSERTE(FALSE); - return NULL; + return PTR_NULL; } virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo) { // Not used for the interpreter _ASSERTE(FALSE); - return NULL; + return 0; } virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index dc1ef7d12d1ca7..cbab7a7a59b062 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -13003,7 +13003,7 @@ PCODE UnsafeJitFunctionWorker(EECodeGenManager *pJitMgr, CEECodeGenInfo *pJitInf if (res == CORJIT_SKIPPED) { // We are done - return NULL; + return 0; } if (SUCCEEDED(res)) @@ -13164,7 +13164,7 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, } #endif // FEATURE_INTERPRETER - if (ret == NULL) + if (!ret) { #if defined(TARGET_AMD64) || defined(TARGET_ARM64) BOOL fForceJumpStubOverflow = FALSE; From b2e79526ebb76201d8fc6e2ad591ca5ad4f637f6 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 3 Mar 2025 16:53:19 +0100 Subject: [PATCH 05/15] Rework of the CodeHeader separation The previous way was introducing 5% regression in all exception handling microbenchmarks, this gets us back to the same perf as without any code manager changes. --- src/coreclr/vm/codeman.cpp | 227 +++++-------------- src/coreclr/vm/codeman.h | 198 +++++------------ src/coreclr/vm/codeman.inl | 142 ++++++++++++ src/coreclr/vm/jitinterface.cpp | 380 +++++++++++++++++++++----------- src/coreclr/vm/jitinterface.h | 55 +++-- 5 files changed, 535 insertions(+), 467 deletions(-) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index fe09874aa73a3c..e403b2642d5a85 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -3166,39 +3166,13 @@ LoaderHeap *EECodeGenManager::GetJitMetaHeap(MethodDesc *pMD) return pAllocator->GetLowFrequencyHeap(); } -BYTE* EECodeGenManager::allocGCInfo(void* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) +void* EECodeGenManager::allocEHInfoRaw(MethodDesc* pMD, DWORD blockSize, size_t * pAllocationSize) { CONTRACTL { THROWS; GC_NOTRIGGER; } CONTRACTL_END; - MethodDesc* pMD = GetMethodDesc(pCodeHeader); - // sadly for light code gen I need the check in here. We should change GetJitMetaHeap - if (pMD->IsLCGMethod()) - { - CrstHolder ch(&m_CodeHeapCritSec); - SetGCInfo(pCodeHeader, (BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize)); - } - else - { - SetGCInfo(pCodeHeader, (BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize))); - } - _ASSERTE(GetGCInfo(pCodeHeader)); // AllocMem throws if there's not enough memory - - * pAllocationSize = blockSize; // Store the allocation size so we can backout later. - - return(GetGCInfo(pCodeHeader)); -} - -void* EECodeGenManager::allocEHInfoRaw(void* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) -{ - CONTRACTL { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - MethodDesc* pMD = GetMethodDesc(pCodeHeader); void * mem = NULL; // sadly for light code gen I need the check in here. We should change GetJitMetaHeap @@ -3219,28 +3193,6 @@ void* EECodeGenManager::allocEHInfoRaw(void* pCodeHeader, DWORD blockSize, size_ } -EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(void* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) -{ - CONTRACTL { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - // Note - pCodeHeader->phdrJitEHInfo - sizeof(size_t) contains the number of EH clauses - - DWORD temp = EE_ILEXCEPTION::Size(numClauses); - DWORD blockSize = 0; - if (!ClrSafeInt::addition(temp, sizeof(size_t), blockSize)) - COMPlusThrowOM(); - - BYTE *EHInfo = (BYTE*)allocEHInfoRaw(pCodeHeader, blockSize, pAllocationSize); - - SetEHInfo(pCodeHeader, (EE_ILEXCEPTION*) (EHInfo + sizeof(size_t))); - GetEHInfo(pCodeHeader)->Init(numClauses); - *((size_t *)EHInfo) = numClauses; - return(GetEHInfo(pCodeHeader)); -} - JumpStubBlockHeader * EEJitManager::allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps, BYTE * loAddr, BYTE * hiAddr, LoaderAllocator *pLoaderAllocator, @@ -3345,7 +3297,7 @@ void * EEJitManager::allocCodeFragmentBlock(size_t blockSize, unsigned alignment #endif // !DACCESS_COMPILE -GCInfoToken EECodeGenManager::GetGCInfoToken(const METHODTOKEN& MethodToken) +GCInfoToken EEJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken) { CONTRACTL { NOTHROW; @@ -3354,14 +3306,28 @@ GCInfoToken EECodeGenManager::GetGCInfoToken(const METHODTOKEN& MethodToken) } CONTRACTL_END; // The JIT-ed code always has the current version of GCInfo - return{ GetGCInfo(GetCodeHeader(MethodToken)), GCINFO_VERSION }; + return{ GetCodeHeader(MethodToken)->GetGCInfo(), GCINFO_VERSION }; } +#ifdef FEATURE_INTERPRETER +GCInfoToken InterpreterJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } CONTRACTL_END; + + // The JIT-ed code always has the current version of GCInfo + return{ GetCodeHeader(MethodToken)->GetGCInfo(), GCINFO_VERSION }; +} +#endif // FEATURE_INTERPRETER + // creates an enumeration and returns the number of EH clauses -unsigned EECodeGenManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState) +unsigned EEJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState) { LIMITED_METHOD_CONTRACT; - EE_ILEXCEPTION * EHInfo = GetEHInfo(GetCodeHeader(MethodToken)); + EE_ILEXCEPTION * EHInfo = GetCodeHeader(MethodToken)->GetEHInfo(); pEnumState->iCurrentPos = 0; // since the EH info is not compressed, the clause number is used to do the enumeration pEnumState->pExceptionClauseArray = 0; @@ -3373,6 +3339,24 @@ unsigned EECodeGenManager::InitializeEHEnumeration(const METHODTOKEN& MethodToke return *(dac_cast(dac_cast(EHInfo) - sizeof(size_t))); } +#ifdef FEATURE_INTERPRETER +// creates an enumeration and returns the number of EH clauses +unsigned InterpreterJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState) +{ + LIMITED_METHOD_CONTRACT; + EE_ILEXCEPTION * EHInfo = GetCodeHeader(MethodToken)->GetEHInfo(); + + pEnumState->iCurrentPos = 0; // since the EH info is not compressed, the clause number is used to do the enumeration + pEnumState->pExceptionClauseArray = 0; + + if (!EHInfo) + return 0; + + pEnumState->pExceptionClauseArray = dac_cast(EHInfo->EHClause(0)); + return *(dac_cast(dac_cast(EHInfo) - sizeof(size_t))); +} +#endif // FEATURE_INTERPRETER + PTR_EXCEPTION_CLAUSE_TOKEN EECodeGenManager::GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, EE_ILEXCEPTION_CLAUSE* pEHClauseOut) { @@ -3433,95 +3417,6 @@ void EEJitManager::UnpublishUnwindInfoForMethod(TADDR codeStart) #endif // defined(TARGET_AMD64) } -void EECodeGenManager::RemoveJitData(void * pCHdr, size_t GCinfo_len, size_t EHinfo_len) -{ - CONTRACTL { - NOTHROW; - GC_TRIGGERS; - } CONTRACTL_END; - - MethodDesc* pMD = GetMethodDesc(pCHdr); - - void * codeStart = (void*)GetCodeStartAddress(pCHdr); - - if (pMD->IsLCGMethod()) - { - { - CrstHolder ch(&m_CodeHeapCritSec); - - LCGMethodResolver * pResolver = pMD->AsDynamicMethodDesc()->GetLCGMethodResolver(); - - // Clear the pointer only if it matches what we are about to free. - // There can be cases where the JIT is reentered and we JITed the method multiple times. - if (pResolver->m_recordCodePointer == codeStart) - pResolver->m_recordCodePointer = NULL; - } - - // Remove the unwind information (if applicable) - UnpublishUnwindInfoForMethod((TADDR)codeStart); - - HostCodeHeap* pHeap = HostCodeHeap::GetCodeHeap((TADDR)codeStart); - FreeCodeMemory(pHeap, codeStart); - - // We are leaking GCInfo and EHInfo. They will be freed once the dynamic method is destroyed. - - return; - } - - { - CrstHolder ch(&m_CodeHeapCritSec); - - HeapList *pHp = GetCodeHeapList(); - - while (pHp && ((pHp->startAddress > (TADDR)pCHdr) || - (pHp->endAddress < (TADDR)codeStart))) - { - pHp = pHp->GetNext(); - } - - _ASSERTE(pHp && pHp->pHdrMap); - - // Better to just return than AV? - if (pHp == NULL) - return; - - NibbleMapDeleteUnlocked(pHp, (TADDR)codeStart); - } - - // Backout the GCInfo - if (GCinfo_len > 0) { - GetJitMetaHeap(pMD)->BackoutMem(GetGCInfo(pCHdr), GCinfo_len); - } - - // Backout the EHInfo - BYTE *EHInfo = (BYTE *)GetEHInfo(pCHdr); - if (EHInfo) { - EHInfo -= sizeof(size_t); - - _ASSERTE(EHinfo_len>0); - GetJitMetaHeap(pMD)->BackoutMem(EHInfo, EHinfo_len); - } - - // - // TODO: Although we have backout the GCInfo and EHInfo, we haven't actually backout the - // code buffer itself. As a result, we might leak the CodeHeap if jitting fails after - // the code buffer is allocated. - // - // However, it appears non-trivial to fix this. - // Here are some of the reasons: - // (1) AllocCode calls in AllocCodeRaw to alloc code buffer in the CodeHeap. The exact size - // of the code buffer is not known until the alignment is calculated deep on the stack. - // (2) AllocCodeRaw is called in 3 different places. We might need to remember the - // information for these places. - // (3) AllocCodeRaw might create a new CodeHeap. We should remember exactly which - // CodeHeap is used to allocate the code buffer. - // - // Fortunately, this is not a severe leak since the CodeHeap will be reclaimed on appdomain unload. - // - // - return; -} - // appdomain is being unloaded, so delete any data associated with it. We have to do this in two stages. // On the first stage, we remove the elements from the list. On the second stage, which occurs after a GC // we know that only threads who were in preemptive mode prior to the GC could possibly still be looking @@ -3992,22 +3887,6 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ } } -void EEJitManager::EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SUPPORTS_DAC; - } - CONTRACTL_END; - - DAC_ENUM_DTHIS(); - - PTR_CodeHeader pCH = dac_cast(pCodeHeader); - pCH->EnumMemoryRegions(flags, pJitMan); -} - #ifdef FEATURE_INTERPRETER void InterpreterCodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) { @@ -4028,22 +3907,6 @@ void InterpreterCodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJit CompressDebugInfo::EnumMemoryRegions(flags, this->GetDebugInfo(), FALSE /* hasFlagByte */); } } - -void InterpreterJitManager::EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SUPPORTS_DAC; - } - CONTRACTL_END; - - DAC_ENUM_DTHIS(); - - PTR_InterpreterCodeHeader pCH = dac_cast(pCodeHeader); - pCH->EnumMemoryRegions(flags, pJitMan); -} #endif // FEATURE_INTERPRETER //----------------------------------------------------------------------------- @@ -4069,13 +3932,23 @@ void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlag } #endif // DACCESS_COMPILE -PCODE EECodeGenManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) +PCODE EEJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) +{ + WRAPPER_NO_CONTRACT; + + CodeHeader * pHeader = GetCodeHeader(MethodToken); + return pHeader->GetCodeStartAddress() + relOffset; +} + +#ifdef FEATURE_INTERPRETER +PCODE InterpreterJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) { WRAPPER_NO_CONTRACT; - void * pHeader = GetCodeHeader(MethodToken); - return GetCodeStartAddress(pHeader) + relOffset; + InterpreterCodeHeader * pHeader = GetCodeHeader(MethodToken); + return pHeader->GetCodeStartAddress() + relOffset; } +#endif // FEATURE_INTERPRETER BOOL EECodeGenManager::JitCodeToMethodInfo( RangeSection * pRangeSection, diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index c86885dcf9d751..0ce9b2637ef22f 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -1802,23 +1802,14 @@ class EECodeGenManager : public IJitManager OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, OUT ULONG32* pNumRichMappings); - virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset); - virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc ** ppMethodDesc, EECodeInfo * pCodeInfo); - virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken); - - virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState); virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, EE_ILEXCEPTION_CLAUSE* pEHclause); - GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); - - virtual void * GetCodeHeader(const METHODTOKEN& MethodToken) = 0; - virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC); static TADDR FindMethodCode(RangeSection * pRangeSection, PCODE currentPC); @@ -1830,31 +1821,12 @@ class EECodeGenManager : public IJitManager return m_storeRichDebugInfo; } - // CodeHeader accessors - virtual PTR_BYTE GetDebugInfo(void* pCodeHeader) = 0; - virtual PTR_EE_ILEXCEPTION GetEHInfo(void* pCodeHeader) = 0; - virtual PTR_BYTE GetGCInfo(void* pCodeHeader) = 0; - virtual PTR_MethodDesc GetMethodDesc(void* pCodeHeader) = 0; -#if defined(FEATURE_GDBJIT) - virtual VOID* GetCalledMethods(void* pCodeHeader) = 0; -#endif - virtual TADDR GetCodeStartAddress(void* pCodeHeader) = 0; - virtual void SetRealCodeHeader(void* pCodeHeader, BYTE* pRCH) = 0; - virtual void SetDebugInfo(void* pCodeHeader, PTR_BYTE pDI) = 0; - virtual void SetEHInfo(void* pCodeHeader, PTR_EE_ILEXCEPTION pEH) = 0; - virtual void SetGCInfo(void* pCodeHeader, PTR_BYTE pGC) = 0; - virtual void SetMethodDesc(void* pCodeHeader, PTR_MethodDesc pMD) = 0; - -#ifdef DACCESS_COMPILE - virtual void EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) = 0; -#endif // DACCESS_COMPILE - - #ifndef DACCESS_COMPILE virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, CrawlFrame *pCf); - void RemoveJitData(void * pCHdr, size_t GCinfo_len, size_t EHinfo_len); + template + void RemoveJitData(TCodeHeader* pCHdr, size_t GCinfo_len, size_t EHinfo_len); void Unload(LoaderAllocator* pAllocator); void CleanupCodeHeaps(); @@ -1864,8 +1836,12 @@ class EECodeGenManager : public IJitManager , UINT nUnwindInfos #endif ); - BYTE *allocGCInfo(void* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); - EE_ILEXCEPTION* allocEHInfo(void* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); + + template + inline BYTE *allocGCInfo(TCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); + + template + inline EE_ILEXCEPTION* allocEHInfo(TCodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); // Heap Management functions void NibbleMapSet(HeapList * pHp, TADDR pCode, size_t codeSize); @@ -1884,7 +1860,7 @@ class EECodeGenManager : public IJitManager protected: void* allocCodeRaw(CodeHeapRequestInfo *pInfo, size_t header, size_t blockSize, unsigned align, HeapList ** ppCodeHeap); - void* allocEHInfoRaw(void* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); + void* allocEHInfoRaw(MethodDesc *pMD, DWORD blockSize, size_t * pAllocationSize); virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) = 0; DomainCodeHeapList *GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly = FALSE); @@ -2054,64 +2030,15 @@ class EEJitManager final : public EECodeGenManager return (miManaged | miIL); } + virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken); virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo *methodRegionInfo); - // CodeHeader accessors - // TODO: void* or TADDR? - virtual PTR_BYTE GetDebugInfo(void* pCodeHeader) - { - return ((CodeHeader*)pCodeHeader)->GetDebugInfo(); - } - virtual PTR_EE_ILEXCEPTION GetEHInfo(void* pCodeHeader) - { - return ((CodeHeader*)pCodeHeader)->GetEHInfo(); - } - virtual PTR_BYTE GetGCInfo(void* pCodeHeader) - { - return ((CodeHeader*)pCodeHeader)->GetGCInfo(); - } - virtual PTR_MethodDesc GetMethodDesc(void* pCodeHeader) - { - return ((CodeHeader*)pCodeHeader)->GetMethodDesc(); - } -#if defined(FEATURE_GDBJIT) - virtual VOID* GetCalledMethods(void* pCodeHeader) - { - return ((CodeHeader*)pCodeHeader)->GetCalledMethods(); - } -#endif - virtual TADDR GetCodeStartAddress(void* pCodeHeader) - { - return ((CodeHeader*)pCodeHeader)->GetCodeStartAddress(); - } - virtual void SetRealCodeHeader(void* pCodeHeader, BYTE* pRCH) - { - ((CodeHeader*)pCodeHeader)->SetRealCodeHeader(pRCH); - } - virtual void SetDebugInfo(void* pCodeHeader, PTR_BYTE pDI) - { - ((CodeHeader*)pCodeHeader)->SetDebugInfo(pDI); - } - virtual void SetEHInfo(void* pCodeHeader, PTR_EE_ILEXCEPTION pEH) - { - ((CodeHeader*)pCodeHeader)->SetEHInfo(pEH); - } - virtual void SetGCInfo(void* pCodeHeader, PTR_BYTE pGC) - { - ((CodeHeader*)pCodeHeader)->SetGCInfo(pGC); - } - - virtual void SetMethodDesc(void* pCodeHeader, PTR_MethodDesc pMD) - { - ((CodeHeader*)pCodeHeader)->SetMethodDesc(pMD); - } - -#ifdef DACCESS_COMPILE - virtual void EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); -#endif // DACCESS_COMPILE - static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); - virtual void * GetCodeHeader(const METHODTOKEN& MethodToken); + static CodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); + + GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); + virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState); + virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset); #if !defined DACCESS_COMPILE BOOL LoadJIT(); @@ -2508,7 +2435,7 @@ struct cdac_data }; #endif -inline void * EEJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) +inline CodeHeader * EEJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(!MethodToken.IsNull()); @@ -2523,7 +2450,7 @@ inline CodeHeader * EEJitManager::GetCodeHeaderFromStartAddress(TADDR methodStar return dac_cast(methodStartAddress - sizeof(CodeHeader)); } -inline TADDR EECodeGenManager::JitTokenToStartAddress(const METHODTOKEN& MethodToken) +inline TADDR EEJitManager::JitTokenToStartAddress(const METHODTOKEN& MethodToken) { CONTRACTL { NOTHROW; @@ -2531,8 +2458,8 @@ inline TADDR EECodeGenManager::JitTokenToStartAddress(const METHODTOKEN& MethodT SUPPORTS_DAC; } CONTRACTL_END; - void * pCH = GetCodeHeader(MethodToken); - return GetCodeStartAddress(pCH); + CodeHeader * pCH = GetCodeHeader(MethodToken); + return pCH->GetCodeStartAddress(); } inline void EEJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, @@ -2705,67 +2632,20 @@ class InterpreterJitManager final : public EECodeGenManager return (miManaged | miIL); } + GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); + virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState); + virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset); + + virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken); + virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo * methodRegionInfo) { // Not used for the interpreter _ASSERTE(FALSE); } - // CodeHeader accessors - // TODO: void* or TADDR? - virtual PTR_BYTE GetDebugInfo(void* pCodeHeader) - { - return ((InterpreterCodeHeader*)pCodeHeader)->GetDebugInfo(); - } - virtual PTR_EE_ILEXCEPTION GetEHInfo(void* pCodeHeader) - { - return ((InterpreterCodeHeader*)pCodeHeader)->GetEHInfo(); - } - virtual PTR_BYTE GetGCInfo(void* pCodeHeader) - { - return ((InterpreterCodeHeader*)pCodeHeader)->GetGCInfo(); - } - virtual PTR_MethodDesc GetMethodDesc(void* pCodeHeader) - { - return ((InterpreterCodeHeader*)pCodeHeader)->GetMethodDesc(); - } -#if defined(FEATURE_GDBJIT) - virtual VOID* GetCalledMethods(void* pCodeHeader) - { - return ((InterpreterCodeHeader*)pCodeHeader)->GetCalledMethods(); - } -#endif - virtual TADDR GetCodeStartAddress(void* pCodeHeader) - { - return ((InterpreterCodeHeader*)pCodeHeader)->GetCodeStartAddress(); - } - virtual void SetRealCodeHeader(void* pCodeHeader, BYTE* pRCH) - { - ((InterpreterCodeHeader*)pCodeHeader)->SetRealCodeHeader(pRCH); - } - virtual void SetDebugInfo(void* pCodeHeader, PTR_BYTE pDI) - { - ((InterpreterCodeHeader*)pCodeHeader)->SetDebugInfo(pDI); - } - virtual void SetEHInfo(void* pCodeHeader, PTR_EE_ILEXCEPTION pEH) - { - ((InterpreterCodeHeader*)pCodeHeader)->SetEHInfo(pEH); - } - virtual void SetGCInfo(void* pCodeHeader, PTR_BYTE pGC) - { - ((InterpreterCodeHeader*)pCodeHeader)->SetGCInfo(pGC); - } - - virtual void SetMethodDesc(void* pCodeHeader, PTR_MethodDesc pMD) - { - ((InterpreterCodeHeader*)pCodeHeader)->SetMethodDesc(pMD); - } - -#ifdef DACCESS_COMPILE - virtual void EnumMemoryRegions(void* pCodeHeader, CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); -#endif // DACCESS_COMPILE - - virtual void * GetCodeHeader(const METHODTOKEN& MethodToken); + static InterpreterCodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); + static InterpreterCodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); #if defined(FEATURE_EH_FUNCLETS) virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo) @@ -2969,12 +2849,34 @@ ULONG GetFixedStackSize(); }; #ifdef FEATURE_INTERPRETER -inline void * InterpreterJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) + +inline InterpreterCodeHeader* InterpreterJitManager::GetCodeHeader(const METHODTOKEN& MethodToken) { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(!MethodToken.IsNull()); return dac_cast(MethodToken.m_pCodeHeader); } + +inline InterpreterCodeHeader * InterpreterJitManager::GetCodeHeaderFromStartAddress(TADDR methodStartAddress) +{ + LIMITED_METHOD_DAC_CONTRACT; + _ASSERTE(methodStartAddress != (TADDR)NULL); + ARM_ONLY(_ASSERTE((methodStartAddress & THUMB_CODE) == 0)); + return dac_cast(methodStartAddress - sizeof(CodeHeader)); +} + +inline TADDR InterpreterJitManager::JitTokenToStartAddress(const METHODTOKEN& MethodToken) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } CONTRACTL_END; + + InterpreterCodeHeader * pCH = GetCodeHeader(MethodToken); + return pCH->GetCodeStartAddress(); +} + #endif // FEATURE_INTERPRETER #include "codeman.inl" diff --git a/src/coreclr/vm/codeman.inl b/src/coreclr/vm/codeman.inl index 8af0fc0e48bfbd..736d6101e8adc7 100644 --- a/src/coreclr/vm/codeman.inl +++ b/src/coreclr/vm/codeman.inl @@ -13,3 +13,145 @@ inline TADDR IJitManager::JitTokenToModuleBase(const METHODTOKEN& MethodToken) { return MethodToken.m_pRangeSection->_range.RangeStart(); } + +#ifndef DACCESS_COMPILE +template +inline BYTE* EECodeGenManager::allocGCInfo(TCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) +{ + CONTRACTL { + THROWS; + GC_NOTRIGGER; + } CONTRACTL_END; + + MethodDesc* pMD = pCodeHeader->GetMethodDesc(); + // sadly for light code gen I need the check in here. We should change GetJitMetaHeap + if (pMD->IsLCGMethod()) + { + CrstHolder ch(&m_CodeHeapCritSec); + pCodeHeader->SetGCInfo((BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize)); + } + else + { + pCodeHeader->SetGCInfo((BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize))); + } + _ASSERTE(pCodeHeader->GetGCInfo()); // AllocMem throws if there's not enough memory + + * pAllocationSize = blockSize; // Store the allocation size so we can backout later. + + return(pCodeHeader->GetGCInfo()); +} + +template +inline EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(TCodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) +{ + CONTRACTL { + THROWS; + GC_NOTRIGGER; + } CONTRACTL_END; + + // Note - pCodeHeader->phdrJitEHInfo - sizeof(size_t) contains the number of EH clauses + + DWORD temp = EE_ILEXCEPTION::Size(numClauses); + DWORD blockSize = 0; + if (!ClrSafeInt::addition(temp, sizeof(size_t), blockSize)) + COMPlusThrowOM(); + + BYTE *EHInfo = (BYTE*)allocEHInfoRaw(pCodeHeader->GetMethodDesc(), blockSize, pAllocationSize); + + pCodeHeader->SetEHInfo((EE_ILEXCEPTION*) (EHInfo + sizeof(size_t))); + pCodeHeader->GetEHInfo()->Init(numClauses); + *((size_t *)EHInfo) = numClauses; + return(pCodeHeader->GetEHInfo()); +} + +template +void EEJitManager::RemoveJitData(TCodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len) +{ + CONTRACTL { + NOTHROW; + GC_TRIGGERS; + } CONTRACTL_END; + + MethodDesc* pMD = pCHdr->GetMethodDesc(); + + void * codeStart = (void*)pCHdr->GetCodeStartAddress(); + + if (pMD->IsLCGMethod()) + { + { + CrstHolder ch(&m_CodeHeapCritSec); + + LCGMethodResolver * pResolver = pMD->AsDynamicMethodDesc()->GetLCGMethodResolver(); + + // Clear the pointer only if it matches what we are about to free. + // There can be cases where the JIT is reentered and we JITed the method multiple times. + if (pResolver->m_recordCodePointer == codeStart) + pResolver->m_recordCodePointer = NULL; + } + + // Remove the unwind information (if applicable) + UnpublishUnwindInfoForMethod((TADDR)codeStart); + + HostCodeHeap* pHeap = HostCodeHeap::GetCodeHeap((TADDR)codeStart); + FreeCodeMemory(pHeap, codeStart); + + // We are leaking GCInfo and EHInfo. They will be freed once the dynamic method is destroyed. + + return; + } + + { + CrstHolder ch(&m_CodeHeapCritSec); + + HeapList *pHp = GetCodeHeapList(); + + while (pHp && ((pHp->startAddress > (TADDR)pCHdr) || + (pHp->endAddress < (TADDR)codeStart))) + { + pHp = pHp->GetNext(); + } + + _ASSERTE(pHp && pHp->pHdrMap); + + // Better to just return than AV? + if (pHp == NULL) + return; + + NibbleMapDeleteUnlocked(pHp, (TADDR)codeStart); + } + + // Backout the GCInfo + if (GCinfo_len > 0) { + GetJitMetaHeap(pMD)->BackoutMem(pCHdr->GetGCInfo(), GCinfo_len); + } + + // Backout the EHInfo + BYTE *EHInfo = (BYTE *)pCHdr->GetEHInfo(); + if (EHInfo) { + EHInfo -= sizeof(size_t); + + _ASSERTE(EHinfo_len>0); + GetJitMetaHeap(pMD)->BackoutMem(EHInfo, EHinfo_len); + } + + // + // TODO: Although we have backout the GCInfo and EHInfo, we haven't actually backout the + // code buffer itself. As a result, we might leak the CodeHeap if jitting fails after + // the code buffer is allocated. + // + // However, it appears non-trivial to fix this. + // Here are some of the reasons: + // (1) AllocCode calls in AllocCodeRaw to alloc code buffer in the CodeHeap. The exact size + // of the code buffer is not known until the alignment is calculated deep on the stack. + // (2) AllocCodeRaw is called in 3 different places. We might need to remember the + // information for these places. + // (3) AllocCodeRaw might create a new CodeHeap. We should remember exactly which + // CodeHeap is used to allocate the code buffer. + // + // Fortunately, this is not a severe leak since the CodeHeap will be reclaimed on appdomain unload. + // + // + return; +} + +#endif // DACCESS_COMPILE \ No newline at end of file diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index cbab7a7a59b062..5079b65d7bf4a1 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10896,17 +10896,23 @@ void CEEJitInfo::GetProfilingHandle(bool *pbHookFunction, *pbIndirectedHandles = false; } -/*********************************************************************/ -void CEECodeGenInfo::WriteCodeBytes() +template +void CEECodeGenInfo::SetRealCodeHeader() { - LIMITED_METHOD_CONTRACT; - if (m_pRealCodeHeader != NULL) { // Restore the read only version of the real code header - m_jitManager->SetRealCodeHeader(m_CodeHeaderRW, m_pRealCodeHeader); + ((TCodeHeader*)m_CodeHeaderRW)->SetRealCodeHeader(m_pRealCodeHeader); m_pRealCodeHeader = NULL; } +} + +/*********************************************************************/ +void CEEJitInfo::WriteCodeBytes() +{ + LIMITED_METHOD_CONTRACT; + + SetRealCodeHeader(); if (m_CodeHeaderRW != m_CodeHeader) { @@ -10916,7 +10922,7 @@ void CEECodeGenInfo::WriteCodeBytes() } /*********************************************************************/ -void CEECodeGenInfo::BackoutJitData(EECodeGenManager * jitMgr) +void CEEJitInfo::BackoutJitData(EECodeGenManager * jitMgr) { CONTRACTL { NOTHROW; @@ -10927,38 +10933,28 @@ void CEECodeGenInfo::BackoutJitData(EECodeGenManager * jitMgr) // the code bytes to the target memory location. WriteCodeBytes(); - void* pCodeHeader = m_CodeHeader; + CodeHeader* pCodeHeader = (CodeHeader*)m_CodeHeader; if (pCodeHeader) jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len); } -/*********************************************************************/ -void CEEJitInfo::WriteCode(EECodeGenManager * jitMgr) +template +void CEECodeGenInfo::NibbleMapSet() { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; } CONTRACTL_END; - WriteCodeBytes(); + TCodeHeader* pCodeHeader = (TCodeHeader*)m_CodeHeader; - CodeHeader* pCodeHeader = (CodeHeader*)m_CodeHeader; - - // Now that the code header was written to the final location, publish the code via the nibble map // m_codeWriteBufferSize is the size of the code region + code header. The nibble map should only use // the code region, therefore we subtract the size of the CodeHeader. - jitMgr->NibbleMapSet(m_pCodeHeap, pCodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(CodeHeader)); - -#if defined(TARGET_AMD64) - // Publish the new unwind information in a way that the ETW stack crawler can find - _ASSERTE(m_usedUnwindInfos == m_totalUnwindInfos); - UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, pCodeHeader->GetUnwindInfo(0), m_totalUnwindInfos); -#endif // defined(TARGET_AMD64) + m_jitManager->NibbleMapSet(m_pCodeHeap, pCodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(TCodeHeader)); } -#ifdef FEATURE_INTERPRETER /*********************************************************************/ -void CInterpreterJitInfo::WriteCode(EECodeGenManager * jitMgr) +void CEEJitInfo::WriteCode(EECodeGenManager * jitMgr) { CONTRACTL { THROWS; @@ -10966,15 +10962,15 @@ void CInterpreterJitInfo::WriteCode(EECodeGenManager * jitMgr) } CONTRACTL_END; WriteCodeBytes(); - - InterpreterCodeHeader* pCodeHeader = (InterpreterCodeHeader*)m_CodeHeader; - // Now that the code header was written to the final location, publish the code via the nibble map - // m_codeWriteBufferSize is the size of the code region + code header. The nibble map should only use - // the code region, therefore we subtract the size of the CodeHeader. - jitMgr->NibbleMapSet(m_pCodeHeap, pCodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(InterpreterCodeHeader)); + NibbleMapSet(); + +#if defined(TARGET_AMD64) + // Publish the new unwind information in a way that the ETW stack crawler can find + _ASSERTE(m_usedUnwindInfos == m_totalUnwindInfos); + UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, ((CodeHeader*)m_CodeHeader)->GetUnwindInfo(0), m_totalUnwindInfos); +#endif // defined(TARGET_AMD64) } -#endif // FEATURE_INTERPRETER /*********************************************************************/ // Route jit information to the Jit Debug store. @@ -11105,6 +11101,184 @@ PatchpointInfo* CEEJitInfo::getOSRInfo(unsigned* ilOffset) return result; } +void CEEJitInfo::SetDebugInfo(PTR_BYTE pDebugInfo) +{ + ((CodeHeader*)m_CodeHeaderRW)->SetDebugInfo(pDebugInfo); +} + +#ifdef FEATURE_INTERPRETER + +void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs) +{ + JIT_TO_EE_TRANSITION(); + + _ASSERTE(pArgs->coldCodeSize == 0); + _ASSERTE(pArgs->roDataSize == 0); + + ULONG codeSize = pArgs->hotCodeSize; + void **codeBlock = &pArgs->hotCodeBlock; + void **codeBlockRW = &pArgs->hotCodeBlockRW; + S_SIZE_T totalSize = S_SIZE_T(codeSize); + + _ASSERTE(m_CodeHeader == 0 && + // The jit-compiler sometimes tries to compile a method a second time + // if it failed the first time. In such a situation, m_CodeHeader may + // have already been assigned. Its OK to ignore this assert in such a + // situation - we will leak some memory, but that is acceptable + // since this should happen very rarely. + "Note that this may fire if the JITCompiler tries to recompile a method"); + if( totalSize.IsOverflow() ) + { + COMPlusThrowHR(CORJIT_OUTOFMEM); + } + if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, MethodJitMemoryAllocatedForCode)) + { + ULONGLONG ullMethodIdentifier = 0; + ULONGLONG ullModuleID = 0; + if (m_pMethodBeingCompiled) + { + Module* pModule = m_pMethodBeingCompiled->GetModule(); + ullModuleID = (ULONGLONG)(TADDR)pModule; + ullMethodIdentifier = (ULONGLONG)m_pMethodBeingCompiled; + } + FireEtwMethodJitMemoryAllocatedForCode(ullMethodIdentifier, ullModuleID, + pArgs->hotCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId()); + } + + m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), 0, pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap + , &m_pRealCodeHeader +#ifdef FEATURE_EH_FUNCLETS + , 0 +#endif + ); + + BYTE* current = (BYTE *)((InterpreterCodeHeader*)m_CodeHeader)->GetCodeStartAddress(); + + // Interpreter doesn't use executable memory, so the writeable pointer to the header is the same as the read only one + _ASSERTE(m_CodeHeaderRW == m_CodeHeader); + + *codeBlock = current; + *codeBlockRW = current; + + current += codeSize; + + pArgs->coldCodeBlock = NULL; + pArgs->coldCodeBlockRW = NULL; + pArgs->roDataBlock = NULL; + pArgs->roDataBlockRW = NULL; + + _ASSERTE((SIZE_T)(current - (BYTE *)((InterpreterCodeHeader*)m_CodeHeader)->GetCodeStartAddress()) <= totalSize.Value()); + +#ifdef _DEBUG + m_codeSize = codeSize; +#endif // _DEBUG + + EE_TO_JIT_TRANSITION(); +} + +void * CInterpreterJitInfo::allocGCInfo (size_t size) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + void * block = NULL; + + JIT_TO_EE_TRANSITION(); + + _ASSERTE(m_CodeHeaderRW != 0); + _ASSERTE(((InterpreterCodeHeader*)m_CodeHeaderRW)->GetGCInfo() == 0); + +#ifdef HOST_64BIT + if (size & 0xFFFFFFFF80000000LL) + { + COMPlusThrowHR(CORJIT_OUTOFMEM); + } +#endif // HOST_64BIT + + block = m_jitManager->allocGCInfo((InterpreterCodeHeader*)m_CodeHeaderRW,(DWORD)size, &m_GCinfo_len); + if (!block) + { + COMPlusThrowHR(CORJIT_OUTOFMEM); + } + + _ASSERTE(((InterpreterCodeHeader*)m_CodeHeaderRW)->GetGCInfo() != 0 && block == ((InterpreterCodeHeader*)m_CodeHeaderRW)->GetGCInfo()); + + EE_TO_JIT_TRANSITION(); + + return block; +} + +void CInterpreterJitInfo::setEHcount ( + unsigned cEH) +{ + WRAPPER_NO_CONTRACT; + + setEHcountWorker(cEH); +} + +void CInterpreterJitInfo::setEHinfo ( + unsigned EHnumber, + const CORINFO_EH_CLAUSE* clause) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION(); + + // Fix make the Code Manager EH clauses EH_INFO+ + EE_ILEXCEPTION *pEHInfo = ((InterpreterCodeHeader*)m_CodeHeaderRW)->GetEHInfo(); + setEHinfoWorker(pEHInfo, EHnumber, clause); + + EE_TO_JIT_TRANSITION(); +} + +void CInterpreterJitInfo::WriteCodeBytes() +{ + LIMITED_METHOD_CONTRACT; + + SetRealCodeHeader(); +} + +void CInterpreterJitInfo::BackoutJitData(EECodeGenManager * jitMgr) +{ + CONTRACTL { + NOTHROW; + GC_TRIGGERS; + } CONTRACTL_END; + + // The RemoveJitData call below requires the m_CodeHeader to be valid, so we need to write + // the code bytes to the target memory location. + WriteCodeBytes(); + + InterpreterCodeHeader* pCodeHeader = (InterpreterCodeHeader*)m_CodeHeader; + if (pCodeHeader) + jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len); +} + +void CInterpreterJitInfo::WriteCode(EECodeGenManager * jitMgr) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + } CONTRACTL_END; + + WriteCodeBytes(); + // Now that the code header was written to the final location, publish the code via the nibble map + NibbleMapSet(); +} + +void CInterpreterJitInfo::SetDebugInfo(PTR_BYTE pDebugInfo) +{ + ((InterpreterCodeHeader*)m_CodeHeaderRW)->SetDebugInfo(pDebugInfo); +} +#endif // FEATURE_INTERPRETER + void CEECodeGenInfo::CompressDebugInfo() { CONTRACTL { @@ -11145,7 +11319,7 @@ void CEECodeGenInfo::CompressDebugInfo() writeFlagByte, m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap()); - m_jitManager->SetDebugInfo(m_CodeHeaderRW, pDebugInfo); + SetDebugInfo(pDebugInfo); } EX_CATCH { @@ -12226,72 +12400,17 @@ HRESULT CEEJitInfo::getPgoInstrumentationResults( void CEEJitInfo::allocMem (AllocMemArgs *pArgs) { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } CONTRACTL_END; - JIT_TO_EE_TRANSITION(); - allocMemWorker(pArgs, GetReserveForJumpStubs() -#ifdef FEATURE_EH_FUNCLETS - , m_totalUnwindInfos, m_totalUnwindSize, &m_theUnwindBlock -#endif - ); - -#ifdef FEATURE_EH_FUNCLETS - m_moduleBase = m_pCodeHeap->GetModuleBase(); -#endif - - EE_TO_JIT_TRANSITION(); -} - -#ifdef FEATURE_INTERPRETER -void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - JIT_TO_EE_TRANSITION(); - - allocMemWorker(pArgs, 0 /* reserveForJumpStubs */ -#ifdef FEATURE_EH_FUNCLETS - , 0 /* unwindInfoCount */, 0 /* unwindSize */, NULL /* ppUnwindBlock */ -#endif - ); - - EE_TO_JIT_TRANSITION(); -} -#endif // FEATURE_INTERPRETER - -void CEECodeGenInfo::allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpStubs -#ifdef FEATURE_EH_FUNCLETS - , ULONG unwindInfoCount, ULONG unwindSize, BYTE** ppUnwindBlock -#endif -) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } CONTRACTL_END; - _ASSERTE(pArgs->coldCodeSize == 0); if (pArgs->coldCodeBlock) { pArgs->coldCodeBlock = NULL; } - ULONG codeSize = pArgs->hotCodeSize; void **codeBlock = &pArgs->hotCodeBlock; void **codeBlockRW = &pArgs->hotCodeBlockRW; - S_SIZE_T totalSize = S_SIZE_T(codeSize); - size_t roDataAlignment = sizeof(void*); if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_RODATA_64BYTE_ALIGN)!= 0) { @@ -12312,7 +12431,6 @@ void CEECodeGenInfo::allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpSt if (pArgs->roDataSize > 0) { size_t codeAlignment = sizeof(void*); - if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN) != 0) { codeAlignment = 32; @@ -12322,7 +12440,6 @@ void CEECodeGenInfo::allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpSt codeAlignment = 16; } totalSize.AlignUp(codeAlignment); - if (roDataAlignment > codeAlignment) { // Add padding to align read-only data. totalSize += (roDataAlignment - codeAlignment); @@ -12331,11 +12448,8 @@ void CEECodeGenInfo::allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpSt } #ifdef FEATURE_EH_FUNCLETS - if (unwindSize > 0) - { - totalSize.AlignUp(sizeof(DWORD)); - totalSize += unwindSize; - } + totalSize.AlignUp(sizeof(DWORD)); + totalSize += m_totalUnwindSize; #endif _ASSERTE(m_CodeHeader == 0 && @@ -12345,42 +12459,41 @@ void CEECodeGenInfo::allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpSt // situation - we will leak some memory, but that is acceptable // since this should happen very rarely. "Note that this may fire if the JITCompiler tries to recompile a method"); - if( totalSize.IsOverflow() ) { COMPlusThrowHR(CORJIT_OUTOFMEM); } - if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, MethodJitMemoryAllocatedForCode)) { ULONGLONG ullMethodIdentifier = 0; ULONGLONG ullModuleID = 0; - if (m_pMethodBeingCompiled) { Module* pModule = m_pMethodBeingCompiled->GetModule(); ullModuleID = (ULONGLONG)(TADDR)pModule; ullMethodIdentifier = (ULONGLONG)m_pMethodBeingCompiled; } - FireEtwMethodJitMemoryAllocatedForCode(ullMethodIdentifier, ullModuleID, pArgs->hotCodeSize + pArgs->coldCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId()); } - m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), reserveForJumpStubs, pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap + m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap , &m_pRealCodeHeader #ifdef FEATURE_EH_FUNCLETS - , unwindInfoCount + , m_totalUnwindInfos #endif ); - BYTE* current = (BYTE *)m_jitManager->GetCodeStartAddress(m_CodeHeader); +#ifdef FEATURE_EH_FUNCLETS + m_moduleBase = m_pCodeHeap->GetModuleBase(); +#endif + + BYTE* current = (BYTE *)((CodeHeader*)m_CodeHeader)->GetCodeStartAddress(); size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader; *codeBlock = current; *codeBlockRW = current + writeableOffset; current += codeSize; - if (pArgs->roDataSize > 0) { current = (BYTE *)ALIGN_UP(current, roDataAlignment); @@ -12396,22 +12509,22 @@ void CEECodeGenInfo::allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpSt #ifdef FEATURE_EH_FUNCLETS current = (BYTE *)ALIGN_UP(current, sizeof(DWORD)); - if (unwindSize > 0) - { - *ppUnwindBlock = current; - current += unwindSize; - } + + m_theUnwindBlock = current; + current += m_totalUnwindSize; #endif - _ASSERTE((SIZE_T)(current - (BYTE *)m_jitManager->GetCodeStartAddress(m_CodeHeader)) <= totalSize.Value()); + _ASSERTE((SIZE_T)(current - (BYTE *)((CodeHeader*)m_CodeHeader)->GetCodeStartAddress()) <= totalSize.Value()); #ifdef _DEBUG m_codeSize = codeSize; #endif // _DEBUG + + EE_TO_JIT_TRANSITION(); } /*********************************************************************/ -void * CEECodeGenInfo::allocGCInfo (size_t size) +void * CEEJitInfo::allocGCInfo (size_t size) { CONTRACTL { THROWS; @@ -12424,7 +12537,7 @@ void * CEECodeGenInfo::allocGCInfo (size_t size) JIT_TO_EE_TRANSITION(); _ASSERTE(m_CodeHeaderRW != 0); - _ASSERTE(m_jitManager->GetGCInfo(m_CodeHeaderRW) == 0); + _ASSERTE(((CodeHeader*)m_CodeHeaderRW)->GetGCInfo() == 0); #ifdef HOST_64BIT if (size & 0xFFFFFFFF80000000LL) @@ -12433,22 +12546,21 @@ void * CEECodeGenInfo::allocGCInfo (size_t size) } #endif // HOST_64BIT - block = m_jitManager->allocGCInfo(m_CodeHeaderRW,(DWORD)size, &m_GCinfo_len); + block = m_jitManager->allocGCInfo((CodeHeader*)m_CodeHeaderRW, (DWORD)size, &m_GCinfo_len); if (!block) { COMPlusThrowHR(CORJIT_OUTOFMEM); } - _ASSERTE(m_jitManager->GetGCInfo(m_CodeHeaderRW) != 0 && block == m_jitManager->GetGCInfo(m_CodeHeaderRW)); + _ASSERTE(((CodeHeader*)m_CodeHeaderRW)->GetGCInfo() != 0 && block == ((CodeHeader*)m_CodeHeaderRW)->GetGCInfo()); EE_TO_JIT_TRANSITION(); return block; } -/*********************************************************************/ -void CEECodeGenInfo::setEHcount ( - unsigned cEH) +template +void CEECodeGenInfo::setEHcountWorker(unsigned cEH) { CONTRACTL { THROWS; @@ -12460,20 +12572,28 @@ void CEECodeGenInfo::setEHcount ( _ASSERTE(cEH != 0); _ASSERTE(m_CodeHeaderRW != 0); - _ASSERTE(m_jitManager->GetEHInfo(m_CodeHeaderRW) == 0); + _ASSERTE(((TCodeHeader*)m_CodeHeaderRW)->GetEHInfo() == 0); EE_ILEXCEPTION* ret; - ret = m_jitManager->allocEHInfo(m_CodeHeaderRW,cEH, &m_EHinfo_len); + ret = m_jitManager->allocEHInfo((TCodeHeader*)m_CodeHeaderRW, cEH, &m_EHinfo_len); _ASSERTE(ret); // allocEHInfo throws if there's not enough memory - _ASSERTE(m_jitManager->GetEHInfo(m_CodeHeaderRW) != 0 && m_jitManager->GetEHInfo(m_CodeHeaderRW)->EHCount() == cEH); + _ASSERTE(((TCodeHeader*)m_CodeHeaderRW)->GetEHInfo() != 0 && ((TCodeHeader*)m_CodeHeaderRW)->GetEHInfo()->EHCount() == cEH); EE_TO_JIT_TRANSITION(); } /*********************************************************************/ +void CEEJitInfo::setEHcount ( + unsigned cEH) +{ + WRAPPER_NO_CONTRACT; + + setEHcountWorker(cEH); +} -void CEECodeGenInfo::setEHinfo ( +void CEECodeGenInfo::setEHinfoWorker( + EE_ILEXCEPTION *pEHInfo, unsigned EHnumber, const CORINFO_EH_CLAUSE* clause) { @@ -12483,10 +12603,6 @@ void CEECodeGenInfo::setEHinfo ( MODE_PREEMPTIVE; } CONTRACTL_END; - JIT_TO_EE_TRANSITION(); - - // Fix make the Code Manager EH clauses EH_INFO+ - EE_ILEXCEPTION *pEHInfo = m_jitManager->GetEHInfo(m_CodeHeaderRW); _ASSERTE(pEHInfo != 0 && EHnumber < pEHInfo->EHCount()); EE_ILEXCEPTION_CLAUSE* pEHClause = pEHInfo->EHClause(EHnumber); @@ -12517,11 +12633,27 @@ void CEECodeGenInfo::setEHinfo ( SetHasCachedTypeHandle(pEHClause); LOG((LF_EH, LL_INFO1000000, " CachedTypeHandle: 0x%08x -> %p\n", clause->ClassToken, pEHClause->TypeHandle)); } +} + +void CEEJitInfo::setEHinfo ( + unsigned EHnumber, + const CORINFO_EH_CLAUSE* clause) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION(); + + // Fix make the Code Manager EH clauses EH_INFO+ + EE_ILEXCEPTION *pEHInfo = ((CodeHeader*)m_CodeHeaderRW)->GetEHInfo(); + setEHinfoWorker(pEHInfo, EHnumber, clause); EE_TO_JIT_TRANSITION(); } - /*********************************************************************/ // get individual exception handler void CEECodeGenInfo::getEHinfo( diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index a58ac815651c4f..2530d71bd0265a 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -622,8 +622,6 @@ class CEECodeGenInfo : public CEEInfo freeArrayInternal(m_pNativeVarInfo); } - void BackoutJitData(EECodeGenManager * jitMgr); - void ResetForJitRetry() { CONTRACTL { @@ -663,12 +661,15 @@ class CEECodeGenInfo : public CEEInfo m_numRichOffsetMappings = 0; } + virtual void BackoutJitData(EECodeGenManager * jitMgr) = 0; + // ICorDebugInfo stuff. void setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap) override final; void setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars) override final; void CompressDebugInfo(); + virtual void SetDebugInfo(PTR_BYTE pDebugInfo) = 0; virtual PatchpointInfo* GetPatchpointInfo() { @@ -692,13 +693,14 @@ class CEECodeGenInfo : public CEEInfo protected: - void allocMemWorker(AllocMemArgs *pArgs, size_t reserveForJumpStubs -#ifdef FEATURE_EH_FUNCLETS - , ULONG unwindInfoSize, ULONG unwindSize, BYTE** ppUnwindBlock -#endif - ); + template + void setEHcountWorker(unsigned cEH); - void WriteCodeBytes(); + template + void SetRealCodeHeader(); + + template + void NibbleMapSet(); virtual void getEHinfo( CORINFO_METHOD_HANDLE ftn, /* IN */ @@ -706,14 +708,11 @@ class CEECodeGenInfo : public CEEInfo CORINFO_EH_CLAUSE* clause /* OUT */ ) override final; - virtual void * allocGCInfo (size_t size) override final; - - virtual void setEHcount (unsigned cEH) override final; - - virtual void setEHinfo ( - unsigned EHnumber, - const CORINFO_EH_CLAUSE* clause - ) override final; + void setEHinfoWorker( + EE_ILEXCEPTION* pEHInfo, + unsigned EHnumber, + const CORINFO_EH_CLAUSE* clause + ); EECodeGenManager* m_jitManager; // responsible for allocating memory void* m_CodeHeader; // descriptor for JITTED code - read/execute address @@ -768,8 +767,15 @@ class CEEJitInfo : public CEECodeGenInfo public: // ICorJitInfo stuff - void allocMem (AllocMemArgs *pArgs) override final; + void allocMem(AllocMemArgs *pArgs) override final; + void * allocGCInfo(size_t size) override final; + virtual void setEHcount (unsigned cEH) override final; + virtual void setEHinfo ( + unsigned EHnumber, + const CORINFO_EH_CLAUSE* clause + ) override final; + void WriteCodeBytes(); void WriteCode(EECodeGenManager * jitMgr) override final; void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unwindSize) override final; @@ -817,6 +823,9 @@ class CEEJitInfo : public CEECodeGenInfo uint32_t getExpectedTargetArchitecture() override final; + void BackoutJitData(EECodeGenManager * jitMgr) override final; + void SetDebugInfo(PTR_BYTE pDebugInfo); + void ResetForJitRetry() { CONTRACTL { @@ -1063,10 +1072,20 @@ class CInterpreterJitInfo : public CEECodeGenInfo } CONTRACTL_END; } - void allocMem (AllocMemArgs *pArgs) override final; + void allocMem(AllocMemArgs *pArgs) override final; + void * allocGCInfo(size_t size) override final; + virtual void setEHcount (unsigned cEH) override final; + virtual void setEHinfo ( + unsigned EHnumber, + const CORINFO_EH_CLAUSE* clause + ) override final; + void WriteCodeBytes(); void WriteCode(EECodeGenManager * jitMgr) override final; + void BackoutJitData(EECodeGenManager * jitMgr) override final; + void SetDebugInfo(PTR_BYTE pDebugInfo); + void ResetForJitRetry() { CONTRACTL { From 35df12b5ea0fb2602793c7e63439c80e89c397d4 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Tue, 4 Mar 2025 21:48:23 +0100 Subject: [PATCH 06/15] PR feedback and some cleanup --- src/coreclr/debug/daccess/fntableaccess.cpp | 2 +- src/coreclr/debug/daccess/fntableaccess.h | 4 +- src/coreclr/inc/corjit.h | 1 - src/coreclr/interpreter/eeinterp.cpp | 2 +- src/coreclr/vm/codeman.cpp | 290 ++++++++++++++++---- src/coreclr/vm/codeman.h | 218 +++++++++------ src/coreclr/vm/dynamicmethod.cpp | 11 +- src/coreclr/vm/dynamicmethod.h | 3 +- src/coreclr/vm/eventtrace.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 33 ++- src/coreclr/vm/jitinterface.h | 2 +- src/coreclr/vm/loaderallocator.cpp | 3 + src/coreclr/vm/loaderallocator.hpp | 2 + src/coreclr/vm/perfmap.cpp | 2 +- src/coreclr/vm/profilingenumerators.cpp | 2 +- src/coreclr/vm/stackwalktypes.h | 1 + 16 files changed, 416 insertions(+), 162 deletions(-) diff --git a/src/coreclr/debug/daccess/fntableaccess.cpp b/src/coreclr/debug/daccess/fntableaccess.cpp index c342ad31bc09ae..023a82e268c8ed 100644 --- a/src/coreclr/debug/daccess/fntableaccess.cpp +++ b/src/coreclr/debug/daccess/fntableaccess.cpp @@ -169,7 +169,7 @@ extern "C" NTSTATUS OutOfProcessFunctionTableCallbackEx(IN ReadMemoryFunction *ppFunctions = 0; *pnEntries = 0; - DWORD_PTR pHp = JitMan + (DWORD_PTR)offsetof(FakeEECodeGenManager, m_pCodeHeap); + DWORD_PTR pHp = JitMan + (DWORD_PTR)offsetof(FakeEEJitManager, m_pCodeHeap); move(pHp, pHp); diff --git a/src/coreclr/debug/daccess/fntableaccess.h b/src/coreclr/debug/daccess/fntableaccess.h index a0617422edb51a..722f0581e218a0 100644 --- a/src/coreclr/debug/daccess/fntableaccess.h +++ b/src/coreclr/debug/daccess/fntableaccess.h @@ -11,7 +11,7 @@ #define _FN_TABLE_ACCESS_H -struct FakeEECodeGenManager +struct FakeEEJitManager { LPVOID __VFN_table; LPVOID m_runtimeSupport; @@ -76,7 +76,7 @@ class CheckDuplicatedStructLayouts { #define CHECK_OFFSET(cls, fld) CPP_ASSERT(cls##fld, offsetof(Fake##cls, fld) == offsetof(cls, fld)) - CHECK_OFFSET(EECodeGenManager, m_pCodeHeap); + CHECK_OFFSET(EEJitManager, m_pCodeHeap); CHECK_OFFSET(HeapList, hpNext); CHECK_OFFSET(HeapList, startAddress); diff --git a/src/coreclr/inc/corjit.h b/src/coreclr/inc/corjit.h index 77ee42d46343ab..d8e6a774784f52 100644 --- a/src/coreclr/inc/corjit.h +++ b/src/coreclr/inc/corjit.h @@ -52,7 +52,6 @@ enum CorJitAllocMemFlag CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN = 0x00000004, // The code will be 32-byte aligned CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN = 0x00000008, // The read-only data will be 32-byte aligned CORJIT_ALLOCMEM_FLG_RODATA_64BYTE_ALIGN = 0x00000010, // The read-only data will be 64-byte aligned - CORJIT_ALLOCMEM_FLG_INTERPRETED = 0x00000020, // The code is interpreted byte code }; inline CorJitAllocMemFlag operator |(CorJitAllocMemFlag a, CorJitAllocMemFlag b) diff --git a/src/coreclr/interpreter/eeinterp.cpp b/src/coreclr/interpreter/eeinterp.cpp index 09bdedd79ea9bf..b801c83eba39c4 100644 --- a/src/coreclr/interpreter/eeinterp.cpp +++ b/src/coreclr/interpreter/eeinterp.cpp @@ -95,7 +95,7 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd, args.coldCodeSize = 0; args.roDataSize = 0; args.xcptnsCount = 0; - args.flag = CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN | CORJIT_ALLOCMEM_FLG_INTERPRETED; + args.flag = CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN; compHnd->allocMem(&args); // We store first the InterpMethod pointer as the code header, followed by the actual code diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index e403b2642d5a85..00a746231291d7 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -19,6 +19,7 @@ #include "dynamicmethod.h" #include "eventtrace.h" #include "threadsuspend.h" +#include "daccess.h" #include "exceptionhandling.h" @@ -438,7 +439,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R STANDARD_VM_CONTRACT; { // CodeHeapIterator holds the m_CodeHeapCritSec, which ensures code heaps don't get deallocated while being walked - EECodeGenManager::CodeHeapIterator heapIterator(ExecutionManager::GetEEJitManager(), NULL); + EEJitManager::CodeHeapIterator heapIterator(NULL); // Currently m_CodeHeapCritSec is given the CRST_UNSAFE_ANYMODE flag which allows it to be taken in a GC_NOTRIGGER // region but also disallows GC_TRIGGERS. We need GC_TRIGGERS because we take another lock. Ideally we would @@ -541,8 +542,8 @@ DeleteJitHeapCache #if !defined(DACCESS_COMPILE) -EECodeGenManager::CodeHeapIterator::CodeHeapIterator(EECodeGenManager *pJitMgr, LoaderAllocator *pLoaderAllocatorFilter) - : m_lockHolder(&(pJitMgr->m_CodeHeapCritSec)), m_Iterator(NULL, 0, NULL, 0) +EEJitManager::CodeHeapIterator::CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter) + : m_lockHolder(&(ExecutionManager::GetEEJitManager()->m_CodeHeapCritSec)), m_Iterator(NULL, 0, NULL, 0) { CONTRACTL { @@ -554,12 +555,12 @@ EECodeGenManager::CodeHeapIterator::CodeHeapIterator(EECodeGenManager *pJitMgr, m_pHeapList = NULL; m_pLoaderAllocator = pLoaderAllocatorFilter; - m_pHeapList = pJitMgr->GetCodeHeapList(); + m_pHeapList = ExecutionManager::GetEEJitManager()->GetCodeHeapList(); if(m_pHeapList) new (&m_Iterator) MethodSectionIterator((const void *)m_pHeapList->mapBase, (COUNT_T)m_pHeapList->maxCodeHeapSize, m_pHeapList->pHdrMap, (COUNT_T)HEAP2MAPSIZE(ROUND_UP_TO_PAGE(m_pHeapList->maxCodeHeapSize))); }; -EECodeGenManager::CodeHeapIterator::~CodeHeapIterator() +EEJitManager::CodeHeapIterator::~CodeHeapIterator() { CONTRACTL { @@ -570,7 +571,7 @@ EECodeGenManager::CodeHeapIterator::~CodeHeapIterator() CONTRACTL_END; } -BOOL EECodeGenManager::CodeHeapIterator::Next() +BOOL EEJitManager::CodeHeapIterator::Next() { CONTRACTL { @@ -1191,7 +1192,8 @@ EECodeGenManager::EECodeGenManager() m_cleanupList(NULL), // CRST_DEBUGGER_THREAD - We take this lock on debugger thread during EnC add method, among other things // CRST_TAKEN_DURING_SHUTDOWN - We take this lock during shutdown if ETW is on (to do rundown) - m_CodeHeapCritSec( CrstSingleUseLock, CrstFlags(CRST_UNSAFE_ANYMODE|CRST_DEBUGGER_THREAD|CRST_TAKEN_DURING_SHUTDOWN)), + m_CodeHeapCritSec( CrstSingleUseLock, + CrstFlags(CRST_UNSAFE_ANYMODE|CRST_DEBUGGER_THREAD|CRST_TAKEN_DURING_SHUTDOWN)), m_storeRichDebugInfo(false) { } @@ -2729,12 +2731,14 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, // Avoid going through the full list in the common case - try to use the most recently used codeheap if (pInfo->IsDynamicDomain()) { +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap; pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap = NULL; } else +#endif // FEATURE_INTERPRETER { pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap; pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = NULL; @@ -2742,12 +2746,14 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, } else { +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap; pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap = NULL; } else +#endif // FEATURE_INTERPRETER { pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedCodeHeap; pInfo->m_pAllocator->m_pLastUsedCodeHeap = NULL; @@ -2806,22 +2812,26 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, if (pInfo->IsDynamicDomain()) { +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap = pCodeHeap; } else +#endif // FEATURE_INTERPRETER { pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = pCodeHeap; } } else { +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap = pCodeHeap; } else +#endif // FEATURE_INTERPRETER { pInfo->m_pAllocator->m_pLastUsedCodeHeap = pCodeHeap; } @@ -2841,13 +2851,14 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, RETURN(mem); } +template void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader #ifdef FEATURE_EH_FUNCLETS , UINT nUnwindInfos #endif - ) + ) { CONTRACTL { THROWS; @@ -2884,8 +2895,8 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser SIZE_T totalSize = blockSize; - CodeHeader * pCodeHdr = NULL; - CodeHeader * pCodeHdrRW = NULL; + TCodeHeader * pCodeHdr = NULL; + TCodeHeader * pCodeHdrRW = NULL; CodeHeapRequestInfo requestInfo(pMD); #if defined(FEATURE_JIT_PITCHING) @@ -2895,22 +2906,20 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser } #endif - if (flag & CORJIT_ALLOCMEM_FLG_INTERPRETED) + SIZE_T realHeaderSize; +#ifdef FEATURE_INTERPRETER + if (std::is_same::value) { #ifdef FEATURE_EH_FUNCLETS _ASSERTE(nUnwindInfos == 0); #endif _ASSERTE(reserveForJumpStubs == 0); - requestInfo.SetInterpreted(); - } - - SIZE_T realHeaderSize; - if (requestInfo.IsInterpreted()) - { + requestInfo.SetDynamicDomain(); realHeaderSize = sizeof(InterpreterRealCodeHeader); } else +#endif // FEATURE_INTERPRETER { requestInfo.setReserveForJumpStubs(reserveForJumpStubs); @@ -2935,7 +2944,7 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser CrstHolder ch(&m_CodeHeapCritSec); *ppCodeHeap = NULL; - TADDR pCode = (TADDR) allocCodeRaw(&requestInfo, sizeof(CodeHeader), totalSize, alignment, ppCodeHeap); + TADDR pCode = (TADDR) allocCodeRaw(&requestInfo, sizeof(TCodeHeader), totalSize, alignment, ppCodeHeap); _ASSERTE(*ppCodeHeap); if (pMD->IsLCGMethod()) @@ -2945,13 +2954,17 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser _ASSERTE(IS_ALIGNED(pCode, alignment)); - pCodeHdr = ((CodeHeader *)pCode) - 1; + pCodeHdr = ((TCodeHeader *)pCode) - 1; - *pAllocatedSize = sizeof(CodeHeader) + totalSize; + *pAllocatedSize = sizeof(TCodeHeader) + totalSize; - if (ExecutableAllocator::IsWXORXEnabled() && !requestInfo.IsInterpreted()) + if (ExecutableAllocator::IsWXORXEnabled() +#ifdef FEATURE_INTERPRETER + && !std::is_same::value +#endif // FEATURE_INTERPRETER + ) { - pCodeHdrRW = (CodeHeader *)new BYTE[*pAllocatedSize]; + pCodeHdrRW = (TCodeHeader *)new BYTE[*pAllocatedSize]; } else { @@ -2977,7 +2990,7 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser pCodeHdrRW->SetGCInfo(NULL); pCodeHdrRW->SetMethodDesc(pMD); #ifdef FEATURE_EH_FUNCLETS - if (!requestInfo.IsInterpreted()) + if (std::is_same::value) { ((CodeHeader*)pCodeHdrRW)->SetNumberOfUnwindInfos(nUnwindInfos); } @@ -2997,6 +3010,24 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser *ppCodeHeaderRW = pCodeHdrRW; } +template void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, + size_t* pAllocatedSize, HeapList** ppCodeHeap + , BYTE** ppRealHeader +#ifdef FEATURE_EH_FUNCLETS + , UINT nUnwindInfos +#endif + ); + +#ifdef FEATURE_INTERPRETER +template void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, + size_t* pAllocatedSize, HeapList** ppCodeHeap + , BYTE** ppRealHeader +#ifdef FEATURE_EH_FUNCLETS + , UINT nUnwindInfos +#endif + ); +#endif // FEATURE_INTERPRETER + EEJitManager::DomainCodeHeapList *EECodeGenManager::GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly) { CONTRACTL { @@ -3417,6 +3448,11 @@ void EEJitManager::UnpublishUnwindInfoForMethod(TADDR codeStart) #endif // defined(TARGET_AMD64) } +void EEJitManager::DeleteFunctionTable(PVOID pvTableID) +{ + DeleteEEFunctionTable(pvTableID); +} + // appdomain is being unloaded, so delete any data associated with it. We have to do this in two stages. // On the first stage, we remove the elements from the list. On the second stage, which occurs after a GC // we know that only threads who were in preemptive mode prior to the GC could possibly still be looking @@ -3567,7 +3603,7 @@ BOOL InterpreterJitManager::LoadInterpreter() // Publish the interpreter. m_interpreter = newInterpreter; - return IsInterpreterLoaded(); + return IsInterpreterLoaded(); } #endif // FEATURE_INTERPRETER @@ -3742,7 +3778,7 @@ void EECodeGenManager::DeleteCodeHeap(HeapList *pHeapList) pHp->SetNext(pHeapList->GetNext()); } - DeleteEEFunctionTable((PVOID)pHeapList->GetModuleBase()); + DeleteFunctionTable((PVOID)pHeapList->GetModuleBase()); ExecutionManager::DeleteRange((TADDR)pHeapList->GetModuleBase()); @@ -3757,7 +3793,8 @@ void EECodeGenManager::DeleteCodeHeap(HeapList *pHeapList) #endif // #ifndef DACCESS_COMPILE -static CodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & request) +template +static TCodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & request) { CONTRACTL { NOTHROW; @@ -3768,7 +3805,7 @@ static CodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & r TADDR address = (TADDR) request.GetStartAddress(); _ASSERTE(address != (TADDR)0); - CodeHeader * pHeader = dac_cast(address & ~3) - 1; + TCodeHeader * pHeader = dac_cast(address & ~3) - 1; _ASSERTE(pHeader != NULL); return pHeader; @@ -3777,7 +3814,8 @@ static CodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & r //----------------------------------------------------------------------------- // Get vars from Jit Store //----------------------------------------------------------------------------- -BOOL EECodeGenManager::GetBoundariesAndVars( +template +BOOL EECodeGenManager::GetBoundariesAndVarsWorker( const DebugInfoRequest & request, IN FP_IDS_NEW fpNew, IN void * pNewData, OUT ULONG32 * pcMap, @@ -3791,7 +3829,7 @@ BOOL EECodeGenManager::GetBoundariesAndVars( SUPPORTS_DAC; } CONTRACTL_END; - CodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + TCodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); _ASSERTE(pHdr != NULL); PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); @@ -3823,7 +3861,25 @@ BOOL EECodeGenManager::GetBoundariesAndVars( return TRUE; } -BOOL EECodeGenManager::GetRichDebugInfo( +BOOL EEJitManager::GetBoundariesAndVars( + const DebugInfoRequest & request, + IN FP_IDS_NEW fpNew, IN void * pNewData, + OUT ULONG32 * pcMap, + OUT ICorDebugInfo::OffsetMapping **ppMap, + OUT ULONG32 * pcVars, + OUT ICorDebugInfo::NativeVarInfo **ppVars) +{ + CONTRACTL { + THROWS; // on OOM. + GC_NOTRIGGER; // getting vars shouldn't trigger + SUPPORTS_DAC; + } CONTRACTL_END; + + return GetBoundariesAndVarsWorker(request, fpNew, pNewData, pcMap, ppMap, pcVars, ppVars); +} + +template +BOOL EECodeGenManager::GetRichDebugInfoWorker( const DebugInfoRequest& request, IN FP_IDS_NEW fpNew, IN void* pNewData, OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, @@ -3842,7 +3898,7 @@ BOOL EECodeGenManager::GetRichDebugInfo( return FALSE; } - CodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + TCodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); _ASSERTE(pHdr != NULL); PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); @@ -3860,6 +3916,59 @@ BOOL EECodeGenManager::GetRichDebugInfo( return TRUE; } +BOOL EEJitManager::GetRichDebugInfo( + const DebugInfoRequest& request, + IN FP_IDS_NEW fpNew, IN void* pNewData, + OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, + OUT ULONG32* pNumInlineTree, + OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, + OUT ULONG32* pNumRichMappings) +{ + CONTRACTL { + THROWS; // on OOM. + GC_NOTRIGGER; // getting debug info shouldn't trigger + SUPPORTS_DAC; + } CONTRACTL_END; + + return GetRichDebugInfoWorker(request, fpNew, pNewData, ppInlineTree, pNumInlineTree, ppRichMappings, pNumRichMappings); +} + +#ifdef FEATURE_INTERPRETER +BOOL InterpreterJitManager::GetBoundariesAndVars( + const DebugInfoRequest & request, + IN FP_IDS_NEW fpNew, IN void * pNewData, + OUT ULONG32 * pcMap, + OUT ICorDebugInfo::OffsetMapping **ppMap, + OUT ULONG32 * pcVars, + OUT ICorDebugInfo::NativeVarInfo **ppVars) +{ + CONTRACTL { + THROWS; // on OOM. + GC_NOTRIGGER; // getting vars shouldn't trigger + SUPPORTS_DAC; + } CONTRACTL_END; + + return GetBoundariesAndVarsWorker(request, fpNew, pNewData, pcMap, ppMap, pcVars, ppVars); +} + +BOOL InterpreterJitManager::GetRichDebugInfo( + const DebugInfoRequest& request, + IN FP_IDS_NEW fpNew, IN void* pNewData, + OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, + OUT ULONG32* pNumInlineTree, + OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, + OUT ULONG32* pNumRichMappings) +{ + CONTRACTL { + THROWS; // on OOM. + GC_NOTRIGGER; // getting debug info shouldn't trigger + SUPPORTS_DAC; + } CONTRACTL_END; + + return GetRichDebugInfoWorker(request, fpNew, pNewData, ppInlineTree, pNumInlineTree, ppRichMappings, pNumRichMappings); +} +#endif // FEATURE_INTERPRETER + #ifdef DACCESS_COMPILE void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) { @@ -3887,6 +3996,42 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ } } +//----------------------------------------------------------------------------- +// Enumerate for minidumps. +//----------------------------------------------------------------------------- +template +void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfoWorker(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } + CONTRACTL_END; + + DebugInfoRequest request; + PCODE addrCode = pMD->GetNativeCode(); + request.InitFromStartingAddr(pMD, addrCode); + + TCodeHeader * pHeader = GetCodeHeaderFromDebugInfoRequest(request); + + pHeader->EnumMemoryRegions(flags, NULL); +} + +void EEJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } + CONTRACTL_END; + + EnumMemoryRegionsForMethodDebugInfoWorker(flags, pMD); +} + #ifdef FEATURE_INTERPRETER void InterpreterCodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) { @@ -3907,12 +4052,8 @@ void InterpreterCodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJit CompressDebugInfo::EnumMemoryRegions(flags, this->GetDebugInfo(), FALSE /* hasFlagByte */); } } -#endif // FEATURE_INTERPRETER -//----------------------------------------------------------------------------- -// Enumerate for minidumps. -//----------------------------------------------------------------------------- -void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +void InterpreterJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) { CONTRACTL { @@ -3922,14 +4063,10 @@ void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlag } CONTRACTL_END; - DebugInfoRequest request; - PCODE addrCode = pMD->GetNativeCode(); - request.InitFromStartingAddr(pMD, addrCode); - - CodeHeader * pHeader = GetCodeHeaderFromDebugInfoRequest(request); - - pHeader->EnumMemoryRegions(flags, NULL); + EnumMemoryRegionsForMethodDebugInfoWorker(flags, pMD); } +#endif // FEATURE_INTERPRETER + #endif // DACCESS_COMPILE PCODE EEJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) @@ -3950,11 +4087,12 @@ PCODE InterpreterJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& Metho } #endif // FEATURE_INTERPRETER -BOOL EECodeGenManager::JitCodeToMethodInfo( - RangeSection * pRangeSection, - PCODE currentPC, - MethodDesc ** ppMethodDesc, - EECodeInfo * pCodeInfo) +template +BOOL EECodeGenManager::JitCodeToMethodInfoWorker( + RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo) { CONTRACTL { NOTHROW; @@ -3971,7 +4109,7 @@ BOOL EECodeGenManager::JitCodeToMethodInfo( if (start == (TADDR)0) return FALSE; - CodeHeader * pCHdr = PTR_CodeHeader(start - sizeof(CodeHeader)); + TCodeHeader * pCHdr = (DPTR(TCodeHeader))(start - sizeof(TCodeHeader)); if (pCHdr->IsStubCodeBlock()) return FALSE; @@ -3984,7 +4122,7 @@ BOOL EECodeGenManager::JitCodeToMethodInfo( // This can be counted on for Jitted code. For NGEN code in the case // where we have hot/cold splitting this isn't valid and we need to // take into account cold code. - pCodeInfo->m_relOffset = (DWORD)(PCODEToPINSTR(currentPC) - pCHdr->GetCodeStartAddress()); + pCodeInfo->m_relOffset = (DWORD)(PCODEToPINSTR(currentPC) - start); #ifdef FEATURE_EH_FUNCLETS // Computed lazily by code:EEJitManager::LazyGetFunctionEntry @@ -3999,7 +4137,39 @@ BOOL EECodeGenManager::JitCodeToMethodInfo( return TRUE; } -StubCodeBlockKind EECodeGenManager::GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) +BOOL EEJitManager::JitCodeToMethodInfo( + RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } CONTRACTL_END; + + return JitCodeToMethodInfoWorker(pRangeSection, currentPC, ppMethodDesc, pCodeInfo); +} + +#ifdef FEATURE_INTERPRETER +BOOL InterpreterJitManager::JitCodeToMethodInfo( + RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } CONTRACTL_END; + + return JitCodeToMethodInfoWorker(pRangeSection, currentPC, ppMethodDesc, pCodeInfo); +} +#endif // FEATURE_INTERPRETER + +StubCodeBlockKind EEJitManager::GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) { CONTRACTL { NOTHROW; @@ -4012,7 +4182,7 @@ StubCodeBlockKind EECodeGenManager::GetStubCodeBlockKind(RangeSection * pRangeSe return pRangeSection->_pRangeList->GetCodeBlockKind(); } - TADDR start = dac_cast(pRangeSection->_pjit)->FindMethodCode(pRangeSection, currentPC); + TADDR start = dac_cast(pRangeSection->_pjit)->FindMethodCode(pRangeSection, currentPC); if (start == (TADDR)0) return STUB_CODE_BLOCK_NOCODE; CodeHeader * pCHdr = PTR_CodeHeader(start - sizeof(CodeHeader)); @@ -4702,6 +4872,14 @@ BOOL ExecutionManager::IsManagedCodeWorker(PCODE currentPC, RangeSectionLockStat if (pRS == NULL) return FALSE; +#ifdef FEATURE_INTERPRETER + if (pRS->_flags & RangeSection::RANGE_SECTION_INTERPRETER) + { + if (dac_cast(pRS->_pjit)->JitCodeToMethodInfo(pRS, currentPC, NULL, NULL)) + return TRUE; + } + else +#endif if (pRS->_flags & RangeSection::RANGE_SECTION_CODEHEAP) { // Typically if we find a Jit Manager we are inside a managed method @@ -4722,14 +4900,6 @@ BOOL ExecutionManager::IsManagedCodeWorker(PCODE currentPC, RangeSectionLockStat return TRUE; } #endif -#ifdef FEATURE_INTERPRETER - else - if (pRS->_flags & RangeSection::RANGE_SECTION_INTERPRETER) - { - if (dac_cast(pRS->_pjit)->JitCodeToMethodInfo(pRS, currentPC, NULL, NULL)) - return TRUE; - } -#endif return FALSE; } diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 0ce9b2637ef22f..7aff613aa5407b 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -155,15 +155,7 @@ struct InterpreterRealCodeHeader // contains the number of EH clauses, See EEJitManager::allocEHInfo PTR_EE_ILEXCEPTION phdrJitEHInfo; PTR_BYTE phdrJitGCInfo; - -#if defined(FEATURE_GDBJIT) - VOID* pCalledMethods; -#endif - PTR_MethodDesc phdrMDesc; - -public: -// if we're using the indirect codeheaders then all enumeration is done by the code header }; struct CodeHeader @@ -339,17 +331,19 @@ struct InterpreterCodeHeader pRealCodeHeader->phdrMDesc = pMD; } + BOOL IsStubCodeBlock() + { + return FALSE; + } + #ifdef DACCESS_COMPILE void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); #endif // DACCESS_COMPILE - }; typedef DPTR(InterpreterCodeHeader) PTR_InterpreterCodeHeader; -static_assert(sizeof(InterpreterCodeHeader) == sizeof(CodeHeader), "InterpreterCodeHeader and CodeHeader must have the same size"); - #endif // FEATURE_INTERPRETER //----------------------------------------------------------------------------- @@ -1687,14 +1681,14 @@ class IJitManager OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, OUT ULONG32* pNumRichMappings) = 0; - virtual BOOL JitCodeToMethodInfo( - RangeSection * pRangeSection, - PCODE currentPC, - MethodDesc** ppMethodDesc, - OUT EECodeInfo * pCodeInfo) = 0; - virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) = 0; + virtual BOOL JitCodeToMethodInfo( + RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc** ppMethodDesc, + OUT EECodeInfo * pCodeInfo) = 0; + virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken)=0; virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo *methodRegionInfo) = 0; virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState)=0; @@ -1768,6 +1762,7 @@ class EECodeGenManager : public IJitManager friend class DacDbiInterfaceImpl; #endif friend class CheckDuplicatedStructLayouts; + friend class EECodeInfo; VPTR_ABSTRACT_VTABLE_CLASS(EECodeGenManager, IJitManager) @@ -1785,8 +1780,21 @@ class EECodeGenManager : public IJitManager virtual ICorJitCompiler* GetCompiler() = 0; virtual ICorJitCompiler* GetAltCompiler() = 0; - // Used to read debug info. - virtual BOOL GetBoundariesAndVars( + virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, + EE_ILEXCEPTION_CLAUSE* pEHclause); + + static TADDR FindMethodCode(RangeSection * pRangeSection, PCODE currentPC); + static TADDR FindMethodCode(PCODE currentPC); + + bool IsStoringRichDebugInfo() + { + LIMITED_METHOD_CONTRACT; + return m_storeRichDebugInfo; + } + +protected: + template + BOOL GetBoundariesAndVarsWorker( const DebugInfoRequest & request, IN FP_IDS_NEW fpNew, IN void * pNewData, OUT ULONG32 * pcMap, @@ -1794,7 +1802,8 @@ class EECodeGenManager : public IJitManager OUT ULONG32 * pcVars, OUT ICorDebugInfo::NativeVarInfo **ppVars); - virtual BOOL GetRichDebugInfo( + template + BOOL GetRichDebugInfoWorker( const DebugInfoRequest& request, IN FP_IDS_NEW fpNew, IN void* pNewData, OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, @@ -1802,25 +1811,14 @@ class EECodeGenManager : public IJitManager OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, OUT ULONG32* pNumRichMappings); - virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection, - PCODE currentPC, - MethodDesc ** ppMethodDesc, - EECodeInfo * pCodeInfo); - - virtual PTR_EXCEPTION_CLAUSE_TOKEN GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, - EE_ILEXCEPTION_CLAUSE* pEHclause); - - virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC); - - static TADDR FindMethodCode(RangeSection * pRangeSection, PCODE currentPC); - static TADDR FindMethodCode(PCODE currentPC); - - bool IsStoringRichDebugInfo() - { - LIMITED_METHOD_CONTRACT; - return m_storeRichDebugInfo; - } + template + BOOL JitCodeToMethodInfoWorker( + RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo); +public: #ifndef DACCESS_COMPILE virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, CrawlFrame *pCf); @@ -1830,12 +1828,13 @@ class EECodeGenManager : public IJitManager void Unload(LoaderAllocator* pAllocator); void CleanupCodeHeaps(); + template void allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader #ifdef FEATURE_EH_FUNCLETS , UINT nUnwindInfos #endif - ); + ); template inline BYTE *allocGCInfo(TCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); @@ -1862,6 +1861,7 @@ class EECodeGenManager : public IJitManager void* allocCodeRaw(CodeHeapRequestInfo *pInfo, size_t header, size_t blockSize, unsigned align, HeapList ** ppCodeHeap); void* allocEHInfoRaw(MethodDesc *pMD, DWORD blockSize, size_t * pAllocationSize); virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) = 0; + virtual void DeleteFunctionTable(PVOID pvTableID) = 0; DomainCodeHeapList *GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly = FALSE); DomainCodeHeapList* CreateCodeHeapList(CodeHeapRequestInfo *pInfo); @@ -1872,35 +1872,11 @@ class EECodeGenManager : public IJitManager return m_pCodeHeap; } -public: - class CodeHeapIterator - { - CrstHolder m_lockHolder; - HeapList *m_pHeapList; - LoaderAllocator *m_pLoaderAllocator; - MethodSectionIterator m_Iterator; - MethodDesc *m_pCurrent; - - public: - CodeHeapIterator(EECodeGenManager *pJitMgr, LoaderAllocator *pLoaderAllocatorFilter = NULL); - ~CodeHeapIterator(); - BOOL Next(); - - MethodDesc *GetMethod() - { - LIMITED_METHOD_CONTRACT; - return m_pCurrent; - } - - TADDR GetMethodCode() - { - LIMITED_METHOD_CONTRACT; - return (TADDR)m_Iterator.GetMethodCode(); - } - }; #else // !DACCESS_COMPILE virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); - virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); +protected: + template + void EnumMemoryRegionsForMethodDebugInfoWorker(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); #endif // !DACCESS_COMPILE private: @@ -1976,7 +1952,6 @@ class EEJitManager final : public EECodeGenManager VPTR_VTABLE_CLASS(EEJitManager, EECodeGenManager) public: - virtual ICorJitCompiler* GetCompiler() { return m_jit; @@ -2030,15 +2005,40 @@ class EEJitManager final : public EECodeGenManager return (miManaged | miIL); } + // Used to read debug info. + virtual BOOL GetBoundariesAndVars( + const DebugInfoRequest & request, + IN FP_IDS_NEW fpNew, IN void * pNewData, + OUT ULONG32 * pcMap, + OUT ICorDebugInfo::OffsetMapping **ppMap, + OUT ULONG32 * pcVars, + OUT ICorDebugInfo::NativeVarInfo **ppVars); + + virtual BOOL GetRichDebugInfo( + const DebugInfoRequest& request, + IN FP_IDS_NEW fpNew, IN void* pNewData, + OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, + OUT ULONG32* pNumInlineTree, + OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, + OUT ULONG32* pNumRichMappings); + + virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset); + + virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo); + virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken); virtual void JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo *methodRegionInfo); - static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); - static CodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); + virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState); - GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); - virtual unsigned InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState); - virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset); + GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); + +#ifdef DACCESS_COMPILE + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); +#endif // DACCESS_COMPILE #if !defined DACCESS_COMPILE BOOL LoadJIT(); @@ -2049,9 +2049,11 @@ class EEJitManager final : public EECodeGenManager bool throwOnOutOfMemoryWithinRange); void * allocCodeFragmentBlock(size_t blockSize, unsigned alignment, LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind); - #endif // !DACCESS_COMPILE + static CodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); + static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); + #if defined(FEATURE_EH_FUNCLETS) // Compute function entry lazily. Do not call directly. Use EECodeInfo::GetFunctionEntry instead. virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo); @@ -2059,6 +2061,8 @@ class EEJitManager final : public EECodeGenManager virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength); #endif // FEATURE_EH_FUNCLETS + virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC); + #if defined(FEATURE_EH_FUNCLETS) // Enumerate the memory necessary to retrieve the unwind info for a specific method virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) @@ -2072,7 +2076,34 @@ class EEJitManager final : public EECodeGenManager #endif // FEATURE_EH_FUNCLETS #if !defined DACCESS_COMPILE + class CodeHeapIterator + { + CrstHolder m_lockHolder; + HeapList *m_pHeapList; + LoaderAllocator *m_pLoaderAllocator; + MethodSectionIterator m_Iterator; + MethodDesc *m_pCurrent; + + public: + CodeHeapIterator(LoaderAllocator *pLoaderAllocatorFilter = NULL); + ~CodeHeapIterator(); + BOOL Next(); + + MethodDesc *GetMethod() + { + LIMITED_METHOD_CONTRACT; + return m_pCurrent; + } + + TADDR GetMethodCode() + { + LIMITED_METHOD_CONTRACT; + return (TADDR)m_Iterator.GetMethodCode(); + } + }; +protected: virtual void UnpublishUnwindInfoForMethod(TADDR codeStart); + virtual void DeleteFunctionTable(PVOID pvTableID); #endif // !DACCESS_COMPILE private: @@ -2090,7 +2121,6 @@ class EEJitManager final : public EECodeGenManager } private : - //When EH Clauses are resolved we need to atomically update the TypeHandle Crst m_JitLoadCritSec; #ifdef TARGET_AMD64 @@ -2619,7 +2649,7 @@ class InterpreterJitManager final : public EECodeGenManager } BOOL LoadInterpreter(); - + BOOL IsInterpreterLoaded() { LIMITED_METHOD_CONTRACT; @@ -2647,6 +2677,28 @@ class InterpreterJitManager final : public EECodeGenManager static InterpreterCodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); static InterpreterCodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); + virtual BOOL JitCodeToMethodInfo(RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo); + + // Used to read debug info. + virtual BOOL GetBoundariesAndVars( + const DebugInfoRequest & request, + IN FP_IDS_NEW fpNew, IN void * pNewData, + OUT ULONG32 * pcMap, + OUT ICorDebugInfo::OffsetMapping **ppMap, + OUT ULONG32 * pcVars, + OUT ICorDebugInfo::NativeVarInfo **ppVars); + + virtual BOOL GetRichDebugInfo( + const DebugInfoRequest& request, + IN FP_IDS_NEW fpNew, IN void* pNewData, + OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, + OUT ULONG32* pNumInlineTree, + OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, + OUT ULONG32* pNumRichMappings); + #if defined(FEATURE_EH_FUNCLETS) virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo) { @@ -2675,7 +2727,12 @@ class InterpreterJitManager final : public EECodeGenManager { // Nothing to do for the interpreter } - + + virtual void DeleteFunctionTable(PVOID pvTableID) + { + // Nothing to do for the interpreter + } + public: #endif // !DACCESS_COMPILE @@ -2688,6 +2745,8 @@ class InterpreterJitManager final : public EECodeGenManager #if defined(DACCESS_COMPILE) + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); + #if defined(FEATURE_EH_FUNCLETS) virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { @@ -2714,7 +2773,10 @@ private : // class EECodeInfo { - friend BOOL EECodeGenManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo); + friend BOOL EECodeGenManager::JitCodeToMethodInfoWorker(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo); +#ifdef FEATURE_INTERPRETER + friend BOOL EECodeGenManager::JitCodeToMethodInfoWorker(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo); +#endif #ifdef FEATURE_READYTORUN friend BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo); #endif @@ -2862,7 +2924,7 @@ inline InterpreterCodeHeader * InterpreterJitManager::GetCodeHeaderFromStartAddr LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(methodStartAddress != (TADDR)NULL); ARM_ONLY(_ASSERTE((methodStartAddress & THUMB_CODE) == 0)); - return dac_cast(methodStartAddress - sizeof(CodeHeader)); + return dac_cast(methodStartAddress - sizeof(InterpreterCodeHeader)); } inline TADDR InterpreterJitManager::JitTokenToStartAddress(const METHODTOKEN& MethodToken) diff --git a/src/coreclr/vm/dynamicmethod.cpp b/src/coreclr/vm/dynamicmethod.cpp index fe899f4d5238d2..867724b02cb618 100644 --- a/src/coreclr/vm/dynamicmethod.cpp +++ b/src/coreclr/vm/dynamicmethod.cpp @@ -335,7 +335,7 @@ HeapList* HostCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, EECodeGenMana } CONTRACT_END; - NewHolder pCodeHeap(new HostCodeHeap(pJitManager)); + NewHolder pCodeHeap(new HostCodeHeap(pJitManager, !pInfo->IsInterpreted())); HeapList *pHp = pCodeHeap->InitializeHeapList(pInfo); if (pHp == NULL) @@ -353,7 +353,7 @@ HeapList* HostCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, EECodeGenMana RETURN pHp; } -HostCodeHeap::HostCodeHeap(EECodeGenManager *pJitManager) +HostCodeHeap::HostCodeHeap(EECodeGenManager *pJitManager, bool isExecutable) { CONTRACTL { @@ -369,6 +369,7 @@ HostCodeHeap::HostCodeHeap(EECodeGenManager *pJitManager) m_TotalBytesAvailable = 0; m_ApproximateLargestBlock = 0; m_AllocationCount = 0; + m_isExecutable = isExecutable; m_pHeapList = NULL; m_pJitManager = (PTR_EEJitManager)pJitManager; m_pFreeList = NULL; @@ -689,7 +690,7 @@ void* HostCodeHeap::AllocMemForCode_NoThrow(size_t header, size_t size, DWORD al } CONTRACTL_END; - _ASSERTE(header == sizeof(CodeHeader)); + _ASSERTE(header == sizeof(CodeHeader) || header == sizeof(InterpreterCodeHeader)); _ASSERTE(alignment <= HOST_CODEHEAP_SIZE_ALIGN); // The code allocator has to guarantee that there is only one entrypoint per nibble map entry. @@ -707,7 +708,7 @@ void* HostCodeHeap::AllocMemForCode_NoThrow(size_t header, size_t size, DWORD al BYTE * pCode = ALIGN_UP((BYTE*)(pTracker + 1) + header, alignment); // Pointer to the TrackAllocation record is stored just before the code header - CodeHeader * pHdr = (CodeHeader *)pCode - 1; + void * pHdr = pCode - header; ExecutableWriterHolder trackerWriterHolder((TrackAllocation **)(pHdr) - 1, sizeof(TrackAllocation *)); *trackerWriterHolder.GetRW() = pTracker; @@ -770,7 +771,7 @@ HostCodeHeap::TrackAllocation* HostCodeHeap::AllocMemory_NoThrow(size_t header, if (m_pLastAvailableCommittedAddr + sizeToCommit <= m_pBaseAddr + m_TotalBytesAvailable) { - if (NULL == ExecutableAllocator::Instance()->Commit(m_pLastAvailableCommittedAddr, sizeToCommit, true /* isExecutable */)) + if (NULL == ExecutableAllocator::Instance()->Commit(m_pLastAvailableCommittedAddr, sizeToCommit, m_isExecutable)) { LOG((LF_BCL, LL_ERROR, "CodeHeap [0x%p] - VirtualAlloc failed\n", this)); return NULL; diff --git a/src/coreclr/vm/dynamicmethod.h b/src/coreclr/vm/dynamicmethod.h index 6ea8662ca41180..7a17acffc9b5b1 100644 --- a/src/coreclr/vm/dynamicmethod.h +++ b/src/coreclr/vm/dynamicmethod.h @@ -288,6 +288,7 @@ class HostCodeHeap : CodeHeap size_t m_ApproximateLargestBlock; // Heap ref count DWORD m_AllocationCount; + bool m_isExecutable; // data to track free list and pointers into this heap // - on an used block this struct has got a pointer back to the CodeHeap, size and start of aligned allocation @@ -309,7 +310,7 @@ class HostCodeHeap : CodeHeap static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, EECodeGenManager *pJitManager); private: - HostCodeHeap(EECodeGenManager *pJitManager); + HostCodeHeap(EECodeGenManager *pJitManager, bool isExecutable); HeapList* InitializeHeapList(CodeHeapRequestInfo *pInfo); TrackAllocation* AllocFromFreeList(size_t header, size_t size, DWORD alignment, size_t reserveForJumpStubs); void AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocation *pBlockToInsertRW); diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index 363395e752deaa..19c35aa9452ed7 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -5221,7 +5221,7 @@ VOID ETW::MethodLog::SendEventsForJitMethodsHelper(LoaderAllocator *pLoaderAlloc MethodDescSet sentMethodDetailsSet; MethodDescSet* pSentMethodDetailsSet = fSendRichDebugInfoEvent ? &sentMethodDetailsSet : NULL; - EECodeGenManager::CodeHeapIterator heapIterator(ExecutionManager::GetEEJitManager(), pLoaderAllocatorFilter); + EEJitManager::CodeHeapIterator heapIterator(pLoaderAllocatorFilter); while (heapIterator.Next()) { MethodDesc * pMD = heapIterator.GetMethod(); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 5079b65d7bf4a1..ff935d51b49d20 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11145,12 +11145,12 @@ void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs) pArgs->hotCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId()); } - m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), 0, pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap - , &m_pRealCodeHeader + m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), 0, pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap + , &m_pRealCodeHeader #ifdef FEATURE_EH_FUNCLETS - , 0 + , 0 #endif - ); + ); BYTE* current = (BYTE *)((InterpreterCodeHeader*)m_CodeHeader)->GetCodeStartAddress(); @@ -12400,6 +12400,12 @@ HRESULT CEEJitInfo::getPgoInstrumentationResults( void CEEJitInfo::allocMem (AllocMemArgs *pArgs) { + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + JIT_TO_EE_TRANSITION(); _ASSERTE(pArgs->coldCodeSize == 0); @@ -12407,10 +12413,13 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) { pArgs->coldCodeBlock = NULL; } + ULONG codeSize = pArgs->hotCodeSize; void **codeBlock = &pArgs->hotCodeBlock; void **codeBlockRW = &pArgs->hotCodeBlockRW; + S_SIZE_T totalSize = S_SIZE_T(codeSize); + size_t roDataAlignment = sizeof(void*); if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_RODATA_64BYTE_ALIGN)!= 0) { @@ -12431,6 +12440,7 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) if (pArgs->roDataSize > 0) { size_t codeAlignment = sizeof(void*); + if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN) != 0) { codeAlignment = 32; @@ -12459,30 +12469,34 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) // situation - we will leak some memory, but that is acceptable // since this should happen very rarely. "Note that this may fire if the JITCompiler tries to recompile a method"); + if( totalSize.IsOverflow() ) { COMPlusThrowHR(CORJIT_OUTOFMEM); } + if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, MethodJitMemoryAllocatedForCode)) { ULONGLONG ullMethodIdentifier = 0; ULONGLONG ullModuleID = 0; + if (m_pMethodBeingCompiled) { Module* pModule = m_pMethodBeingCompiled->GetModule(); ullModuleID = (ULONGLONG)(TADDR)pModule; ullMethodIdentifier = (ULONGLONG)m_pMethodBeingCompiled; } + FireEtwMethodJitMemoryAllocatedForCode(ullMethodIdentifier, ullModuleID, pArgs->hotCodeSize + pArgs->coldCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId()); } - m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap - , &m_pRealCodeHeader + m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap + , &m_pRealCodeHeader #ifdef FEATURE_EH_FUNCLETS - , m_totalUnwindInfos + , m_totalUnwindInfos #endif - ); + ); #ifdef FEATURE_EH_FUNCLETS m_moduleBase = m_pCodeHeap->GetModuleBase(); @@ -12494,6 +12508,7 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) *codeBlock = current; *codeBlockRW = current + writeableOffset; current += codeSize; + if (pArgs->roDataSize > 0) { current = (BYTE *)ALIGN_UP(current, roDataAlignment); @@ -12559,7 +12574,7 @@ void * CEEJitInfo::allocGCInfo (size_t size) return block; } -template +template void CEECodeGenInfo::setEHcountWorker(unsigned cEH) { CONTRACTL { diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 2530d71bd0265a..f5c4ea13f328e6 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -767,7 +767,7 @@ class CEEJitInfo : public CEECodeGenInfo public: // ICorJitInfo stuff - void allocMem(AllocMemArgs *pArgs) override final; + void allocMem (AllocMemArgs *pArgs) override final; void * allocGCInfo(size_t size) override final; virtual void setEHcount (unsigned cEH) override final; virtual void setEHinfo ( diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 83001346d2bc46..fe23d482c9538d 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -70,7 +70,10 @@ LoaderAllocator::LoaderAllocator(bool collectible) : m_pVSDHeapInitialAlloc = NULL; m_pLastUsedCodeHeap = NULL; m_pLastUsedDynamicCodeHeap = NULL; +#ifdef FEATURE_INTERPRETER m_pLastUsedInterpreterCodeHeap = NULL; + m_pLastUsedInterpreterDynamicCodeHeap = NULL; +#endif // FEATURE_INTERPRETER m_pJumpStubCache = NULL; m_IsCollectible = collectible; diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 606dc53b8fd20d..82f0546ee1e80b 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -371,8 +371,10 @@ class LoaderAllocator // ExecutionManager caches void * m_pLastUsedCodeHeap; void * m_pLastUsedDynamicCodeHeap; +#ifdef FEATURE_INTERPRETER void * m_pLastUsedInterpreterCodeHeap; void * m_pLastUsedInterpreterDynamicCodeHeap; +#endif // FEATURE_INTERPRETER void * m_pJumpStubCache; // LoaderAllocator GC Structures diff --git a/src/coreclr/vm/perfmap.cpp b/src/coreclr/vm/perfmap.cpp index b51667ef11d3b0..e3892bd1018f6c 100644 --- a/src/coreclr/vm/perfmap.cpp +++ b/src/coreclr/vm/perfmap.cpp @@ -135,7 +135,7 @@ void PerfMap::Enable(PerfMapType type, bool sendExisting) { CodeVersionManager::LockHolder codeVersioningLockHolder; - EECodeGenManager::CodeHeapIterator heapIterator(ExecutionManager::GetEEJitManager(), nullptr); + EEJitManager::CodeHeapIterator heapIterator(nullptr); while (heapIterator.Next()) { MethodDesc * pMethod = heapIterator.GetMethod(); diff --git a/src/coreclr/vm/profilingenumerators.cpp b/src/coreclr/vm/profilingenumerators.cpp index ef7b8d9c2f1818..50883da5ea8822 100644 --- a/src/coreclr/vm/profilingenumerators.cpp +++ b/src/coreclr/vm/profilingenumerators.cpp @@ -47,7 +47,7 @@ BOOL ProfilerFunctionEnum::Init(BOOL fWithReJITIDs) } CONTRACTL_END; - EECodeGenManager::CodeHeapIterator heapIterator(ExecutionManager::GetEEJitManager()); + EEJitManager::CodeHeapIterator heapIterator; while(heapIterator.Next()) { MethodDesc *pMD = heapIterator.GetMethod(); diff --git a/src/coreclr/vm/stackwalktypes.h b/src/coreclr/vm/stackwalktypes.h index 26764372994b00..c3990af8ca8fec 100644 --- a/src/coreclr/vm/stackwalktypes.h +++ b/src/coreclr/vm/stackwalktypes.h @@ -34,6 +34,7 @@ struct METHODTOKEN RangeSection * m_pRangeSection; // CodeHeader* for EEJitManager + // InterpreterCodeHeader* for InterpreterJitManager // PTR_RUNTIME_FUNCTION for managed native code TADDR m_pCodeHeader; From 9c2d92cf95d993f2bf9756ac370e21ad7939ff2b Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 3 Mar 2025 22:15:53 +0100 Subject: [PATCH 07/15] Fix Unix build failure The clang doesn't do late parsing of the template code, so the helpers cannot be in the .inl file as they reference some types that are not defined yet at that point. --- src/coreclr/vm/codeman.cpp | 163 ++++++++++++++++++++++++++++++++++ src/coreclr/vm/codeman.inl | 142 ----------------------------- src/coreclr/vm/jitinterface.h | 4 +- 3 files changed, 165 insertions(+), 144 deletions(-) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 00a746231291d7..1a9958826a8a04 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -3325,6 +3325,169 @@ void * EEJitManager::allocCodeFragmentBlock(size_t blockSize, unsigned alignment RETURN((void *)mem); } +template +BYTE* EECodeGenManager::allocGCInfo(TCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) +{ + CONTRACTL { + THROWS; + GC_NOTRIGGER; + } CONTRACTL_END; + + MethodDesc* pMD = pCodeHeader->GetMethodDesc(); + // sadly for light code gen I need the check in here. We should change GetJitMetaHeap + if (pMD->IsLCGMethod()) + { + CrstHolder ch(&m_CodeHeapCritSec); + pCodeHeader->SetGCInfo((BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize)); + } + else + { + pCodeHeader->SetGCInfo((BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize))); + } + _ASSERTE(pCodeHeader->GetGCInfo()); // AllocMem throws if there's not enough memory + + * pAllocationSize = blockSize; // Store the allocation size so we can backout later. + + return(pCodeHeader->GetGCInfo()); +} + +template +EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(TCodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) +{ + CONTRACTL { + THROWS; + GC_NOTRIGGER; + } CONTRACTL_END; + + // Note - pCodeHeader->phdrJitEHInfo - sizeof(size_t) contains the number of EH clauses + + DWORD temp = EE_ILEXCEPTION::Size(numClauses); + DWORD blockSize = 0; + if (!ClrSafeInt::addition(temp, sizeof(size_t), blockSize)) + COMPlusThrowOM(); + + BYTE *EHInfo = (BYTE*)allocEHInfoRaw(pCodeHeader->GetMethodDesc(), blockSize, pAllocationSize); + + pCodeHeader->SetEHInfo((EE_ILEXCEPTION*) (EHInfo + sizeof(size_t))); + pCodeHeader->GetEHInfo()->Init(numClauses); + *((size_t *)EHInfo) = numClauses; + return(pCodeHeader->GetEHInfo()); +} + +template +void EECodeGenManager::RemoveJitData(TCodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len) +{ + CONTRACTL { + NOTHROW; + GC_TRIGGERS; + } CONTRACTL_END; + + MethodDesc* pMD = pCHdr->GetMethodDesc(); + + void * codeStart = (void*)pCHdr->GetCodeStartAddress(); + + if (pMD->IsLCGMethod()) + { + { + CrstHolder ch(&m_CodeHeapCritSec); + + LCGMethodResolver * pResolver = pMD->AsDynamicMethodDesc()->GetLCGMethodResolver(); + + // Clear the pointer only if it matches what we are about to free. + // There can be cases where the JIT is reentered and we JITed the method multiple times. + if (pResolver->m_recordCodePointer == codeStart) + pResolver->m_recordCodePointer = NULL; + } + + // Remove the unwind information (if applicable) + UnpublishUnwindInfoForMethod((TADDR)codeStart); + + HostCodeHeap* pHeap = HostCodeHeap::GetCodeHeap((TADDR)codeStart); + FreeCodeMemory(pHeap, codeStart); + + // We are leaking GCInfo and EHInfo. They will be freed once the dynamic method is destroyed. + + return; + } + + { + CrstHolder ch(&m_CodeHeapCritSec); + + HeapList *pHp = GetCodeHeapList(); + + while (pHp && ((pHp->startAddress > (TADDR)pCHdr) || + (pHp->endAddress < (TADDR)codeStart))) + { + pHp = pHp->GetNext(); + } + + _ASSERTE(pHp && pHp->pHdrMap); + + // Better to just return than AV? + if (pHp == NULL) + return; + + NibbleMapDeleteUnlocked(pHp, (TADDR)codeStart); + } + + // Backout the GCInfo + if (GCinfo_len > 0) { + GetJitMetaHeap(pMD)->BackoutMem(pCHdr->GetGCInfo(), GCinfo_len); + } + + // Backout the EHInfo + BYTE *EHInfo = (BYTE *)pCHdr->GetEHInfo(); + if (EHInfo) { + EHInfo -= sizeof(size_t); + + _ASSERTE(EHinfo_len>0); + GetJitMetaHeap(pMD)->BackoutMem(EHInfo, EHinfo_len); + } + + // + // TODO: Although we have backout the GCInfo and EHInfo, we haven't actually backout the + // code buffer itself. As a result, we might leak the CodeHeap if jitting fails after + // the code buffer is allocated. + // + // However, it appears non-trivial to fix this. + // Here are some of the reasons: + // (1) AllocCode calls in AllocCodeRaw to alloc code buffer in the CodeHeap. The exact size + // of the code buffer is not known until the alignment is calculated deep on the stack. + // (2) AllocCodeRaw is called in 3 different places. We might need to remember the + // information for these places. + // (3) AllocCodeRaw might create a new CodeHeap. We should remember exactly which + // CodeHeap is used to allocate the code buffer. + // + // Fortunately, this is not a severe leak since the CodeHeap will be reclaimed on appdomain unload. + // + // + return; +} + +// Explicit instantiation of the templates so that they can be used externally without the bodies of the methods +// being in the header file. The bodies call methods of multiple data types that cannot be reasonably defined +// before the codeman.h is included. + +template +BYTE* EECodeGenManager::allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); + +template +EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); + +template +void EECodeGenManager::RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); + +#ifdef FEATURE_INTERPRETER +template +BYTE* EECodeGenManager::allocGCInfo(InterpreterCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); + +template +EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(InterpreterCodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); + +template +void EECodeGenManager::RemoveJitData(InterpreterCodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); +#endif // FEATURE_INTERPRETER + #endif // !DACCESS_COMPILE diff --git a/src/coreclr/vm/codeman.inl b/src/coreclr/vm/codeman.inl index 736d6101e8adc7..8af0fc0e48bfbd 100644 --- a/src/coreclr/vm/codeman.inl +++ b/src/coreclr/vm/codeman.inl @@ -13,145 +13,3 @@ inline TADDR IJitManager::JitTokenToModuleBase(const METHODTOKEN& MethodToken) { return MethodToken.m_pRangeSection->_range.RangeStart(); } - -#ifndef DACCESS_COMPILE -template -inline BYTE* EECodeGenManager::allocGCInfo(TCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) -{ - CONTRACTL { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - MethodDesc* pMD = pCodeHeader->GetMethodDesc(); - // sadly for light code gen I need the check in here. We should change GetJitMetaHeap - if (pMD->IsLCGMethod()) - { - CrstHolder ch(&m_CodeHeapCritSec); - pCodeHeader->SetGCInfo((BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize)); - } - else - { - pCodeHeader->SetGCInfo((BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize))); - } - _ASSERTE(pCodeHeader->GetGCInfo()); // AllocMem throws if there's not enough memory - - * pAllocationSize = blockSize; // Store the allocation size so we can backout later. - - return(pCodeHeader->GetGCInfo()); -} - -template -inline EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(TCodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) -{ - CONTRACTL { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - // Note - pCodeHeader->phdrJitEHInfo - sizeof(size_t) contains the number of EH clauses - - DWORD temp = EE_ILEXCEPTION::Size(numClauses); - DWORD blockSize = 0; - if (!ClrSafeInt::addition(temp, sizeof(size_t), blockSize)) - COMPlusThrowOM(); - - BYTE *EHInfo = (BYTE*)allocEHInfoRaw(pCodeHeader->GetMethodDesc(), blockSize, pAllocationSize); - - pCodeHeader->SetEHInfo((EE_ILEXCEPTION*) (EHInfo + sizeof(size_t))); - pCodeHeader->GetEHInfo()->Init(numClauses); - *((size_t *)EHInfo) = numClauses; - return(pCodeHeader->GetEHInfo()); -} - -template -void EEJitManager::RemoveJitData(TCodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len) -{ - CONTRACTL { - NOTHROW; - GC_TRIGGERS; - } CONTRACTL_END; - - MethodDesc* pMD = pCHdr->GetMethodDesc(); - - void * codeStart = (void*)pCHdr->GetCodeStartAddress(); - - if (pMD->IsLCGMethod()) - { - { - CrstHolder ch(&m_CodeHeapCritSec); - - LCGMethodResolver * pResolver = pMD->AsDynamicMethodDesc()->GetLCGMethodResolver(); - - // Clear the pointer only if it matches what we are about to free. - // There can be cases where the JIT is reentered and we JITed the method multiple times. - if (pResolver->m_recordCodePointer == codeStart) - pResolver->m_recordCodePointer = NULL; - } - - // Remove the unwind information (if applicable) - UnpublishUnwindInfoForMethod((TADDR)codeStart); - - HostCodeHeap* pHeap = HostCodeHeap::GetCodeHeap((TADDR)codeStart); - FreeCodeMemory(pHeap, codeStart); - - // We are leaking GCInfo and EHInfo. They will be freed once the dynamic method is destroyed. - - return; - } - - { - CrstHolder ch(&m_CodeHeapCritSec); - - HeapList *pHp = GetCodeHeapList(); - - while (pHp && ((pHp->startAddress > (TADDR)pCHdr) || - (pHp->endAddress < (TADDR)codeStart))) - { - pHp = pHp->GetNext(); - } - - _ASSERTE(pHp && pHp->pHdrMap); - - // Better to just return than AV? - if (pHp == NULL) - return; - - NibbleMapDeleteUnlocked(pHp, (TADDR)codeStart); - } - - // Backout the GCInfo - if (GCinfo_len > 0) { - GetJitMetaHeap(pMD)->BackoutMem(pCHdr->GetGCInfo(), GCinfo_len); - } - - // Backout the EHInfo - BYTE *EHInfo = (BYTE *)pCHdr->GetEHInfo(); - if (EHInfo) { - EHInfo -= sizeof(size_t); - - _ASSERTE(EHinfo_len>0); - GetJitMetaHeap(pMD)->BackoutMem(EHInfo, EHinfo_len); - } - - // - // TODO: Although we have backout the GCInfo and EHInfo, we haven't actually backout the - // code buffer itself. As a result, we might leak the CodeHeap if jitting fails after - // the code buffer is allocated. - // - // However, it appears non-trivial to fix this. - // Here are some of the reasons: - // (1) AllocCode calls in AllocCodeRaw to alloc code buffer in the CodeHeap. The exact size - // of the code buffer is not known until the alignment is calculated deep on the stack. - // (2) AllocCodeRaw is called in 3 different places. We might need to remember the - // information for these places. - // (3) AllocCodeRaw might create a new CodeHeap. We should remember exactly which - // CodeHeap is used to allocate the code buffer. - // - // Fortunately, this is not a severe leak since the CodeHeap will be reclaimed on appdomain unload. - // - // - return; -} - -#endif // DACCESS_COMPILE \ No newline at end of file diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index f5c4ea13f328e6..b39ecb06e58bb4 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -824,7 +824,7 @@ class CEEJitInfo : public CEECodeGenInfo uint32_t getExpectedTargetArchitecture() override final; void BackoutJitData(EECodeGenManager * jitMgr) override final; - void SetDebugInfo(PTR_BYTE pDebugInfo); + void SetDebugInfo(PTR_BYTE pDebugInfo) override final; void ResetForJitRetry() { @@ -1084,7 +1084,7 @@ class CInterpreterJitInfo : public CEECodeGenInfo void WriteCode(EECodeGenManager * jitMgr) override final; void BackoutJitData(EECodeGenManager * jitMgr) override final; - void SetDebugInfo(PTR_BYTE pDebugInfo); + void SetDebugInfo(PTR_BYTE pDebugInfo) override final; void ResetForJitRetry() { From 54e39114688ef1334271d957add0e0c4834b9620 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 5 Mar 2025 00:42:00 +0100 Subject: [PATCH 08/15] Fix a bug --- src/coreclr/vm/dynamicmethod.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/dynamicmethod.cpp b/src/coreclr/vm/dynamicmethod.cpp index 867724b02cb618..847bea4b1bfcbf 100644 --- a/src/coreclr/vm/dynamicmethod.cpp +++ b/src/coreclr/vm/dynamicmethod.cpp @@ -699,6 +699,7 @@ void* HostCodeHeap::AllocMemForCode_NoThrow(size_t header, size_t size, DWORD al // Assert the later fact here. _ASSERTE(HOST_CODEHEAP_SIZE_ALIGN >= BYTES_PER_BUCKET); + size_t codeHeaderSize = header; header += sizeof(TrackAllocation*); TrackAllocation* pTracker = AllocMemory_NoThrow(header, size, alignment, reserveForJumpStubs); @@ -708,7 +709,7 @@ void* HostCodeHeap::AllocMemForCode_NoThrow(size_t header, size_t size, DWORD al BYTE * pCode = ALIGN_UP((BYTE*)(pTracker + 1) + header, alignment); // Pointer to the TrackAllocation record is stored just before the code header - void * pHdr = pCode - header; + void * pHdr = pCode - codeHeaderSize; ExecutableWriterHolder trackerWriterHolder((TrackAllocation **)(pHdr) - 1, sizeof(TrackAllocation *)); *trackerWriterHolder.GetRW() = pTracker; From a2b1d1bea33ba7da70a4045db42a263486180d33 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 5 Mar 2025 09:58:29 +0100 Subject: [PATCH 09/15] Fix build break --- src/coreclr/vm/dynamicmethod.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/coreclr/vm/dynamicmethod.cpp b/src/coreclr/vm/dynamicmethod.cpp index 847bea4b1bfcbf..2fc4698f2b3b4e 100644 --- a/src/coreclr/vm/dynamicmethod.cpp +++ b/src/coreclr/vm/dynamicmethod.cpp @@ -690,7 +690,11 @@ void* HostCodeHeap::AllocMemForCode_NoThrow(size_t header, size_t size, DWORD al } CONTRACTL_END; +#ifdef FEATURE_INTERPRETER _ASSERTE(header == sizeof(CodeHeader) || header == sizeof(InterpreterCodeHeader)); +#else + _ASSERTE(header == sizeof(CodeHeader)); +#endif _ASSERTE(alignment <= HOST_CODEHEAP_SIZE_ALIGN); // The code allocator has to guarantee that there is only one entrypoint per nibble map entry. From 0ddc4486752f88afdb1542dc9da34391943629af Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 10 Mar 2025 22:22:54 +0100 Subject: [PATCH 10/15] Add dummy ICodeManager derived InterpreterCodeManager --- src/coreclr/inc/dacvars.h | 1 + src/coreclr/inc/eetwain.h | 277 +++++++++++++++++++++++++++++ src/coreclr/inc/vptr_list.h | 1 + src/coreclr/vm/codeman.cpp | 25 ++- src/coreclr/vm/codeman.h | 9 +- src/coreclr/vm/common.h | 3 + src/coreclr/vm/eetwain.cpp | 57 ++++++ src/coreclr/vm/loaderallocator.cpp | 2 +- 8 files changed, 364 insertions(+), 11 deletions(-) diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index 585f700f7e1c7a..b43cb3fd5eff51 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -86,6 +86,7 @@ DEFINE_DACVAR(PTR_ReadyToRunJitManager, ExecutionManager__m_pReadyToRunJitManage #endif #ifdef FEATURE_INTERPRETER DEFINE_DACVAR(PTR_InterpreterJitManager, ExecutionManager__m_pInterpreterJitManager, ExecutionManager::m_pInterpreterJitManager) +DEFINE_DACVAR(PTR_InterpreterCodeManager, ExecutionManager__m_pInterpreterCodeMan, ExecutionManager::m_pInterpreterCodeMan) #endif DEFINE_DACVAR_NO_DUMP(VMHELPDEF *, dac__hlpFuncTable, ::hlpFuncTable) diff --git a/src/coreclr/inc/eetwain.h b/src/coreclr/inc/eetwain.h index e229ae1fe29d38..74c17d0416ec4d 100644 --- a/src/coreclr/inc/eetwain.h +++ b/src/coreclr/inc/eetwain.h @@ -646,6 +646,283 @@ struct CodeManStateBuf #endif +#ifdef FEATURE_INTERPRETER + +class InterpreterCodeManager : public ICodeManager { + + VPTR_VTABLE_CLASS_AND_CTOR(InterpreterCodeManager, ICodeManager) + +public: + + +#ifndef DACCESS_COMPILE +#ifndef FEATURE_EH_FUNCLETS +/* + Last chance for the runtime support to do fixups in the context + before execution continues inside a filter, catch handler, or finally +*/ +virtual +void FixContext(ContextType ctxType, + EHContext *ctx, + EECodeInfo *pCodeInfo, + DWORD dwRelOffset, + DWORD nestingLevel, + OBJECTREF thrownObject, + CodeManState *pState, + size_t ** ppShadowSP, // OUT + size_t ** ppEndRegion) // OUT +{ + _ASSERTE(FALSE); +} +#endif // !FEATURE_EH_FUNCLETS +#endif // !DACCESS_COMPILE + +#ifdef TARGET_X86 +/* + Gets the ambient stack pointer value at the given nesting level within + the method. +*/ +virtual +TADDR GetAmbientSP(PREGDISPLAY pContext, + EECodeInfo *pCodeInfo, + DWORD dwRelOffset, + DWORD nestingLevel, + CodeManState *pState) +{ + _ASSERTE(FALSE); + return NULL; +} +#endif // TARGET_X86 + +/* + Get the number of bytes used for stack parameters. + This is currently only used on x86. +*/ +virtual +ULONG32 GetStackParameterSize(EECodeInfo* pCodeInfo) +{ + _ASSERTE(FALSE); + return 0; +} + +/* + Unwind the current stack frame, i.e. update the virtual register + set in pContext. This will be similar to the state after the function + returns back to caller (IP points to after the call, Frame and Stack + pointer has been reset, callee-saved registers restored + (if UpdateAllRegs), callee-UNsaved registers are trashed) + Returns success of operation. +*/ +virtual +bool UnwindStackFrame( + PREGDISPLAY pContext, + EECodeInfo *pCodeInfo, + unsigned flags, + CodeManState *pState); + +/* + Is the function currently at a "GC safe point" ? + Can call EnumGcRefs() successfully +*/ +virtual +bool IsGcSafe( EECodeInfo *pCodeInfo, + DWORD dwRelOffset); + +#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) +virtual +bool HasTailCalls(EECodeInfo *pCodeInfo) +{ + _ASSERTE(FALSE); + return false; +} +#endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || defined(TARGET_RISCV64) + +#if defined(TARGET_AMD64) && defined(_DEBUG) +/* + Locates the end of the last interruptible region in the given code range. + Returns 0 if the entire range is uninterruptible. Returns the end point + if the entire range is interruptible. +*/ +virtual +unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset, + unsigned endOffset, + GCInfoToken gcInfoToken) +{ + _ASSERTE(FALSE); + return 0; +} +#endif // TARGET_AMD64 && _DEBUG + +/* + Enumerate all live object references in that function using + the virtual register set. Same reference location cannot be enumerated + multiple times (but all differenct references pointing to the same + object have to be individually enumerated). + Returns success of operation. +*/ +virtual +bool EnumGcRefs(PREGDISPLAY pContext, + EECodeInfo *pCodeInfo, + unsigned flags, + GCEnumCallback pCallback, + LPVOID hCallBack, + DWORD relOffsetOverride = NO_OVERRIDE_OFFSET); + +virtual +OBJECTREF GetInstance( + PREGDISPLAY pContext, + EECodeInfo * pCodeInfo); + +/* + Returns the extra argument passed to shared generic code if it is still alive. + Returns NULL in all other cases. +*/ +virtual +PTR_VOID GetParamTypeArg(PREGDISPLAY pContext, + EECodeInfo * pCodeInfo); + +// Returns the type of the context parameter (this, methodtable, methoddesc, or none) +virtual GenericParamContextType GetParamContextType(PREGDISPLAY pContext, + EECodeInfo * pCodeInfo); + +/* + Returns the offset of the GuardStack cookie if it exists. + Returns NULL if there is no cookie. +*/ +virtual +void * GetGSCookieAddr(PREGDISPLAY pContext, + EECodeInfo * pCodeInfo, + unsigned flags, + CodeManState * pState) +{ + _ASSERTE(FALSE); + return NULL; +} + + +#ifndef USE_GC_INFO_DECODER +/* + Returns true if the given IP is in the given method's prolog or an epilog. +*/ +virtual +bool IsInPrologOrEpilog( + DWORD relOffset, + GCInfoToken gcInfoToken, + size_t* prologSize) +{ + _ASSERTE(FALSE); + return false; +} + +/* + Returns true if the given IP is in the synchronized region of the method (valid for synchronized functions only) +*/ +virtual +bool IsInSynchronizedRegion( + DWORD relOffset, + GCInfoToken gcInfoToken, + unsigned flags) +{ + _ASSERTE(FALSE); + return false; +} +#endif // !USE_GC_INFO_DECODER + +/* + Returns the size of a given function. +*/ +virtual +size_t GetFunctionSize(GCInfoToken gcInfoToken); + +/* +* Get information necessary for return address hijacking of the method represented by the gcInfoToken. +* If it can be hijacked, it sets the returnKind output parameter to the kind of the return value and +* returns true. +* If hijacking is not possible for some reason, it return false. +*/ +virtual bool GetReturnAddressHijackInfo(GCInfoToken gcInfoToken X86_ARG(ReturnKind * returnKind)) +{ + _ASSERTE(FALSE); + return false; +} + +#ifndef USE_GC_INFO_DECODER +/* + Returns the size of the frame (barring localloc) +*/ +virtual +unsigned int GetFrameSize(GCInfoToken gcInfoToken) +{ + _ASSERTE(FALSE); + return 0; +} +#endif // USE_GC_INFO_DECODER + +#ifndef DACCESS_COMPILE + +#ifndef FEATURE_EH_FUNCLETS +virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg) +{ + _ASSERTE(FALSE); + return NULL; +} + +virtual BOOL IsInFilter(GCInfoToken gcInfoToken, + unsigned offset, + PCONTEXT pCtx, + DWORD curNestLevel) +{ + _ASSERTE(FALSE); + return FALSE; +} +virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, + unsigned offset, + PCONTEXT pCtx) +{ + _ASSERTE(FALSE); + return FALSE; +} + +virtual void LeaveCatch(GCInfoToken gcInfoToken, + unsigned offset, + PCONTEXT pCtx) +{ + _ASSERTE(FALSE); +} +#endif // FEATURE_EH_FUNCLETS + +#ifdef FEATURE_REMAP_FUNCTION +/* + Last chance for the runtime support to do fixups in the context + before execution continues inside an EnC updated function. +*/ +virtual +HRESULT FixContextForEnC(PCONTEXT pCtx, + EECodeInfo * pOldCodeInfo, + const ICorDebugInfo::NativeVarInfo * oldMethodVars, + SIZE_T oldMethodVarsCount, + EECodeInfo * pNewCodeInfo, + const ICorDebugInfo::NativeVarInfo * newMethodVars, + SIZE_T newMethodVarsCount) +{ + _ASSERTE(FALSE); + return E_NOTIMPL; +} +#endif // FEATURE_REMAP_FUNCTION + +#endif // !DACCESS_COMPILE + +#ifdef DACCESS_COMPILE + virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) + { + // Nothing to do + } +#endif + +}; + +#endif // FEATURE_INTERPRETER + //***************************************************************************** #endif // _EETWAIN_H //***************************************************************************** diff --git a/src/coreclr/inc/vptr_list.h b/src/coreclr/inc/vptr_list.h index 761d79b1fa59ec..b5581b019478b5 100644 --- a/src/coreclr/inc/vptr_list.h +++ b/src/coreclr/inc/vptr_list.h @@ -11,6 +11,7 @@ VPTR_CLASS(ReadyToRunJitManager) #endif #ifdef FEATURE_INTERPRETER VPTR_CLASS(InterpreterJitManager) +VPTR_CLASS(InterpreterCodeManager) #endif VPTR_CLASS(EECodeManager) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 1a9958826a8a04..a9316e72f86f2c 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -55,6 +55,7 @@ SPTR_IMPL(ReadyToRunJitManager, ExecutionManager, m_pReadyToRunJitManager); #ifdef FEATURE_INTERPRETER SPTR_IMPL(InterpreterJitManager, ExecutionManager, m_pInterpreterJitManager); +SPTR_IMPL(InterpreterCodeManager, ExecutionManager, m_pInterpreterCodeMan); #endif SVAL_IMPL(RangeSectionMapData, ExecutionManager, g_codeRangeMap); @@ -2731,14 +2732,14 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, // Avoid going through the full list in the common case - try to use the most recently used codeheap if (pInfo->IsDynamicDomain()) { -#ifdef FEATURE_INTERPRETER +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap; pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap = NULL; } else -#endif // FEATURE_INTERPRETER +#endif // FEATURE_INTERPRETER { pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap; pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = NULL; @@ -2746,14 +2747,14 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, } else { -#ifdef FEATURE_INTERPRETER +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap; pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap = NULL; } else -#endif // FEATURE_INTERPRETER +#endif // FEATURE_INTERPRETER { pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedCodeHeap; pInfo->m_pAllocator->m_pLastUsedCodeHeap = NULL; @@ -2812,20 +2813,20 @@ void* EECodeGenManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, if (pInfo->IsDynamicDomain()) { -#ifdef FEATURE_INTERPRETER +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap = pCodeHeap; } else -#endif // FEATURE_INTERPRETER +#endif // FEATURE_INTERPRETER { pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = pCodeHeap; } } else { -#ifdef FEATURE_INTERPRETER +#ifdef FEATURE_INTERPRETER if (pInfo->IsInterpreted()) { pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap = pCodeHeap; @@ -2907,7 +2908,7 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser #endif SIZE_T realHeaderSize; -#ifdef FEATURE_INTERPRETER +#ifdef FEATURE_INTERPRETER if (std::is_same::value) { #ifdef FEATURE_EH_FUNCLETS @@ -2919,7 +2920,7 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser realHeaderSize = sizeof(InterpreterRealCodeHeader); } else -#endif // FEATURE_INTERPRETER +#endif // FEATURE_INTERPRETER { requestInfo.setReserveForJumpStubs(reserveForJumpStubs); @@ -3734,6 +3735,7 @@ InterpreterJitManager::InterpreterJitManager() : m_interpreterLoadCritSec(CrstSingleUseLock) { LIMITED_METHOD_CONTRACT; + SetCodeManager(ExecutionManager::GetInterpreterCodeManager()); } BOOL InterpreterJitManager::LoadInterpreter() @@ -4882,6 +4884,7 @@ void ExecutionManager::Init() #endif #ifdef FEATURE_INTERPRETER + m_pInterpreterCodeMan = new InterpreterCodeManager(); m_pInterpreterJitManager = new InterpreterJitManager(); #endif } @@ -5386,6 +5389,10 @@ void ExecutionManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) GetCodeRangeMap().EnumMem(); m_pDefaultCodeMan.EnumMem(); +#ifdef FEATURE_INTERPRETER + m_pInterpreterCodeMan.EnumMem(); +#endif // FEATURE_INTERPRETER + // // Walk structures and report. // diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 7aff613aa5407b..42b624de8faabe 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -2267,6 +2267,12 @@ class ExecutionManager #ifdef FEATURE_INTERPRETER static LPCWSTR GetInterpreterName(); + + static ICodeManager* GetInterpreterCodeManager() + { + LIMITED_METHOD_CONTRACT; + return (ICodeManager *)m_pInterpreterCodeMan; + } #endif // FEATURE_INTERPRETER static void Unload(LoaderAllocator *pLoaderAllocator); @@ -2328,8 +2334,9 @@ class ExecutionManager #ifdef FEATURE_READYTORUN SPTR_DECL(ReadyToRunJitManager, m_pReadyToRunJitManager); #endif -#ifdef FEATURE_READYTORUN +#ifdef FEATURE_INTERPRETER SPTR_DECL(InterpreterJitManager, m_pInterpreterJitManager); + SPTR_DECL(InterpreterCodeManager, m_pInterpreterCodeMan); #endif static CrstStatic m_JumpStubCrst; diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h index 7234839e886b86..3d4ff5e9610065 100644 --- a/src/coreclr/vm/common.h +++ b/src/coreclr/vm/common.h @@ -123,6 +123,9 @@ typedef VPTR(class EditAndContinueModule) PTR_EditAndContinueModule; typedef DPTR(class EEClass) PTR_EEClass; typedef DPTR(class DelegateEEClass) PTR_DelegateEEClass; typedef VPTR(class EECodeManager) PTR_EECodeManager; +#ifdef FEATURE_INTERPRETER +typedef VPTR(class InterpreterCodeManager) PTR_InterpreterCodeManager; +#endif typedef DPTR(class RangeSectionMap) PTR_RangeSectionMap; typedef DPTR(class EEConfig) PTR_EEConfig; typedef VPTR(class EEDbgInterfaceImpl) PTR_EEDbgInterfaceImpl; diff --git a/src/coreclr/vm/eetwain.cpp b/src/coreclr/vm/eetwain.cpp index 0c06eaf159e6f3..0ad9cf9fda95ff 100644 --- a/src/coreclr/vm/eetwain.cpp +++ b/src/coreclr/vm/eetwain.cpp @@ -2394,3 +2394,60 @@ ULONG32 EECodeManager::GetStackParameterSize(EECodeInfo * pCodeInfo) #endif // TARGET_X86 } +#ifdef FEATURE_INTERPRETER + +bool InterpreterCodeManager::UnwindStackFrame(PREGDISPLAY pContext, + EECodeInfo *pCodeInfo, + unsigned flags, + CodeManState *pState) +{ + // Interpreter-TODO: Implement this + return false; +} + +bool InterpreterCodeManager::IsGcSafe(EECodeInfo *pCodeInfo, + DWORD dwRelOffset) +{ + // Interpreter-TODO: Implement this + return true; +} + +bool InterpreterCodeManager::EnumGcRefs(PREGDISPLAY pContext, + EECodeInfo *pCodeInfo, + unsigned flags, + GCEnumCallback pCallback, + LPVOID hCallBack, + DWORD relOffsetOverride) +{ + // Interpreter-TODO: Implement this + return false; +} + +OBJECTREF InterpreterCodeManager::GetInstance(PREGDISPLAY pContext, + EECodeInfo * pCodeInfo) +{ + // Interpreter-TODO: Implement this + return NULL; +} + +PTR_VOID InterpreterCodeManager::GetParamTypeArg(PREGDISPLAY pContext, + EECodeInfo * pCodeInfo) +{ + // Interpreter-TODO: Implement this + return NULL; +} + +GenericParamContextType InterpreterCodeManager::GetParamContextType(PREGDISPLAY pContext, + EECodeInfo * pCodeInfo) +{ + // Interpreter-TODO: Implement this + return GENERIC_PARAM_CONTEXT_NONE; +} + +size_t InterpreterCodeManager::GetFunctionSize(GCInfoToken gcInfoToken) +{ + // Interpreter-TODO: Implement this + return 0; +} + +#endif // FEATURE_INTERPRETER \ No newline at end of file diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index fe23d482c9538d..e58ad1b4ec3e1e 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -70,7 +70,7 @@ LoaderAllocator::LoaderAllocator(bool collectible) : m_pVSDHeapInitialAlloc = NULL; m_pLastUsedCodeHeap = NULL; m_pLastUsedDynamicCodeHeap = NULL; -#ifdef FEATURE_INTERPRETER +#ifdef FEATURE_INTERPRETER m_pLastUsedInterpreterCodeHeap = NULL; m_pLastUsedInterpreterDynamicCodeHeap = NULL; #endif // FEATURE_INTERPRETER From 87068a87b786234825a6bc4efc256cec166a6aeb Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 10 Mar 2025 22:38:46 +0100 Subject: [PATCH 11/15] Remove unused ICodeManager methods --- src/coreclr/inc/eetwain.h | 56 ------------------ src/coreclr/vm/eetwain.cpp | 117 ------------------------------------- 2 files changed, 173 deletions(-) diff --git a/src/coreclr/inc/eetwain.h b/src/coreclr/inc/eetwain.h index 74c17d0416ec4d..9d8dbb9c98993a 100644 --- a/src/coreclr/inc/eetwain.h +++ b/src/coreclr/inc/eetwain.h @@ -217,17 +217,6 @@ virtual bool IsGcSafe(EECodeInfo *pCodeInfo, virtual bool HasTailCalls(EECodeInfo *pCodeInfo) = 0; #endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64 -#if defined(TARGET_AMD64) && defined(_DEBUG) -/* - Locates the end of the last interruptible region in the given code range. - Returns 0 if the entire range is uninterruptible. Returns the end point - if the entire range is interruptible. -*/ -virtual unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset, - unsigned endOffset, - GCInfoToken gcInfoToken) = 0; -#endif // TARGET_AMD64 && _DEBUG - /* Enumerate all live object references in that function using the virtual register set. Same reference location cannot be enumerated @@ -321,11 +310,6 @@ virtual unsigned int GetFrameSize(GCInfoToken gcInfoToken) = 0; #ifndef FEATURE_EH_FUNCLETS virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg)=0; -virtual BOOL IsInFilter(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx, - DWORD curNestLevel) = 0; - virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, unsigned offset, PCONTEXT pCtx) = 0; @@ -462,18 +446,6 @@ virtual bool HasTailCalls(EECodeInfo *pCodeInfo); #endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || defined(TARGET_RISCV64) -#if defined(TARGET_AMD64) && defined(_DEBUG) -/* - Locates the end of the last interruptible region in the given code range. - Returns 0 if the entire range is uninterruptible. Returns the end point - if the entire range is interruptible. -*/ -virtual -unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset, - unsigned endOffset, - GCInfoToken gcInfoToken); -#endif // TARGET_AMD64 && _DEBUG - /* Enumerate all live object references in that function using the virtual register set. Same reference location cannot be enumerated @@ -588,10 +560,6 @@ unsigned int GetFrameSize(GCInfoToken gcInfoToken); #ifndef FEATURE_EH_FUNCLETS virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg); -virtual BOOL IsInFilter(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx, - DWORD curNestLevel); virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, unsigned offset, PCONTEXT pCtx); @@ -737,22 +705,6 @@ bool HasTailCalls(EECodeInfo *pCodeInfo) } #endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || defined(TARGET_RISCV64) -#if defined(TARGET_AMD64) && defined(_DEBUG) -/* - Locates the end of the last interruptible region in the given code range. - Returns 0 if the entire range is uninterruptible. Returns the end point - if the entire range is interruptible. -*/ -virtual -unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset, - unsigned endOffset, - GCInfoToken gcInfoToken) -{ - _ASSERTE(FALSE); - return 0; -} -#endif // TARGET_AMD64 && _DEBUG - /* Enumerate all live object references in that function using the virtual register set. Same reference location cannot be enumerated @@ -867,14 +819,6 @@ virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg) return NULL; } -virtual BOOL IsInFilter(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx, - DWORD curNestLevel) -{ - _ASSERTE(FALSE); - return FALSE; -} virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, unsigned offset, PCONTEXT pCtx) diff --git a/src/coreclr/vm/eetwain.cpp b/src/coreclr/vm/eetwain.cpp index 0ad9cf9fda95ff..67d4ba822cb7ad 100644 --- a/src/coreclr/vm/eetwain.cpp +++ b/src/coreclr/vm/eetwain.cpp @@ -872,86 +872,6 @@ bool EECodeManager::HasTailCalls( EECodeInfo *pCodeInfo) } #endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64 -#if defined(TARGET_AMD64) && defined(_DEBUG) - -struct FindEndOfLastInterruptibleRegionState -{ - unsigned curOffset; - unsigned endOffset; - unsigned lastRangeOffset; -}; - -bool FindEndOfLastInterruptibleRegionCB ( - UINT32 startOffset, - UINT32 stopOffset, - LPVOID hCallback) -{ - FindEndOfLastInterruptibleRegionState *pState = (FindEndOfLastInterruptibleRegionState*)hCallback; - - // - // If the current range doesn't overlap the given range, keep searching. - // - if ( startOffset >= pState->endOffset - || stopOffset < pState->curOffset) - { - return false; - } - - // - // If the range overlaps the end, then the last point is the end. - // - if ( stopOffset > pState->endOffset - /*&& startOffset < pState->endOffset*/) - { - // The ranges should be sorted in increasing order. - CONSISTENCY_CHECK(startOffset >= pState->lastRangeOffset); - - pState->lastRangeOffset = pState->endOffset; - return true; - } - - // - // See if the end of this range is the closet to the end that we've found - // so far. - // - if (stopOffset > pState->lastRangeOffset) - pState->lastRangeOffset = stopOffset; - - return false; -} - -/* - Locates the end of the last interruptible region in the given code range. - Returns 0 if the entire range is uninterruptible. Returns the end point - if the entire range is interruptible. -*/ -unsigned EECodeManager::FindEndOfLastInterruptibleRegion(unsigned curOffset, - unsigned endOffset, - GCInfoToken gcInfoToken) -{ -#ifndef DACCESS_COMPILE - GcInfoDecoder gcInfoDecoder( - gcInfoToken, - DECODE_FOR_RANGES_CALLBACK - ); - - FindEndOfLastInterruptibleRegionState state; - state.curOffset = curOffset; - state.endOffset = endOffset; - state.lastRangeOffset = 0; - - gcInfoDecoder.EnumerateInterruptibleRanges(&FindEndOfLastInterruptibleRegionCB, &state); - - return state.lastRangeOffset; -#else - DacNotImpl(); - return 0; -#endif // #ifndef DACCESS_COMPILE -} - -#endif // TARGET_AMD64 && _DEBUG - - #else // !USE_GC_INFO_DECODER /***************************************************************************** @@ -2142,43 +2062,6 @@ const BYTE* EECodeManager::GetFinallyReturnAddr(PREGDISPLAY pReg) return *(const BYTE**)(size_t)(GetRegdisplaySP(pReg)); } -BOOL EECodeManager::IsInFilter(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx, - DWORD curNestLevel) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - /* Extract the necessary information from the info block header */ - - hdrInfo info; - - DecodeGCHdrInfo(gcInfoToken, - offset, - &info); - - /* make sure that we have an ebp stack frame */ - - _ASSERTE(info.ebpFrame); - _ASSERTE(info.handlers); // This will always be set. Remove it - - TADDR baseSP; - DWORD nestingLevel; - - FrameType frameType = GetHandlerFrameInfo(&info, pCtx->Ebp, - pCtx->Esp, (DWORD) IGNORE_VAL, - &baseSP, &nestingLevel); - _ASSERTE(frameType != FR_INVALID); - -// _ASSERTE(nestingLevel == curNestLevel); - - return frameType == FR_FILTER; -} - - BOOL EECodeManager::LeaveFinally(GCInfoToken gcInfoToken, unsigned offset, PCONTEXT pCtx) From 5998460de4cb38ef3a2d00662d930539f4d54e79 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 12 Mar 2025 17:48:13 +0100 Subject: [PATCH 12/15] PR feedback --- src/coreclr/vm/jitinterface.h | 66 +++++++++---------- .../JIT/interpreter/InterpreterTester.cs | 6 +- 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index b39ecb06e58bb4..910caefa45ac90 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -762,23 +762,23 @@ class CEECodeGenInfo : public CEEInfo // CEEJitInfo is the concrete implementation of callbacks that the EE must provide for the JIT to do its // work. See code:ICorJitInfo#JitToEEInterface for more on this interface. -class CEEJitInfo : public CEECodeGenInfo +class CEEJitInfo final : public CEECodeGenInfo { public: // ICorJitInfo stuff - void allocMem (AllocMemArgs *pArgs) override final; - void * allocGCInfo(size_t size) override final; - virtual void setEHcount (unsigned cEH) override final; + void allocMem (AllocMemArgs *pArgs) override; + void * allocGCInfo(size_t size) override; + virtual void setEHcount (unsigned cEH) override; virtual void setEHinfo ( unsigned EHnumber, const CORINFO_EH_CLAUSE* clause - ) override final; + ) override; void WriteCodeBytes(); - void WriteCode(EECodeGenManager * jitMgr) override final; + void WriteCode(EECodeGenManager * jitMgr) override; - void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unwindSize) override final; + void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unwindSize) override; void allocUnwindInfo ( uint8_t * pHotCode, /* IN */ @@ -788,14 +788,14 @@ class CEEJitInfo : public CEECodeGenInfo uint32_t unwindSize, /* IN */ uint8_t * pUnwindBlock, /* IN */ CorJitFuncKind funcKind /* IN */ - ) override final; + ) override; HRESULT allocPgoInstrumentationBySchema( CORINFO_METHOD_HANDLE ftnHnd, /* IN */ PgoInstrumentationSchema* pSchema, /* IN/OUT */ uint32_t countSchemaItems, /* IN */ uint8_t** pInstrumentationData /* OUT */ - ) override final; + ) override; HRESULT getPgoInstrumentationResults( CORINFO_METHOD_HANDLE ftnHnd, /* IN */ @@ -804,27 +804,27 @@ class CEEJitInfo : public CEECodeGenInfo uint8_t**pInstrumentationData, /* OUT */ PgoSource *pPgoSource, /* OUT */ bool* pDynamicPgo /* OUT */ - ) override final; + ) override; void recordCallSite( uint32_t instrOffset, /* IN */ CORINFO_SIG_INFO * callSig, /* IN */ CORINFO_METHOD_HANDLE methodHandle /* IN */ - ) override final; + ) override; void recordRelocation( void *location, void *locationRW, void *target, uint16_t fRelocType, - int32_t addlDelta) override final; + int32_t addlDelta) override; - uint16_t getRelocTypeHint(void * target) override final; + uint16_t getRelocTypeHint(void * target) override; - uint32_t getExpectedTargetArchitecture() override final; + uint32_t getExpectedTargetArchitecture() override; - void BackoutJitData(EECodeGenManager * jitMgr) override final; - void SetDebugInfo(PTR_BYTE pDebugInfo) override final; + void BackoutJitData(EECodeGenManager * jitMgr) override; + void SetDebugInfo(PTR_BYTE pDebugInfo) override; void ResetForJitRetry() { @@ -891,7 +891,7 @@ class CEEJitInfo : public CEECodeGenInfo m_reserveForJumpStubs = value; } - virtual PatchpointInfo* GetPatchpointInfo() override final + virtual PatchpointInfo* GetPatchpointInfo() override { #ifdef FEATURE_ON_STACK_REPLACEMENT return m_pPatchpointInfoFromJit; @@ -985,7 +985,7 @@ class CEEJitInfo : public CEECodeGenInfo } void* getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ - void ** ppIndirection) override final; /* OUT */ + void ** ppIndirection) override; /* OUT */ static PCODE getHelperFtnStatic(CorInfoHelpFunc ftnNum); // Override of CEEInfo::GetProfilingHandle. The first time this is called for a @@ -997,15 +997,15 @@ class CEEJitInfo : public CEECodeGenInfo bool *pbHookFunction, void **pProfilerHandle, bool *pbIndirectedHandles - ) override final; + ) override; - InfoAccessType constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok, void **ppValue) override final; - InfoAccessType emptyStringLiteral(void ** ppValue) override final; - CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override final; - void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override final; + InfoAccessType constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok, void **ppValue) override; + InfoAccessType emptyStringLiteral(void ** ppValue) override; + CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override; + void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override; - void setPatchpointInfo(PatchpointInfo* patchpointInfo) override final; - PatchpointInfo* getOSRInfo(unsigned* ilOffset) override final; + void setPatchpointInfo(PatchpointInfo* patchpointInfo) override; + PatchpointInfo* getOSRInfo(unsigned* ilOffset) override; protected : @@ -1055,7 +1055,7 @@ protected : }; #ifdef FEATURE_INTERPRETER -class CInterpreterJitInfo : public CEECodeGenInfo +class CInterpreterJitInfo final : public CEECodeGenInfo { public: // ICorJitInfo stuff @@ -1072,19 +1072,19 @@ class CInterpreterJitInfo : public CEECodeGenInfo } CONTRACTL_END; } - void allocMem(AllocMemArgs *pArgs) override final; - void * allocGCInfo(size_t size) override final; - virtual void setEHcount (unsigned cEH) override final; + void allocMem(AllocMemArgs *pArgs) override; + void * allocGCInfo(size_t size) override; + virtual void setEHcount (unsigned cEH) override; virtual void setEHinfo ( unsigned EHnumber, const CORINFO_EH_CLAUSE* clause - ) override final; + ) override; void WriteCodeBytes(); - void WriteCode(EECodeGenManager * jitMgr) override final; + void WriteCode(EECodeGenManager * jitMgr) override; - void BackoutJitData(EECodeGenManager * jitMgr) override final; - void SetDebugInfo(PTR_BYTE pDebugInfo) override final; + void BackoutJitData(EECodeGenManager * jitMgr) override; + void SetDebugInfo(PTR_BYTE pDebugInfo) override; void ResetForJitRetry() { diff --git a/src/tests/JIT/interpreter/InterpreterTester.cs b/src/tests/JIT/interpreter/InterpreterTester.cs index fafbc331ba2178..f06c22965d4234 100644 --- a/src/tests/JIT/interpreter/InterpreterTester.cs +++ b/src/tests/JIT/interpreter/InterpreterTester.cs @@ -16,14 +16,10 @@ public class InterpreterTester [Fact] public static void RunTests() { - string corerun = TestLibrary.Utilities.IsWindows ? "corerun.exe" : "corerun"; - string libInterp = TestLibrary.Utilities.IsWindows ? "clrinterpreter.dll" : (TestLibrary.Utilities.IsMacOSX ? "libclrinterpreter.dylib" : "libclrinterpreter.so"); string coreRoot = Environment.GetEnvironmentVariable("CORE_ROOT"); string interpreterApp = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Interpreter.dll"); - var startInfo = new ProcessStartInfo(Path.Combine(coreRoot, corerun), interpreterApp); - startInfo.EnvironmentVariables["DOTNET_InterpreterName"] = libInterp; - startInfo.EnvironmentVariables["DOTNET_InterpreterPath"] = Path.Combine(coreRoot, libInterp); + var startInfo = new ProcessStartInfo(Path.Combine(coreRoot, "corerun"), interpreterApp); startInfo.EnvironmentVariables["DOTNET_Interpreter"] = "RunInterpreterTests"; using (Process p = Process.Start(startInfo)) From f690f1dace502e3dfd03b62e55ae9488b5c309e8 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 19 Mar 2025 22:30:20 +0100 Subject: [PATCH 13/15] PR feedback * Refactored GC and EH info allocation * Added Interpreter-TODO at some places * Reverted some changes that were not needed anymore --- src/coreclr/inc/eetwain.h | 72 ++++++---------------------- src/coreclr/vm/codeman.cpp | 84 ++++----------------------------- src/coreclr/vm/codeman.h | 11 ++--- src/coreclr/vm/jitinterface.cpp | 48 ++++++++++--------- 4 files changed, 52 insertions(+), 163 deletions(-) diff --git a/src/coreclr/inc/eetwain.h b/src/coreclr/inc/eetwain.h index 9d8dbb9c98993a..96860e694f3da3 100644 --- a/src/coreclr/inc/eetwain.h +++ b/src/coreclr/inc/eetwain.h @@ -625,10 +625,6 @@ class InterpreterCodeManager : public ICodeManager { #ifndef DACCESS_COMPILE #ifndef FEATURE_EH_FUNCLETS -/* - Last chance for the runtime support to do fixups in the context - before execution continues inside a filter, catch handler, or finally -*/ virtual void FixContext(ContextType ctxType, EHContext *ctx, @@ -640,6 +636,7 @@ void FixContext(ContextType ctxType, size_t ** ppShadowSP, // OUT size_t ** ppEndRegion) // OUT { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); } #endif // !FEATURE_EH_FUNCLETS @@ -657,30 +654,20 @@ TADDR GetAmbientSP(PREGDISPLAY pContext, DWORD nestingLevel, CodeManState *pState) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return NULL; } #endif // TARGET_X86 -/* - Get the number of bytes used for stack parameters. - This is currently only used on x86. -*/ virtual ULONG32 GetStackParameterSize(EECodeInfo* pCodeInfo) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return 0; } -/* - Unwind the current stack frame, i.e. update the virtual register - set in pContext. This will be similar to the state after the function - returns back to caller (IP points to after the call, Frame and Stack - pointer has been reset, callee-saved registers restored - (if UpdateAllRegs), callee-UNsaved registers are trashed) - Returns success of operation. -*/ virtual bool UnwindStackFrame( PREGDISPLAY pContext, @@ -688,10 +675,6 @@ bool UnwindStackFrame( unsigned flags, CodeManState *pState); -/* - Is the function currently at a "GC safe point" ? - Can call EnumGcRefs() successfully -*/ virtual bool IsGcSafe( EECodeInfo *pCodeInfo, DWORD dwRelOffset); @@ -705,13 +688,6 @@ bool HasTailCalls(EECodeInfo *pCodeInfo) } #endif // TARGET_ARM || TARGET_ARM64 || TARGET_LOONGARCH64 || defined(TARGET_RISCV64) -/* - Enumerate all live object references in that function using - the virtual register set. Same reference location cannot be enumerated - multiple times (but all differenct references pointing to the same - object have to be individually enumerated). - Returns success of operation. -*/ virtual bool EnumGcRefs(PREGDISPLAY pContext, EECodeInfo *pCodeInfo, @@ -725,86 +701,65 @@ OBJECTREF GetInstance( PREGDISPLAY pContext, EECodeInfo * pCodeInfo); -/* - Returns the extra argument passed to shared generic code if it is still alive. - Returns NULL in all other cases. -*/ virtual PTR_VOID GetParamTypeArg(PREGDISPLAY pContext, EECodeInfo * pCodeInfo); -// Returns the type of the context parameter (this, methodtable, methoddesc, or none) virtual GenericParamContextType GetParamContextType(PREGDISPLAY pContext, EECodeInfo * pCodeInfo); -/* - Returns the offset of the GuardStack cookie if it exists. - Returns NULL if there is no cookie. -*/ virtual void * GetGSCookieAddr(PREGDISPLAY pContext, EECodeInfo * pCodeInfo, unsigned flags, CodeManState * pState) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return NULL; } #ifndef USE_GC_INFO_DECODER -/* - Returns true if the given IP is in the given method's prolog or an epilog. -*/ virtual bool IsInPrologOrEpilog( DWORD relOffset, GCInfoToken gcInfoToken, size_t* prologSize) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return false; } -/* - Returns true if the given IP is in the synchronized region of the method (valid for synchronized functions only) -*/ virtual bool IsInSynchronizedRegion( DWORD relOffset, GCInfoToken gcInfoToken, unsigned flags) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return false; } #endif // !USE_GC_INFO_DECODER -/* - Returns the size of a given function. -*/ virtual size_t GetFunctionSize(GCInfoToken gcInfoToken); -/* -* Get information necessary for return address hijacking of the method represented by the gcInfoToken. -* If it can be hijacked, it sets the returnKind output parameter to the kind of the return value and -* returns true. -* If hijacking is not possible for some reason, it return false. -*/ virtual bool GetReturnAddressHijackInfo(GCInfoToken gcInfoToken X86_ARG(ReturnKind * returnKind)) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return false; } #ifndef USE_GC_INFO_DECODER -/* - Returns the size of the frame (barring localloc) -*/ + virtual unsigned int GetFrameSize(GCInfoToken gcInfoToken) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return 0; } @@ -815,6 +770,7 @@ unsigned int GetFrameSize(GCInfoToken gcInfoToken) #ifndef FEATURE_EH_FUNCLETS virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return NULL; } @@ -823,6 +779,7 @@ virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, unsigned offset, PCONTEXT pCtx) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); return FALSE; } @@ -831,15 +788,13 @@ virtual void LeaveCatch(GCInfoToken gcInfoToken, unsigned offset, PCONTEXT pCtx) { + // Interpreter-TODO: Implement this if needed _ASSERTE(FALSE); } #endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_REMAP_FUNCTION -/* - Last chance for the runtime support to do fixups in the context - before execution continues inside an EnC updated function. -*/ + virtual HRESULT FixContextForEnC(PCONTEXT pCtx, EECodeInfo * pOldCodeInfo, @@ -849,6 +804,7 @@ HRESULT FixContextForEnC(PCONTEXT pCtx, const ICorDebugInfo::NativeVarInfo * newMethodVars, SIZE_T newMethodVarsCount) { + // Interpreter-TODO: Implement this _ASSERTE(FALSE); return E_NOTIMPL; } diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index a9316e72f86f2c..e541784edec247 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -422,7 +422,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R { // This cast is justified because only EEJitManager's have the code type above. EEJitManager* pJitMgr = (EEJitManager*)(pRS->_pjit); - CodeHeader * pHeader = dac_cast(pJitMgr->GetCodeHeaderFromStartAddress(entryPoint)); + CodeHeader * pHeader = pJitMgr->GetCodeHeaderFromStartAddress(entryPoint); for(ULONG i = 0; i < pHeader->GetNumberOfUnwindInfos(); i++) RemoveFromUnwindInfoTable(&pRS->_pUnwindInfoTable, pRS->_range.RangeStart(), pRS->_range.RangeStart() + pHeader->GetUnwindInfo(i)->BeginAddress); } @@ -461,7 +461,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R { // This cast is justified because only EEJitManager's have the code type above. EEJitManager* pJitMgr = (EEJitManager*)(pRS->_pjit); - CodeHeader * pHeader = dac_cast(pJitMgr->GetCodeHeaderFromStartAddress(methodEntry)); + CodeHeader * pHeader = pJitMgr->GetCodeHeaderFromStartAddress(methodEntry); int unwindInfoCount = pHeader->GetNumberOfUnwindInfos(); for(int i = 0; i < unwindInfoCount; i++) AddToUnwindInfoTable(&pRS->_pUnwindInfoTable, pHeader->GetUnwindInfo(i), pRS->_range.RangeStart(), pRS->_range.RangeEndOpen()); @@ -519,8 +519,7 @@ void UnwindInfoTable::AddToUnwindInfoTable(UnwindInfoTable** unwindInfoPtr, PT_R Setters of EECodeGenManager::m_CodeHeapCritSec ----------------------------------------------- allocCode -allocGCInfo -allocEHInfo +allocFromJitMetaHeap allocJumpStubBlock ResolveEHClause RemoveJitData @@ -2916,7 +2915,6 @@ void EECodeGenManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reser #endif _ASSERTE(reserveForJumpStubs == 0); requestInfo.SetInterpreted(); - requestInfo.SetDynamicDomain(); realHeaderSize = sizeof(InterpreterRealCodeHeader); } else @@ -3198,33 +3196,6 @@ LoaderHeap *EECodeGenManager::GetJitMetaHeap(MethodDesc *pMD) return pAllocator->GetLowFrequencyHeap(); } -void* EECodeGenManager::allocEHInfoRaw(MethodDesc* pMD, DWORD blockSize, size_t * pAllocationSize) -{ - CONTRACTL { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - void * mem = NULL; - - // sadly for light code gen I need the check in here. We should change GetJitMetaHeap - if (pMD->IsLCGMethod()) - { - CrstHolder ch(&m_CodeHeapCritSec); - mem = (void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize); - } - else - { - mem = (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize)); - } - _ASSERTE(mem); // AllocMem throws if there's not enough memory - - * pAllocationSize = blockSize; // Store the allocation size so we can backout later. - - return(mem); -} - - JumpStubBlockHeader * EEJitManager::allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps, BYTE * loAddr, BYTE * hiAddr, LoaderAllocator *pLoaderAllocator, @@ -3326,53 +3297,27 @@ void * EEJitManager::allocCodeFragmentBlock(size_t blockSize, unsigned alignment RETURN((void *)mem); } -template -BYTE* EECodeGenManager::allocGCInfo(TCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) +BYTE* EECodeGenManager::allocFromJitMetaHeap(MethodDesc* pMD, DWORD blockSize, size_t * pAllocationSize) { CONTRACTL { THROWS; GC_NOTRIGGER; } CONTRACTL_END; - MethodDesc* pMD = pCodeHeader->GetMethodDesc(); - // sadly for light code gen I need the check in here. We should change GetJitMetaHeap + BYTE *pMem = NULL; if (pMD->IsLCGMethod()) { CrstHolder ch(&m_CodeHeapCritSec); - pCodeHeader->SetGCInfo((BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize)); + pMem = (BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize); } else { - pCodeHeader->SetGCInfo((BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize))); + pMem = (BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize)); } - _ASSERTE(pCodeHeader->GetGCInfo()); // AllocMem throws if there's not enough memory - - * pAllocationSize = blockSize; // Store the allocation size so we can backout later. - - return(pCodeHeader->GetGCInfo()); -} - -template -EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(TCodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize) -{ - CONTRACTL { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - // Note - pCodeHeader->phdrJitEHInfo - sizeof(size_t) contains the number of EH clauses - - DWORD temp = EE_ILEXCEPTION::Size(numClauses); - DWORD blockSize = 0; - if (!ClrSafeInt::addition(temp, sizeof(size_t), blockSize)) - COMPlusThrowOM(); - BYTE *EHInfo = (BYTE*)allocEHInfoRaw(pCodeHeader->GetMethodDesc(), blockSize, pAllocationSize); + *pAllocationSize = blockSize; // Store the allocation size so we can backout later. - pCodeHeader->SetEHInfo((EE_ILEXCEPTION*) (EHInfo + sizeof(size_t))); - pCodeHeader->GetEHInfo()->Init(numClauses); - *((size_t *)EHInfo) = numClauses; - return(pCodeHeader->GetEHInfo()); + return pMem; } template @@ -3469,21 +3414,10 @@ void EECodeGenManager::RemoveJitData(TCodeHeader * pCHdr, size_t GCinfo_len, siz // being in the header file. The bodies call methods of multiple data types that cannot be reasonably defined // before the codeman.h is included. -template -BYTE* EECodeGenManager::allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); - -template -EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); - template void EECodeGenManager::RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); #ifdef FEATURE_INTERPRETER -template -BYTE* EECodeGenManager::allocGCInfo(InterpreterCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); - -template -EE_ILEXCEPTION* EECodeGenManager::allocEHInfo(InterpreterCodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); template void EECodeGenManager::RemoveJitData(InterpreterCodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 42b624de8faabe..712505701b3c9d 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -127,7 +127,7 @@ struct RealCodeHeader PTR_BYTE phdrDebugInfo; // Note - *(&(pCodeHeader->phdrJitEHInfo) - sizeof(size_t)) - // contains the number of EH clauses, See EEJitManager::allocEHInfo + // contains the number of EH clauses, See CEECodeGenInfo::setEHcountWorker PTR_EE_ILEXCEPTION phdrJitEHInfo; PTR_BYTE phdrJitGCInfo; @@ -152,7 +152,7 @@ struct InterpreterRealCodeHeader PTR_BYTE phdrDebugInfo; // Note - *(&(pCodeHeader->phdrJitEHInfo) - sizeof(size_t)) - // contains the number of EH clauses, See EEJitManager::allocEHInfo + // contains the number of EH clauses, See CEECodeGenInfo::setEHcountWorker PTR_EE_ILEXCEPTION phdrJitEHInfo; PTR_BYTE phdrJitGCInfo; PTR_MethodDesc phdrMDesc; @@ -1836,11 +1836,7 @@ class EECodeGenManager : public IJitManager #endif ); - template - inline BYTE *allocGCInfo(TCodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize); - - template - inline EE_ILEXCEPTION* allocEHInfo(TCodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize); + BYTE *allocFromJitMetaHeap(MethodDesc *pMD, DWORD blockSize, size_t * pAllocationSize); // Heap Management functions void NibbleMapSet(HeapList * pHp, TADDR pCode, size_t codeSize); @@ -1859,7 +1855,6 @@ class EECodeGenManager : public IJitManager protected: void* allocCodeRaw(CodeHeapRequestInfo *pInfo, size_t header, size_t blockSize, unsigned align, HeapList ** ppCodeHeap); - void* allocEHInfoRaw(MethodDesc *pMD, DWORD blockSize, size_t * pAllocationSize); virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) = 0; virtual void DeleteFunctionTable(PVOID pvTableID) = 0; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ff935d51b49d20..09ddfdfb7a709a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11025,7 +11025,7 @@ void CEECodeGenInfo::reportRichMappings( JIT_TO_EE_TRANSITION(); - if (((EEJitManager*)m_jitManager)->IsStoringRichDebugInfo()) + if (((EECodeGenManager*)m_jitManager)->IsStoringRichDebugInfo()) { m_inlineTreeNodes = inlineTreeNodes; m_numInlineTreeNodes = numInlineTreeNodes; @@ -11184,7 +11184,7 @@ void * CInterpreterJitInfo::allocGCInfo (size_t size) MODE_PREEMPTIVE; } CONTRACTL_END; - void * block = NULL; + BYTE * block = NULL; JIT_TO_EE_TRANSITION(); @@ -11198,13 +11198,10 @@ void * CInterpreterJitInfo::allocGCInfo (size_t size) } #endif // HOST_64BIT - block = m_jitManager->allocGCInfo((InterpreterCodeHeader*)m_CodeHeaderRW,(DWORD)size, &m_GCinfo_len); - if (!block) - { - COMPlusThrowHR(CORJIT_OUTOFMEM); - } + block = m_jitManager->allocFromJitMetaHeap(m_pMethodBeingCompiled,(DWORD)size, &m_GCinfo_len); + _ASSERTE(block); // allocFromJitMetaHeap throws if there's not enough memory - _ASSERTE(((InterpreterCodeHeader*)m_CodeHeaderRW)->GetGCInfo() != 0 && block == ((InterpreterCodeHeader*)m_CodeHeaderRW)->GetGCInfo()); + ((InterpreterCodeHeader*)m_CodeHeaderRW)->SetGCInfo(block); EE_TO_JIT_TRANSITION(); @@ -12547,7 +12544,7 @@ void * CEEJitInfo::allocGCInfo (size_t size) MODE_PREEMPTIVE; } CONTRACTL_END; - void * block = NULL; + BYTE * block = NULL; JIT_TO_EE_TRANSITION(); @@ -12561,13 +12558,10 @@ void * CEEJitInfo::allocGCInfo (size_t size) } #endif // HOST_64BIT - block = m_jitManager->allocGCInfo((CodeHeader*)m_CodeHeaderRW, (DWORD)size, &m_GCinfo_len); - if (!block) - { - COMPlusThrowHR(CORJIT_OUTOFMEM); - } + block = m_jitManager->allocFromJitMetaHeap(m_pMethodBeingCompiled,(DWORD)size, &m_GCinfo_len); + _ASSERTE(block); // allocFromJitMetaHeap throws if there's not enough memory - _ASSERTE(((CodeHeader*)m_CodeHeaderRW)->GetGCInfo() != 0 && block == ((CodeHeader*)m_CodeHeaderRW)->GetGCInfo()); + ((CodeHeader*)m_CodeHeaderRW)->SetGCInfo(block); EE_TO_JIT_TRANSITION(); @@ -12587,13 +12581,23 @@ void CEECodeGenInfo::setEHcountWorker(unsigned cEH) _ASSERTE(cEH != 0); _ASSERTE(m_CodeHeaderRW != 0); - _ASSERTE(((TCodeHeader*)m_CodeHeaderRW)->GetEHInfo() == 0); - EE_ILEXCEPTION* ret; - ret = m_jitManager->allocEHInfo((TCodeHeader*)m_CodeHeaderRW, cEH, &m_EHinfo_len); - _ASSERTE(ret); // allocEHInfo throws if there's not enough memory + TCodeHeader *pCodeHeaderRW = ((TCodeHeader*)m_CodeHeaderRW); + + _ASSERTE(pCodeHeaderRW->GetEHInfo() == 0); + + DWORD temp = EE_ILEXCEPTION::Size(cEH); + DWORD blockSize = 0; + if (!ClrSafeInt::addition(temp, sizeof(size_t), blockSize)) + COMPlusThrowOM(); + + BYTE *pEHInfo = m_jitManager->allocFromJitMetaHeap(m_pMethodBeingCompiled, blockSize, &m_EHinfo_len); + _ASSERTE(pEHInfo); // allocFromJitMetaHeap throws if there's not enough memory + _ASSERTE(m_EHinfo_len != 0); - _ASSERTE(((TCodeHeader*)m_CodeHeaderRW)->GetEHInfo() != 0 && ((TCodeHeader*)m_CodeHeaderRW)->GetEHInfo()->EHCount() == cEH); + pCodeHeaderRW->SetEHInfo((EE_ILEXCEPTION*)(pEHInfo + sizeof(size_t))); + pCodeHeaderRW->GetEHInfo()->Init(cEH); + *((size_t *)pEHInfo) = cEH; EE_TO_JIT_TRANSITION(); } @@ -13306,8 +13310,8 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, if (useInterpreter) { - CInterpreterJitInfo jitInfo(ftn, ILHeader, interpreterMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING)); - ret = UnsafeJitFunctionWorker(interpreterMgr, &jitInfo, pJitFlags, methodInfo, &cxt, nativeCodeVersion, pSizeOfCode); + CInterpreterJitInfo interpreterJitInfo(ftn, ILHeader, interpreterMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING)); + ret = UnsafeJitFunctionWorker(interpreterMgr, &interpreterJitInfo, pJitFlags, methodInfo, &cxt, nativeCodeVersion, pSizeOfCode); } #endif // FEATURE_INTERPRETER From bf8f2287b006711738b1411b12765384a62eee39 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 20 Mar 2025 17:08:37 +0100 Subject: [PATCH 14/15] PR Feedback * Get rid of some template usages by small refactoring --- src/coreclr/vm/codeman.cpp | 44 ++++++++++++++++++++++---------------- src/coreclr/vm/codeman.h | 6 ++---- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index e541784edec247..256bbe13ea7cb0 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -3913,9 +3913,8 @@ static TCodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & //----------------------------------------------------------------------------- // Get vars from Jit Store //----------------------------------------------------------------------------- -template BOOL EECodeGenManager::GetBoundariesAndVarsWorker( - const DebugInfoRequest & request, + PTR_BYTE pDebugInfo, IN FP_IDS_NEW fpNew, IN void * pNewData, OUT ULONG32 * pcMap, OUT ICorDebugInfo::OffsetMapping **ppMap, @@ -3928,11 +3927,6 @@ BOOL EECodeGenManager::GetBoundariesAndVarsWorker( SUPPORTS_DAC; } CONTRACTL_END; - TCodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); - _ASSERTE(pHdr != NULL); - - PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); - // No header created, which means no jit information is available. if (pDebugInfo == NULL) return FALSE; @@ -3974,12 +3968,16 @@ BOOL EEJitManager::GetBoundariesAndVars( SUPPORTS_DAC; } CONTRACTL_END; - return GetBoundariesAndVarsWorker(request, fpNew, pNewData, pcMap, ppMap, pcVars, ppVars); + CodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + _ASSERTE(pHdr != NULL); + + PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); + + return GetBoundariesAndVarsWorker(pDebugInfo, fpNew, pNewData, pcMap, ppMap, pcVars, ppVars); } -template BOOL EECodeGenManager::GetRichDebugInfoWorker( - const DebugInfoRequest& request, + PTR_BYTE pDebugInfo, IN FP_IDS_NEW fpNew, IN void* pNewData, OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, OUT ULONG32* pNumInlineTree, @@ -3997,11 +3995,6 @@ BOOL EECodeGenManager::GetRichDebugInfoWorker( return FALSE; } - TCodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); - _ASSERTE(pHdr != NULL); - - PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); - // No header created, which means no debug information is available. if (pDebugInfo == NULL) return FALSE; @@ -4029,7 +4022,12 @@ BOOL EEJitManager::GetRichDebugInfo( SUPPORTS_DAC; } CONTRACTL_END; - return GetRichDebugInfoWorker(request, fpNew, pNewData, ppInlineTree, pNumInlineTree, ppRichMappings, pNumRichMappings); + CodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + _ASSERTE(pHdr != NULL); + + PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); + + return GetRichDebugInfoWorker(pDebugInfo, fpNew, pNewData, ppInlineTree, pNumInlineTree, ppRichMappings, pNumRichMappings); } #ifdef FEATURE_INTERPRETER @@ -4047,7 +4045,12 @@ BOOL InterpreterJitManager::GetBoundariesAndVars( SUPPORTS_DAC; } CONTRACTL_END; - return GetBoundariesAndVarsWorker(request, fpNew, pNewData, pcMap, ppMap, pcVars, ppVars); + InterpreterCodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + _ASSERTE(pHdr != NULL); + + PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); + + return GetBoundariesAndVarsWorker(pDebugInfo, fpNew, pNewData, pcMap, ppMap, pcVars, ppVars); } BOOL InterpreterJitManager::GetRichDebugInfo( @@ -4064,7 +4067,12 @@ BOOL InterpreterJitManager::GetRichDebugInfo( SUPPORTS_DAC; } CONTRACTL_END; - return GetRichDebugInfoWorker(request, fpNew, pNewData, ppInlineTree, pNumInlineTree, ppRichMappings, pNumRichMappings); + InterpreterCodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + _ASSERTE(pHdr != NULL); + + PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); + + return GetRichDebugInfoWorker(pDebugInfo, fpNew, pNewData, ppInlineTree, pNumInlineTree, ppRichMappings, pNumRichMappings); } #endif // FEATURE_INTERPRETER diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 712505701b3c9d..e6a888fbdfe6b9 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -1793,18 +1793,16 @@ class EECodeGenManager : public IJitManager } protected: - template BOOL GetBoundariesAndVarsWorker( - const DebugInfoRequest & request, + PTR_BYTE pDebugInfo, IN FP_IDS_NEW fpNew, IN void * pNewData, OUT ULONG32 * pcMap, OUT ICorDebugInfo::OffsetMapping **ppMap, OUT ULONG32 * pcVars, OUT ICorDebugInfo::NativeVarInfo **ppVars); - template BOOL GetRichDebugInfoWorker( - const DebugInfoRequest& request, + PTR_BYTE pDebugInfo, IN FP_IDS_NEW fpNew, IN void* pNewData, OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, OUT ULONG32* pNumInlineTree, From 220883a0fb1d833a8c1c9ddb6f0bd5acc350939f Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 21 Mar 2025 18:49:10 +0100 Subject: [PATCH 15/15] Reflect feedback --- src/coreclr/vm/codeman.cpp | 9 +++++---- src/coreclr/vm/codeman.h | 9 +-------- src/coreclr/vm/jitinterface.h | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 256bbe13ea7cb0..7e53187573fb77 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1649,7 +1649,8 @@ enum JIT_LOAD_JIT_ID { JIT_LOAD_MAIN = 500, // The "main" JIT. Normally, this is named "clrjit.dll". Start at a number that is somewhat uncommon (i.e., not zero or 1) to help distinguish from garbage, in process dumps. // 501 is JIT_LOAD_LEGACY on some platforms; please do not reuse this value. - JIT_LOAD_ALTJIT = 502 // An "altjit". By default, named something like "clrjit___.dll". Used both internally, as well as externally for JIT CTP builds. + JIT_LOAD_ALTJIT = 502, // An "altjit". By default, named something like "clrjit___.dll". Used both internally, as well as externally for JIT CTP builds. + JIT_LOAD_INTERPRETER = 503 // The interpreter compilation phase. Named "clrinterpreter.dll". }; enum JIT_LOAD_STATUS @@ -3676,14 +3677,14 @@ BOOL InterpreterJitManager::LoadInterpreter() { STANDARD_VM_CONTRACT; - // If the JIT is already loaded, don't take the lock. + // If the interpreter is already loaded, don't take the lock. if (IsInterpreterLoaded()) return TRUE; // Use m_interpreterLoadCritSec to ensure that the interpreter is loaded on one thread only CrstHolder chRead(&m_interpreterLoadCritSec); - // Did someone load the JIT before we got the lock? + // Did someone load the interpreter before we got the lock? if (IsInterpreterLoaded()) return TRUE; @@ -3692,7 +3693,7 @@ BOOL InterpreterJitManager::LoadInterpreter() ICorJitCompiler* newInterpreter = NULL; m_interpreter = NULL; - g_interpreterLoadData.jld_id = JIT_LOAD_MAIN; + g_interpreterLoadData.jld_id = JIT_LOAD_INTERPRETER; LPWSTR interpreterPath = NULL; #ifdef _DEBUG IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_InterpreterPath, &interpreterPath)); diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index e6a888fbdfe6b9..8a7daf320e0402 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -296,13 +296,6 @@ struct InterpreterCodeHeader SUPPORTS_DAC; return pRealCodeHeader->phdrMDesc; } -#if defined(FEATURE_GDBJIT) - VOID* GetCalledMethods() - { - SUPPORTS_DAC; - return pRealCodeHeader->pCalledMethods; - } -#endif TADDR GetCodeStartAddress() { SUPPORTS_DAC; @@ -2659,6 +2652,7 @@ class InterpreterJitManager final : public EECodeGenManager virtual DWORD GetCodeType() { LIMITED_METHOD_DAC_CONTRACT; + // Interpreter-TODO: consider adding some extra flag for the interpreter return (miManaged | miIL); } @@ -2923,7 +2917,6 @@ inline InterpreterCodeHeader * InterpreterJitManager::GetCodeHeaderFromStartAddr { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(methodStartAddress != (TADDR)NULL); - ARM_ONLY(_ASSERTE((methodStartAddress & THUMB_CODE) == 0)); return dac_cast(methodStartAddress - sizeof(InterpreterCodeHeader)); } diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 910caefa45ac90..b6d981df4a56ba 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -702,11 +702,11 @@ class CEECodeGenInfo : public CEEInfo template void NibbleMapSet(); - virtual void getEHinfo( - CORINFO_METHOD_HANDLE ftn, /* IN */ - unsigned EHnumber, /* IN */ - CORINFO_EH_CLAUSE* clause /* OUT */ - ) override final; + void getEHinfo( + CORINFO_METHOD_HANDLE ftn, /* IN */ + unsigned EHnumber, /* IN */ + CORINFO_EH_CLAUSE* clause /* OUT */ + ) override final; void setEHinfoWorker( EE_ILEXCEPTION* pEHInfo, @@ -769,8 +769,8 @@ class CEEJitInfo final : public CEECodeGenInfo void allocMem (AllocMemArgs *pArgs) override; void * allocGCInfo(size_t size) override; - virtual void setEHcount (unsigned cEH) override; - virtual void setEHinfo ( + void setEHcount (unsigned cEH) override; + void setEHinfo ( unsigned EHnumber, const CORINFO_EH_CLAUSE* clause ) override; @@ -873,7 +873,7 @@ class CEEJitInfo final : public CEECodeGenInfo return m_fJumpStubOverflow; } - virtual BOOL JitAgain() override + BOOL JitAgain() override { LIMITED_METHOD_CONTRACT; return m_fJumpStubOverflow; @@ -891,7 +891,7 @@ class CEEJitInfo final : public CEECodeGenInfo m_reserveForJumpStubs = value; } - virtual PatchpointInfo* GetPatchpointInfo() override + PatchpointInfo* GetPatchpointInfo() override { #ifdef FEATURE_ON_STACK_REPLACEMENT return m_pPatchpointInfoFromJit; @@ -901,7 +901,7 @@ class CEEJitInfo final : public CEECodeGenInfo } #else - virtual BOOL JitAgain() override + BOOL JitAgain() override { LIMITED_METHOD_CONTRACT; return FALSE; @@ -1074,8 +1074,8 @@ class CInterpreterJitInfo final : public CEECodeGenInfo void allocMem(AllocMemArgs *pArgs) override; void * allocGCInfo(size_t size) override; - virtual void setEHcount (unsigned cEH) override; - virtual void setEHinfo ( + void setEHcount (unsigned cEH) override; + void setEHinfo ( unsigned EHnumber, const CORINFO_EH_CLAUSE* clause ) override;