diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index fdae380a90cb4f..bb14b672cb0c26 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -70,7 +70,9 @@ #define UNKNOWN_POINTER_TYPE SIZE_T -DEFINE_DACVAR(ULONG, PTR_RangeSection, ExecutionManager__m_CodeRangeList, ExecutionManager::m_CodeRangeList) +DEFINE_DACVAR(ULONG, PTR_RangeSectionHandle, ExecutionManager__m_RangeSectionHandleArray, ExecutionManager::m_RangeSectionHandleArray) +DEFINE_DACVAR(ULONG, LONG, ExecutionManager__m_RangeSectionArraySize, ExecutionManager::m_RangeSectionArraySize) +DEFINE_DACVAR(ULONG, LONG, ExecutionManager__m_RangeSectionArrayCapacity, ExecutionManager::m_RangeSectionArrayCapacity) DEFINE_DACVAR(ULONG, PTR_EECodeManager, ExecutionManager__m_pDefaultCodeMan, ExecutionManager::m_pDefaultCodeMan) DEFINE_DACVAR(ULONG, LONG, ExecutionManager__m_dwReaderCount, ExecutionManager::m_dwReaderCount) DEFINE_DACVAR(ULONG, LONG, ExecutionManager__m_dwWriterLock, ExecutionManager::m_dwWriterLock) diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 4e8117c7b7c6f6..27c0a415569d9a 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -51,11 +51,16 @@ SPTR_IMPL(ReadyToRunJitManager, ExecutionManager, m_pReadyToRunJitManager); #endif #ifndef DACCESS_COMPILE -Volatile ExecutionManager::m_CodeRangeList = NULL; +Volatile ExecutionManager::m_RangeSectionHandleArray = nullptr; +Volatile ExecutionManager::m_LastUsedRSIndex = -1; +Volatile ExecutionManager::m_RangeSectionArraySize = 0; +Volatile ExecutionManager::m_RangeSectionArrayCapacity = 0; Volatile ExecutionManager::m_dwReaderCount = 0; Volatile ExecutionManager::m_dwWriterLock = 0; #else -SPTR_IMPL(RangeSection, ExecutionManager, m_CodeRangeList); +SPTR_IMPL(RangeSectionHandle, ExecutionManager, m_RangeSectionHandleArray); +SVAL_IMPL(SIZE_T, ExecutionManager, m_RangeSectionArraySize); +SVAL_IMPL(SIZE_T, ExecutionManager, m_RangeSectionArrayCapacity); SVAL_IMPL(LONG, ExecutionManager, m_dwReaderCount); SVAL_IMPL(LONG, ExecutionManager, m_dwWriterLock); #endif @@ -4211,8 +4216,8 @@ ExecutionManager::FindCodeRange(PCODE currentPC, ScanFlag scanFlag) if (currentPC == NULL) return NULL; - if (scanFlag == ScanReaderLock) - return FindCodeRangeWithLock(currentPC); + //if (scanFlag == ScanReaderLock) + //return FindCodeRangeWithLock(currentPC); return GetRangeSection(currentPC); } @@ -4433,118 +4438,58 @@ RangeSection* ExecutionManager::GetRangeSection(TADDR addr) SUPPORTS_DAC; } CONTRACTL_END; - RangeSection * pHead = m_CodeRangeList; - - if (pHead == NULL) + if (m_RangeSectionHandleArray == nullptr) { return NULL; } - RangeSection *pCurr = pHead; - RangeSection *pLast = NULL; - #ifndef DACCESS_COMPILE - RangeSection *pLastUsedRS = (pCurr != NULL) ? pCurr->pLastUsed : NULL; - - if (pLastUsedRS != NULL) + int LastUsedRSIndex = (int)m_LastUsedRSIndex; + if (LastUsedRSIndex != -1) { - // positive case - if ((addr >= pLastUsedRS->LowAddress) && - (addr < pLastUsedRS->HighAddress) ) - { - return pLastUsedRS; - } + RangeSection* pRS = m_RangeSectionHandleArray[LastUsedRSIndex].pRS; + TADDR LowAddress = pRS->LowAddress; + TADDR HighAddress = pRS->HighAddress; - RangeSection * pNextAfterLastUsedRS = pLastUsedRS->pnext; + //positive case + if ((addr >= LowAddress) && (addr < HighAddress)) + return pRS; - // negative case - if ((addr < pLastUsedRS->LowAddress) && - (pNextAfterLastUsedRS == NULL || addr >= pNextAfterLastUsedRS->HighAddress)) - { + //negative case + if ((addr < LowAddress) && (LastUsedRSIndex == 0)) return NULL; - } } #endif - while (pCurr != NULL) - { - // See if addr is in [pCurr->LowAddress .. pCurr->HighAddress) - if (pCurr->LowAddress <= addr) - { - // Since we are sorted, once pCurr->HighAddress is less than addr - // then all subsequence ones will also be lower, so we are done. - if (addr >= pCurr->HighAddress) - { - // we'll return NULL and put pLast into pLastUsed - pCurr = NULL; - } - else - { - // addr must be in [pCurr->LowAddress .. pCurr->HighAddress) - _ASSERTE((pCurr->LowAddress <= addr) && (addr < pCurr->HighAddress)); - - // Found the matching RangeSection - // we'll return pCurr and put it into pLastUsed - pLast = pCurr; - } - - break; - } - pLast = pCurr; - pCurr = pCurr->pnext; - } + ReaderLockHolder rlh(HostCallPreference::NoHostCalls); #ifndef DACCESS_COMPILE - // Cache pCurr as pLastUsed in the head node - // Unless we are on an MP system with many cpus - // where this sort of caching actually diminishes scaling during server GC - // due to many processors writing to a common location - if (g_SystemInfo.dwNumberOfProcessors < 4 || !GCHeapUtilities::IsServerHeap() || !GCHeapUtilities::IsGCInProgress()) - pHead->pLastUsed = pLast; + while (!rlh.Acquired()); // rlh con did not yield and we have HOST_NOCALLS limitation + //negative case + LastUsedRSIndex = (int)m_LastUsedRSIndex; + if ((LastUsedRSIndex > 0) + && (addr < m_RangeSectionHandleArray[LastUsedRSIndex].LowAddress) + && (addr >= m_RangeSectionHandleArray[LastUsedRSIndex - 1].pRS->HighAddress)) + return NULL; #endif - return pCurr; -} - -RangeSection* ExecutionManager::GetRangeSectionAndPrev(RangeSection *pHead, TADDR addr, RangeSection** ppPrev) -{ - WRAPPER_NO_CONTRACT; - - RangeSection *pCurr; - RangeSection *pPrev; - RangeSection *result = NULL; + int foundIndex = FindRangeSectionHandleHelper(addr); - for (pPrev = NULL, pCurr = pHead; - pCurr != NULL; - pPrev = pCurr, pCurr = pCurr->pnext) +#ifndef DACCESS_COMPILE + if (foundIndex >= 0) { - // See if addr is in [pCurr->LowAddress .. pCurr->HighAddress) - if (pCurr->LowAddress > addr) - continue; - - if (addr >= pCurr->HighAddress) - break; - - // addr must be in [pCurr->LowAddress .. pCurr->HighAddress) - _ASSERTE((pCurr->LowAddress <= addr) && (addr < pCurr->HighAddress)); - - // Found the matching RangeSection - result = pCurr; - - // Write back pPrev to ppPrev if it is non-null - if (ppPrev != NULL) - *ppPrev = pPrev; - - break; + LastUsedRSIndex = foundIndex; } - - // If we failed to find a match write NULL to ppPrev if it is non-null - if ((ppPrev != NULL) && (result == NULL)) + else { - *ppPrev = NULL; + LastUsedRSIndex = (int)m_RangeSectionArraySize - 1; } - return result; + if (g_SystemInfo.dwNumberOfProcessors < 4 || !GCHeapUtilities::IsServerHeap() || !GCHeapUtilities::IsGCInProgress()) + m_LastUsedRSIndex = LastUsedRSIndex; +#endif + + return (foundIndex>=0)?m_RangeSectionHandleArray[foundIndex].pRS:NULL; } /* static */ @@ -4635,6 +4580,81 @@ PTR_Module ExecutionManager::FindModuleForGCRefMap(TADDR currentData) return dac_cast(pRS->pHeapListOrZapModule); } +/*********************************************************************/ +// This function returns coded index: a number to be converted +// to an actual index of RangeSectionHandleArray. Coded index uses +// non-negative values to store actual index of an element already +// existed in the array or it uses negative values to code an index +// to be used for placing a new element to the array. If value +// returned from FindRangeSectionHandleHelper is not negative, it can +// be immediately used to read an existing element like this: +// pRS = RangeSectionHandleArray[non_negative].pRS; +// If the value becomes negative then there is no element with +// requested TADDR in the RangeSectionHandleArray, and the value +// might be decoded to an actual index of RangeSectionHandleArray cell +// to place new RangeSectionHandle (if intended). +// The function to decode is DecodeRangeSectionIndex that takes +// negative coded index and returns an actual index. +// +int ExecutionManager::FindRangeSectionHandleHelper(TADDR addr) +{ + CONTRACTL { + NOTHROW; + HOST_NOCALLS; + GC_NOTRIGGER; + SUPPORTS_DAC; + } CONTRACTL_END; + + _ASSERTE(m_RangeSectionHandleArray != nullptr); + _ASSERTE(m_RangeSectionArrayCapacity != (SIZE_T)0); + + if ((int)m_RangeSectionArraySize == 0) + { + return EncodeRangeSectionIndex(0); + } + + int iLow = 0; + int iHigh = (int)m_RangeSectionArraySize - 1; + int iMid = (iHigh + iLow)/2; + + if(addr < m_RangeSectionHandleArray[0].LowAddress) + { + return EncodeRangeSectionIndex(0); + } + + if (addr >= m_RangeSectionHandleArray[iHigh].pRS->HighAddress) + { + return EncodeRangeSectionIndex(iHigh + 1); + } + + do + { + if (addr < m_RangeSectionHandleArray[iMid].LowAddress) + { + iHigh = iMid; + iMid = (iHigh + iLow)/2; + } + else if (addr >= m_RangeSectionHandleArray[iMid+1].LowAddress) + { + iLow = iMid + 1; + iMid = (iHigh + iLow)/2; + } + else + { + iLow = iHigh = iMid; + } + } while(iHigh > iLow); + + if ((addr >= m_RangeSectionHandleArray[iHigh].LowAddress) + && (addr < m_RangeSectionHandleArray[iHigh].pRS->HighAddress)) + { + return iHigh; + } + else + { + return EncodeRangeSectionIndex(iHigh + 1); + } +} #ifndef DACCESS_COMPILE /* NGenMem depends on this entrypoint */ @@ -4659,6 +4679,84 @@ void ExecutionManager::AddCodeRange(TADDR pStartRange, dac_cast(pHp)); } +void ExecutionManager::AddRangeSection(RangeSection *pRS) +{ + CONTRACTL { + GC_NOTRIGGER; + } CONTRACTL_END; + + if (m_RangeSectionHandleArray == nullptr) + { + m_RangeSectionHandleArray = new RangeSectionHandle[RangeSectionHandleArrayInitialSize]; + m_RangeSectionArrayCapacity = RangeSectionHandleArrayInitialSize; + m_RangeSectionArraySize = 0; + } + + if (m_RangeSectionArraySize == m_RangeSectionArrayCapacity) + { + //reallocate array +#ifdef _DEBUG + m_RangeSectionArrayCapacity = (SIZE_T)m_RangeSectionArrayCapacity + RangeSectionHandleArrayIncrement; +#else + m_RangeSectionArrayCapacity = (SIZE_T)m_RangeSectionArrayCapacity * RangeSectionHandleArrayExpansionFactor; +#endif //_DEBUG + RangeSectionHandle *tmp = new RangeSectionHandle[m_RangeSectionArrayCapacity]; + memcpy(tmp, m_RangeSectionHandleArray, m_RangeSectionArraySize*sizeof(RangeSectionHandle)); + delete[] m_RangeSectionHandleArray; + m_RangeSectionHandleArray = tmp; + } + + //where to add? + SIZE_T size = m_RangeSectionArraySize; + if ((size == 0) || (pRS->LowAddress >= m_RangeSectionHandleArray[size - 1].pRS->HighAddress)) + { + m_RangeSectionHandleArray[size].LowAddress = pRS->LowAddress; + m_RangeSectionHandleArray[size].pRS = pRS; + m_RangeSectionArraySize = size + 1; + return; + } + + int index = FindRangeSectionHandleHelper(pRS->LowAddress); + if (index < 0) + { + index = DecodeRangeSectionIndex(index); + //push and shift + memmove(m_RangeSectionHandleArray+index+1, m_RangeSectionHandleArray+index, (m_RangeSectionArraySize-index)*sizeof(RangeSectionHandle)); + m_RangeSectionHandleArray[index].LowAddress = pRS->LowAddress; + m_RangeSectionHandleArray[index].pRS = pRS; + m_RangeSectionArraySize = size + 1; +#ifndef DACCESS_COMPILE + if (m_LastUsedRSIndex >= index) + m_LastUsedRSIndex = m_LastUsedRSIndex + 1; +#endif + return; + } + return; +} + +void ExecutionManager::DeleteRangeSection(int index) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + if (m_RangeSectionHandleArray == nullptr) + return; + + if (index < 0) + return; + + memmove(m_RangeSectionHandleArray+index, m_RangeSectionHandleArray+index+1, (m_RangeSectionArraySize-index-1)*sizeof(RangeSectionHandle)); + m_RangeSectionArraySize--; +#ifndef DACCESS_COMPILE + if (m_LastUsedRSIndex > index) + m_LastUsedRSIndex = m_LastUsedRSIndex - 1; + else if (m_LastUsedRSIndex == index) + m_LastUsedRSIndex = (int)m_RangeSectionArraySize - 1; +#endif +} + void ExecutionManager::AddRangeHelper(TADDR pStartRange, TADDR pEndRange, IJitManager * pJit, @@ -4680,9 +4778,7 @@ void ExecutionManager::AddRangeHelper(TADDR pStartRange, pnewrange->LowAddress = pStartRange; pnewrange->HighAddress = pEndRange; pnewrange->pjit = pJit; - pnewrange->pnext = NULL; pnewrange->flags = flags; - pnewrange->pLastUsed = NULL; pnewrange->pHeapListOrZapModule = pHeapListOrZapModule; #if defined(TARGET_AMD64) pnewrange->pUnwindInfoTable = NULL; @@ -4690,48 +4786,9 @@ void ExecutionManager::AddRangeHelper(TADDR pStartRange, { CrstHolder ch(&m_RangeCrst); // Acquire the Crst before linking in a new RangeList - RangeSection * current = m_CodeRangeList; - RangeSection * previous = NULL; - - if (current != NULL) - { - while (true) - { - // Sort addresses top down so that more recently created ranges - // will populate the top of the list - if (pnewrange->LowAddress > current->LowAddress) - { - // Asserts if ranges are overlapping - _ASSERTE(pnewrange->LowAddress >= current->HighAddress); - pnewrange->pnext = current; - - if (previous == NULL) // insert new head - { - m_CodeRangeList = pnewrange; - } - else - { // insert in the middle - previous->pnext = pnewrange; - } - break; - } - - RangeSection * next = current->pnext; - if (next == NULL) // insert at end of list - { - current->pnext = pnewrange; - break; - } + WriterLockHolder wlh; - // Continue walking the RangeSection list - previous = current; - current = next; - } - } - else - { - m_CodeRangeList = pnewrange; - } + AddRangeSection(pnewrange); } } @@ -4743,7 +4800,7 @@ void ExecutionManager::DeleteRange(TADDR pStartRange) GC_NOTRIGGER; } CONTRACTL_END; - RangeSection *pCurr = NULL; + RangeSection *deleted = NULL; { // Acquire the Crst before unlinking a RangeList. // NOTE: The Crst must be acquired BEFORE we grab the writer lock, as the @@ -4757,51 +4814,21 @@ void ExecutionManager::DeleteRange(TADDR pStartRange) // require the reader lock, which would cause a deadlock). WriterLockHolder wlh; - RangeSection *pPrev = NULL; - - pCurr = GetRangeSectionAndPrev(m_CodeRangeList, pStartRange, &pPrev); - - // pCurr points at the Range that needs to be unlinked from the RangeList - if (pCurr != NULL) - { - - // If pPrev is NULL the the head of this list is to be deleted - if (pPrev == NULL) - { - m_CodeRangeList = pCurr->pnext; - } - else - { - _ASSERT(pPrev->pnext == pCurr); - - pPrev->pnext = pCurr->pnext; - } - - // Clear the cache pLastUsed in the head node (if any) - RangeSection * head = m_CodeRangeList; - if (head != NULL) - { - head->pLastUsed = NULL; - } - - // - // Cannot delete pCurr here because we own the WriterLock and if this is - // a hosted scenario then the hosting api callback cannot occur in a forbid - // suspend region, which the writer lock is. - // - } + int index = FindRangeSectionHandleHelper(pStartRange); + if (index >= 0) + deleted = m_RangeSectionHandleArray[index].pRS; + DeleteRangeSection(index); } - // // Now delete the node // - if (pCurr != NULL) + if (deleted != NULL) { #if defined(TARGET_AMD64) - if (pCurr->pUnwindInfoTable != 0) - delete pCurr->pUnwindInfoTable; + if (deleted->pUnwindInfoTable != 0) + delete deleted->pUnwindInfoTable; #endif // defined(TARGET_AMD64) - delete pCurr; + delete deleted; } } @@ -4809,24 +4836,27 @@ void ExecutionManager::DeleteRange(TADDR pStartRange) #ifdef DACCESS_COMPILE -void ExecutionManager::EnumRangeList(RangeSection* list, - CLRDataEnumMemoryFlags flags) +void ExecutionManager::EnumRangeSectionArray(CLRDataEnumMemoryFlags flags) { - while (list != NULL) + for (int i = 0; i < (int)m_RangeSectionArraySize; ++i) { // If we can't read the target memory, stop immediately so we don't work // with broken data. - if (!DacEnumMemoryRegion(dac_cast(list), sizeof(*list))) + RangeSection *pRS = m_RangeSectionHandleArray[i].pRS; +#if defined (_DEBUG) +EnumRangeArray_REDO: +#endif // (_DEBUG) + if (!DacEnumMemoryRegion(dac_cast(pRS), sizeof(*pRS))) break; - if (list->pjit.IsValid()) + if (pRS->pjit.IsValid()) { - list->pjit->EnumMemoryRegions(flags); + pRS->pjit->EnumMemoryRegions(flags); } - if (!(list->flags & RangeSection::RANGE_SECTION_CODEHEAP)) + if (!(pRS->flags & RangeSection::RANGE_SECTION_CODEHEAP)) { - PTR_Module pModule = dac_cast(list->pHeapListOrZapModule); + PTR_Module pModule = dac_cast(pRS->pHeapListOrZapModule); if (pModule.IsValid()) { @@ -4834,20 +4864,20 @@ void ExecutionManager::EnumRangeList(RangeSection* list, } } - list = list->pnext; #if defined (_DEBUG) - // Test hook: when testing on debug builds, we want an easy way to test that the while + // Test hook: when testing on debug builds, we want an easy way to test that the for loop // correctly terminates in the face of ridiculous stuff from the target. if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DumpGeneration_IntentionallyCorruptDataFromTarget) == 1) { // Force us to struggle on with something bad. - if (list == NULL) + if (i == (int)m_RangeSectionArraySize - 1) { - list = (RangeSection *)&flags; + i++; + pRS = (RangeSection *)&flags; + goto EnumRangeArray_REDO; } } #endif // (_DEBUG) - } } @@ -4861,16 +4891,16 @@ void ExecutionManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) // Report the global data portions. // - m_CodeRangeList.EnumMem(); + m_RangeSectionHandleArray.EnumMem(); m_pDefaultCodeMan.EnumMem(); // // Walk structures and report. // - if (m_CodeRangeList.IsValid()) + if (m_RangeSectionHandleArray.IsValid()) { - EnumRangeList(m_CodeRangeList, flags); + EnumRangeSectionArray(flags); } } #endif // #ifdef DACCESS_COMPILE diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 032ee960f63198..2dc8c295c65f23 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -608,6 +608,19 @@ class UnwindInfoTable { // address range to track the code heaps. typedef DPTR(struct RangeSection) PTR_RangeSection; +typedef DPTR(struct RangeSectionHandle) PTR_RangeSectionHandle; + +struct RangeSectionHandle +{ + TADDR LowAddress; + PTR_RangeSection pRS; + + RangeSectionHandle() + { + LowAddress = 0; + pRS = NULL; + } +}; struct RangeSection { @@ -616,15 +629,6 @@ struct RangeSection PTR_IJitManager pjit; // The owner of this address range -#ifndef DACCESS_COMPILE - // Volatile because of the list can be walked lock-free - Volatile pnext; // link rangesections in a sorted list -#else - PTR_RangeSection pnext; -#endif - - PTR_RangeSection pLastUsed; // for the head node only: a link to rangesections that was used most recently - enum RangeSectionFlags { RANGE_SECTION_NONE = 0x0, @@ -1167,6 +1171,29 @@ class ExecutionManager friend class ClrDataAccess; #endif + enum + { +#ifndef _DEBUG + RangeSectionHandleArrayInitialSize = 100, + RangeSectionHandleArrayExpansionFactor = 2 +#else + RangeSectionHandleArrayInitialSize = 8, + RangeSectionHandleArrayIncrement = 1 +#endif //(_DEBUG) + }; + + static int FindRangeSectionHandleHelper(TADDR addr); + + static int EncodeRangeSectionIndex(int index) + { + return -(index+1); + } + + static int DecodeRangeSectionIndex(int codedIndex) + { + return -codedIndex - 1; + } + public: static void Init(); @@ -1264,6 +1291,12 @@ class ExecutionManager SIZE_T Size, Module * pModule); +#ifndef DACCESS_COMPILE + static void AddRangeSection(RangeSection *pRS); + + static void DeleteRangeSection(int index); +#endif //DACCESS_COMPILE + static void DeleteRange(TADDR StartRange); static void CleanupCodeHeaps(); @@ -1280,11 +1313,8 @@ class ExecutionManager // FindZapModule flavor to be used during GC to find GCRefMap static PTR_Module FindModuleForGCRefMap(TADDR currentData); - static RangeSection* GetRangeSectionAndPrev(RangeSection *pRS, TADDR addr, RangeSection **ppPrev); - #ifdef DACCESS_COMPILE - static void EnumRangeList(RangeSection* list, - CLRDataEnumMemoryFlags flags); + static void EnumRangeSectionArray(CLRDataEnumMemoryFlags flags); static void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); #endif @@ -1318,11 +1348,16 @@ class ExecutionManager // infrastructure to manage readers so we can lock them out and delete domain data // make ReaderCount volatile because we have order dependency in READER_INCREMENT #ifndef DACCESS_COMPILE - static Volatile m_CodeRangeList; + static Volatile m_RangeSectionHandleArray; + static Volatile m_LastUsedRSIndex; + static Volatile m_RangeSectionArraySize; + static Volatile m_RangeSectionArrayCapacity; static Volatile m_dwReaderCount; static Volatile m_dwWriterLock; #else - SPTR_DECL(RangeSection, m_CodeRangeList); + SPTR_DECL(RangeSectionHandle, m_RangeSectionHandleArray); + SVAL_DECL(SIZE_T, m_RangeSectionArraySize); + SVAL_DECL(SIZE_T, m_RangeSectionArrayCapacity); SVAL_DECL(LONG, m_dwReaderCount); SVAL_DECL(LONG, m_dwWriterLock); #endif @@ -1357,8 +1392,6 @@ class ExecutionManager IJitManager* pJit, RangeSection::RangeSectionFlags flags, TADDR pHeapListOrZapModule); - static void DeleteRangeHelper(RangeSection** ppRangeList, - TADDR StartRange); #ifndef DACCESS_COMPILE static PCODE getNextJumpStub(MethodDesc* pMD, diff --git a/src/coreclr/vm/codeversion.cpp b/src/coreclr/vm/codeversion.cpp index 8fa82da46db6e2..e6ff66cfac9df8 100644 --- a/src/coreclr/vm/codeversion.cpp +++ b/src/coreclr/vm/codeversion.cpp @@ -1637,7 +1637,8 @@ PCODE CodeVersionManager::PublishVersionableCodeIfNecessary( MethodDesc* pMethodDesc, CallerGCMode callerGCMode, bool *doBackpatchRef, - bool *doFullBackpatchRef) + bool *doFullBackpatchRef, + Module* pModule) { STANDARD_VM_CONTRACT; _ASSERTE(!IsLockOwnedByCurrentThread()); @@ -1698,7 +1699,7 @@ PCODE CodeVersionManager::PublishVersionableCodeIfNecessary( // Record the caller's GC mode. config->SetCallerGCMode(callerGCMode); - pCode = pMethodDesc->PrepareCode(config); + pCode = pMethodDesc->PrepareCode(config, pModule); #ifdef FEATURE_CODE_VERSIONING if (config->ProfilerMayHaveActivatedNonDefaultCodeVersion()) diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index bacc5305d9bb6c..b3ec3345114168 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -594,7 +594,8 @@ class CodeVersionManager MethodDesc* pMethodDesc, CallerGCMode callerGCMode, bool *doBackpatchRef, - bool *doFullBackpatchRef); + bool *doFullBackpatchRef, + Module* pModule = NULL); HRESULT PublishNativeCodeVersion(MethodDesc* pMethodDesc, NativeCodeVersion nativeCodeVersion); HRESULT GetOrCreateMethodDescVersioningState(MethodDesc* pMethod, MethodDescVersioningState** ppMethodDescVersioningState); HRESULT GetOrCreateILCodeVersioningState(Module* pModule, mdMethodDef methodDef, ILCodeVersioningState** ppILCodeVersioningState); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index cdd50fc038a727..d1890205c827fd 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1645,7 +1645,7 @@ class MethodDesc // PCODE DoBackpatch(MethodTable * pMT, MethodTable * pDispatchingMT, BOOL fFullBackPatch); - PCODE DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMode = CallerGCMode::Unknown); + PCODE DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMode = CallerGCMode::Unknown, Module* pModule = NULL); VOID GetMethodInfo(SString &namespaceOrClassName, SString &methodName, SString &methodSignature); VOID GetMethodInfoWithNewSig(SString &namespaceOrClassName, SString &methodName, SString &methodSignature); @@ -1846,12 +1846,12 @@ class MethodDesc #ifndef DACCESS_COMPILE public: PCODE PrepareInitialCode(CallerGCMode callerGCMode = CallerGCMode::Unknown); - PCODE PrepareCode(PrepareCodeConfig* pConfig); + PCODE PrepareCode(PrepareCodeConfig* pConfig, Module* pModule = NULL); private: - PCODE PrepareILBasedCode(PrepareCodeConfig* pConfig); - PCODE GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier); - PCODE GetPrecompiledR2RCode(PrepareCodeConfig* pConfig); + PCODE PrepareILBasedCode(PrepareCodeConfig* pConfig, Module* pModule = NULL); + PCODE GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier, Module* pModule = NULL); + PCODE GetPrecompiledR2RCode(PrepareCodeConfig* pConfig, Module* pModule_probe = NULL); PCODE GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0); COR_ILMETHOD_DECODER* GetAndVerifyILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory); COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory); diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 342ea0c3912af8..25772b3d649517 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -314,14 +314,14 @@ PCODE MethodDesc::PrepareInitialCode(CallerGCMode callerGCMode) return PrepareCode(&config); } -PCODE MethodDesc::PrepareCode(PrepareCodeConfig* pConfig) +PCODE MethodDesc::PrepareCode(PrepareCodeConfig* pConfig, Module* pModule) { STANDARD_VM_CONTRACT; // If other kinds of code need multi-versioning we could add more cases here, // but for now generation of all other code/stubs occurs in other code paths _ASSERTE(IsIL() || IsNoMetadata()); - PCODE pCode = PrepareILBasedCode(pConfig); + PCODE pCode = PrepareILBasedCode(pConfig, pModule); #if defined(FEATURE_GDBJIT) && defined(TARGET_UNIX) NotifyGdb::MethodPrepared(this); @@ -344,7 +344,7 @@ bool MayUsePrecompiledILStub() return true; } -PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig) +PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig, Module* pModule) { STANDARD_VM_CONTRACT; PCODE pCode = NULL; @@ -394,7 +394,7 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig) MethodDesc* pTargetMD = stubMethodDesc->GetILStubResolver()->GetStubTargetMethodDesc(); if (pTargetMD != NULL) { - pCode = pTargetMD->GetPrecompiledR2RCode(pConfig); + pCode = pTargetMD->GetPrecompiledR2RCode(pConfig, pModule); if (pCode != NULL) { LOG_USING_R2R_CODE(this); @@ -409,7 +409,7 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig) if (pCode == NULL) { - pCode = GetPrecompiledCode(pConfig, shouldTier); + pCode = GetPrecompiledCode(pConfig, shouldTier, pModule); } #ifdef FEATURE_PERFMAP @@ -441,7 +441,7 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig) return pCode; } -PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier) +PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier, Module* pModule) { STANDARD_VM_CONTRACT; PCODE pCode = NULL; @@ -455,7 +455,7 @@ PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier #ifdef FEATURE_READYTORUN else { - pCode = GetPrecompiledR2RCode(pConfig); + pCode = GetPrecompiledR2RCode(pConfig, pModule); if (pCode != NULL) { LOG_USING_R2R_CODE(this); @@ -505,7 +505,7 @@ PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier return pCode; } -PCODE MethodDesc::GetPrecompiledR2RCode(PrepareCodeConfig* pConfig) +PCODE MethodDesc::GetPrecompiledR2RCode(PrepareCodeConfig* pConfig, Module* pModule_probe) { STANDARD_VM_CONTRACT; @@ -527,6 +527,12 @@ PCODE MethodDesc::GetPrecompiledR2RCode(PrepareCodeConfig* pConfig) { pCode = pModule->GetReadyToRunInfo()->GetEntryPoint(this, pConfig, TRUE /* fFixups */); } + + if ((!pCode) + && pModule_probe + && (pModule_probe->IsReadyToRun()) + && (pModule_probe->IsInSameVersionBubble(GetModule()))) + pCode = pModule_probe->GetReadyToRunInfo()->GetEntryPoint(this, pConfig, TRUE /* fFixups */); } #endif @@ -1795,7 +1801,8 @@ extern "C" MethodDesc * STDCALL PreStubGetMethodDescForCompactEntryPoint (PCODE static PCODE PreStubWorker_Preemptive( _In_ TransitionBlock* pTransitionBlock, _In_ MethodDesc* pMD, - _In_opt_ Thread* currentThread) + _In_opt_ Thread* currentThread, + Module* pModule = NULL) { _ASSERTE(pMD->HasUnmanagedCallersOnlyAttribute()); @@ -1828,7 +1835,7 @@ static PCODE PreStubWorker_Preemptive( pMD->CheckRestore(); CONSISTENCY_CHECK(GetAppDomain()->CheckCanExecuteManagedCode(pMD)); - pbRetVal = pMD->DoPrestub(NULL, CallerGCMode::Preemptive); + pbRetVal = pMD->DoPrestub(NULL, CallerGCMode::Preemptive, pModule); UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; @@ -1855,6 +1862,11 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method BEGIN_PRESERVE_LAST_ERROR; + TADDR pRetAddr = dac_cast(pTransitionBlock) + TransitionBlock::GetOffsetOfReturnAddress(); + TADDR retAddr = (pRetAddr != NULL) ? *PTR_PCODE(pRetAddr) : NULL; + Module* pModule = NULL; + pModule = ExecutionManager::FindReadyToRunModule((TADDR)(((BYTE*)retAddr)-1)); + STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_TRIGGERS; STATIC_CONTRACT_MODE_ANY; @@ -1868,7 +1880,7 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method if (CURRENT_THREAD == NULL || !CURRENT_THREAD->PreemptiveGCDisabled()) { - pbRetVal = PreStubWorker_Preemptive(pTransitionBlock, pMD, CURRENT_THREAD); + pbRetVal = PreStubWorker_Preemptive(pTransitionBlock, pMD, CURRENT_THREAD, pModule); } else { @@ -1932,7 +1944,7 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method GCX_PREEMP_THREAD_EXISTS(CURRENT_THREAD); { - pbRetVal = pMD->DoPrestub(pDispatchingMT, CallerGCMode::Coop); + pbRetVal = pMD->DoPrestub(pDispatchingMT, CallerGCMode::Coop, pModule); } UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; @@ -2001,7 +2013,7 @@ static void TestSEHGuardPageRestore() // the case of methods that require stubs to be executed first (e.g., remoted methods // that require remoting stubs to be executed first), this stable entrypoint would be a // pointer to the stub, and not a pointer directly to the JITted code. -PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMode) +PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMode, Module* pModule) { CONTRACT(PCODE) { @@ -2106,7 +2118,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo { bool doBackpatch = true; bool doFullBackpatch = false; - pCode = GetCodeVersionManager()->PublishVersionableCodeIfNecessary(this, callerGCMode, &doBackpatch, &doFullBackpatch); + pCode = GetCodeVersionManager()->PublishVersionableCodeIfNecessary(this, callerGCMode, &doBackpatch, &doFullBackpatch, pModule); if (doBackpatch) {