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/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 8bdde4c7baa642..8e935e76cbfd77 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/dacvars.h b/src/coreclr/inc/dacvars.h index 7df74b3c480732..b43cb3fd5eff51 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -84,6 +84,10 @@ 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) +DEFINE_DACVAR(PTR_InterpreterCodeManager, ExecutionManager__m_pInterpreterCodeMan, ExecutionManager::m_pInterpreterCodeMan) +#endif DEFINE_DACVAR_NO_DUMP(VMHELPDEF *, dac__hlpFuncTable, ::hlpFuncTable) DEFINE_DACVAR(VMHELPDEF *, dac__hlpDynamicFuncTable, ::hlpDynamicFuncTable) diff --git a/src/coreclr/inc/eetwain.h b/src/coreclr/inc/eetwain.h index e229ae1fe29d38..96860e694f3da3 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); @@ -646,6 +614,215 @@ 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 +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 +{ + // Interpreter-TODO: Implement this if needed + _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) +{ + // Interpreter-TODO: Implement this if needed + _ASSERTE(FALSE); + return NULL; +} +#endif // TARGET_X86 + +virtual +ULONG32 GetStackParameterSize(EECodeInfo* pCodeInfo) +{ + // Interpreter-TODO: Implement this if needed + _ASSERTE(FALSE); + return 0; +} + +virtual +bool UnwindStackFrame( + PREGDISPLAY pContext, + EECodeInfo *pCodeInfo, + unsigned flags, + CodeManState *pState); + +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) + +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); + +virtual +PTR_VOID GetParamTypeArg(PREGDISPLAY pContext, + EECodeInfo * pCodeInfo); + +virtual GenericParamContextType GetParamContextType(PREGDISPLAY pContext, + EECodeInfo * pCodeInfo); + +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 +virtual +bool IsInPrologOrEpilog( + DWORD relOffset, + GCInfoToken gcInfoToken, + size_t* prologSize) +{ + // Interpreter-TODO: Implement this if needed + _ASSERTE(FALSE); + return false; +} + +virtual +bool IsInSynchronizedRegion( + DWORD relOffset, + GCInfoToken gcInfoToken, + unsigned flags) +{ + // Interpreter-TODO: Implement this if needed + _ASSERTE(FALSE); + return false; +} +#endif // !USE_GC_INFO_DECODER + +virtual +size_t GetFunctionSize(GCInfoToken gcInfoToken); + +virtual bool GetReturnAddressHijackInfo(GCInfoToken gcInfoToken X86_ARG(ReturnKind * returnKind)) +{ + // Interpreter-TODO: Implement this if needed + _ASSERTE(FALSE); + return false; +} + +#ifndef USE_GC_INFO_DECODER + +virtual +unsigned int GetFrameSize(GCInfoToken gcInfoToken) +{ + // Interpreter-TODO: Implement this if needed + _ASSERTE(FALSE); + return 0; +} +#endif // USE_GC_INFO_DECODER + +#ifndef DACCESS_COMPILE + +#ifndef FEATURE_EH_FUNCLETS +virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg) +{ + // Interpreter-TODO: Implement this if needed + _ASSERTE(FALSE); + return NULL; +} + +virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, + unsigned offset, + PCONTEXT pCtx) +{ + // Interpreter-TODO: Implement this if needed + _ASSERTE(FALSE); + return FALSE; +} + +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 + +virtual +HRESULT FixContextForEnC(PCONTEXT pCtx, + EECodeInfo * pOldCodeInfo, + const ICorDebugInfo::NativeVarInfo * oldMethodVars, + SIZE_T oldMethodVarsCount, + EECodeInfo * pNewCodeInfo, + const ICorDebugInfo::NativeVarInfo * newMethodVars, + SIZE_T newMethodVarsCount) +{ + // Interpreter-TODO: Implement this + _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 fa61a7b81aa9ba..b5581b019478b5 100644 --- a/src/coreclr/inc/vptr_list.h +++ b/src/coreclr/inc/vptr_list.h @@ -9,6 +9,10 @@ VPTR_CLASS(EEJitManager) #ifdef FEATURE_READYTORUN VPTR_CLASS(ReadyToRunJitManager) #endif +#ifdef FEATURE_INTERPRETER +VPTR_CLASS(InterpreterJitManager) +VPTR_CLASS(InterpreterCodeManager) +#endif VPTR_CLASS(EECodeManager) VPTR_CLASS(RangeList) diff --git a/src/coreclr/interpreter/eeinterp.cpp b/src/coreclr/interpreter/eeinterp.cpp index 7d7960e5ebc88a..b801c83eba39c4 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,9 +90,7 @@ 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; @@ -104,9 +102,6 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd, *(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 0a26fe9076ff83..b621f0293fafd2 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" @@ -52,6 +53,11 @@ SPTR_IMPL(EEJitManager, ExecutionManager, m_pEEJitManager); SPTR_IMPL(ReadyToRunJitManager, ExecutionManager, m_pReadyToRunJitManager); #endif +#ifdef FEATURE_INTERPRETER +SPTR_IMPL(InterpreterJitManager, ExecutionManager, m_pInterpreterJitManager); +SPTR_IMPL(InterpreterCodeManager, ExecutionManager, m_pInterpreterCodeMan); +#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); @@ -507,14 +513,13 @@ 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 -allocEHInfo +allocFromJitMetaHeap allocJumpStubBlock ResolveEHClause RemoveJitData @@ -523,7 +528,7 @@ ReleaseReferenceToHeap JitCodeToMethodInfo -Need EEJitManager::m_CodeHeapCritSec to be set +Need EECodeGenManager::m_CodeHeapCritSec to be set ----------------------------------------------- NewCodeHeap allocCodeRaw @@ -1181,12 +1186,20 @@ 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, + 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 +1208,6 @@ EEJitManager::EEJitManager() GC_NOTRIGGER; } CONTRACTL_END; - m_pCodeHeap = NULL; m_jit = NULL; m_JITCompiler = NULL; #ifdef TARGET_AMD64 @@ -1211,9 +1223,6 @@ EEJitManager::EEJitManager() m_AltJITRequired = false; #endif - m_storeRichDebugInfo = false; - m_cleanupList = NULL; - SetCpuInfo(); } @@ -1673,7 +1682,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 @@ -1701,6 +1711,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(...) \ @@ -2201,9 +2215,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; @@ -2392,11 +2406,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; @@ -2404,7 +2418,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) @@ -2461,7 +2478,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. @@ -2471,13 +2496,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); @@ -2485,7 +2516,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; @@ -2494,11 +2533,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; } @@ -2584,7 +2618,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; @@ -2616,7 +2650,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) @@ -2629,6 +2666,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; @@ -2664,15 +2706,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 { @@ -2699,9 +2745,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; @@ -2719,13 +2765,33 @@ 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; +#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; + } } else { - pCodeHeap = (HeapList *)pInfo->m_pAllocator->m_pLastUsedCodeHeap; - pInfo->m_pAllocator->m_pLastUsedCodeHeap = NULL; +#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; + } } // If we will use a cached code heap, ensure that the code heap meets the constraints @@ -2780,11 +2846,29 @@ void* EEJitManager::allocCodeRaw(CodeHeapRequestInfo *pInfo, if (pInfo->IsDynamicDomain()) { - pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = pCodeHeap; +#ifdef FEATURE_INTERPRETER + if (pInfo->IsInterpreted()) + { + pInfo->m_pAllocator->m_pLastUsedInterpreterDynamicCodeHeap = pCodeHeap; + } + else +#endif // FEATURE_INTERPRETER + { + pInfo->m_pAllocator->m_pLastUsedDynamicCodeHeap = pCodeHeap; + } } else { - pInfo->m_pAllocator->m_pLastUsedCodeHeap = pCodeHeap; +#ifdef FEATURE_INTERPRETER + if (pInfo->IsInterpreted()) + { + pInfo->m_pAllocator->m_pLastUsedInterpreterCodeHeap = pCodeHeap; + } + else +#endif // FEATURE_INTERPRETER + { + pInfo->m_pAllocator->m_pLastUsedCodeHeap = pCodeHeap; + } } // Record the pCodeHeap value into ppCodeHeap @@ -2801,13 +2885,14 @@ 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 +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 + , UINT nUnwindInfos #endif - ) + ) { CONTRACTL { THROWS; @@ -2844,8 +2929,8 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo SIZE_T totalSize = blockSize; - CodeHeader * pCodeHdr = NULL; - CodeHeader * pCodeHdrRW = NULL; + TCodeHeader * pCodeHdr = NULL; + TCodeHeader * pCodeHdrRW = NULL; CodeHeapRequestInfo requestInfo(pMD); #if defined(FEATURE_JIT_PITCHING) @@ -2854,13 +2939,29 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo requestInfo.SetDynamicDomain(); } #endif - requestInfo.setReserveForJumpStubs(reserveForJumpStubs); + + SIZE_T realHeaderSize; +#ifdef FEATURE_INTERPRETER + if (std::is_same::value) + { +#ifdef FEATURE_EH_FUNCLETS + _ASSERTE(nUnwindInfos == 0); +#endif + _ASSERTE(reserveForJumpStubs == 0); + requestInfo.SetInterpreted(); + realHeaderSize = sizeof(InterpreterRealCodeHeader); + } + else +#endif // FEATURE_INTERPRETER + { + requestInfo.setReserveForJumpStubs(reserveForJumpStubs); #ifdef FEATURE_EH_FUNCLETS - SIZE_T realHeaderSize = offsetof(RealCodeHeader, unwindInfos[0]) + (sizeof(T_RUNTIME_FUNCTION) * nUnwindInfos); + realHeaderSize = offsetof(RealCodeHeader, unwindInfos[0]) + (sizeof(T_RUNTIME_FUNCTION) * nUnwindInfos); #else - SIZE_T realHeaderSize = sizeof(RealCodeHeader); + realHeaderSize = sizeof(RealCodeHeader); #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 @@ -2876,7 +2977,7 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo 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()) @@ -2886,13 +2987,17 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo _ASSERTE(IS_ALIGNED(pCode, alignment)); - pCodeHdr = ((CodeHeader *)pCode) - 1; + pCodeHdr = ((TCodeHeader *)pCode) - 1; - *pAllocatedSize = sizeof(CodeHeader) + totalSize; + *pAllocatedSize = sizeof(TCodeHeader) + totalSize; - if (ExecutableAllocator::IsWXORXEnabled()) + if (ExecutableAllocator::IsWXORXEnabled() +#ifdef FEATURE_INTERPRETER + && !std::is_same::value +#endif // FEATURE_INTERPRETER + ) { - pCodeHdrRW = (CodeHeader *)new BYTE[*pAllocatedSize]; + pCodeHdrRW = (TCodeHeader *)new BYTE[*pAllocatedSize]; } else { @@ -2918,7 +3023,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 (std::is_same::value) + { + ((CodeHeader*)pCodeHdrRW)->SetNumberOfUnwindInfos(nUnwindInfos); + } #endif if (requestInfo.IsDynamicDomain()) @@ -2935,7 +3043,25 @@ void EEJitManager::allocCode(MethodDesc* pMD, size_t blockSize, size_t reserveFo *ppCodeHeaderRW = pCodeHdrRW; } -EEJitManager::DomainCodeHeapList *EEJitManager::GetCodeHeapList(CodeHeapRequestInfo *pInfo, LoaderAllocator *pAllocator, BOOL fDynamicOnly) +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 { NOTHROW; @@ -2976,7 +3102,7 @@ EEJitManager::DomainCodeHeapList *EEJitManager::GetCodeHeapList(CodeHeapRequestI return pList; } -bool EEJitManager::CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHeap) +bool EECodeGenManager::CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHeap) { CONTRACTL { NOTHROW; @@ -3070,7 +3196,7 @@ bool EEJitManager::CanUseCodeHeap(CodeHeapRequestInfo *pInfo, HeapList *pCodeHea return retVal; } -EEJitManager::DomainCodeHeapList * EEJitManager::CreateCodeHeapList(CodeHeapRequestInfo *pInfo) +EEJitManager::DomainCodeHeapList * EECodeGenManager::CreateCodeHeapList(CodeHeapRequestInfo *pInfo) { CONTRACTL { THROWS; @@ -3091,7 +3217,7 @@ EEJitManager::DomainCodeHeapList * EEJitManager::CreateCodeHeapList(CodeHeapRequ return pNewList.Extract(); } -LoaderHeap *EEJitManager::GetJitMetaHeap(MethodDesc *pMD) +LoaderHeap *EECodeGenManager::GetJitMetaHeap(MethodDesc *pMD) { CONTRACTL { NOTHROW; @@ -3104,81 +3230,6 @@ LoaderHeap *EEJitManager::GetJitMetaHeap(MethodDesc *pMD) return pAllocator->GetLowFrequencyHeap(); } -BYTE* EEJitManager::allocGCInfo(CodeHeader* 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()); -} - -void* EEJitManager::allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize) -{ - CONTRACTL { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; - - MethodDesc* pMD = pCodeHeader->GetMethodDesc(); - 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); -} - - -EE_ILEXCEPTION* EEJitManager::allocEHInfo(CodeHeader* 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); - - pCodeHeader->SetEHInfo((EE_ILEXCEPTION*) (EHInfo + sizeof(size_t))); - pCodeHeader->GetEHInfo()->Init(numClauses); - *((size_t *)EHInfo) = numClauses; - return(pCodeHeader->GetEHInfo()); -} - JumpStubBlockHeader * EEJitManager::allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps, BYTE * loAddr, BYTE * hiAddr, LoaderAllocator *pLoaderAllocator, @@ -3280,91 +3331,31 @@ void * EEJitManager::allocCodeFragmentBlock(size_t blockSize, unsigned alignment RETURN((void *)mem); } -#endif // !DACCESS_COMPILE - - -GCInfoToken EEJitManager::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 }; -} - -// creates an enumeration and returns the number of EH clauses -unsigned EEJitManager::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))); -} - -PTR_EXCEPTION_CLAUSE_TOKEN EEJitManager::GetNextEHClause(EH_CLAUSE_ENUMERATOR* pEnumState, - EE_ILEXCEPTION_CLAUSE* pEHClauseOut) +BYTE* EECodeGenManager::allocFromJitMetaHeap(MethodDesc* pMD, DWORD blockSize, size_t * pAllocationSize) { CONTRACTL { - NOTHROW; + THROWS; GC_NOTRIGGER; } CONTRACTL_END; - unsigned iCurrentPos = pEnumState->iCurrentPos; - pEnumState->iCurrentPos++; - - EE_ILEXCEPTION_CLAUSE* pClause = &(dac_cast(pEnumState->pExceptionClauseArray)[iCurrentPos]); - *pEHClauseOut = *pClause; - return dac_cast(pClause); -} - -#ifndef DACCESS_COMPILE -TypeHandle EEJitManager::ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, - CrawlFrame *pCf) -{ - // We don't want to use a runtime contract here since this codepath is used during - // the processing of a hard SO. Contracts use a significant amount of stack - // which we can't afford for those cases. - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - - _ASSERTE(NULL != pCf); - _ASSERTE(NULL != pEHClause); - _ASSERTE(IsTypedHandler(pEHClause)); - - - TypeHandle typeHnd = TypeHandle(); - mdToken typeTok = mdTokenNil; - - // CachedTypeHandle's are filled in at JIT time, and not cached when accessed multiple times - if (HasCachedTypeHandle(pEHClause)) + BYTE *pMem = NULL; + if (pMD->IsLCGMethod()) { - return TypeHandle::FromPtr(pEHClause->TypeHandle); + CrstHolder ch(&m_CodeHeapCritSec); + pMem = (BYTE*)(void*)pMD->AsDynamicMethodDesc()->GetResolver()->GetJitMetaHeap()->New(blockSize); } else { - typeTok = pEHClause->ClassToken; + pMem = (BYTE*) (void*)GetJitMetaHeap(pMD)->AllocMem(S_SIZE_T(blockSize)); } - MethodDesc* pMD = pCf->GetFunction(); - Module* pModule = pMD->GetModule(); - PREFIX_ASSUME(pModule != NULL); + *pAllocationSize = blockSize; // Store the allocation size so we can backout later. - SigTypeContext typeContext(pMD); - return ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, typeTok, &typeContext, - ClassLoader::ReturnNullIfNotFound); + return pMem; } -void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len) +template +void EECodeGenManager::RemoveJitData(TCodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len) { CONTRACTL { NOTHROW; @@ -3373,10 +3364,10 @@ void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t MethodDesc* pMD = pCHdr->GetMethodDesc(); - if (pMD->IsLCGMethod()) { - - void * codeStart = (pCHdr + 1); + void * codeStart = (void*)pCHdr->GetCodeStartAddress(); + if (pMD->IsLCGMethod()) + { { CrstHolder ch(&m_CodeHeapCritSec); @@ -3388,10 +3379,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); @@ -3407,7 +3396,7 @@ void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t HeapList *pHp = GetCodeHeapList(); while (pHp && ((pHp->startAddress > (TADDR)pCHdr) || - (pHp->endAddress < (TADDR)pCHdr + sizeof(CodeHeader)))) + (pHp->endAddress < (TADDR)codeStart))) { pHp = pHp->GetNext(); } @@ -3418,7 +3407,7 @@ void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t if (pHp == NULL) return; - NibbleMapDeleteUnlocked(pHp, (TADDR)(pCHdr + 1)); + NibbleMapDeleteUnlocked(pHp, (TADDR)codeStart); } // Backout the GCInfo @@ -3455,43 +3444,184 @@ void EEJitManager::RemoveJitData (CodeHeader * pCHdr, size_t GCinfo_len, size_t 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 -// at an element that is about to be deleted. All such threads are guarded with a reader count, so if the -// 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) +// 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 +void EECodeGenManager::RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); + +#ifdef FEATURE_INTERPRETER + +template +void EECodeGenManager::RemoveJitData(InterpreterCodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len); +#endif // FEATURE_INTERPRETER + +#endif // !DACCESS_COMPILE + + +GCInfoToken EEJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken) { CONTRACTL { NOTHROW; GC_NOTRIGGER; + SUPPORTS_DAC; } CONTRACTL_END; - CrstHolder ch(&m_CodeHeapCritSec); + // The JIT-ed code always has the current version of GCInfo + return{ GetCodeHeader(MethodToken)->GetGCInfo(), GCINFO_VERSION }; +} - DomainCodeHeapList **ppList = m_DomainCodeHeaps.Table(); - int count = m_DomainCodeHeaps.Count(); +#ifdef FEATURE_INTERPRETER +GCInfoToken InterpreterJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } CONTRACTL_END; - for (int i=0; i < count; i++) { - if (ppList[i]->m_pAllocator== pAllocator) { - DomainCodeHeapList *pList = ppList[i]; - m_DomainCodeHeaps.DeleteByIndex(i); + // The JIT-ed code always has the current version of GCInfo + return{ GetCodeHeader(MethodToken)->GetGCInfo(), GCINFO_VERSION }; +} +#endif // FEATURE_INTERPRETER - // pHeapList is allocated in pHeap, so only need to delete the LoaderHeap itself - count = pList->m_CodeHeapList.Count(); - for (i=0; i < count; i++) { - HeapList *pHeapList = pList->m_CodeHeapList[i]; - DeleteCodeHeap(pHeapList); - } +// creates an enumeration and returns the number of EH clauses +unsigned EEJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState) +{ + LIMITED_METHOD_CONTRACT; + EE_ILEXCEPTION * EHInfo = GetCodeHeader(MethodToken)->GetEHInfo(); - // this is ok to do delete as anyone accessing the DomainCodeHeapList structure holds the critical section. - delete pList; + pEnumState->iCurrentPos = 0; // since the EH info is not compressed, the clause number is used to do the enumeration + pEnumState->pExceptionClauseArray = 0; - break; - } - } + if (!EHInfo) + return 0; + + pEnumState->pExceptionClauseArray = dac_cast(EHInfo->EHClause(0)); + 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) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + unsigned iCurrentPos = pEnumState->iCurrentPos; + pEnumState->iCurrentPos++; + + EE_ILEXCEPTION_CLAUSE* pClause = &(dac_cast(pEnumState->pExceptionClauseArray)[iCurrentPos]); + *pEHClauseOut = *pClause; + return dac_cast(pClause); +} + +#ifndef DACCESS_COMPILE +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 + // the processing of a hard SO. Contracts use a significant amount of stack + // which we can't afford for those cases. + STATIC_CONTRACT_THROWS; + STATIC_CONTRACT_GC_TRIGGERS; + + _ASSERTE(NULL != pCf); + _ASSERTE(NULL != pEHClause); + _ASSERTE(IsTypedHandler(pEHClause)); + + + TypeHandle typeHnd = TypeHandle(); + mdToken typeTok = mdTokenNil; + + // CachedTypeHandle's are filled in at JIT time, and not cached when accessed multiple times + if (HasCachedTypeHandle(pEHClause)) + { + return TypeHandle::FromPtr(pEHClause->TypeHandle); + } + else + { + typeTok = pEHClause->ClassToken; + } + + MethodDesc* pMD = pCf->GetFunction(); + Module* pModule = pMD->GetModule(); + PREFIX_ASSUME(pModule != NULL); + + SigTypeContext typeContext(pMD); + return ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, typeTok, &typeContext, + ClassLoader::ReturnNullIfNotFound); +} + +void EEJitManager::UnpublishUnwindInfoForMethod(TADDR codeStart) +{ +#if defined(TARGET_AMD64) + UnwindInfoTable::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 +// at an element that is about to be deleted. All such threads are guarded with a reader count, so if the +// 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 EECodeGenManager::Unload(LoaderAllocator *pAllocator) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + CrstHolder ch(&m_CodeHeapCritSec); + + DomainCodeHeapList **ppList = m_DomainCodeHeaps.Table(); + int count = m_DomainCodeHeaps.Count(); + + for (int i=0; i < count; i++) { + if (ppList[i]->m_pAllocator== pAllocator) { + DomainCodeHeapList *pList = ppList[i]; + m_DomainCodeHeaps.DeleteByIndex(i); + + // pHeapList is allocated in pHeap, so only need to delete the LoaderHeap itself + count = pList->m_CodeHeapList.Count(); + for (i=0; i < count; i++) { + HeapList *pHeapList = pList->m_CodeHeapList[i]; + DeleteCodeHeap(pHeapList); + } + + // this is ok to do delete as anyone accessing the DomainCodeHeapList structure holds the critical section. + delete pList; + + break; + } + } ppList = m_DynamicDomainCodeHeaps.Table(); count = m_DynamicDomainCodeHeaps.Count(); for (int i=0; i < count; i++) { @@ -3529,7 +3659,7 @@ EEJitManager::DomainCodeHeapList::~DomainCodeHeapList() LIMITED_METHOD_CONTRACT; } -void EEJitManager::RemoveCodeHeapFromDomainList(CodeHeap *pHeap, LoaderAllocator *pAllocator) +void EECodeGenManager::RemoveCodeHeapFromDomainList(CodeHeap *pHeap, LoaderAllocator *pAllocator) { CONTRACTL { NOTHROW; @@ -3565,7 +3695,52 @@ 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; + SetCodeManager(ExecutionManager::GetInterpreterCodeManager()); +} + +BOOL InterpreterJitManager::LoadInterpreter() +{ + STANDARD_VM_CONTRACT; + + // 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 interpreter 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_INTERPRETER; + 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 { @@ -3599,9 +3774,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 { @@ -3649,7 +3827,7 @@ void EEJitManager::CleanupCodeHeaps() } } -void EEJitManager::RemoveFromCleanupList(HostCodeHeap *pCodeHeap) +void EECodeGenManager::RemoveFromCleanupList(HostCodeHeap *pCodeHeap) { CONTRACTL { NOTHROW; @@ -3679,7 +3857,7 @@ void EEJitManager::RemoveFromCleanupList(HostCodeHeap *pCodeHeap) } } -void EEJitManager::AddToCleanupList(HostCodeHeap *pCodeHeap) +void EECodeGenManager::AddToCleanupList(HostCodeHeap *pCodeHeap) { CONTRACTL { NOTHROW; @@ -3709,7 +3887,7 @@ void EEJitManager::AddToCleanupList(HostCodeHeap *pCodeHeap) } } -void EEJitManager::DeleteCodeHeap(HeapList *pHeapList) +void EECodeGenManager::DeleteCodeHeap(HeapList *pHeapList) { CONTRACTL { NOTHROW; @@ -3733,7 +3911,7 @@ void EEJitManager::DeleteCodeHeap(HeapList *pHeapList) pHp->SetNext(pHeapList->GetNext()); } - DeleteEEFunctionTable((PVOID)pHeapList->GetModuleBase()); + DeleteFunctionTable((PVOID)pHeapList->GetModuleBase()); ExecutionManager::DeleteRange((TADDR)pHeapList->GetModuleBase()); @@ -3748,7 +3926,8 @@ void EEJitManager::DeleteCodeHeap(HeapList *pHeapList) #endif // #ifndef DACCESS_COMPILE -static CodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & request) +template +static TCodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & request) { CONTRACTL { NOTHROW; @@ -3759,7 +3938,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; @@ -3768,8 +3947,8 @@ static CodeHeader * GetCodeHeaderFromDebugInfoRequest(const DebugInfoRequest & r //----------------------------------------------------------------------------- // Get vars from Jit Store //----------------------------------------------------------------------------- -BOOL EEJitManager::GetBoundariesAndVars( - const DebugInfoRequest & request, +BOOL EECodeGenManager::GetBoundariesAndVarsWorker( + PTR_BYTE pDebugInfo, IN FP_IDS_NEW fpNew, IN void * pNewData, OUT ULONG32 * pcMap, OUT ICorDebugInfo::OffsetMapping **ppMap, @@ -3782,11 +3961,6 @@ BOOL EEJitManager::GetBoundariesAndVars( SUPPORTS_DAC; } CONTRACTL_END; - CodeHeader * 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; @@ -3814,8 +3988,30 @@ BOOL EEJitManager::GetBoundariesAndVars( return TRUE; } -BOOL EEJitManager::GetRichDebugInfo( - const DebugInfoRequest& request, +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; + + CodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + _ASSERTE(pHdr != NULL); + + PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); + + return GetBoundariesAndVarsWorker(pDebugInfo, fpNew, pNewData, pcMap, ppMap, pcVars, ppVars); +} + +BOOL EECodeGenManager::GetRichDebugInfoWorker( + PTR_BYTE pDebugInfo, IN FP_IDS_NEW fpNew, IN void* pNewData, OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, OUT ULONG32* pNumInlineTree, @@ -3833,11 +4029,6 @@ BOOL EEJitManager::GetRichDebugInfo( return FALSE; } - CodeHeader * 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; @@ -3851,6 +4042,74 @@ BOOL EEJitManager::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; + + CodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + _ASSERTE(pHdr != NULL); + + PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); + + return GetRichDebugInfoWorker(pDebugInfo, 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; + + InterpreterCodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + _ASSERTE(pHdr != NULL); + + PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); + + return GetBoundariesAndVarsWorker(pDebugInfo, 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; + + InterpreterCodeHeader * pHdr = GetCodeHeaderFromDebugInfoRequest(request); + _ASSERTE(pHdr != NULL); + + PTR_BYTE pDebugInfo = pHdr->GetDebugInfo(); + + return GetRichDebugInfoWorker(pDebugInfo, fpNew, pNewData, ppInlineTree, pNumInlineTree, ppRichMappings, pNumRichMappings); +} +#endif // FEATURE_INTERPRETER + #ifdef DACCESS_COMPILE void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan) { @@ -3881,7 +4140,8 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ //----------------------------------------------------------------------------- // Enumerate for minidumps. //----------------------------------------------------------------------------- -void EEJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +template +void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfoWorker(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) { CONTRACTL { @@ -3895,10 +4155,59 @@ void EEJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags fl PCODE addrCode = pMD->GetNativeCode(); request.InitFromStartingAddr(pMD, addrCode); - CodeHeader * pHeader = GetCodeHeaderFromDebugInfoRequest(request); + 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) +{ + 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::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SUPPORTS_DAC; + } + CONTRACTL_END; + + EnumMemoryRegionsForMethodDebugInfoWorker(flags, pMD); +} +#endif // FEATURE_INTERPRETER + #endif // DACCESS_COMPILE PCODE EEJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) @@ -3909,11 +4218,22 @@ PCODE EEJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, D return pHeader->GetCodeStartAddress() + relOffset; } -BOOL EEJitManager::JitCodeToMethodInfo( - RangeSection * pRangeSection, - PCODE currentPC, - MethodDesc ** ppMethodDesc, - EECodeInfo * pCodeInfo) +#ifdef FEATURE_INTERPRETER +PCODE InterpreterJitManager::GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset) +{ + WRAPPER_NO_CONTRACT; + + InterpreterCodeHeader * pHeader = GetCodeHeader(MethodToken); + return pHeader->GetCodeStartAddress() + relOffset; +} +#endif // FEATURE_INTERPRETER + +template +BOOL EECodeGenManager::JitCodeToMethodInfoWorker( + RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo) { CONTRACTL { NOTHROW; @@ -3926,11 +4246,11 @@ 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; - CodeHeader * pCHdr = PTR_CodeHeader(start - sizeof(CodeHeader)); + TCodeHeader * pCHdr = (DPTR(TCodeHeader))(start - sizeof(TCodeHeader)); if (pCHdr->IsStubCodeBlock()) return FALSE; @@ -3943,7 +4263,7 @@ BOOL EEJitManager::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 @@ -3958,6 +4278,38 @@ BOOL EEJitManager::JitCodeToMethodInfo( return TRUE; } +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 { @@ -3979,7 +4331,7 @@ StubCodeBlockKind EEJitManager::GetStubCodeBlockKind(RangeSection * pRangeSectio } -TADDR EEJitManager::FindMethodCode(PCODE currentPC) +TADDR EECodeGenManager::FindMethodCode(PCODE currentPC) { CONTRACTL { NOTHROW; @@ -3990,13 +4342,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; @@ -4100,7 +4452,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; @@ -4112,7 +4464,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; @@ -4164,7 +4516,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; @@ -4175,7 +4527,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; @@ -4238,7 +4590,7 @@ PTR_RUNTIME_FUNCTION EEJitManager::LazyGetFunctionEntry(EECodeInfo * pCodeInfo) return NULL; } - CodeHeader * pHeader = GetCodeHeader(pCodeInfo->GetMethodToken()); + CodeHeader * pHeader = dac_cast(GetCodeHeader(pCodeInfo->GetMethodToken())); DWORD address = RUNTIME_FUNCTION__BeginAddress(pHeader->GetUnwindInfo(0)) + pCodeInfo->GetRelOffset(); @@ -4269,7 +4621,7 @@ DWORD EEJitManager::GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD } CONTRACTL_END; - CodeHeader * pCH = GetCodeHeader(MethodToken); + CodeHeader * pCH = dac_cast(GetCodeHeader(MethodToken)); TADDR moduleBase = JitTokenToModuleBase(MethodToken); _ASSERTE(pCH->GetNumberOfUnwindInfos() >= 1); @@ -4446,7 +4798,7 @@ extern "C" void GetRuntimeStackWalkInfo(IN ULONG64 ControlPc, #ifdef DACCESS_COMPILE -void EEJitManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) +void EECodeGenManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) { IJitManager::EnumMemoryRegions(flags); @@ -4506,6 +4858,11 @@ void ExecutionManager::Init() #ifdef FEATURE_READYTORUN m_pReadyToRunJitManager = new ReadyToRunJitManager(); #endif + +#ifdef FEATURE_INTERPRETER + m_pInterpreterCodeMan = new InterpreterCodeManager(); + m_pInterpreterJitManager = new InterpreterJitManager(); +#endif } #endif // #ifndef DACCESS_COMPILE @@ -4657,12 +5014,20 @@ 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 // 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)); @@ -4745,8 +5110,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 { @@ -4977,6 +5365,10 @@ void ExecutionManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) GetCodeRangeMap().EnumMem(); m_pDefaultCodeMan.EnumMem(); +#ifdef FEATURE_INTERPRETER + m_pInterpreterCodeMan.EnumMem(); +#endif // FEATURE_INTERPRETER + // // Walk structures and report. // @@ -5004,6 +5396,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 35c149355fae27..8a7daf320e0402 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -118,16 +118,16 @@ 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; // 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; @@ -144,9 +144,21 @@ typedef struct _hpRealCodeHdr public: // if we're using the indirect codeheaders then all enumeration is done by the code header -} RealCodeHeader; +}; + +struct InterpreterRealCodeHeader +{ +public: + PTR_BYTE phdrDebugInfo; + + // Note - *(&(pCodeHeader->phdrJitEHInfo) - sizeof(size_t)) + // contains the number of EH clauses, See CEECodeGenInfo::setEHcountWorker + PTR_EE_ILEXCEPTION phdrJitEHInfo; + PTR_BYTE phdrJitGCInfo; + PTR_MethodDesc phdrMDesc; +}; -typedef struct _hpCodeHdr +struct CodeHeader { PTR_RealCodeHeader pRealCodeHeader; @@ -247,12 +259,85 @@ typedef struct _hpCodeHdr } #endif // FEATURE_EH_FUNCLETS + +#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 +{ + 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; + } + 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; + } + + BOOL IsStubCodeBlock() + { + return FALSE; + } + #ifdef DACCESS_COMPILE void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); #endif // DACCESS_COMPILE +}; -} CodeHeader; +typedef DPTR(InterpreterCodeHeader) PTR_InterpreterCodeHeader; + +#endif // FEATURE_INTERPRETER //----------------------------------------------------------------------------- // This is a structure used to consolidate the information that we @@ -271,6 +356,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 +364,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 +385,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 +393,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 +409,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 +473,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 +512,9 @@ class LoaderCodeHeap : CodeHeap ExplicitControlLoaderHeap m_LoaderHeap; SSIZE_T m_cbMinNextPad; - LoaderCodeHeap(); +#ifndef DACCESS_COMPILE + LoaderCodeHeap(bool fMakeExecutable); +#endif public: static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap *pJitMetaHeap); @@ -566,6 +659,7 @@ struct RangeSection RANGE_SECTION_COLLECTIBLE = 0x1, RANGE_SECTION_CODEHEAP = 0x2, RANGE_SECTION_RANGELIST = 0x4, + RANGE_SECTION_INTERPRETER = 0x8, }; #ifdef FEATURE_READYTORUN @@ -1580,14 +1674,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; @@ -1651,13 +1745,143 @@ 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; + friend class EECodeInfo; + + 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; + + 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: + BOOL GetBoundariesAndVarsWorker( + 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); + + BOOL GetRichDebugInfoWorker( + PTR_BYTE pDebugInfo, + IN FP_IDS_NEW fpNew, IN void* pNewData, + OUT ICorDebugInfo::InlineTreeNode** ppInlineTree, + OUT ULONG32* pNumInlineTree, + OUT ICorDebugInfo::RichOffsetMapping** ppRichMappings, + OUT ULONG32* pNumRichMappings); + + template + BOOL JitCodeToMethodInfoWorker( + RangeSection * pRangeSection, + PCODE currentPC, + MethodDesc ** ppMethodDesc, + EECodeInfo * pCodeInfo); + +public: +#ifndef DACCESS_COMPILE + virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause, + CrawlFrame *pCf); + + template + void RemoveJitData(TCodeHeader* pCHdr, size_t GCinfo_len, size_t EHinfo_len); + 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 + ); + + BYTE *allocFromJitMetaHeap(MethodDesc *pMD, DWORD blockSize, 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); + 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); + LoaderHeap* GetJitMetaHeap(MethodDesc *pMD); + + HeapList * GetCodeHeapList() + { + return m_pCodeHeap; + } + +#else // !DACCESS_COMPILE + virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); +protected: + template + void EnumMemoryRegionsForMethodDebugInfoWorker(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 +1926,7 @@ struct JumpStubBlockHeader /*****************************************************************************/ -class EEJitManager : public IJitManager +class EEJitManager final : public EECodeGenManager { #ifdef DACCESS_COMPILE friend class ClrDataAccess; @@ -1711,9 +1935,18 @@ class EEJitManager : public IJitManager friend class CheckDuplicatedStructLayouts; friend class CodeHeapIterator; - VPTR_VTABLE_CLASS(EEJitManager, IJitManager) + VPTR_VTABLE_CLASS(EEJitManager, EECodeGenManager) public: + virtual ICorJitCompiler* GetCompiler() + { + return m_jit; + } + + virtual ICorJitCompiler* GetAltCompiler() + { + 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. @@ -1786,29 +2019,16 @@ class EEJitManager : public IJitManager 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(); +#ifdef DACCESS_COMPILE + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); +#endif // DACCESS_COMPILE + +#if !defined DACCESS_COMPILE 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, @@ -1829,10 +2049,6 @@ class EEJitManager : public IJitManager 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,61 +2061,7 @@ 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; @@ -1925,6 +2087,9 @@ protected : return (TADDR)m_Iterator.GetMethodCode(); } }; +protected: + virtual void UnpublishUnwindInfoForMethod(TADDR codeStart); + virtual void DeleteFunctionTable(PVOID pvTableID); #endif // !DACCESS_COMPILE private: @@ -1941,25 +2106,9 @@ 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 +2241,26 @@ 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(); + + static ICodeManager* GetInterpreterCodeManager() + { + LIMITED_METHOD_CONTRACT; + return (ICodeManager *)m_pInterpreterCodeMan; + } +#endif // FEATURE_INTERPRETER + static void Unload(LoaderAllocator *pLoaderAllocator); static void AddCodeRange(TADDR StartRange, TADDR EndRange, @@ -2153,6 +2320,10 @@ class ExecutionManager #ifdef FEATURE_READYTORUN SPTR_DECL(ReadyToRunJitManager, m_pReadyToRunJitManager); #endif +#ifdef FEATURE_INTERPRETER + SPTR_DECL(InterpreterJitManager, m_pInterpreterJitManager); + SPTR_DECL(InterpreterCodeManager, m_pInterpreterCodeMan); +#endif static CrstStatic m_JumpStubCrst; static CrstStatic m_RangeCrst; // Acquire before writing into m_CodeRangeList and m_DataRangeList @@ -2449,6 +2620,142 @@ class ReadyToRunJitManager final: public IJitManager #endif +#ifdef FEATURE_INTERPRETER + +class InterpreterJitManager final : public EECodeGenManager +{ + VPTR_VTABLE_CLASS(InterpreterJitManager, EECodeGenManager) +public: + ICorJitCompiler * m_interpreter; + HINSTANCE m_interpreterHandle; + + InterpreterJitManager(); + + virtual ICorJitCompiler* GetCompiler() + { + return m_interpreter; + } + + virtual ICorJitCompiler* GetAltCompiler() + { + return NULL; + } + + BOOL LoadInterpreter(); + + BOOL IsInterpreterLoaded() + { + LIMITED_METHOD_CONTRACT; + return m_interpreter != NULL; + } + + virtual DWORD GetCodeType() + { + LIMITED_METHOD_DAC_CONTRACT; + // Interpreter-TODO: consider adding some extra flag for the interpreter + 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); + } + + 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) + { + // Not used for the interpreter + _ASSERTE(FALSE); + return PTR_NULL; + } + + virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo) + { + // Not used for the interpreter + _ASSERTE(FALSE); + return 0; + } + + virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength) + { + // Not used for the interpreter + _ASSERTE(FALSE); + return 0; + } + +#if !defined DACCESS_COMPILE +protected: + virtual void UnpublishUnwindInfoForMethod(TADDR codeStart) + { + // Nothing to do for the interpreter + } + + virtual void DeleteFunctionTable(PVOID pvTableID) + { + // Nothing to do for the interpreter + } + +public: +#endif // !DACCESS_COMPILE + +#endif // FEATURE_EH_FUNCLETS + + virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) + { + return STUB_CODE_BLOCK_UNKNOWN; + } + +#if defined(DACCESS_COMPILE) + + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); + +#if defined(FEATURE_EH_FUNCLETS) + virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) + { + // 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 @@ -2460,7 +2767,10 @@ class ReadyToRunJitManager final: public IJitManager // class EECodeInfo { - friend BOOL EEJitManager::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 @@ -2594,6 +2904,36 @@ ULONG GetFixedStackSize(); }; +#ifdef FEATURE_INTERPRETER + +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); + return dac_cast(methodStartAddress - sizeof(InterpreterCodeHeader)); +} + +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" void ThrowOutOfMemoryWithinRange(); 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/dynamicmethod.cpp b/src/coreclr/vm/dynamicmethod.cpp index 5285bc76e7af1c..2fc4698f2b3b4e 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*) { @@ -335,7 +335,7 @@ HeapList* HostCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, EEJitManager } 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, EEJitManager RETURN pHp; } -HostCodeHeap::HostCodeHeap(EEJitManager *pJitManager) +HostCodeHeap::HostCodeHeap(EECodeGenManager *pJitManager, bool isExecutable) { CONTRACTL { @@ -369,6 +369,7 @@ HostCodeHeap::HostCodeHeap(EEJitManager *pJitManager) m_TotalBytesAvailable = 0; m_ApproximateLargestBlock = 0; m_AllocationCount = 0; + m_isExecutable = isExecutable; m_pHeapList = NULL; m_pJitManager = (PTR_EEJitManager)pJitManager; m_pFreeList = NULL; @@ -439,19 +440,29 @@ 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) +#ifdef FEATURE_INTERPRETER + if (pInfo->IsInterpreted()) { - // This should only ever happen with fault injection - _ASSERTE(g_pConfig->ShouldInjectFault(INJECTFAULT_DYNAMICCODEHEAP)); - delete pHp; - ThrowOutOfMemory(); + pHp->CLRPersonalityRoutine = NULL; } + else +#endif // FEATURE_INTERPRETER + { +#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 +482,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)); @@ -676,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. @@ -685,6 +703,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); @@ -694,7 +713,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 - codeHeaderSize; ExecutableWriterHolder trackerWriterHolder((TrackAllocation **)(pHdr) - 1, sizeof(TrackAllocation *)); *trackerWriterHolder.GetRW() = pTracker; @@ -757,7 +776,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 894bd178856ae6..7a17acffc9b5b1 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; @@ -284,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 @@ -302,10 +307,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, 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/eetwain.cpp b/src/coreclr/vm/eetwain.cpp index 0c06eaf159e6f3..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) @@ -2394,3 +2277,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/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 00eede9ce5685b..7fa84d674018d4 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 CEEJitInfo::WriteCodeBytes() +template +void CEECodeGenInfo::SetRealCodeHeader() { - LIMITED_METHOD_CONTRACT; - if (m_pRealCodeHeader != NULL) { // Restore the read only version of the real code header - m_CodeHeaderRW->SetRealCodeHeader(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 CEEJitInfo::WriteCodeBytes() } /*********************************************************************/ -void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr) +void CEEJitInfo::BackoutJitData(EECodeGenManager * jitMgr) { CONTRACTL { NOTHROW; @@ -10927,13 +10933,28 @@ void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr) // the code bytes to the target memory location. WriteCodeBytes(); - CodeHeader* pCodeHeader = m_CodeHeader; + CodeHeader* pCodeHeader = (CodeHeader*)m_CodeHeader; if (pCodeHeader) jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len); } +template +void CEECodeGenInfo::NibbleMapSet() +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + TCodeHeader* pCodeHeader = (TCodeHeader*)m_CodeHeader; + + // 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. + m_jitManager->NibbleMapSet(m_pCodeHeap, pCodeHeader->GetCodeStartAddress(), m_codeWriteBufferSize - sizeof(TCodeHeader)); +} + /*********************************************************************/ -void CEEJitInfo::WriteCode(EEJitManager * jitMgr) +void CEEJitInfo::WriteCode(EECodeGenManager * jitMgr) { CONTRACTL { THROWS; @@ -10941,24 +10962,19 @@ void CEEJitInfo::WriteCode(EEJitManager * jitMgr) } 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)); + 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, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos); + UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, ((CodeHeader*)m_CodeHeader)->GetUnwindInfo(0), m_totalUnwindInfos); #endif // defined(TARGET_AMD64) - } - /*********************************************************************/ // 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 +10993,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 +11011,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 +11025,7 @@ void CEEJitInfo::reportRichMappings( JIT_TO_EE_TRANSITION(); - if (m_jitManager->IsStoringRichDebugInfo()) + if (((EECodeGenManager*)m_jitManager)->IsStoringRichDebugInfo()) { m_inlineTreeNodes = inlineTreeNodes; m_numInlineTreeNodes = numInlineTreeNodes; @@ -11025,7 +11041,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 +11101,82 @@ PatchpointInfo* CEEJitInfo::getOSRInfo(unsigned* ilOffset) return result; } -void CEEJitInfo::CompressDebugInfo() +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; @@ -11093,11 +11184,107 @@ void CEEJitInfo::CompressDebugInfo() MODE_PREEMPTIVE; } CONTRACTL_END; -#ifdef FEATURE_ON_STACK_REPLACEMENT - PatchpointInfo* patchpointInfo = m_pPatchpointInfoFromJit; -#else - PatchpointInfo* patchpointInfo = NULL; -#endif + BYTE * 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->allocFromJitMetaHeap(m_pMethodBeingCompiled,(DWORD)size, &m_GCinfo_len); + _ASSERTE(block); // allocFromJitMetaHeap throws if there's not enough memory + + ((InterpreterCodeHeader*)m_CodeHeaderRW)->SetGCInfo(block); + + 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 { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + PatchpointInfo* patchpointInfo = GetPatchpointInfo(); // Don't track JIT info for DynamicMethods. if (m_pMethodBeingCompiled->IsDynamicMethod() && !g_pConfig->GetTrackDynamicMethodDebugInfo()) @@ -11129,7 +11316,7 @@ void CEEJitInfo::CompressDebugInfo() writeFlagByte, m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap()); - m_CodeHeaderRW->SetDebugInfo(pDebugInfo); + SetDebugInfo(pDebugInfo); } EX_CATCH { @@ -11285,7 +11472,9 @@ void CEEJitInfo::allocUnwindInfo ( _ASSERTE(m_usedUnwindInfos > 0); } - PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeaderRW->GetUnwindInfo(m_usedUnwindInfos); + CodeHeader *pCodeHeaderRW = (CodeHeader *)m_CodeHeaderRW; + + PT_RUNTIME_FUNCTION pRuntimeFunction = pCodeHeaderRW->GetUnwindInfo(m_usedUnwindInfos); m_usedUnwindInfos++; @@ -11355,7 +11544,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 = pCodeHeaderRW->GetUnwindInfo(iUnwindInfo); _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress + writeableOffset) || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress + writeableOffset) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction))); } @@ -11711,6 +11900,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 } /*********************************************************************/ @@ -12249,7 +12447,6 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) codeAlignment = 16; } totalSize.AlignUp(codeAlignment); - if (roDataAlignment > codeAlignment) { // Add padding to align read-only data. totalSize += (roDataAlignment - codeAlignment); @@ -12291,18 +12488,18 @@ 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_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(); #endif - BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress(); + BYTE* current = (BYTE *)((CodeHeader*)m_CodeHeader)->GetCodeStartAddress(); size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader; *codeBlock = current; @@ -12329,7 +12526,7 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) current += m_totalUnwindSize; #endif - _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value()); + _ASSERTE((SIZE_T)(current - (BYTE *)((CodeHeader*)m_CodeHeader)->GetCodeStartAddress()) <= totalSize.Value()); #ifdef _DEBUG m_codeSize = codeSize; @@ -12347,12 +12544,12 @@ void * CEEJitInfo::allocGCInfo (size_t size) MODE_PREEMPTIVE; } CONTRACTL_END; - void * block = NULL; + BYTE * block = NULL; JIT_TO_EE_TRANSITION(); _ASSERTE(m_CodeHeaderRW != 0); - _ASSERTE(m_CodeHeaderRW->GetGCInfo() == 0); + _ASSERTE(((CodeHeader*)m_CodeHeaderRW)->GetGCInfo() == 0); #ifdef HOST_64BIT if (size & 0xFFFFFFFF80000000LL) @@ -12361,22 +12558,18 @@ void * CEEJitInfo::allocGCInfo (size_t size) } #endif // HOST_64BIT - block = m_jitManager->allocGCInfo(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(m_CodeHeaderRW->GetGCInfo() != 0 && block == m_CodeHeaderRW->GetGCInfo()); + ((CodeHeader*)m_CodeHeaderRW)->SetGCInfo(block); EE_TO_JIT_TRANSITION(); return block; } -/*********************************************************************/ -void CEEJitInfo::setEHcount ( - unsigned cEH) +template +void CEECodeGenInfo::setEHcountWorker(unsigned cEH) { CONTRACTL { THROWS; @@ -12388,19 +12581,38 @@ void CEEJitInfo::setEHcount ( _ASSERTE(cEH != 0); _ASSERTE(m_CodeHeaderRW != 0); - _ASSERTE(m_CodeHeaderRW->GetEHInfo() == 0); - EE_ILEXCEPTION* ret; - ret = m_jitManager->allocEHInfo(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); - _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && m_CodeHeaderRW->GetEHInfo()->EHCount() == cEH); + 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); + + pCodeHeaderRW->SetEHInfo((EE_ILEXCEPTION*)(pEHInfo + sizeof(size_t))); + pCodeHeaderRW->GetEHInfo()->Init(cEH); + *((size_t *)pEHInfo) = cEH; EE_TO_JIT_TRANSITION(); } /*********************************************************************/ -void CEEJitInfo::setEHinfo ( +void CEEJitInfo::setEHcount ( + unsigned cEH) +{ + WRAPPER_NO_CONTRACT; + + setEHcountWorker(cEH); +} + +void CEECodeGenInfo::setEHinfoWorker( + EE_ILEXCEPTION *pEHInfo, unsigned EHnumber, const CORINFO_EH_CLAUSE* clause) { @@ -12410,12 +12622,9 @@ void CEEJitInfo::setEHinfo ( MODE_PREEMPTIVE; } CONTRACTL_END; - JIT_TO_EE_TRANSITION(); - - // Fix make the Code Manager EH clauses EH_INFO+ - _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && EHnumber < m_CodeHeaderRW->GetEHInfo()->EHCount()); + _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; @@ -12443,13 +12652,30 @@ void CEEJitInfo::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 CEEJitInfo::getEHinfo( +void CEECodeGenInfo::getEHinfo( CORINFO_METHOD_HANDLE ftn, /* IN */ unsigned EHnumber, /* IN */ CORINFO_EH_CLAUSE* clause) /* OUT */ @@ -12480,15 +12706,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; @@ -12496,36 +12719,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 @@ -12533,31 +12768,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, @@ -12821,6 +13044,168 @@ BOOL g_fAllowRel32 = TRUE; #endif +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()) + 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 0; + } + + 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!! // ******************************************************************** @@ -12854,6 +13239,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()) { @@ -12913,233 +13310,99 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, *pJitFlags = GetCompileFlags(config, ftn, &methodInfo); +#ifdef FEATURE_INTERPRETER + bool useInterpreter = interpreterMgr->IsInterpreterLoaded(); + + if (useInterpreter) + { + 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 + + if (!ret) + { #if defined(TARGET_AMD64) || defined(TARGET_ARM64) - BOOL fForceJumpStubOverflow = FALSE; + BOOL fForceJumpStubOverflow = FALSE; #ifdef _DEBUG - // Always exercise the overflow codepath with force relocs - if (PEDecoder::GetForceRelocs()) - fForceJumpStubOverflow = TRUE; + // 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(); + BOOL fAllowRel32 = (g_fAllowRel32 | fForceJumpStubOverflow) && g_pConfig->JitEnableOptionalRelocs(); #endif - size_t reserveForJumpStubs = 0; + 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)); + 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. - { - 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 (SUCCEEDED(res)) - { - jitInfo.WriteCode(jitMgr); -#if defined(DEBUGGING_SUPPORTED) - // - // Notify the debugger that we have successfully jitted the function - // - if (g_pDebugInterface) + // 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)) { - if (!jitInfo.JitAgain()) - { - g_pDebugInterface->JITComplete(nativeCodeVersion, (TADDR)nativeEntry); - } + unsigned ilOffset = 0; + PatchpointInfo* patchpointInfo = nativeCodeVersion.GetOSRInfo(&ilOffset); + jitInfo.SetOSRInfo(patchpointInfo, ilOffset); } -#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, pSizeOfCode); + 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..b6d981df4a56ba 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -565,20 +565,220 @@ 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 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; + } + + 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() + { + 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) = 0; + +protected: + + template + void setEHcountWorker(unsigned cEH); + + template + void SetRealCodeHeader(); + + template + void NibbleMapSet(); + + void getEHinfo( + CORINFO_METHOD_HANDLE ftn, /* IN */ + unsigned EHnumber, /* IN */ + CORINFO_EH_CLAUSE* clause /* OUT */ + ) 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 + void* 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 final : public CEECodeGenInfo { public: // ICorJitInfo stuff - void allocMem (AllocMemArgs *pArgs) override final; + void allocMem (AllocMemArgs *pArgs) override; + void * allocGCInfo(size_t size) override; + void setEHcount (unsigned cEH) override; + void setEHinfo ( + unsigned EHnumber, + const CORINFO_EH_CLAUSE* clause + ) override; + + void WriteCodeBytes(); + 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 */ @@ -588,28 +788,14 @@ class CEEJitInfo : public CEEInfo uint32_t unwindSize, /* IN */ uint8_t * pUnwindBlock, /* IN */ 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; + ) 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 */ @@ -618,24 +804,27 @@ class CEEJitInfo : public CEEInfo 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; - uint16_t getRelocTypeHint(void * target) override final; + uint32_t getExpectedTargetArchitecture() override; - uint32_t getExpectedTargetArchitecture() override final; + void BackoutJitData(EECodeGenManager * jitMgr) override; + void SetDebugInfo(PTR_BYTE pDebugInfo) override; void ResetForJitRetry() { @@ -644,36 +833,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 +873,7 @@ class CEEJitInfo : public CEEInfo return m_fJumpStubOverflow; } - BOOL JitAgain() + BOOL JitAgain() override { LIMITED_METHOD_CONTRACT; return m_fJumpStubOverflow; @@ -730,8 +890,18 @@ class CEEJitInfo : public CEEInfo LIMITED_METHOD_CONTRACT; m_reserveForJumpStubs = value; } + + PatchpointInfo* GetPatchpointInfo() override + { +#ifdef FEATURE_ON_STACK_REPLACEMENT + return m_pPatchpointInfoFromJit; +#else + return NULL; +#endif + } + #else - BOOL JitAgain() + BOOL JitAgain() override { LIMITED_METHOD_CONTRACT; return FALSE; @@ -756,46 +926,28 @@ 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_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 - 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_pPatchpointInfoFromJit(NULL), m_pPatchpointInfoFromRuntime(NULL), - m_ilOffset(0), + m_ilOffset(0) #endif - m_gphCache() { CONTRACTL { @@ -814,15 +966,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,23 +984,8 @@ 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 */ + void ** ppIndirection) override; /* OUT */ static PCODE getHelperFtnStatic(CorInfoHelpFunc ftnNum); // Override of CEEInfo::GetProfilingHandle. The first time this is called for a @@ -869,24 +997,18 @@ class CEEJitInfo : public CEEInfo bool *pbHookFunction, void **pProfilerHandle, bool *pbIndirectedHandles - ) override final; - - 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; + ) override; - void BackoutJitData(EEJitManager * jitMgr); + 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 WriteCode(EEJitManager * jitMgr); - - void setPatchpointInfo(PatchpointInfo* patchpointInfo) override final; - PatchpointInfo* getOSRInfo(unsigned* ilOffset) override final; + void setPatchpointInfo(PatchpointInfo* patchpointInfo) override; + PatchpointInfo* getOSRInfo(unsigned* ilOffset) override; protected : - void WriteCodeBytes(); - #ifdef FEATURE_PGO // PGO data struct ComputedPgoData @@ -906,13 +1028,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,50 +1046,57 @@ 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 +}; + +#ifdef FEATURE_INTERPRETER +class CInterpreterJitInfo final : 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; + void * allocGCInfo(size_t size) override; + void setEHcount (unsigned cEH) override; + void setEHinfo ( + unsigned EHnumber, + const CORINFO_EH_CLAUSE* clause + ) override; + + void WriteCodeBytes(); + void WriteCode(EECodeGenManager * jitMgr) override; + void BackoutJitData(EECodeGenManager * jitMgr) override; + void SetDebugInfo(PTR_BYTE pDebugInfo) override; + + void ResetForJitRetry() + { + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + CEECodeGenInfo::ResetForJitRetry(); + } }; +#endif // FEATURE_INTERPRETER /*********************************************************************/ /*********************************************************************/ diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 5257358d4758e5..e58ad1b4ec3e1e 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -70,6 +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 9880a627636720..82f0546ee1e80b 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -371,6 +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/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; diff --git a/src/tests/JIT/interpreter/InterpreterTester.cs b/src/tests/JIT/interpreter/InterpreterTester.cs index 9895bc2608082e..f06c22965d4234 100644 --- a/src/tests/JIT/interpreter/InterpreterTester.cs +++ b/src/tests/JIT/interpreter/InterpreterTester.cs @@ -16,15 +16,11 @@ 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_AltJitName"] = libInterp; - startInfo.EnvironmentVariables["DOTNET_AltJitPath"] = Path.Combine(coreRoot, libInterp); - startInfo.EnvironmentVariables["DOTNET_AltJit"] = "RunInterpreterTests"; + var startInfo = new ProcessStartInfo(Path.Combine(coreRoot, "corerun"), interpreterApp); + startInfo.EnvironmentVariables["DOTNET_Interpreter"] = "RunInterpreterTests"; using (Process p = Process.Start(startInfo)) {