From 11a0671c0b8d30740e5f507a077bed87c905acd0 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 13 Apr 2023 06:43:40 -0700 Subject: [PATCH] More efficient executable allocator (#83632) * Add multi-element caching scheme to ExecutableAllocator * CodePageGenerator generated code for LoaderHeaps should not cache the RW mapping created, as it is never accessed again, and caching it is evicting useful data from the cache * Fix build breaks introduced by executable mapping cache changes * Fix build breaks caused by changes to introduce the concept of executable pages that aren't cached ever * Move VSD executable heaps from being LoaderHeaps to being CodeFragmentHeaps - Should reduce the amount of contention on the ExecutableAllocator cache - Will improve the performance of identifying what type of stub is in use by avoiding the RangeList structure - Note, this will only apply to stubs which are used in somewhat larger applications * Add statistics gathering features to ExecutableAllocator * In progress * Fix Dac api failing when called early in process startup * Implement interleaved stubs as 16KB pages instead of 4KB pages * Remove api incorrectly added * Adjust cache size down to 3, and leave a breadcrumb for enabling more cache size exploration * Fix x86 build * Tweaks to make it all build and fix some bugs - Notably, arm32 is now only using 4K pages as before, as it can't generate the proper immediate as needed. * Add statistics for linked list walk lengths * Reorder linked list on access * Fix some more asserts and build breaks * Fix Arm build for real this time, and fix unix arm64 miscalculation of which stubs to use * Update based on code review comments * More code review feedback * Fix oops * Attempt to fix Unix Arm64 build * Try tweaking the number of cached mappings to see if the illegal instruction signal will go away in our testing * Revert "Try tweaking the number of cached mappings to see if the illegal instruction signal will go away in our testing" This reverts commit 983846083fea60eab9df53cf07a2fb5230c6c818. * Fix last code review comment --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 4 - src/coreclr/debug/daccess/fntableaccess.h | 1 + src/coreclr/debug/daccess/request.cpp | 24 -- src/coreclr/inc/executableallocator.h | 48 +++- src/coreclr/inc/holder.h | 2 +- src/coreclr/inc/loaderheap.h | 20 +- src/coreclr/utilcode/executableallocator.cpp | 140 +++++++-- src/coreclr/utilcode/loaderheap.cpp | 25 +- src/coreclr/vm/amd64/excepamd64.cpp | 7 +- src/coreclr/vm/amd64/thunktemplates.S | 5 +- src/coreclr/vm/amd64/thunktemplates.asm | 6 +- src/coreclr/vm/amd64/virtualcallstubcpu.hpp | 57 ---- src/coreclr/vm/appdomain.hpp | 3 - src/coreclr/vm/arm/exceparm.cpp | 7 +- src/coreclr/vm/arm/virtualcallstubcpu.hpp | 61 ---- src/coreclr/vm/arm64/stubs.cpp | 7 +- src/coreclr/vm/arm64/thunktemplates.S | 22 +- src/coreclr/vm/arm64/thunktemplates.asm | 7 +- src/coreclr/vm/arm64/virtualcallstubcpu.hpp | 49 ---- src/coreclr/vm/callcounting.cpp | 10 +- src/coreclr/vm/callcounting.h | 14 +- src/coreclr/vm/codeman.cpp | 2 + src/coreclr/vm/codeman.h | 5 + src/coreclr/vm/excep.cpp | 7 +- src/coreclr/vm/gccover.cpp | 22 +- src/coreclr/vm/i386/excepx86.cpp | 8 +- src/coreclr/vm/i386/thunktemplates.S | 2 +- src/coreclr/vm/i386/thunktemplates.asm | 2 +- src/coreclr/vm/i386/virtualcallstubcpu.hpp | 62 ---- src/coreclr/vm/jitinterface.cpp | 1 - src/coreclr/vm/loaderallocator.cpp | 12 +- src/coreclr/vm/loongarch64/stubs.cpp | 7 +- src/coreclr/vm/loongarch64/thunktemplates.S | 10 +- .../vm/loongarch64/virtualcallstubcpu.hpp | 49 ---- src/coreclr/vm/precode.cpp | 30 +- src/coreclr/vm/precode.h | 30 +- src/coreclr/vm/prestub.cpp | 2 +- src/coreclr/vm/stubmgr.cpp | 25 +- src/coreclr/vm/util.cpp | 6 +- src/coreclr/vm/util.hpp | 4 +- src/coreclr/vm/virtualcallstub.cpp | 269 +++++------------- src/coreclr/vm/virtualcallstub.h | 212 ++------------ 42 files changed, 419 insertions(+), 867 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 161d2a7261367..2b2a39c1c282d 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -3617,11 +3617,7 @@ void DacDbiInterfaceImpl::EnumerateMemRangesForLoaderAllocator(PTR_LoaderAllocat if (pVcsMgr) { if (pVcsMgr->indcell_heap != NULL) heapsToEnumerate.Push(pVcsMgr->indcell_heap); - if (pVcsMgr->lookup_heap != NULL) heapsToEnumerate.Push(pVcsMgr->lookup_heap); - if (pVcsMgr->resolve_heap != NULL) heapsToEnumerate.Push(pVcsMgr->resolve_heap); - if (pVcsMgr->dispatch_heap != NULL) heapsToEnumerate.Push(pVcsMgr->dispatch_heap); if (pVcsMgr->cache_entry_heap != NULL) heapsToEnumerate.Push(pVcsMgr->cache_entry_heap); - if (pVcsMgr->vtable_heap != NULL) heapsToEnumerate.Push(pVcsMgr->vtable_heap); } TADDR rangeAccumAsTaddr = TO_TADDR(rangeAcummulator); diff --git a/src/coreclr/debug/daccess/fntableaccess.h b/src/coreclr/debug/daccess/fntableaccess.h index 64b7d35271b2a..cfe9a2eea2aea 100644 --- a/src/coreclr/debug/daccess/fntableaccess.h +++ b/src/coreclr/debug/daccess/fntableaccess.h @@ -41,6 +41,7 @@ struct FakeHeapList DWORD_PTR pHdrMap; // changed from DWORD* size_t maxCodeHeapSize; size_t reserveForJumpStubs; + DWORD_PTR pLoaderAllocator; #if defined(TARGET_AMD64) || defined(TARGET_ARM64) DWORD_PTR CLRPersonalityRoutine; #endif diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index ca33ce1b6f401..b5a0aa1986bd2 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -3531,26 +3531,10 @@ ClrDataAccess::TraverseVirtCallStubHeap(CLRDATA_ADDRESS pAppDomain, VCSHeapType pLoaderHeap = pVcsMgr->indcell_heap; break; - case LookupHeap: - pLoaderHeap = pVcsMgr->lookup_heap; - break; - - case ResolveHeap: - pLoaderHeap = pVcsMgr->resolve_heap; - break; - - case DispatchHeap: - pLoaderHeap = pVcsMgr->dispatch_heap; - break; - case CacheEntryHeap: pLoaderHeap = pVcsMgr->cache_entry_heap; break; - case VtableHeap: - pLoaderHeap = pVcsMgr->vtable_heap; - break; - default: hr = E_INVALIDARG; } @@ -3597,11 +3581,7 @@ static const char *LoaderAllocatorLoaderHeapNames[] = "FixupPrecodeHeap", "NewStubPrecodeHeap", "IndcellHeap", - "LookupHeap", - "ResolveHeap", - "DispatchHeap", "CacheEntryHeap", - "VtableHeap", }; @@ -3644,11 +3624,7 @@ HRESULT ClrDataAccess::GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocatorAd else { pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->indcell_heap); - pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->lookup_heap); - pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->resolve_heap); - pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->dispatch_heap); pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->cache_entry_heap); - pLoaderHeaps[i++] = HOST_CDADDR(pVcsMgr->vtable_heap); } // All of the above are "LoaderHeap" and not the ExplicitControl version. diff --git a/src/coreclr/inc/executableallocator.h b/src/coreclr/inc/executableallocator.h index 2d4e2a2035032..22d9437b65068 100644 --- a/src/coreclr/inc/executableallocator.h +++ b/src/coreclr/inc/executableallocator.h @@ -20,6 +20,16 @@ // This class is responsible for allocation of all the executable memory in the runtime. class ExecutableAllocator { +public: + + enum CacheableMapping + { + AddToCache, + DoNotAddToCache, + }; + +private: + // RX address range block descriptor struct BlockRX { @@ -61,6 +71,11 @@ class ExecutableAllocator static int64_t g_releaseCount; static int64_t g_reserveCount; + + static int64_t g_MapRW_Calls; + static int64_t g_MapRW_CallsWithCacheMiss; + static int64_t g_MapRW_LinkedListWalkDepth; + static int64_t g_LinkedListTotalDepth; #endif // Instance of the allocator static ExecutableAllocator* g_instance; @@ -102,9 +117,19 @@ class ExecutableAllocator // for platforms that don't use shared memory. size_t m_freeOffset = 0; - // Last RW mapping cached so that it can be reused for the next mapping +// Uncomment these to gather information to better choose caching parameters +//#define VARIABLE_SIZED_CACHEDMAPPING_SIZE + + // Last RW mappings cached so that it can be reused for the next mapping // request if it goes into the same range. - BlockRW* m_cachedMapping = NULL; + // This is handled as a 3 element cache with an LRU replacement policy +#ifdef VARIABLE_SIZED_CACHEDMAPPING_SIZE + // If variable sized mappings enabled, make the cache physically big enough to cover all interesting sizes + static int g_cachedMappingSize; + BlockRW* m_cachedMapping[16] = { 0 }; +#else + BlockRW* m_cachedMapping[3] = { 0 }; +#endif // Synchronization of the public allocator methods CRITSEC_COOKIE m_CriticalSection; @@ -114,15 +139,18 @@ class ExecutableAllocator // and replaces it by the passed in one. void UpdateCachedMapping(BlockRW *pBlock); - // Remove the cached mapping - void RemoveCachedMapping(); + // Remove the cached mapping (1 based indexing) + void RemoveCachedMapping(size_t indexToRemove); + + // Find an overlapped cached mapping with pBlock, or return 0 + size_t FindOverlappingCachedMapping(BlockRX* pBlock); // Find existing RW block that maps the whole specified range of RX memory. // Return NULL if no such block exists. - void* FindRWBlock(void* baseRX, size_t size); + void* FindRWBlock(void* baseRX, size_t size, CacheableMapping cacheMapping); // Add RW block to the list of existing RW blocks - bool AddRWBlock(void* baseRW, void* baseRX, size_t size); + bool AddRWBlock(void* baseRW, void* baseRX, size_t size, CacheableMapping cacheMapping); // Remove RW block from the list of existing RW blocks and return the base // address and size the underlying memory was mapped at. @@ -230,7 +258,7 @@ class ExecutableAllocator void Release(void* pRX); // Map the specified block of executable memory as RW - void* MapRW(void* pRX, size_t size); + void* MapRW(void* pRX, size_t size, CacheableMapping cacheMapping); // Unmap the RW mapping at the specified address void UnmapRW(void* pRW); @@ -290,14 +318,14 @@ class ExecutableWriterHolder { } - ExecutableWriterHolder(T* addressRX, size_t size) + ExecutableWriterHolder(T* addressRX, size_t size, ExecutableAllocator::CacheableMapping cacheMapping = ExecutableAllocator::AddToCache) { m_addressRX = addressRX; #if defined(HOST_OSX) && defined(HOST_ARM64) m_addressRW = addressRX; PAL_JitWriteProtect(true); #else - m_addressRW = (T *)ExecutableAllocator::Instance()->MapRW((void*)addressRX, size); + m_addressRW = (T *)ExecutableAllocator::Instance()->MapRW((void*)addressRX, size, cacheMapping); #endif } @@ -320,7 +348,7 @@ class ExecutableWriterHolder #ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS #undef ExecutableWriterHolder -#ifdef TARGET_UNIX +#ifdef HOST_UNIX #define ExecutableWriterHolder ExecutableAllocator::LogUsage(__FILE__, __LINE__, __PRETTY_FUNCTION__); ExecutableWriterHolderNoLog #define AssignExecutableWriterHolder(addressRX, size) AssignExecutableWriterHolder(addressRX, size); ExecutableAllocator::LogUsage(__FILE__, __LINE__, __PRETTY_FUNCTION__); #else diff --git a/src/coreclr/inc/holder.h b/src/coreclr/inc/holder.h index 4aa8a0b8fba4f..325036bb2eac5 100644 --- a/src/coreclr/inc/holder.h +++ b/src/coreclr/inc/holder.h @@ -946,7 +946,7 @@ FORCEINLINE void StubRelease(TYPE* value) if (value) { #ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS -#ifdef TARGET_UNIX +#ifdef HOST_UNIX LOGGER::LogUsage(__FILE__, __LINE__, __PRETTY_FUNCTION__); #else LOGGER::LogUsage(__FILE__, __LINE__, __FUNCTION__); diff --git a/src/coreclr/inc/loaderheap.h b/src/coreclr/inc/loaderheap.h index bc3cf5cf38e4b..216668315cbff 100644 --- a/src/coreclr/inc/loaderheap.h +++ b/src/coreclr/inc/loaderheap.h @@ -154,6 +154,17 @@ struct LoaderHeapEvent; +// When an interleaved LoaderHeap is constructed, this is the interleaving size +inline UINT32 GetStubCodePageSize() +{ +#if defined(TARGET_ARM64) && defined(TARGET_UNIX) + return max(16*1024, GetOsPageSize()); +#elif defined(TARGET_ARM) + return 4096; // ARM is special as the 32bit instruction set does not easily permit a 16KB offset +#else + return 16*1024; +#endif +} @@ -185,6 +196,7 @@ class UnlockedLoaderHeap { #ifdef _DEBUG friend class LoaderHeapSniffer; + friend struct LoaderHeapFreeBlock; #endif #ifdef DACCESS_COMPILE @@ -276,7 +288,7 @@ class UnlockedLoaderHeap public: BOOL m_fExplicitControl; // Am I a LoaderHeap or an ExplicitControlLoaderHeap? - void (*m_codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX); + void (*m_codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); #ifdef DACCESS_COMPILE public: @@ -298,7 +310,7 @@ class UnlockedLoaderHeap SIZE_T dwReservedRegionSize, RangeList *pRangeList = NULL, HeapKind kind = HeapKind::Data, - void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX) = NULL, + void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size) = NULL, DWORD dwGranularity = 1); ~UnlockedLoaderHeap(); @@ -467,7 +479,7 @@ class LoaderHeap : public UnlockedLoaderHeap, public ILoaderHeapBackout RangeList *pRangeList = NULL, UnlockedLoaderHeap::HeapKind kind = UnlockedLoaderHeap::HeapKind::Data, BOOL fUnlocked = FALSE, - void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX) = NULL, + void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size) = NULL, DWORD dwGranularity = 1 ) : UnlockedLoaderHeap(dwReserveBlockSize, @@ -491,7 +503,7 @@ class LoaderHeap : public UnlockedLoaderHeap, public ILoaderHeapBackout RangeList *pRangeList = NULL, UnlockedLoaderHeap::HeapKind kind = UnlockedLoaderHeap::HeapKind::Data, BOOL fUnlocked = FALSE, - void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX) = NULL, + void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size) = NULL, DWORD dwGranularity = 1 ) : UnlockedLoaderHeap(dwReserveBlockSize, diff --git a/src/coreclr/utilcode/executableallocator.cpp b/src/coreclr/utilcode/executableallocator.cpp index 046504050d819..65802615fc6aa 100644 --- a/src/coreclr/utilcode/executableallocator.cpp +++ b/src/coreclr/utilcode/executableallocator.cpp @@ -19,6 +19,14 @@ bool ExecutableAllocator::g_isWXorXEnabled = false; ExecutableAllocator::FatalErrorHandler ExecutableAllocator::g_fatalErrorHandler = NULL; ExecutableAllocator* ExecutableAllocator::g_instance = NULL; +#ifndef VARIABLE_SIZED_CACHEDMAPPING_SIZE +#define EXECUTABLE_ALLOCATOR_CACHE_SIZE ARRAY_SIZE(m_cachedMapping) +#else +int ExecutableAllocator::g_cachedMappingSize = 0; + +#define EXECUTABLE_ALLOCATOR_CACHE_SIZE ExecutableAllocator::g_cachedMappingSize +#endif + #ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS int64_t ExecutableAllocator::g_mapTimeSum = 0; int64_t ExecutableAllocator::g_mapTimeWithLockSum = 0; @@ -28,6 +36,10 @@ int64_t ExecutableAllocator::g_mapFindRXTimeSum = 0; int64_t ExecutableAllocator::g_mapCreateTimeSum = 0; int64_t ExecutableAllocator::g_releaseCount = 0; int64_t ExecutableAllocator::g_reserveCount = 0; +int64_t ExecutableAllocator::g_MapRW_Calls = 0; +int64_t ExecutableAllocator::g_MapRW_CallsWithCacheMiss = 0; +int64_t ExecutableAllocator::g_MapRW_LinkedListWalkDepth = 0; +int64_t ExecutableAllocator::g_LinkedListTotalDepth = 0; ExecutableAllocator::LogEntry ExecutableAllocator::s_usageLog[256]; int ExecutableAllocator::s_logMaxIndex = 0; @@ -91,6 +103,12 @@ void ExecutableAllocator::DumpHolderUsage() fprintf(stderr, "Reserve count: %lld\n", g_reserveCount); fprintf(stderr, "Release count: %lld\n", g_releaseCount); + fprintf(stderr, "g_MapRW_Calls: %lld\n", g_MapRW_Calls); + fprintf(stderr, "g_MapRW_CallsWithCacheMiss: %lld\n", g_MapRW_CallsWithCacheMiss); + fprintf(stderr, "g_MapRW_LinkedListWalkDepth: %lld\n", g_MapRW_LinkedListWalkDepth); + fprintf(stderr, "g_MapRW_LinkedListAverageDepth: %f\n", (double)g_MapRW_LinkedListWalkDepth/(double)g_MapRW_CallsWithCacheMiss); + fprintf(stderr, "g_LinkedListTotalDepth: %lld\n", g_LinkedListTotalDepth); + fprintf(stderr, "ExecutableWriterHolder usage:\n"); for (int i = 0; i < s_logMaxIndex; i++) @@ -222,6 +240,25 @@ HRESULT ExecutableAllocator::StaticInitialize(FatalErrorHandler fatalErrorHandle { LIMITED_METHOD_CONTRACT; +#ifdef VARIABLE_SIZED_CACHEDMAPPING_SIZE + g_cachedMappingSize = ARRAY_SIZE(m_cachedMapping); + auto envString = getenv("EXECUTABLE_ALLOCATOR_CACHE_SIZE"); + if (envString != NULL) + { + int customCacheSize = atoi(envString); + if (customCacheSize != 0) + { + if ((customCacheSize > ARRAY_SIZE(m_cachedMapping)) || (customCacheSize <= 0)) + { + printf("Invalid value in 'EXECUTABLE_ALLOCATOR_CACHE_SIZE' environment variable'\n"); + return E_FAIL; + } + + g_cachedMappingSize = customCacheSize; + } + } +#endif + g_fatalErrorHandler = fatalErrorHandler; g_isWXorXEnabled = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_EnableWriteXorExecute) != 0; g_instance = new (nothrow) ExecutableAllocator(); @@ -261,13 +298,21 @@ bool ExecutableAllocator::Initialize() #define ENABLE_CACHED_MAPPINGS -void ExecutableAllocator::RemoveCachedMapping() +void ExecutableAllocator::RemoveCachedMapping(size_t index) { #ifdef ENABLE_CACHED_MAPPINGS + if (index == 0) + return; + + BlockRW* cachedMapping = m_cachedMapping[index - 1]; + + if (cachedMapping == NULL) + return; + void* unmapAddress = NULL; size_t unmapSize; - if (!RemoveRWBlock(m_cachedMapping->baseRW, &unmapAddress, &unmapSize)) + if (!RemoveRWBlock(cachedMapping->baseRW, &unmapAddress, &unmapSize)) { g_fatalErrorHandler(COR_E_EXECUTIONENGINE, W("The RW block to unmap was not found")); } @@ -276,28 +321,53 @@ void ExecutableAllocator::RemoveCachedMapping() g_fatalErrorHandler(COR_E_EXECUTIONENGINE, W("Releasing the RW mapping failed")); } - m_cachedMapping = NULL; + m_cachedMapping[index - 1] = NULL; #endif // ENABLE_CACHED_MAPPINGS } +#ifdef ENABLE_CACHED_MAPPINGS +size_t ExecutableAllocator::FindOverlappingCachedMapping(BlockRX* pBlock) +{ + for (size_t index = 0; index < EXECUTABLE_ALLOCATOR_CACHE_SIZE; index++) + { + BlockRW* cachedMapping = m_cachedMapping[index]; + if (cachedMapping != NULL) + { + // In case the cached mapping maps the region being released, it needs to be removed + if ((pBlock->baseRX <= cachedMapping->baseRX) && (cachedMapping->baseRX < ((BYTE*)pBlock->baseRX + pBlock->size))) + { + return index + 1; + } + } + } + return 0; +} +#endif + void ExecutableAllocator::UpdateCachedMapping(BlockRW* pBlock) { LIMITED_METHOD_CONTRACT; #ifdef ENABLE_CACHED_MAPPINGS - if (m_cachedMapping != pBlock) + for (size_t index = 0; index < EXECUTABLE_ALLOCATOR_CACHE_SIZE; index++) { - if (m_cachedMapping != NULL) + if (pBlock == m_cachedMapping[index]) { - RemoveCachedMapping(); + // Move the found mapping to the front - note the overlapping memory, use memmove. + memmove(&m_cachedMapping[1], &m_cachedMapping[0], sizeof(m_cachedMapping[0]) * index); + m_cachedMapping[0] = pBlock; + return; } - - m_cachedMapping = pBlock; - pBlock->refCount++; } + + // Must insert mapping in front - note the overlapping memory, use memmove. + RemoveCachedMapping(EXECUTABLE_ALLOCATOR_CACHE_SIZE); + memmove(&m_cachedMapping[1], &m_cachedMapping[0], sizeof(m_cachedMapping[0]) * (EXECUTABLE_ALLOCATOR_CACHE_SIZE - 1)); + m_cachedMapping[0] = pBlock; + pBlock->refCount++; #endif // ENABLE_CACHED_MAPPINGS } -void* ExecutableAllocator::FindRWBlock(void* baseRX, size_t size) +void* ExecutableAllocator::FindRWBlock(void* baseRX, size_t size, CacheableMapping cacheMapping) { LIMITED_METHOD_CONTRACT; @@ -310,7 +380,8 @@ void* ExecutableAllocator::FindRWBlock(void* baseRX, size_t size) #else InterlockedIncrement((LONG*)&pBlock->refCount); #endif - UpdateCachedMapping(pBlock); + if (cacheMapping == AddToCache) + UpdateCachedMapping(pBlock); return (BYTE*)pBlock->baseRW + ((size_t)baseRX - (size_t)pBlock->baseRX); } @@ -319,7 +390,7 @@ void* ExecutableAllocator::FindRWBlock(void* baseRX, size_t size) return NULL; } -bool ExecutableAllocator::AddRWBlock(void* baseRW, void* baseRX, size_t size) +bool ExecutableAllocator::AddRWBlock(void* baseRW, void* baseRX, size_t size, CacheableMapping cacheMapping) { LIMITED_METHOD_CONTRACT; @@ -340,7 +411,8 @@ bool ExecutableAllocator::AddRWBlock(void* baseRW, void* baseRX, size_t size) pBlockRW->refCount = 1; m_pFirstBlockRW = pBlockRW; - UpdateCachedMapping(pBlockRW); + if (cacheMapping == AddToCache) + UpdateCachedMapping(pBlockRW); return true; } @@ -409,6 +481,10 @@ void ExecutableAllocator::AddRXBlock(BlockRX* pBlock) pBlock->next = m_pFirstBlockRX; m_pFirstBlockRX = pBlock; + +#ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS + ExecutableAllocator::g_LinkedListTotalDepth++; +#endif } void* ExecutableAllocator::Commit(void* pStart, size_t size, bool isExecutable) @@ -454,6 +530,9 @@ void ExecutableAllocator::Release(void* pRX) pPrevBlock->next = pBlock->next; } +#ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS + ExecutableAllocator::g_LinkedListTotalDepth--; +#endif break; } pPrevBlock = pBlock; @@ -461,13 +540,11 @@ void ExecutableAllocator::Release(void* pRX) if (pBlock != NULL) { - if (m_cachedMapping != NULL) + size_t cachedMappingThatOverlaps = FindOverlappingCachedMapping(pBlock); + while (cachedMappingThatOverlaps != 0) { - // In case the cached mapping maps the region being released, it needs to be removed - if ((pBlock->baseRX <= m_cachedMapping->baseRX) && (m_cachedMapping->baseRX < ((BYTE*)pBlock->baseRX + pBlock->size))) - { - RemoveCachedMapping(); - } + RemoveCachedMapping(cachedMappingThatOverlaps); + cachedMappingThatOverlaps = FindOverlappingCachedMapping(pBlock); } if (!VMToOSInterface::ReleaseDoubleMappedMemory(m_doubleMemoryMapperHandle, pRX, pBlock->offset, pBlock->size)) @@ -485,7 +562,7 @@ void ExecutableAllocator::Release(void* pRX) g_fatalErrorHandler(COR_E_EXECUTIONENGINE, W("The RX block to release was not found")); } - _ASSERTE(FindRWBlock(pRX, 1) == NULL); + _ASSERTE(FindRWBlock(pRX, 1, CacheableMapping::DoNotAddToCache) == NULL); } else { @@ -766,7 +843,7 @@ void* ExecutableAllocator::ReserveAt(void* baseAddressRX, size_t size) // Map an executable memory block as writeable. If there is already a mapping // covering the specified block, return that mapping instead of creating a new one. // Return starting address of the writeable mapping. -void* ExecutableAllocator::MapRW(void* pRX, size_t size) +void* ExecutableAllocator::MapRW(void* pRX, size_t size, CacheableMapping cacheMapping) { LIMITED_METHOD_CONTRACT; @@ -780,12 +857,15 @@ void* ExecutableAllocator::MapRW(void* pRX, size_t size) #endif CRITSEC_Holder csh(m_CriticalSection); +#ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS + ExecutableAllocator::g_MapRW_Calls++; +#endif #ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS StopWatch sw(&g_mapTimeSum); #endif - void* result = FindRWBlock(pRX, size); + void* result = FindRWBlock(pRX, size, cacheMapping); if (result != NULL) { return result; @@ -793,11 +873,23 @@ void* ExecutableAllocator::MapRW(void* pRX, size_t size) #ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS StopWatch sw2(&g_mapFindRXTimeSum); #endif +#ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS + ExecutableAllocator::g_MapRW_CallsWithCacheMiss++; +#endif - for (BlockRX* pBlock = m_pFirstBlockRX; pBlock != NULL; pBlock = pBlock->next) + for (BlockRX** ppBlock = &m_pFirstBlockRX; *ppBlock != NULL; ppBlock = &((*ppBlock)->next)) { + BlockRX* pBlock = *ppBlock; +#ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS + ExecutableAllocator::g_MapRW_LinkedListWalkDepth++; +#endif if (pRX >= pBlock->baseRX && ((size_t)pRX + size) <= ((size_t)pBlock->baseRX + pBlock->size)) { + // Move found block to the front of the singly linked list + *ppBlock = pBlock->next; + pBlock->next = m_pFirstBlockRX; + m_pFirstBlockRX = pBlock; + // Offset of the RX address in the originally allocated block size_t offset = (size_t)pRX - (size_t)pBlock->baseRX; // Offset of the RX address that will start the newly mapped block @@ -815,7 +907,7 @@ void* ExecutableAllocator::MapRW(void* pRX, size_t size) g_fatalErrorHandler(COR_E_EXECUTIONENGINE, W("Failed to create RW mapping for RX memory")); } - AddRWBlock(pRW, (BYTE*)pBlock->baseRX + mapOffset, mapSize); + AddRWBlock(pRW, (BYTE*)pBlock->baseRX + mapOffset, mapSize, cacheMapping); return (void*)((size_t)pRW + (offset - mapOffset)); } diff --git a/src/coreclr/utilcode/loaderheap.cpp b/src/coreclr/utilcode/loaderheap.cpp index a4dff5783e373..72d0d1a6f6f7f 100644 --- a/src/coreclr/utilcode/loaderheap.cpp +++ b/src/coreclr/utilcode/loaderheap.cpp @@ -740,7 +740,7 @@ struct LoaderHeapFreeBlock } else { - memset((BYTE*)pMem + GetOsPageSize(), 0xcc, dwTotalSize); + memset((BYTE*)pMem + GetStubCodePageSize(), 0xcc, dwTotalSize); } #endif // DEBUG @@ -932,7 +932,7 @@ UnlockedLoaderHeap::UnlockedLoaderHeap(DWORD dwReserveBlockSize, SIZE_T dwReservedRegionSize, RangeList *pRangeList, HeapKind kind, - void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX), + void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size), DWORD dwGranularity) { CONTRACTL @@ -957,6 +957,7 @@ UnlockedLoaderHeap::UnlockedLoaderHeap(DWORD dwReserveBlockSize, // Round to VIRTUAL_ALLOC_RESERVE_GRANULARITY m_dwTotalAlloc = 0; + _ASSERTE((GetStubCodePageSize() % GetOsPageSize()) == 0); // Stub code page size MUST be in increments of the page size. (Really it must be a power of 2 as well, but this is good enough) m_dwGranularity = dwGranularity; #ifdef _DEBUG @@ -1098,7 +1099,7 @@ BOOL UnlockedLoaderHeap::CommitPages(void* pData, size_t dwSizeToCommitPart) if (IsInterleaved()) { - _ASSERTE(dwSizeToCommitPart == GetOsPageSize()); + _ASSERTE(dwSizeToCommitPart == GetStubCodePageSize()); void *pTemp = ExecutableAllocator::Instance()->Commit((BYTE*)pData + dwSizeToCommitPart, dwSizeToCommitPart, FALSE); if (pTemp == NULL) @@ -1106,9 +1107,9 @@ BOOL UnlockedLoaderHeap::CommitPages(void* pData, size_t dwSizeToCommitPart) return FALSE; } - ExecutableWriterHolder codePageWriterHolder((BYTE*)pData, GetOsPageSize()); - m_codePageGenerator(codePageWriterHolder.GetRW(), (BYTE*)pData); - FlushInstructionCache(GetCurrentProcess(), pData, GetOsPageSize()); + ExecutableWriterHolder codePageWriterHolder((BYTE*)pData, dwSizeToCommitPart, ExecutableAllocator::DoNotAddToCache); + m_codePageGenerator(codePageWriterHolder.GetRW(), (BYTE*)pData, dwSizeToCommitPart); + FlushInstructionCache(GetCurrentProcess(), pData, dwSizeToCommitPart); } return TRUE; @@ -1263,9 +1264,9 @@ BOOL UnlockedLoaderHeap::GetMoreCommittedPages(size_t dwMinSize) { // This mode interleaves data and code pages 1:1. So the code size is required to be smaller than // or equal to the page size to ensure that the code range is consecutive. - _ASSERTE(dwMinSize <= GetOsPageSize()); + _ASSERTE(dwMinSize <= GetStubCodePageSize()); // For interleaved heap, we always get two memory pages - one for code and one for data - dwMinSize = 2 * GetOsPageSize(); + dwMinSize = 2 * GetStubCodePageSize(); } // Does this fit in the reserved region? @@ -1291,7 +1292,7 @@ BOOL UnlockedLoaderHeap::GetMoreCommittedPages(size_t dwMinSize) { // The end of committed region for interleaved heaps points to the end of the executable // page and the data pages goes right after that. So we skip the data page here. - pCommitBaseAddress += GetOsPageSize(); + pCommitBaseAddress += GetStubCodePageSize(); } else { @@ -1319,7 +1320,7 @@ BOOL UnlockedLoaderHeap::GetMoreCommittedPages(size_t dwMinSize) // If the remaining bytes are large enough to allocate data of the allocation granularity, add them to the free // block list. // Otherwise the remaining bytes that are available will be wasted. - if (unusedRemainder >= m_dwGranularity) + if (unusedRemainder >= GetStubCodePageSize()) { LoaderHeapFreeBlock::InsertFreeBlock(&m_pFirstFreeBlock, m_pAllocPtr, unusedRemainder, this); } @@ -1344,7 +1345,7 @@ BOOL UnlockedLoaderHeap::GetMoreCommittedPages(size_t dwMinSize) // block list. // Otherwise the remaining bytes that are available will be wasted. size_t unusedRemainder = (size_t)(m_pPtrToEndOfCommittedRegion - m_pAllocPtr); - if (unusedRemainder >= AllocMem_TotalSize(m_dwGranularity)) + if (unusedRemainder >= AllocMem_TotalSize(GetStubCodePageSize())) { LoaderHeapFreeBlock::InsertFreeBlock(&m_pFirstFreeBlock, m_pAllocPtr, unusedRemainder, this); } @@ -1648,7 +1649,7 @@ void UnlockedLoaderHeap::UnlockedBackoutMem(void *pMem, if (IsInterleaved()) { // Clear the RW page - memset((BYTE*)pMem + GetOsPageSize(), 0x00, dwSize); // Fill freed region with 0 + memset((BYTE*)pMem + GetStubCodePageSize(), 0x00, dwSize); // Fill freed region with 0 } else { diff --git a/src/coreclr/vm/amd64/excepamd64.cpp b/src/coreclr/vm/amd64/excepamd64.cpp index 9dcb91285cac7..d155ceecc5a35 100644 --- a/src/coreclr/vm/amd64/excepamd64.cpp +++ b/src/coreclr/vm/amd64/excepamd64.cpp @@ -600,10 +600,9 @@ AdjustContextForVirtualStub( PCODE f_IP = GetIP(pContext); - VirtualCallStubManager::StubKind sk; - VirtualCallStubManager::FindStubManager(f_IP, &sk); + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(f_IP); - if (sk == VirtualCallStubManager::SK_DISPATCH) + if (sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { if ((*PTR_DWORD(f_IP) & 0xffffff) != X64_INSTR_CMP_IND_THIS_REG_RAX) // cmp [THIS_REG], rax { @@ -612,7 +611,7 @@ AdjustContextForVirtualStub( } } else - if (sk == VirtualCallStubManager::SK_RESOLVE) + if (sk == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) { if ((*PTR_DWORD(f_IP) & 0xffffff) != X64_INSTR_MOV_RAX_IND_THIS_REG) // mov rax, [THIS_REG] { diff --git a/src/coreclr/vm/amd64/thunktemplates.S b/src/coreclr/vm/amd64/thunktemplates.S index 11d417cb3b971..c13a79067cc64 100644 --- a/src/coreclr/vm/amd64/thunktemplates.S +++ b/src/coreclr/vm/amd64/thunktemplates.S @@ -5,9 +5,10 @@ #include "unixasmmacros.inc" #include "asmconstants.h" -PAGE_SIZE = 4096 +// STUB_PAGE_SIZE must match the behavior of GetStubCodePageSize() on this architecture/os +STUB_PAGE_SIZE = 16384 -#define DATA_SLOT(stub, field) C_FUNC(stub##Code) + PAGE_SIZE + stub##Data__##field +#define DATA_SLOT(stub, field) C_FUNC(stub##Code) + STUB_PAGE_SIZE + stub##Data__##field LEAF_ENTRY StubPrecodeCode, _TEXT mov r10, [rip + DATA_SLOT(StubPrecode, MethodDesc)] diff --git a/src/coreclr/vm/amd64/thunktemplates.asm b/src/coreclr/vm/amd64/thunktemplates.asm index af3d03135619e..c841a38b4f5a3 100644 --- a/src/coreclr/vm/amd64/thunktemplates.asm +++ b/src/coreclr/vm/amd64/thunktemplates.asm @@ -4,10 +4,11 @@ include include AsmConstants.inc -PAGE_SIZE = 4096 +; STUB_PAGE_SIZE must match the behavior of GetStubCodePageSize() on this architecture/os +STUB_PAGE_SIZE = 16384 DATA_SLOT macro stub, field - exitm @CatStr(stub, , stub, , field) + exitm @CatStr(stub, , stub, , field) endm LEAF_ENTRY StubPrecodeCode, _TEXT @@ -17,7 +18,6 @@ LEAF_END_MARKED StubPrecodeCode, _TEXT LEAF_ENTRY FixupPrecodeCode, _TEXT jmp QWORD PTR [DATA_SLOT(FixupPrecode, Target)] -PATCH_LABEL FixupPrecodeCode_Fixup mov r10, QWORD PTR [DATA_SLOT(FixupPrecode, MethodDesc)] jmp QWORD PTR [DATA_SLOT(FixupPrecode, PrecodeFixupThunk)] LEAF_END_MARKED FixupPrecodeCode, _TEXT diff --git a/src/coreclr/vm/amd64/virtualcallstubcpu.hpp b/src/coreclr/vm/amd64/virtualcallstubcpu.hpp index 44150d65ecc15..7afd9228fcf41 100644 --- a/src/coreclr/vm/amd64/virtualcallstubcpu.hpp +++ b/src/coreclr/vm/amd64/virtualcallstubcpu.hpp @@ -871,63 +871,6 @@ void VTableCallHolder::Initialize(unsigned slot) _ASSERT(stub()->size() == VTableCallHolder::GetHolderSize(slot)); } -VirtualCallStubManager::StubKind VirtualCallStubManager::predictStubKind(PCODE stubStartAddress) -{ -#ifdef DACCESS_COMPILE - return SK_BREAKPOINT; // Dac always uses the slower lookup -#else - StubKind stubKind = SK_UNKNOWN; - - EX_TRY - { - // If stubStartAddress is completely bogus, then this might AV, - // so we protect it with SEH. An AV here is OK. - AVInRuntimeImplOkayHolder AVOkay; - - WORD firstWord = *((WORD*) stubStartAddress); - - if (firstWord == 0xB848) - { - stubKind = SK_DISPATCH; - } - else if (firstWord == 0x4890) - { - stubKind = SK_LOOKUP; - } - else if (firstWord == 0x4952) - { - stubKind = SK_RESOLVE; - } - else if (firstWord == 0x48F8) - { - stubKind = SK_LOOKUP; - } - else if (firstWord == 0x8B48) - { - stubKind = SK_VTABLECALL; - } - else - { - BYTE firstByte = ((BYTE*) stubStartAddress)[0]; - BYTE secondByte = ((BYTE*) stubStartAddress)[1]; - - if ((firstByte == INSTR_INT3) || (secondByte == INSTR_INT3)) - { - stubKind = SK_BREAKPOINT; - } - } - } - EX_CATCH - { - stubKind = SK_UNKNOWN; - } - EX_END_CATCH(SwallowAllExceptions); - - return stubKind; - -#endif // DACCESS_COMPILE -} - #endif //DECLARE_DATA #endif // _VIRTUAL_CALL_STUB_AMD64_H diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 2c6df2564e7b6..349ac09a4b449 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1217,12 +1217,9 @@ class BaseDomain friend class LoadLockHolder; public: void InitVSD(); - RangeList *GetCollectibleVSDRanges() { return &m_collVSDRanges; } private: TypeIDMap m_typeIDMap; - // Range list for collectible types. Maps VSD PCODEs back to the VirtualCallStubManager they belong to - LockedRangeList m_collVSDRanges; #ifdef HOST_WINDOWS // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. diff --git a/src/coreclr/vm/arm/exceparm.cpp b/src/coreclr/vm/arm/exceparm.cpp index 9df2a36a04e0c..517c3c774cfb9 100644 --- a/src/coreclr/vm/arm/exceparm.cpp +++ b/src/coreclr/vm/arm/exceparm.cpp @@ -73,10 +73,9 @@ AdjustContextForVirtualStub( PCODE f_IP = GetIP(pContext); TADDR pInstr = PCODEToPINSTR(f_IP); - VirtualCallStubManager::StubKind sk; - VirtualCallStubManager::FindStubManager(f_IP, &sk); + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(f_IP); - if (sk == VirtualCallStubManager::SK_DISPATCH) + if (sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { if (*PTR_WORD(pInstr) != DISPATCH_STUB_FIRST_WORD) { @@ -85,7 +84,7 @@ AdjustContextForVirtualStub( } } else - if (sk == VirtualCallStubManager::SK_RESOLVE) + if (sk == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) { if (*PTR_WORD(pInstr) != RESOLVE_STUB_FIRST_WORD) { diff --git a/src/coreclr/vm/arm/virtualcallstubcpu.hpp b/src/coreclr/vm/arm/virtualcallstubcpu.hpp index adb4f16cb3519..0b6c00104ebcd 100644 --- a/src/coreclr/vm/arm/virtualcallstubcpu.hpp +++ b/src/coreclr/vm/arm/virtualcallstubcpu.hpp @@ -483,67 +483,6 @@ void VTableCallHolder::Initialize(unsigned slot) #endif // DACCESS_COMPILE -VirtualCallStubManager::StubKind VirtualCallStubManager::predictStubKind(PCODE stubStartAddress) -{ - SUPPORTS_DAC; -#ifdef DACCESS_COMPILE - - return SK_BREAKPOINT; // Dac always uses the slower lookup - -#else - - StubKind stubKind = SK_UNKNOWN; - TADDR pInstr = PCODEToPINSTR(stubStartAddress); - - EX_TRY - { - // If stubStartAddress is completely bogus, then this might AV, - // so we protect it with SEH. An AV here is OK. - AVInRuntimeImplOkayHolder AVOkay; - - WORD firstWord = *((WORD*) pInstr); - - if (*((UINT32*)pInstr) == 0xc000f8d0) - { - // Confirm the thrid word belongs to the vtable stub pattern - WORD thirdWord = ((WORD*)pInstr)[2]; - if (thirdWord == 0xf84d /* Part of str r0, [sp, #-4] */ || - thirdWord == 0xf8dc /* Part of ldr r12, [r12 + offset] */) - stubKind = SK_VTABLECALL; - } - - if (stubKind == SK_UNKNOWN) - { - //Assuming that RESOLVE_STUB_FIRST_WORD & DISPATCH_STUB_FIRST_WORD have same values - if (firstWord == DISPATCH_STUB_FIRST_WORD) - { - WORD thirdWord = ((WORD*)pInstr)[2]; - if (thirdWord == 0xf84d) - { - stubKind = SK_DISPATCH; - } - else if (thirdWord == 0xb460) - { - stubKind = SK_RESOLVE; - } - } - else if (firstWord == 0xf8df) - { - stubKind = SK_LOOKUP; - } - } - } - EX_CATCH - { - stubKind = SK_UNKNOWN; - } - EX_END_CATCH(SwallowAllExceptions); - - return stubKind; - -#endif // DACCESS_COMPILE -} - #endif //DECLARE_DATA #endif // _VIRTUAL_CALL_STUB_ARM_H diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp index 5f8673b702da5..bc3e2b9609cae 100644 --- a/src/coreclr/vm/arm64/stubs.cpp +++ b/src/coreclr/vm/arm64/stubs.cpp @@ -945,10 +945,9 @@ AdjustContextForVirtualStub( PCODE f_IP = GetIP(pContext); - VirtualCallStubManager::StubKind sk; - VirtualCallStubManager::FindStubManager(f_IP, &sk); + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(f_IP); - if (sk == VirtualCallStubManager::SK_DISPATCH) + if (sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { if (*PTR_DWORD(f_IP) != DISPATCH_STUB_FIRST_DWORD) { @@ -957,7 +956,7 @@ AdjustContextForVirtualStub( } } else - if (sk == VirtualCallStubManager::SK_RESOLVE) + if (sk == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) { if (*PTR_DWORD(f_IP) != RESOLVE_STUB_FIRST_DWORD) { diff --git a/src/coreclr/vm/arm64/thunktemplates.S b/src/coreclr/vm/arm64/thunktemplates.S index 7e4db66ff7b99..5f4a728139d77 100644 --- a/src/coreclr/vm/arm64/thunktemplates.S +++ b/src/coreclr/vm/arm64/thunktemplates.S @@ -4,36 +4,36 @@ #include "unixasmmacros.inc" #include "asmconstants.h" -#define DATA_SLOT(stub, field) . - (. - C_FUNC(stub##Code\PAGE_SIZE)) + \PAGE_SIZE + stub##Data__##field +#define DATA_SLOT(stub, field) . - (. - C_FUNC(stub##Code\STUB_PAGE_SIZE)) + \STUB_PAGE_SIZE + stub##Data__##field - .irp PAGE_SIZE, 4096, 8192, 16384, 32768, 65536 + .irp STUB_PAGE_SIZE, 16384, 32768, 65536 - LEAF_ENTRY StubPrecodeCode\PAGE_SIZE + LEAF_ENTRY StubPrecodeCode\STUB_PAGE_SIZE ldr x10, DATA_SLOT(StubPrecode, Target) ldr x12, DATA_SLOT(StubPrecode, MethodDesc) br x10 - LEAF_END_MARKED StubPrecodeCode\PAGE_SIZE + LEAF_END_MARKED StubPrecodeCode\STUB_PAGE_SIZE - LEAF_ENTRY FixupPrecodeCode\PAGE_SIZE + LEAF_ENTRY FixupPrecodeCode\STUB_PAGE_SIZE ldr x11, DATA_SLOT(FixupPrecode, Target) br x11 ldr x12, DATA_SLOT(FixupPrecode, MethodDesc) ldr x11, DATA_SLOT(FixupPrecode, PrecodeFixupThunk) br x11 - LEAF_END_MARKED FixupPrecodeCode\PAGE_SIZE + LEAF_END_MARKED FixupPrecodeCode\STUB_PAGE_SIZE - LEAF_ENTRY CallCountingStubCode\PAGE_SIZE -LOCAL_LABEL(StubStart\PAGE_SIZE): + LEAF_ENTRY CallCountingStubCode\STUB_PAGE_SIZE +LOCAL_LABEL(StubStart\STUB_PAGE_SIZE): ldr x9, DATA_SLOT(CallCountingStub, RemainingCallCountCell) ldrh w10, [x9] subs w10, w10, #1 strh w10, [x9] - beq LOCAL_LABEL(CountReachedZero\PAGE_SIZE) + beq LOCAL_LABEL(CountReachedZero\STUB_PAGE_SIZE) ldr x9, DATA_SLOT(CallCountingStub, TargetForMethod) br x9 -LOCAL_LABEL(CountReachedZero\PAGE_SIZE): +LOCAL_LABEL(CountReachedZero\STUB_PAGE_SIZE): ldr x10, DATA_SLOT(CallCountingStub, TargetForThresholdReached) br x10 - LEAF_END_MARKED CallCountingStubCode\PAGE_SIZE + LEAF_END_MARKED CallCountingStubCode\STUB_PAGE_SIZE .endr diff --git a/src/coreclr/vm/arm64/thunktemplates.asm b/src/coreclr/vm/arm64/thunktemplates.asm index 958ddb029a6ee..e582a4cc1154a 100644 --- a/src/coreclr/vm/arm64/thunktemplates.asm +++ b/src/coreclr/vm/arm64/thunktemplates.asm @@ -5,7 +5,10 @@ #include "asmconstants.h" #include "asmmacros.h" -#define DATA_SLOT(stub, field) (stub##Code + PAGE_SIZE + stub##Data__##field) +; STUB_PAGE_SIZE must match the behavior of GetStubCodePageSize() on this architecture/os +#define STUB_PAGE_SIZE 16384 + +#define DATA_SLOT(stub, field) (stub##Code + STUB_PAGE_SIZE + stub##Data__##field) LEAF_ENTRY StubPrecodeCode ldr x10, DATA_SLOT(StubPrecode, Target) @@ -29,7 +32,7 @@ beq CountReachedZero ldr x9, DATA_SLOT(CallCountingStub, TargetForMethod) br x9 -CountReachedZero +CountReachedZero ldr x10, DATA_SLOT(CallCountingStub, TargetForThresholdReached) br x10 LEAF_END_MARKED CallCountingStubCode diff --git a/src/coreclr/vm/arm64/virtualcallstubcpu.hpp b/src/coreclr/vm/arm64/virtualcallstubcpu.hpp index 4944b198e5212..89de1bf0f4b9f 100644 --- a/src/coreclr/vm/arm64/virtualcallstubcpu.hpp +++ b/src/coreclr/vm/arm64/virtualcallstubcpu.hpp @@ -578,55 +578,6 @@ void VTableCallHolder::Initialize(unsigned slot) #endif // DACCESS_COMPILE -VirtualCallStubManager::StubKind VirtualCallStubManager::predictStubKind(PCODE stubStartAddress) -{ - - SUPPORTS_DAC; -#ifdef DACCESS_COMPILE - - return SK_BREAKPOINT; // Dac always uses the slower lookup - -#else - - StubKind stubKind = SK_UNKNOWN; - TADDR pInstr = PCODEToPINSTR(stubStartAddress); - - EX_TRY - { - // If stubStartAddress is completely bogus, then this might AV, - // so we protect it with SEH. An AV here is OK. - AVInRuntimeImplOkayHolder AVOkay; - - DWORD firstDword = *((DWORD*) pInstr); - - if (firstDword == DISPATCH_STUB_FIRST_DWORD) // assembly of first instruction of DispatchStub : ldr x13, [x0] - { - stubKind = SK_DISPATCH; - } - else if (firstDword == RESOLVE_STUB_FIRST_DWORD) // assembly of first instruction of ResolveStub : ldr x12, [x0,#Object.m_pMethTab ] - { - stubKind = SK_RESOLVE; - } - else if (firstDword == VTABLECALL_STUB_FIRST_DWORD) // assembly of first instruction of VTableCallStub : ldr x9, [x0] - { - stubKind = SK_VTABLECALL; - } - else if (firstDword == 0x10000089) // assembly of first instruction of LookupStub : adr x9, _resolveWorkerTarget - { - stubKind = SK_LOOKUP; - } - } - EX_CATCH - { - stubKind = SK_UNKNOWN; - } - EX_END_CATCH(SwallowAllExceptions); - - return stubKind; - -#endif // DACCESS_COMPILE -} - #endif //DECLARE_DATA #endif // _VIRTUAL_CALL_STUB_ARM_H diff --git a/src/coreclr/vm/callcounting.cpp b/src/coreclr/vm/callcounting.cpp index a49a2ace6032c..cfa8480439fa4 100644 --- a/src/coreclr/vm/callcounting.cpp +++ b/src/coreclr/vm/callcounting.cpp @@ -297,11 +297,11 @@ void (*CallCountingStub::CallCountingStubCode)(); void CallCountingStub::StaticInitialize() { #if defined(TARGET_ARM64) && defined(TARGET_UNIX) - int pageSize = GetOsPageSize(); + int pageSize = GetStubCodePageSize(); #define ENUM_PAGE_SIZE(size) \ case size: \ CallCountingStubCode = CallCountingStubCode##size; \ - _ASSERTE(((BYTE*)CallCountingStubCode##size##_End - (BYTE*)CallCountingStubCode##size) <= CallCountingStub::CodeSize); \ + _ASSERTE((SIZE_T)((BYTE*)CallCountingStubCode##size##_End - (BYTE*)CallCountingStubCode##size) <= CallCountingStub::CodeSize); \ break; switch (pageSize) @@ -312,16 +312,14 @@ void CallCountingStub::StaticInitialize() } #undef ENUM_PAGE_SIZE #else - _ASSERTE(((BYTE*)CallCountingStubCode_End - (BYTE*)CallCountingStubCode) <= CallCountingStub::CodeSize); + _ASSERTE((SIZE_T)((BYTE*)CallCountingStubCode_End - (BYTE*)CallCountingStubCode) <= CallCountingStub::CodeSize); #endif } #endif // DACCESS_COMPILE -void CallCountingStub::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX) +void CallCountingStub::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T pageSize) { - int pageSize = GetOsPageSize(); - #ifdef TARGET_X86 int totalCodeSize = (pageSize / CallCountingStub::CodeSize) * CallCountingStub::CodeSize; diff --git a/src/coreclr/vm/callcounting.h b/src/coreclr/vm/callcounting.h index 3d25e1c282626..43b6d66451180 100644 --- a/src/coreclr/vm/callcounting.h +++ b/src/coreclr/vm/callcounting.h @@ -90,15 +90,15 @@ class CallCountingStub { public: #if defined(TARGET_AMD64) - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; #elif defined(TARGET_X86) - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; #elif defined(TARGET_ARM64) - static const int CodeSize = 40; + static const SIZE_T CodeSize = 40; #elif defined(TARGET_ARM) - static const int CodeSize = 32; + static const SIZE_T CodeSize = 32; #elif defined(TARGET_LOONGARCH64) - static const int CodeSize = 40; + static const SIZE_T CodeSize = 40; #endif private: @@ -114,7 +114,7 @@ class CallCountingStub protected: PTR_CallCountingStubData GetData() const { - return dac_cast(dac_cast(this) + GetOsPageSize()); + return dac_cast(dac_cast(this) + GetStubCodePageSize()); } #ifndef DACCESS_COMPILE @@ -146,7 +146,7 @@ class CallCountingStub static void StaticInitialize(); #endif // !DACCESS_COMPILE - static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX); + static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); PTR_CallCount GetRemainingCallCountCell() const; PCODE GetTargetForMethod() const; diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index b3f10b5c098aa..74c9567f3168b 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -2760,6 +2760,8 @@ HeapList* LoaderCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap pHp->mapBase = ROUND_DOWN_TO_PAGE(pHp->startAddress); // round down to next lower page align pHp->pHdrMap = (DWORD*)(void*)pJitMetaHeap->AllocMem(S_SIZE_T(nibbleMapSize)); + pHp->pLoaderAllocator = pInfo->m_pAllocator; + LOG((LF_JIT, LL_INFO100, "Created new CodeHeap(" FMT_ADDR ".." FMT_ADDR ")\n", DBG_ADDR(pHp->startAddress), DBG_ADDR(pHp->startAddress+pHp->maxCodeHeapSize) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 5c1ec4230b4d9..cad3608a3d7f1 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -102,6 +102,10 @@ enum StubCodeBlockKind : int STUB_CODE_BLOCK_DYNAMICHELPER, STUB_CODE_BLOCK_STUBPRECODE, STUB_CODE_BLOCK_FIXUPPRECODE, + STUB_CODE_BLOCK_VSD_DISPATCH_STUB, + STUB_CODE_BLOCK_VSD_RESOLVE_STUB, + STUB_CODE_BLOCK_VSD_LOOKUP_STUB, + STUB_CODE_BLOCK_VSD_VTABLE_STUB, // Last valid value. Note that the definition is duplicated in debug\daccess\fntableaccess.cpp STUB_CODE_BLOCK_LAST = 0xF, // Placeholders returned by code:GetStubCodeBlockKind @@ -480,6 +484,7 @@ struct HeapList size_t maxCodeHeapSize;// Size of the entire contiguous block of memory size_t reserveForJumpStubs; // Amount of memory reserved for jump stubs in this block + PTR_LoaderAllocator pLoaderAllocator; // LoaderAllocator of HeapList #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) BYTE* CLRPersonalityRoutine; // jump thunk to personality routine #endif diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index ac867bd6123fd..b83e63e7c5579 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -6314,14 +6314,13 @@ BOOL IsIPinVirtualStub(PCODE f_IP) return FALSE; } - VirtualCallStubManager::StubKind sk; - VirtualCallStubManager::FindStubManager(f_IP, &sk, FALSE /* usePredictStubKind */); + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(f_IP); - if (sk == VirtualCallStubManager::SK_DISPATCH) + if (sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { return TRUE; } - else if (sk == VirtualCallStubManager::SK_RESOLVE) + else if (sk == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) { return TRUE; } diff --git a/src/coreclr/vm/gccover.cpp b/src/coreclr/vm/gccover.cpp index 67cf677273f75..190149c88fa98 100644 --- a/src/coreclr/vm/gccover.cpp +++ b/src/coreclr/vm/gccover.cpp @@ -52,17 +52,23 @@ static MethodDesc* getTargetMethodDesc(PCODE target) return targetMD; } - VirtualCallStubManager::StubKind vsdStubKind = VirtualCallStubManager::SK_UNKNOWN; - VirtualCallStubManager *pVSDStubManager = VirtualCallStubManager::FindStubManager(target, &vsdStubKind); - if (vsdStubKind != VirtualCallStubManager::SK_BREAKPOINT && vsdStubKind != VirtualCallStubManager::SK_UNKNOWN) + auto stubKind = RangeSectionStubManager::GetStubKind(target); + + if ((stubKind == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) || + (stubKind == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) || + (stubKind == STUB_CODE_BLOCK_VSD_LOOKUP_STUB) || + (stubKind == STUB_CODE_BLOCK_VSD_VTABLE_STUB)) { - // It is a VSD stub manager. - DispatchToken token(VirtualCallStubManager::GetTokenFromStubQuick(pVSDStubManager, target, vsdStubKind)); - _ASSERTE(token.IsValid()); - return VirtualCallStubManager::GetInterfaceMethodDescFromToken(token); + VirtualCallStubManager *pVSDStubManager = VirtualCallStubManager::FindStubManager(target, &stubKind); + if (pVSDStubManager != NULL) + { + // It is a VSD stub manager. + DispatchToken token(VirtualCallStubManager::GetTokenFromStubQuick(pVSDStubManager, target, stubKind)); + _ASSERTE(token.IsValid()); + return VirtualCallStubManager::GetInterfaceMethodDescFromToken(token); + } } - auto stubKind = RangeSectionStubManager::GetStubKind(target); if (stubKind == STUB_CODE_BLOCK_PRECODE) { // The address looks like a value stub, try to get the method descriptor. diff --git a/src/coreclr/vm/i386/excepx86.cpp b/src/coreclr/vm/i386/excepx86.cpp index 2dbcc04214363..438338ed312ab 100644 --- a/src/coreclr/vm/i386/excepx86.cpp +++ b/src/coreclr/vm/i386/excepx86.cpp @@ -3438,10 +3438,10 @@ AdjustContextForVirtualStub( PCODE f_IP = GetIP(pContext); - VirtualCallStubManager::StubKind sk; + StubCodeBlockKind sk; VirtualCallStubManager *pMgr = VirtualCallStubManager::FindStubManager(f_IP, &sk); - if (sk == VirtualCallStubManager::SK_DISPATCH) + if (sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { if (*PTR_WORD(f_IP) != X86_INSTR_CMP_IND_ECX_IMM32) { @@ -3450,7 +3450,7 @@ AdjustContextForVirtualStub( } } else - if (sk == VirtualCallStubManager::SK_RESOLVE) + if (sk == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) { if (*PTR_WORD(f_IP) != X86_INSTR_MOV_EAX_ECX_IND) { @@ -3486,7 +3486,7 @@ AdjustContextForVirtualStub( // set the ESP to what it would be after the call (remove pushed arguments) size_t stackArgumentsSize; - if (sk == VirtualCallStubManager::SK_DISPATCH) + if (sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); diff --git a/src/coreclr/vm/i386/thunktemplates.S b/src/coreclr/vm/i386/thunktemplates.S index eedd6ac1dbe2e..128eba016b490 100644 --- a/src/coreclr/vm/i386/thunktemplates.S +++ b/src/coreclr/vm/i386/thunktemplates.S @@ -5,7 +5,7 @@ #include "unixasmmacros.inc" #include "asmconstants.h" -PAGE_SIZE = 4096 +PAGE_SIZE = 16384 //#define DATA_SLOT(stub, field) stub##Code + PAGE_SIZE + stub##Data__##field #define DATA_SLOT(stub, field) PAGE_SIZE + stub##Data__##field diff --git a/src/coreclr/vm/i386/thunktemplates.asm b/src/coreclr/vm/i386/thunktemplates.asm index dfb1a4285c022..5e3203a46859c 100644 --- a/src/coreclr/vm/i386/thunktemplates.asm +++ b/src/coreclr/vm/i386/thunktemplates.asm @@ -13,7 +13,7 @@ include AsmConstants.inc .686P .XMM -PAGE_SIZE EQU 4096 +PAGE_SIZE EQU 16384 DATA_SLOT macro stub, field exitm @CatStr(<_>, stub, , stub, , field) diff --git a/src/coreclr/vm/i386/virtualcallstubcpu.hpp b/src/coreclr/vm/i386/virtualcallstubcpu.hpp index 7268df395f136..34a9c4d86c0ed 100644 --- a/src/coreclr/vm/i386/virtualcallstubcpu.hpp +++ b/src/coreclr/vm/i386/virtualcallstubcpu.hpp @@ -1029,68 +1029,6 @@ void VTableCallHolder::Initialize(unsigned slot) #endif // DACCESS_COMPILE -VirtualCallStubManager::StubKind VirtualCallStubManager::predictStubKind(PCODE stubStartAddress) -{ - SUPPORTS_DAC; -#ifdef DACCESS_COMPILE - - return SK_BREAKPOINT; // Dac always uses the slower lookup - -#else - - StubKind stubKind = SK_UNKNOWN; - - EX_TRY - { - // If stubStartAddress is completely bogus, then this might AV, - // so we protect it with SEH. An AV here is OK. - AVInRuntimeImplOkayHolder AVOkay; - - WORD firstWord = *((WORD*) stubStartAddress); - -#ifndef STUB_LOGGING - if (firstWord == 0x3981) -#else //STUB_LOGGING - if (firstWord == 0x05ff) -#endif - { - stubKind = SK_DISPATCH; - } - else if (firstWord == 0x6850) - { - stubKind = SK_LOOKUP; - } - else if (firstWord == 0x8b50) - { - stubKind = SK_RESOLVE; - } - else if (firstWord == 0x018b) - { - stubKind = SK_VTABLECALL; - } - else - { - BYTE firstByte = ((BYTE*) stubStartAddress)[0]; - BYTE secondByte = ((BYTE*) stubStartAddress)[1]; - - if ((firstByte == X86_INSTR_INT3) || - (secondByte == X86_INSTR_INT3)) - { - stubKind = SK_BREAKPOINT; - } - } - } - EX_CATCH - { - stubKind = SK_UNKNOWN; - } - EX_END_CATCH(SwallowAllExceptions); - - return stubKind; - -#endif // DACCESS_COMPILE -} - #endif //DECLARE_DATA #endif // _VIRTUAL_CALL_STUB_X86_H diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c633517cbf5fa..1ea21c913cf24 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -5302,7 +5302,6 @@ void CEEInfo::getCallInfo( VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager(); PCODE addr = pMgr->GetCallStub(exactType, pTargetMD); - _ASSERTE(pMgr->isStub(addr)); // Now we want to indirect through a cell so that updates can take place atomically. if (m_pMethodBeingCompiled->IsLCGMethod()) diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index b49a100d105f4..c9eed61a132f6 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -1053,8 +1053,8 @@ void LoaderAllocator::ActivateManagedTracking() #define COLLECTIBLE_LOW_FREQUENCY_HEAP_SIZE (0 * GetOsPageSize()) #define COLLECTIBLE_HIGH_FREQUENCY_HEAP_SIZE (3 * GetOsPageSize()) #define COLLECTIBLE_STUB_HEAP_SIZE GetOsPageSize() -#define COLLECTIBLE_CODEHEAP_SIZE (7 * GetOsPageSize()) -#define COLLECTIBLE_VIRTUALSTUBDISPATCH_HEAP_SPACE (5 * GetOsPageSize()) +#define COLLECTIBLE_CODEHEAP_SIZE (10 * GetOsPageSize()) +#define COLLECTIBLE_VIRTUALSTUBDISPATCH_HEAP_SPACE (2 * GetOsPageSize()) void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory) { @@ -1194,16 +1194,16 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory) m_pPrecodeHeap = new (&m_PrecodeHeapInstance) CodeFragmentHeap(this, STUB_CODE_BLOCK_PRECODE); - m_pNewStubPrecodeHeap = new (&m_NewStubPrecodeHeapInstance) LoaderHeap(2 * GetOsPageSize(), - 2 * GetOsPageSize(), + m_pNewStubPrecodeHeap = new (&m_NewStubPrecodeHeapInstance) LoaderHeap(2 * GetStubCodePageSize(), + 2 * GetStubCodePageSize(), &m_stubPrecodeRangeList, UnlockedLoaderHeap::HeapKind::Interleaved, false /* fUnlocked */, StubPrecode::GenerateCodePage, StubPrecode::CodeSize); - m_pFixupPrecodeHeap = new (&m_FixupPrecodeHeapInstance) LoaderHeap(2 * GetOsPageSize(), - 2 * GetOsPageSize(), + m_pFixupPrecodeHeap = new (&m_FixupPrecodeHeapInstance) LoaderHeap(2 * GetStubCodePageSize(), + 2 * GetStubCodePageSize(), &m_fixupPrecodeRangeList, UnlockedLoaderHeap::HeapKind::Interleaved, false /* fUnlocked */, diff --git a/src/coreclr/vm/loongarch64/stubs.cpp b/src/coreclr/vm/loongarch64/stubs.cpp index 12d56e177ebac..d39901c086cb1 100644 --- a/src/coreclr/vm/loongarch64/stubs.cpp +++ b/src/coreclr/vm/loongarch64/stubs.cpp @@ -985,10 +985,9 @@ AdjustContextForVirtualStub( PCODE f_IP = GetIP(pContext); - VirtualCallStubManager::StubKind sk; - VirtualCallStubManager::FindStubManager(f_IP, &sk); + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(f_IP); - if (sk == VirtualCallStubManager::SK_DISPATCH) + if (sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { if (*PTR_DWORD(f_IP - 4) != DISPATCH_STUB_FIRST_DWORD) { @@ -997,7 +996,7 @@ AdjustContextForVirtualStub( } } else - if (sk == VirtualCallStubManager::SK_RESOLVE) + if (sk == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) { if (*PTR_DWORD(f_IP) != RESOLVE_STUB_FIRST_DWORD) { diff --git a/src/coreclr/vm/loongarch64/thunktemplates.S b/src/coreclr/vm/loongarch64/thunktemplates.S index 4ab9c1e938c65..eeaf61752d067 100644 --- a/src/coreclr/vm/loongarch64/thunktemplates.S +++ b/src/coreclr/vm/loongarch64/thunktemplates.S @@ -4,18 +4,20 @@ #include "unixasmmacros.inc" #include "asmconstants.h" +; Note that the offsets specified in pcaddi must match the behavior of GetStubCodePageSize() on this architecture/os. + LEAF_ENTRY StubPrecodeCode - pcaddi $r21, 0x1004 //4, for Type encoding. + pcaddi $r21, 0x4004 //4, for Type encoding. ld.d $t2,$r21, (StubPrecodeData__MethodDesc - 4*4) ld.d $r21,$r21, (StubPrecodeData__Target - 4*4) jirl $r0,$r21,0 LEAF_END_MARKED StubPrecodeCode LEAF_ENTRY FixupPrecodeCode - pcaddi $r21, 0x1003 //3, for Type encoding. + pcaddi $r21, 0x4003 //3, for Type encoding. ld.d $r21,$r21, (FixupPrecodeData__Target - 4*3) jirl $r0,$r21,0 - pcaddi $r21, 0x1003 + pcaddi $r21, 0x4003 ld.d $t2,$r21, (FixupPrecodeData__MethodDesc - 4*3 -4*3) ld.d $r21,$r21, (FixupPrecodeData__PrecodeFixupThunk - 4*3 - 4*3) jirl $r0,$r21,0 @@ -24,7 +26,7 @@ LEAF_END_MARKED FixupPrecodeCode // NOTE: For LoongArch64 `CallCountingStubData__RemainingCallCountCell` must be zero !!! // Because the stub-identifying token is $t1 within the `OnCallCountThresholdReachedStub`. LEAF_ENTRY CallCountingStubCode - pcaddi $t2, 0x1000 + pcaddi $t2, 0x4000 ld.d $t1, $t2, CallCountingStubData__RemainingCallCountCell ld.h $r21, $t1, 0 addi.w $r21, $r21, -1 diff --git a/src/coreclr/vm/loongarch64/virtualcallstubcpu.hpp b/src/coreclr/vm/loongarch64/virtualcallstubcpu.hpp index 66630a6b80a2f..ed1a13fda4257 100644 --- a/src/coreclr/vm/loongarch64/virtualcallstubcpu.hpp +++ b/src/coreclr/vm/loongarch64/virtualcallstubcpu.hpp @@ -527,55 +527,6 @@ void VTableCallHolder::Initialize(unsigned slot) #endif // DACCESS_COMPILE -VirtualCallStubManager::StubKind VirtualCallStubManager::predictStubKind(PCODE stubStartAddress) -{ - - SUPPORTS_DAC; -#ifdef DACCESS_COMPILE - - return SK_BREAKPOINT; // Dac always uses the slower lookup - -#else - - StubKind stubKind = SK_UNKNOWN; - TADDR pInstr = PCODEToPINSTR(stubStartAddress); - - EX_TRY - { - // If stubStartAddress is completely bogus, then this might AV, - // so we protect it with SEH. An AV here is OK. - AVInRuntimeImplOkayHolder AVOkay; - - DWORD firstDword = *((DWORD*) pInstr); - - if (firstDword == DISPATCH_STUB_FIRST_DWORD) // assembly of first instruction of DispatchStub : - { - stubKind = SK_DISPATCH; - } - else if (firstDword == RESOLVE_STUB_FIRST_DWORD) // assembly of first instruction of ResolveStub : - { - stubKind = SK_RESOLVE; - } - else if (firstDword == VTABLECALL_STUB_FIRST_DWORD) // assembly of first instruction of VTableCallStub : - { - stubKind = SK_VTABLECALL; - } - else if (firstDword == LOOKUP_STUB_FIRST_DWORD) // first instruction of LookupStub : - { - stubKind = SK_LOOKUP; - } - } - EX_CATCH - { - stubKind = SK_UNKNOWN; - } - EX_END_CATCH(SwallowAllExceptions); - - return stubKind; - -#endif // DACCESS_COMPILE -} - #endif //DECLARE_DATA #endif // _VIRTUAL_CALL_STUB_LOONGARCH64_H diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp index c997af5f67881..5ad146a07cba0 100644 --- a/src/coreclr/vm/precode.cpp +++ b/src/coreclr/vm/precode.cpp @@ -594,10 +594,10 @@ void StubPrecode::StaticInitialize() case size: \ StubPrecodeCode = StubPrecodeCode##size; \ StubPrecodeCode_End = StubPrecodeCode##size##_End; \ - _ASSERTE(((BYTE*)StubPrecodeCode##size##_End - (BYTE*)StubPrecodeCode##size) <= StubPrecode::CodeSize); \ + _ASSERTE((SIZE_T)((BYTE*)StubPrecodeCode##size##_End - (BYTE*)StubPrecodeCode##size) <= StubPrecode::CodeSize); \ break; - int pageSize = GetOsPageSize(); + int pageSize = GetStubCodePageSize(); switch (pageSize) { ENUM_PAGE_SIZES @@ -606,7 +606,7 @@ void StubPrecode::StaticInitialize() } #undef ENUM_PAGE_SIZE #else - _ASSERTE(((BYTE*)StubPrecodeCode_End - (BYTE*)StubPrecodeCode) <= StubPrecode::CodeSize); + _ASSERTE((SIZE_T)((BYTE*)StubPrecodeCode_End - (BYTE*)StubPrecodeCode) <= StubPrecode::CodeSize); #endif #ifdef TARGET_LOONGARCH64 _ASSERTE(((*((short*)PCODEToPINSTR((PCODE)StubPrecodeCode) + OFFSETOF_PRECODE_TYPE)) >> 5) == StubPrecode::Type); @@ -616,10 +616,8 @@ void StubPrecode::StaticInitialize() } -void StubPrecode::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX) +void StubPrecode::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T pageSize) { - int pageSize = GetOsPageSize(); - #ifdef TARGET_X86 int totalCodeSize = (pageSize / StubPrecode::CodeSize) * StubPrecode::CodeSize; for (int i = 0; i < totalCodeSize; i += StubPrecode::CodeSize) @@ -642,9 +640,9 @@ BOOL StubPrecode::IsStubPrecodeByASM(PCODE addr) BYTE *pInstr = (BYTE*)PCODEToPINSTR(addr); #ifdef TARGET_X86 return *pInstr == *(BYTE*)(StubPrecodeCode) && - *(DWORD*)(pInstr + SYMBOL_VALUE(StubPrecodeCode_MethodDesc_Offset)) == (DWORD)(pInstr + GetOsPageSize() + offsetof(StubPrecodeData, MethodDesc)) && + *(DWORD*)(pInstr + SYMBOL_VALUE(StubPrecodeCode_MethodDesc_Offset)) == (DWORD)(pInstr + GetStubCodePageSize() + offsetof(StubPrecodeData, MethodDesc)) && *(WORD*)(pInstr + 5) == *(WORD*)((BYTE*)StubPrecodeCode + 5) && - *(DWORD*)(pInstr + SYMBOL_VALUE(StubPrecodeCode_Target_Offset)) == (DWORD)(pInstr + GetOsPageSize() + offsetof(StubPrecodeData, Target)); + *(DWORD*)(pInstr + SYMBOL_VALUE(StubPrecodeCode_Target_Offset)) == (DWORD)(pInstr + GetStubCodePageSize() + offsetof(StubPrecodeData, Target)); #else // TARGET_X86 return memcmp(pInstr, (void*)PCODEToPINSTR((PCODE)StubPrecodeCode), (BYTE*)StubPrecodeCode_End - (BYTE*)StubPrecodeCode) == 0; #endif // TARGET_X86 @@ -705,10 +703,10 @@ void FixupPrecode::StaticInitialize() case size: \ FixupPrecodeCode = FixupPrecodeCode##size; \ FixupPrecodeCode_End = FixupPrecodeCode##size##_End; \ - _ASSERTE(((BYTE*)FixupPrecodeCode##size##_End - (BYTE*)FixupPrecodeCode##size) <= FixupPrecode::CodeSize); \ + _ASSERTE((SIZE_T)((BYTE*)FixupPrecodeCode##size##_End - (BYTE*)FixupPrecodeCode##size) <= FixupPrecode::CodeSize); \ break; - int pageSize = GetOsPageSize(); + int pageSize = GetStubCodePageSize(); switch (pageSize) { @@ -718,7 +716,7 @@ void FixupPrecode::StaticInitialize() } #undef ENUM_PAGE_SIZE #else - _ASSERTE((BYTE*)FixupPrecodeCode_End - (BYTE*)FixupPrecodeCode <= FixupPrecode::CodeSize); + _ASSERTE((SIZE_T)((BYTE*)FixupPrecodeCode_End - (BYTE*)FixupPrecodeCode) <= FixupPrecode::CodeSize); #endif #ifdef TARGET_LOONGARCH64 _ASSERTE(((*((short*)PCODEToPINSTR((PCODE)StubPrecodeCode) + OFFSETOF_PRECODE_TYPE)) >> 5) == StubPrecode::Type); @@ -727,10 +725,8 @@ void FixupPrecode::StaticInitialize() #endif } -void FixupPrecode::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX) +void FixupPrecode::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T pageSize) { - int pageSize = GetOsPageSize(); - #ifdef TARGET_X86 int totalCodeSize = (pageSize / FixupPrecode::CodeSize) * FixupPrecode::CodeSize; @@ -757,11 +753,11 @@ BOOL FixupPrecode::IsFixupPrecodeByASM(PCODE addr) #ifdef TARGET_X86 return *(WORD*)(pInstr) == *(WORD*)(FixupPrecodeCode) && - *(DWORD*)(pInstr + SYMBOL_VALUE(FixupPrecodeCode_Target_Offset)) == (DWORD)(pInstr + GetOsPageSize() + offsetof(FixupPrecodeData, Target)) && + *(DWORD*)(pInstr + SYMBOL_VALUE(FixupPrecodeCode_Target_Offset)) == (DWORD)(pInstr + GetStubCodePageSize() + offsetof(FixupPrecodeData, Target)) && *(pInstr + 6) == *((BYTE*)FixupPrecodeCode + 6) && - *(DWORD*)(pInstr + SYMBOL_VALUE(FixupPrecodeCode_MethodDesc_Offset)) == (DWORD)(pInstr + GetOsPageSize() + offsetof(FixupPrecodeData, MethodDesc)) && + *(DWORD*)(pInstr + SYMBOL_VALUE(FixupPrecodeCode_MethodDesc_Offset)) == (DWORD)(pInstr + GetStubCodePageSize() + offsetof(FixupPrecodeData, MethodDesc)) && *(WORD*)(pInstr + 11) == *(WORD*)((BYTE*)FixupPrecodeCode + 11) && - *(DWORD*)(pInstr + SYMBOL_VALUE(FixupPrecodeCode_PrecodeFixupThunk_Offset)) == (DWORD)(pInstr + GetOsPageSize() + offsetof(FixupPrecodeData, PrecodeFixupThunk)); + *(DWORD*)(pInstr + SYMBOL_VALUE(FixupPrecodeCode_PrecodeFixupThunk_Offset)) == (DWORD)(pInstr + GetStubCodePageSize() + offsetof(FixupPrecodeData, PrecodeFixupThunk)); #else // TARGET_X86 return memcmp(pInstr, (void*)PCODEToPINSTR((PCODE)FixupPrecodeCode), (BYTE*)FixupPrecodeCode_End - (BYTE*)FixupPrecodeCode) == 0; #endif // TARGET_X86 diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index 4822ccfec7054..e741614466099 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -85,19 +85,19 @@ struct StubPrecode { #if defined(HOST_AMD64) static const BYTE Type = 0x4C; - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; #elif defined(HOST_X86) static const BYTE Type = 0xA1; - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; #elif defined(HOST_ARM64) static const int Type = 0x4A; - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; #elif defined(HOST_ARM) static const int Type = 0xCF; - static const int CodeSize = 12; + static const SIZE_T CodeSize = 12; #elif defined(HOST_LOONGARCH64) static const int Type = 0x4; - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; #endif // HOST_AMD64 BYTE m_code[CodeSize]; @@ -114,7 +114,7 @@ struct StubPrecode PTR_StubPrecodeData GetData() const { LIMITED_METHOD_CONTRACT; - return dac_cast(dac_cast(this) + GetOsPageSize()); + return dac_cast(dac_cast(this) + GetStubCodePageSize()); } TADDR GetMethodDesc() @@ -165,7 +165,7 @@ struct StubPrecode return InterlockedCompareExchangeT(&pData->Target, (PCODE)target, (PCODE)expected) == expected; } - static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX); + static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); #endif // !DACCESS_COMPILE }; @@ -216,23 +216,23 @@ struct FixupPrecode { #if defined(HOST_AMD64) static const int Type = 0xFF; - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; static const int FixupCodeOffset = 6; #elif defined(HOST_X86) static const int Type = 0xFF; - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; static const int FixupCodeOffset = 6; #elif defined(HOST_ARM64) static const int Type = 0x0B; - static const int CodeSize = 24; + static const SIZE_T CodeSize = 24; static const int FixupCodeOffset = 8; #elif defined(HOST_ARM) static const int Type = 0xFF; - static const int CodeSize = 12; + static const SIZE_T CodeSize = 12; static const int FixupCodeOffset = 4 + THUMB_CODE; #elif defined(HOST_LOONGARCH64) static const int Type = 0x3; - static const int CodeSize = 32; + static const SIZE_T CodeSize = 32; static const int FixupCodeOffset = 12; #endif // HOST_AMD64 @@ -247,12 +247,12 @@ struct FixupPrecode static void StaticInitialize(); - static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX); + static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); PTR_FixupPrecodeData GetData() const { LIMITED_METHOD_CONTRACT; - return dac_cast(dac_cast(this) + GetOsPageSize()); + return dac_cast(dac_cast(this) + GetStubCodePageSize()); } TADDR GetMethodDesc() @@ -579,7 +579,7 @@ class Precode { static DWORD GetMaxTemporaryEntryPointsCount() { SIZE_T maxPrecodeCodeSize = Max(FixupPrecode::CodeSize, StubPrecode::CodeSize); - SIZE_T count = GetOsPageSize() / maxPrecodeCodeSize; + SIZE_T count = GetStubCodePageSize() / maxPrecodeCodeSize; _ASSERTE(count < MAXDWORD); return (DWORD)count; } diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 90889208bebef..7069eab7a72b1 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2587,7 +2587,7 @@ EXTERN_C PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBl token = DispatchToken::CreateDispatchToken(slot); StubCallSite callSite(pIndirection, pEMFrame->GetReturnAddress()); - pCode = pMgr->ResolveWorker(&callSite, protectedObj, token, VirtualCallStubManager::SK_LOOKUP); + pCode = pMgr->ResolveWorker(&callSite, protectedObj, token, STUB_CODE_BLOCK_VSD_LOOKUP_STUB); } else { diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 423465536c627..c212de9e2fa79 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1434,6 +1434,10 @@ BOOL RangeSectionStubManager::CheckIsStub_Internal(PCODE stubStartAddress) case STUB_CODE_BLOCK_VIRTUAL_METHOD_THUNK: case STUB_CODE_BLOCK_EXTERNAL_METHOD_THUNK: case STUB_CODE_BLOCK_METHOD_CALL_THUNK: + case STUB_CODE_BLOCK_VSD_DISPATCH_STUB: + case STUB_CODE_BLOCK_VSD_RESOLVE_STUB: + case STUB_CODE_BLOCK_VSD_LOOKUP_STUB: + case STUB_CODE_BLOCK_VSD_VTABLE_STUB: return TRUE; default: break; @@ -1465,6 +1469,12 @@ BOOL RangeSectionStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestinati case STUB_CODE_BLOCK_STUBLINK: return StubLinkStubManager::g_pManager->DoTraceStub(stubStartAddress, trace); + case STUB_CODE_BLOCK_VSD_DISPATCH_STUB: + case STUB_CODE_BLOCK_VSD_RESOLVE_STUB: + case STUB_CODE_BLOCK_VSD_LOOKUP_STUB: + case STUB_CODE_BLOCK_VSD_VTABLE_STUB: + return VirtualCallStubManagerManager::GlobalManager()->DoTraceStub(stubStartAddress, trace); + case STUB_CODE_BLOCK_METHOD_CALL_THUNK: #ifdef DACCESS_COMPILE DacNotImpl(); @@ -1529,6 +1539,18 @@ LPCWSTR RangeSectionStubManager::GetStubManagerName(PCODE addr) case STUB_CODE_BLOCK_METHOD_CALL_THUNK: return W("MethodCallThunk"); + case STUB_CODE_BLOCK_VSD_DISPATCH_STUB: + return W("VSD_DispatchStub"); + + case STUB_CODE_BLOCK_VSD_RESOLVE_STUB: + return W("VSD_ResolveStub"); + + case STUB_CODE_BLOCK_VSD_LOOKUP_STUB: + return W("VSD_LookupStub"); + + case STUB_CODE_BLOCK_VSD_VTABLE_STUB: + return W("VSD_VTableStub"); + default: break; } @@ -2458,9 +2480,6 @@ VirtualCallStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) WRAPPER_NO_CONTRACT; DAC_ENUM_VTHIS(); EMEM_OUT(("MEM: %p VirtualCallStubManager\n", dac_cast(this))); - GetLookupRangeList()->EnumMemoryRegions(flags); - GetResolveRangeList()->EnumMemoryRegions(flags); - GetDispatchRangeList()->EnumMemoryRegions(flags); GetCacheEntryRangeList()->EnumMemoryRegions(flags); } diff --git a/src/coreclr/vm/util.cpp b/src/coreclr/vm/util.cpp index 4b5cab4078c31..ad6f90607cc4e 100644 --- a/src/coreclr/vm/util.cpp +++ b/src/coreclr/vm/util.cpp @@ -1940,13 +1940,13 @@ HRESULT GetFileVersion( // S_OK or error Volatile NormalizedTimer::s_frequency = -1.0; -void FillStubCodePage(BYTE* pageBase, const void* code, int codeSize, int pageSize) +void FillStubCodePage(BYTE* pageBase, const void* code, SIZE_T codeSize, SIZE_T pageSize) { - int totalCodeSize = (pageSize / codeSize) * codeSize; + SIZE_T totalCodeSize = (pageSize / codeSize) * codeSize; memcpy(pageBase, code, codeSize); - int i; + SIZE_T i; for (i = codeSize; i < pageSize / 2; i *= 2) { memcpy(pageBase + i, pageBase, i); diff --git a/src/coreclr/vm/util.hpp b/src/coreclr/vm/util.hpp index e0c96510f3cee..e7b311d8724d4 100644 --- a/src/coreclr/vm/util.hpp +++ b/src/coreclr/vm/util.hpp @@ -900,13 +900,11 @@ HRESULT GetFileVersion(LPCWSTR wszFilePath, ULARGE_INTEGER* pFileVersion); #endif // !TARGET_UNIX #define ENUM_PAGE_SIZES \ - ENUM_PAGE_SIZE(4096) \ - ENUM_PAGE_SIZE(8192) \ ENUM_PAGE_SIZE(16384) \ ENUM_PAGE_SIZE(32768) \ ENUM_PAGE_SIZE(65536) -void FillStubCodePage(BYTE* pageBase, const void* code, int codeSize, int pageSize); +void FillStubCodePage(BYTE* pageBase, const void* code, SIZE_T codeSize, SIZE_T pageSize); #ifdef TARGET_64BIT // We use modified Daniel Lemire's fastmod algorithm (https://github.com/dotnet/runtime/pull/406), diff --git a/src/coreclr/vm/virtualcallstub.cpp b/src/coreclr/vm/virtualcallstub.cpp index c54d239523f95..26d55c4c07d6d 100644 --- a/src/coreclr/vm/virtualcallstub.cpp +++ b/src/coreclr/vm/virtualcallstub.cpp @@ -519,14 +519,6 @@ void VirtualCallStubManager::Init(BaseDomain *pDomain, LoaderAllocator *pLoaderA DWORD indcell_heap_commit_size; DWORD cache_entry_heap_reserve_size; DWORD cache_entry_heap_commit_size; - DWORD lookup_heap_reserve_size; - DWORD lookup_heap_commit_size; - DWORD dispatch_heap_reserve_size; - DWORD dispatch_heap_commit_size; - DWORD resolve_heap_reserve_size; - DWORD resolve_heap_commit_size; - DWORD vtable_heap_reserve_size; - DWORD vtable_heap_commit_size; // // Setup an expected number of items to commit and reserve @@ -539,20 +531,6 @@ void VirtualCallStubManager::Init(BaseDomain *pDomain, LoaderAllocator *pLoaderA indcell_heap_commit_size = 16; indcell_heap_reserve_size = 2000; cache_entry_heap_commit_size = 16; cache_entry_heap_reserve_size = 800; - lookup_heap_commit_size = 24; lookup_heap_reserve_size = 250; - dispatch_heap_commit_size = 24; dispatch_heap_reserve_size = 600; - resolve_heap_commit_size = 24; resolve_heap_reserve_size = 300; - vtable_heap_commit_size = 24; vtable_heap_reserve_size = 600; - -#ifdef HOST_64BIT - // If we're on 64-bit, there's a ton of address space, so reserve more space to - // try to avoid getting into the situation where the resolve heap is more than - // a rel32 jump away from the dispatch heap, since this will cause us to produce - // larger dispatch stubs on AMD64. - dispatch_heap_reserve_size *= 10; - resolve_heap_reserve_size *= 10; -#endif - // // Convert the number of items into a size in bytes to commit and reserve // @@ -562,23 +540,6 @@ void VirtualCallStubManager::Init(BaseDomain *pDomain, LoaderAllocator *pLoaderA cache_entry_heap_reserve_size *= sizeof(ResolveCacheElem); cache_entry_heap_commit_size *= sizeof(ResolveCacheElem); - lookup_heap_reserve_size *= sizeof(LookupHolder); - lookup_heap_commit_size *= sizeof(LookupHolder); - - DWORD dispatchHolderSize = sizeof(DispatchHolder); -#ifdef TARGET_AMD64 - dispatchHolderSize = static_cast(DispatchHolder::GetHolderSize(DispatchStub::e_TYPE_SHORT)); -#endif - - dispatch_heap_reserve_size *= dispatchHolderSize; - dispatch_heap_commit_size *= dispatchHolderSize; - - resolve_heap_reserve_size *= sizeof(ResolveHolder); - resolve_heap_commit_size *= sizeof(ResolveHolder); - - vtable_heap_reserve_size *= static_cast(VTableCallHolder::GetHolderSize(0)); - vtable_heap_commit_size *= static_cast(VTableCallHolder::GetHolderSize(0)); - // // Align up all of the commit and reserve sizes // @@ -588,28 +549,12 @@ void VirtualCallStubManager::Init(BaseDomain *pDomain, LoaderAllocator *pLoaderA cache_entry_heap_reserve_size = (DWORD) ALIGN_UP(cache_entry_heap_reserve_size, GetOsPageSize()); cache_entry_heap_commit_size = (DWORD) ALIGN_UP(cache_entry_heap_commit_size, GetOsPageSize()); - lookup_heap_reserve_size = (DWORD) ALIGN_UP(lookup_heap_reserve_size, GetOsPageSize()); - lookup_heap_commit_size = (DWORD) ALIGN_UP(lookup_heap_commit_size, GetOsPageSize()); - - dispatch_heap_reserve_size = (DWORD) ALIGN_UP(dispatch_heap_reserve_size, GetOsPageSize()); - dispatch_heap_commit_size = (DWORD) ALIGN_UP(dispatch_heap_commit_size, GetOsPageSize()); - - resolve_heap_reserve_size = (DWORD) ALIGN_UP(resolve_heap_reserve_size, GetOsPageSize()); - resolve_heap_commit_size = (DWORD) ALIGN_UP(resolve_heap_commit_size, GetOsPageSize()); - - vtable_heap_reserve_size = (DWORD) ALIGN_UP(vtable_heap_reserve_size, GetOsPageSize()); - vtable_heap_commit_size = (DWORD) ALIGN_UP(vtable_heap_commit_size, GetOsPageSize()); - BYTE * initReservedMem = NULL; if (!m_loaderAllocator->IsCollectible()) { DWORD dwTotalReserveMemSizeCalc = indcell_heap_reserve_size + - cache_entry_heap_reserve_size + - lookup_heap_reserve_size + - dispatch_heap_reserve_size + - resolve_heap_reserve_size + - vtable_heap_reserve_size; + cache_entry_heap_reserve_size; DWORD dwTotalReserveMemSize = (DWORD) ALIGN_UP(dwTotalReserveMemSizeCalc, VIRTUAL_ALLOC_RESERVE_GRANULARITY); @@ -619,24 +564,17 @@ void VirtualCallStubManager::Init(BaseDomain *pDomain, LoaderAllocator *pLoaderA if (dwWastedReserveMemSize != 0) { DWORD cWastedPages = dwWastedReserveMemSize / GetOsPageSize(); - DWORD cPagesPerHeap = cWastedPages / 6; - DWORD cPagesRemainder = cWastedPages % 6; // We'll throw this at the resolve heap + + // Split the wasted pages over the 2 LoaderHeaps that we allocate as part of a VirtualCallStubManager + DWORD cPagesPerHeap = cWastedPages / 2; + DWORD cPagesRemainder = cWastedPages % 2; // We'll throw this at the cache entry heap indcell_heap_reserve_size += cPagesPerHeap * GetOsPageSize(); - cache_entry_heap_reserve_size += cPagesPerHeap * GetOsPageSize(); - lookup_heap_reserve_size += cPagesPerHeap * GetOsPageSize(); - dispatch_heap_reserve_size += cPagesPerHeap * GetOsPageSize(); - vtable_heap_reserve_size += cPagesPerHeap * GetOsPageSize(); - resolve_heap_reserve_size += cPagesPerHeap * GetOsPageSize(); - resolve_heap_reserve_size += cPagesRemainder * GetOsPageSize(); + cache_entry_heap_reserve_size += (cPagesPerHeap + cPagesRemainder) * GetOsPageSize(); } CONSISTENCY_CHECK((indcell_heap_reserve_size + - cache_entry_heap_reserve_size + - lookup_heap_reserve_size + - dispatch_heap_reserve_size + - resolve_heap_reserve_size + - vtable_heap_reserve_size) == + cache_entry_heap_reserve_size)== dwTotalReserveMemSize); } @@ -655,29 +593,9 @@ void VirtualCallStubManager::Init(BaseDomain *pDomain, LoaderAllocator *pLoaderA cache_entry_heap_reserve_size = GetOsPageSize(); cache_entry_heap_commit_size = GetOsPageSize(); - lookup_heap_reserve_size = GetOsPageSize(); - lookup_heap_commit_size = GetOsPageSize(); - - dispatch_heap_reserve_size = GetOsPageSize(); - dispatch_heap_commit_size = GetOsPageSize(); - - resolve_heap_reserve_size = GetOsPageSize(); - resolve_heap_commit_size = GetOsPageSize(); - - // Heap for the collectible case is carefully tuned to sum up to 16 pages. Today, we only use the - // vtable jump stubs in the R2R scenario, which is unlikely to be loaded in the collectible context, - // so we'll keep the heap numbers at zero for now. If we ever use vtable stubs in the collectible - // scenario, we'll just allocate the memory on demand. - vtable_heap_reserve_size = 0; - vtable_heap_commit_size = 0; - #ifdef _DEBUG DWORD dwTotalReserveMemSizeCalc = indcell_heap_reserve_size + - cache_entry_heap_reserve_size + - lookup_heap_reserve_size + - dispatch_heap_reserve_size + - resolve_heap_reserve_size + - vtable_heap_reserve_size; + cache_entry_heap_reserve_size; #endif DWORD dwActualVSDSize = 0; @@ -708,36 +626,20 @@ void VirtualCallStubManager::Init(BaseDomain *pDomain, LoaderAllocator *pLoaderA initReservedMem += cache_entry_heap_reserve_size; // Warm memory, Writable, Execute, write exactly once - NewHolder lookup_heap_holder( - new LoaderHeap(lookup_heap_reserve_size, lookup_heap_commit_size, - initReservedMem, lookup_heap_reserve_size, - &lookup_rangeList, UnlockedLoaderHeap::HeapKind::Executable)); - - initReservedMem += lookup_heap_reserve_size; + NewHolder lookup_heap_holder( + new CodeFragmentHeap(pLoaderAllocator, STUB_CODE_BLOCK_VSD_LOOKUP_STUB)); // Hot memory, Writable, Execute, write exactly once - NewHolder dispatch_heap_holder( - new LoaderHeap(dispatch_heap_reserve_size, dispatch_heap_commit_size, - initReservedMem, dispatch_heap_reserve_size, - &dispatch_rangeList, UnlockedLoaderHeap::HeapKind::Executable)); - - initReservedMem += dispatch_heap_reserve_size; + NewHolder dispatch_heap_holder( + new CodeFragmentHeap(pLoaderAllocator, STUB_CODE_BLOCK_VSD_DISPATCH_STUB)); // Hot memory, Writable, Execute, write exactly once - NewHolder resolve_heap_holder( - new LoaderHeap(resolve_heap_reserve_size, resolve_heap_commit_size, - initReservedMem, resolve_heap_reserve_size, - &resolve_rangeList, UnlockedLoaderHeap::HeapKind::Executable)); - - initReservedMem += resolve_heap_reserve_size; + NewHolder resolve_heap_holder( + new CodeFragmentHeap(pLoaderAllocator, STUB_CODE_BLOCK_VSD_RESOLVE_STUB)); // Hot memory, Writable, Execute, write exactly once - NewHolder vtable_heap_holder( - new LoaderHeap(vtable_heap_reserve_size, vtable_heap_commit_size, - initReservedMem, vtable_heap_reserve_size, - &vtable_rangeList, UnlockedLoaderHeap::HeapKind::Executable)); - - initReservedMem += vtable_heap_reserve_size; + NewHolder vtable_heap_holder( + new CodeFragmentHeap(pLoaderAllocator, STUB_CODE_BLOCK_VSD_VTABLE_STUB)); // Allocate the initial counter block NewHolder m_counters_holder(new counter_block); @@ -777,11 +679,6 @@ void VirtualCallStubManager::Uninit() { WRAPPER_NO_CONTRACT; - if (m_loaderAllocator->IsCollectible()) - { - parentDomain->GetCollectibleVSDRanges()->RemoveRanges(this); - } - // Keep track of all our managers VirtualCallStubManagerManager::GlobalManager()->RemoveStubManager(this); } @@ -960,7 +857,7 @@ void VirtualCallStubManager::Reclaim() //---------------------------------------------------------------------------- /* static */ -VirtualCallStubManager *VirtualCallStubManager::FindStubManager(PCODE stubAddress, StubKind* wbStubKind, BOOL usePredictStubKind) +VirtualCallStubManager *VirtualCallStubManager::FindStubManager(PCODE stubAddress, StubCodeBlockKind* wbStubKind) { CONTRACTL { NOTHROW; @@ -968,53 +865,33 @@ VirtualCallStubManager *VirtualCallStubManager::FindStubManager(PCODE stubAddres FORBID_FAULT; } CONTRACTL_END -#ifndef DACCESS_COMPILE - VirtualCallStubManager *pCur; - StubKind kind; - - // - // See if we are managed by the current domain - // - AppDomain *pDomain = GetThread()->GetDomain(); - pCur = pDomain->GetLoaderAllocator()->GetVirtualCallStubManager(); - // For the following call stack: - // SimpleRWLock::TryEnterRead - // SimpleRWLock::EnterRead - // LockedRangeList::IsInRangeWorker - // VirtualCallStubManager::isDispatchingStub - // - kind = pCur->getStubKind(stubAddress, usePredictStubKind); - if (kind != SK_UNKNOWN) + StubCodeBlockKind unusedStubKind; + if (wbStubKind == NULL) { - if (wbStubKind) - *wbStubKind = kind; - return pCur; + wbStubKind = &unusedStubKind; } - // - // See if we are managed by a collectible loader allocator - // - if (pDomain->GetCollectibleVSDRanges()->IsInRange(stubAddress, reinterpret_cast(&pCur))) - { - _ASSERTE(pCur != NULL); - - kind = pCur->getStubKind(stubAddress, usePredictStubKind); - if (kind != SK_UNKNOWN) - { - if (wbStubKind) - *wbStubKind = kind; - return pCur; - } - } + *wbStubKind = STUB_CODE_BLOCK_UNKNOWN; - if (wbStubKind) - *wbStubKind = SK_UNKNOWN; + RangeSection * pRS = ExecutionManager::FindCodeRange(stubAddress, ExecutionManager::ScanReaderLock); + if (pRS == NULL) + return NULL; -#else // DACCESS_COMPILE - _ASSERTE(!"DACCESS Not implemented."); -#endif // DACCESS_COMPILE + StubCodeBlockKind kind = pRS->_pjit->GetStubCodeBlockKind(pRS, stubAddress); + switch (kind) + { + case STUB_CODE_BLOCK_VSD_DISPATCH_STUB: + case STUB_CODE_BLOCK_VSD_RESOLVE_STUB: + case STUB_CODE_BLOCK_VSD_LOOKUP_STUB: + case STUB_CODE_BLOCK_VSD_VTABLE_STUB: + // This is a VSD stub, using the RangeSection identify which LoaderAllocator this is from + _ASSERTE(pRS->_flags & RangeSection::RANGE_SECTION_CODEHEAP); + *wbStubKind = kind; + return pRS->_pHeapList->pLoaderAllocator->GetVirtualCallStubManager(); - return NULL; + default: + return NULL; + } } /* for use by debugger. @@ -1026,9 +903,8 @@ BOOL VirtualCallStubManager::CheckIsStub_Internal(PCODE stubStartAddress) STATIC_CONTRACT_FORBID_FAULT; SUPPORTS_DAC; - BOOL fIsOwner = isStub(stubStartAddress); - - return fIsOwner; + // Forwarded to from RangeSectionStubManager + return FALSE; } /* for use by debugger. @@ -1042,8 +918,6 @@ BOOL VirtualCallStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestinatio LOG((LF_CORDB, LL_EVERYTHING, "VirtualCallStubManager::DoTraceStub called\n")); - _ASSERTE(CheckIsStub_Internal(stubStartAddress)); - // @workaround: Well, we really need the context to figure out where we're going, so // we'll do a TRACE_MGR_PUSH so that TraceManager gets called and we can use // the provided context to figure out where we're going. @@ -1071,7 +945,6 @@ BOOL VirtualCallStubManager::TraceManager(Thread *thread, *pRetAddr = (BYTE *)StubManagerHelpers::GetReturnAddress(pContext); // Get the token from the stub - CONSISTENCY_CHECK(isStub(pStub)); DispatchToken token(GetTokenFromStub(pStub)); // Get the this object from ECX @@ -1186,8 +1059,6 @@ VTableCallHolder* VirtualCallStubManager::GenerateVTableCallStub(DWORD slot) ClrFlushInstructionCache(pHolder->stub(), pHolder->stub()->size()); - AddToCollectibleVSDRangeList(pHolder); - //incr our counters stats.stub_vtable_counter++; stats.stub_space += (UINT32)pHolder->stub()->size(); @@ -1225,7 +1096,7 @@ BYTE *VirtualCallStubManager::GenerateStubIndirection(PCODE target, BOOL fUseRec POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; - _ASSERTE(isStub(target)); + _ASSERTE(isStubStatic(target)); CrstHolder lh(&m_indCellLock); @@ -1315,13 +1186,13 @@ size_t VirtualCallStubManager::GetTokenFromStub(PCODE stub) CONTRACTL_END _ASSERTE(stub != NULL); - StubKind stubKind = SK_UNKNOWN; + StubCodeBlockKind stubKind = STUB_CODE_BLOCK_UNKNOWN; VirtualCallStubManager * pMgr = FindStubManager(stub, &stubKind); return GetTokenFromStubQuick(pMgr, stub, stubKind); } -size_t VirtualCallStubManager::GetTokenFromStubQuick(VirtualCallStubManager * pMgr, PCODE stub, StubKind kind) +size_t VirtualCallStubManager::GetTokenFromStubQuick(VirtualCallStubManager * pMgr, PCODE stub, StubCodeBlockKind kind) { CONTRACTL { @@ -1333,33 +1204,33 @@ size_t VirtualCallStubManager::GetTokenFromStubQuick(VirtualCallStubManager * pM _ASSERTE(pMgr != NULL); _ASSERTE(stub != NULL); - _ASSERTE(kind != SK_UNKNOWN); + _ASSERTE(kind != STUB_CODE_BLOCK_UNKNOWN); #ifndef DACCESS_COMPILE - if (kind == SK_DISPATCH) + if (kind == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { - _ASSERTE(pMgr->isDispatchingStub(stub)); + _ASSERTE(RangeSectionStubManager::GetStubKind(stub) == STUB_CODE_BLOCK_VSD_DISPATCH_STUB); DispatchStub * dispatchStub = (DispatchStub *) PCODEToPINSTR(stub); ResolveHolder * resolveHolder = ResolveHolder::FromFailEntry(dispatchStub->failTarget()); - _ASSERTE(pMgr->isResolvingStub(resolveHolder->stub()->resolveEntryPoint())); + _ASSERTE(isResolvingStubStatic(resolveHolder->stub()->resolveEntryPoint())); return resolveHolder->stub()->token(); } - else if (kind == SK_RESOLVE) + else if (kind == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) { - _ASSERTE(pMgr->isResolvingStub(stub)); + _ASSERTE(RangeSectionStubManager::GetStubKind(stub) == STUB_CODE_BLOCK_VSD_RESOLVE_STUB); ResolveHolder * resolveHolder = ResolveHolder::FromResolveEntry(stub); return resolveHolder->stub()->token(); } - else if (kind == SK_LOOKUP) + else if (kind == STUB_CODE_BLOCK_VSD_LOOKUP_STUB) { - _ASSERTE(pMgr->isLookupStub(stub)); + _ASSERTE(RangeSectionStubManager::GetStubKind(stub) == STUB_CODE_BLOCK_VSD_LOOKUP_STUB); LookupHolder * lookupHolder = LookupHolder::FromLookupEntry(stub); return lookupHolder->stub()->token(); } - else if (kind == SK_VTABLECALL) + else if (kind == STUB_CODE_BLOCK_VSD_VTABLE_STUB) { - _ASSERTE(pMgr->isVTableCallStub(stub)); + _ASSERTE(RangeSectionStubManager::GetStubKind(stub) == STUB_CODE_BLOCK_VSD_VTABLE_STUB); VTableCallStub * vtableStub = (VTableCallStub *)PCODEToPINSTR(stub); return vtableStub->token(); } @@ -1494,7 +1365,7 @@ PCODE VSD_ResolveWorker(TransitionBlock * pTransitionBlock, PCODE callSiteTarget = callSite.GetSiteTarget(); CONSISTENCY_CHECK(callSiteTarget != NULL); - VirtualCallStubManager::StubKind stubKind = VirtualCallStubManager::SK_UNKNOWN; + StubCodeBlockKind stubKind = STUB_CODE_BLOCK_UNKNOWN; VirtualCallStubManager *pMgr = VirtualCallStubManager::FindStubManager(callSiteTarget, &stubKind); PREFIX_ASSUME(pMgr != NULL); @@ -1556,7 +1427,7 @@ void BackPatchWorkerStaticStub(PCODE returnAddr, TADDR siteAddrForRegisterIndire PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, OBJECTREF *protectedObj, DispatchToken token, - StubKind stubKind) + StubCodeBlockKind stubKind) { CONTRACTL { THROWS; @@ -1627,7 +1498,7 @@ PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, stats.worker_call++; LOG((LF_STUBS, LL_INFO100000, "ResolveWorker from %sStub, token" FMT_ADDR "object's MT" FMT_ADDR "ind-cell" FMT_ADDR "call-site" FMT_ADDR "%s\n", - (stubKind == SK_DISPATCH) ? "Dispatch" : (stubKind == SK_RESOLVE) ? "Resolve" : (stubKind == SK_LOOKUP) ? "Lookup" : "Unknown", + (stubKind == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) ? "Dispatch" : (stubKind == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) ? "Resolve" : (stubKind == STUB_CODE_BLOCK_VSD_LOOKUP_STUB) ? "Lookup" : "Unknown", DBG_ADDR(token.To_SIZE_T()), DBG_ADDR(objectType), DBG_ADDR(pCallSite->GetIndirectCell()), DBG_ADDR(pCallSite->GetReturnAddress()), bCallToShorterLivedTarget ? "bCallToShorterLivedTarget" : "" )); @@ -1809,7 +1680,7 @@ PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, // 3. The call site is currently wired to a lookup stub. If the call site is wired // to anything else, then we're never going to use the dispatch stub so there's // no use in creating it. - if (pResolveHolder != NULL && stubKind == SK_LOOKUP) + if (pResolveHolder != NULL && stubKind == STUB_CODE_BLOCK_VSD_LOOKUP_STUB) { DispatchEntry entryD; Prober probeD(&entryD); @@ -1876,11 +1747,11 @@ PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, if (insertKind == DispatchCache::IK_NONE) { - if (stubKind == SK_DISPATCH) + if (stubKind == STUB_CODE_BLOCK_VSD_DISPATCH_STUB) { insertKind = DispatchCache::IK_DISPATCH; } - else if (stubKind == SK_RESOLVE) + else if (stubKind == STUB_CODE_BLOCK_VSD_RESOLVE_STUB) { insertKind = DispatchCache::IK_RESOLVE; } @@ -1920,7 +1791,7 @@ PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, g_resolveCache->Insert(e, insertKind); #ifdef STUB_LOGGING - if ((STUB_COLLIDE_MONO_PCT > 0) && !didInsert && (stubKind == SK_RESOLVE)) + if ((STUB_COLLIDE_MONO_PCT > 0) && !didInsert && (stubKind == STUB_CODE_BLOCK_VSD_RESOLVE_STUB)) { // If we decided not to perform the insert and we came in with a resolve stub // then we currently have a polymorphic callsite, So we flip a coin to decide @@ -1977,7 +1848,7 @@ PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, #endif // STUB_LOGGING } - if (stubKind == SK_LOOKUP) + if (stubKind == STUB_CODE_BLOCK_VSD_LOOKUP_STUB) { BackPatchSite(pCallSite, (PCODE)stub); } @@ -2465,7 +2336,7 @@ void VirtualCallStubManager::BackPatchWorker(StubCallSite* pCallSite) PCODE callSiteTarget = pCallSite->GetSiteTarget(); - if (isDispatchingStub(callSiteTarget)) + if (isDispatchingStubStatic(callSiteTarget)) { DispatchHolder * dispatchHolder = DispatchHolder::FromDispatchEntry(callSiteTarget); DispatchStub * dispatchStub = dispatchHolder->stub(); @@ -2518,12 +2389,12 @@ void VirtualCallStubManager::BackPatchSite(StubCallSite* pCallSite, PCODE stub) // prior new // lookup dispatching or resolving // dispatching resolving - if (isResolvingStub(prior)) + if (isResolvingStubStatic(prior)) return; - if(isDispatchingStub(stub)) + if(isDispatchingStubStatic(stub)) { - if(isDispatchingStub(prior)) + if(isDispatchingStubStatic(prior)) { return; } @@ -2626,8 +2497,6 @@ DispatchHolder *VirtualCallStubManager::GenerateDispatchStub(PCODE ad ClrFlushInstructionCache(holder->stub(), holder->stub()->size()); - AddToCollectibleVSDRangeList(holder); - //incr our counters stats.stub_mono_counter++; stats.stub_space += (UINT32)dispatchHolderSize; @@ -2689,8 +2558,6 @@ DispatchHolder *VirtualCallStubManager::GenerateDispatchStubLong(PCODE ClrFlushInstructionCache(holder->stub(), holder->stub()->size()); - AddToCollectibleVSDRangeList(holder); - //incr our counters stats.stub_mono_counter++; stats.stub_space += static_cast(DispatchHolder::GetHolderSize(DispatchStub::e_TYPE_LONG)); @@ -2789,8 +2656,6 @@ ResolveHolder *VirtualCallStubManager::GenerateResolveStub(PCODE addr ); ClrFlushInstructionCache(holder->stub(), holder->stub()->size()); - AddToCollectibleVSDRangeList(holder); - //incr our counters stats.stub_poly_counter++; stats.stub_space += sizeof(ResolveHolder)+sizeof(size_t); @@ -2824,8 +2689,6 @@ LookupHolder *VirtualCallStubManager::GenerateLookupStub(PCODE addrOfResolver, s lookupWriterHolder.GetRW()->Initialize(holder, addrOfResolver, dispatchToken); ClrFlushInstructionCache(holder->stub(), holder->stub()->size()); - AddToCollectibleVSDRangeList(holder); - //incr our counters stats.stub_lookup_counter++; stats.stub_space += sizeof(LookupHolder); @@ -3992,7 +3855,7 @@ MethodDesc *VirtualCallStubManagerManager::Entry2MethodDesc( if (pMT == NULL) return NULL; - VirtualCallStubManager::StubKind sk; + StubCodeBlockKind sk = STUB_CODE_BLOCK_UNKNOWN; // Find the owning manager. VirtualCallStubManager *pMgr = VirtualCallStubManager::FindStubManager(stubStartAddress, &sk); diff --git a/src/coreclr/vm/virtualcallstub.h b/src/coreclr/vm/virtualcallstub.h index 8d30330947ba9..e6d89dcf50381 100644 --- a/src/coreclr/vm/virtualcallstub.h +++ b/src/coreclr/vm/virtualcallstub.h @@ -261,11 +261,7 @@ class VirtualCallStubManager : public StubManager #ifndef DACCESS_COMPILE VirtualCallStubManager() : StubManager(), - lookup_rangeList(), - resolve_rangeList(), - dispatch_rangeList(), cache_entry_rangeList(), - vtable_rangeList(), parentDomain(NULL), m_loaderAllocator(NULL), m_initialReservedMemForHeaps(NULL), @@ -296,185 +292,59 @@ class VirtualCallStubManager : public StubManager ~VirtualCallStubManager(); #endif // !DACCESS_COMPILE - - enum StubKind { - SK_UNKNOWN, - SK_LOOKUP, // Lookup Stubs are SLOW stubs that simply call into the runtime to do all work. - SK_DISPATCH, // Dispatch Stubs have a fast check for one type otherwise jumps to runtime. Works for monomorphic sites - SK_RESOLVE, // Resolve Stubs do a hash lookup before fallling back to the runtime. Works for polymorphic sites. - SK_VTABLECALL, // Stub that jumps to a target method using vtable-based indirections. Works for non-interface calls. - SK_BREAKPOINT - }; - - // peek at the assembly code and predict which kind of a stub we have - StubKind predictStubKind(PCODE stubStartAddress); - - /* know thine own stubs. It is possible that when multiple - virtualcallstub managers are built that these may need to become - non-static, and the callers modified accordingly */ - StubKind getStubKind(PCODE stubStartAddress, BOOL usePredictStubKind = TRUE) + static BOOL isStubStatic(PCODE addr) { WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - // This method can called with stubStartAddress==NULL, e.g. when handling null reference exceptions - // caused by IP=0. Early out for this case to avoid confusing handled access violations inside predictStubKind. - if (PCODEToPINSTR(stubStartAddress) == NULL) - return SK_UNKNOWN; + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(addr); - // Rather than calling IsInRange(stubStartAddress) for each possible stub kind - // we can peek at the assembly code and predict which kind of a stub we have - StubKind predictedKind = (usePredictStubKind) ? predictStubKind(stubStartAddress) : SK_UNKNOWN; - - if (predictedKind == SK_DISPATCH) - { - if (isDispatchingStub(stubStartAddress)) - return SK_DISPATCH; - } - else if (predictedKind == SK_LOOKUP) - { - if (isLookupStub(stubStartAddress)) - return SK_LOOKUP; - } - else if (predictedKind == SK_RESOLVE) - { - if (isResolvingStub(stubStartAddress)) - return SK_RESOLVE; - } - else if (predictedKind == SK_VTABLECALL) - { - if (isVTableCallStub(stubStartAddress)) - return SK_VTABLECALL; - } - - // This is the slow case. If the predict returned SK_UNKNOWN, SK_BREAKPOINT, - // or the predict was found to be incorrect when checked against the RangeLists - // (isXXXStub), then we'll check each stub heap in sequence. - if (isDispatchingStub(stubStartAddress)) - return SK_DISPATCH; - else if (isLookupStub(stubStartAddress)) - return SK_LOOKUP; - else if (isResolvingStub(stubStartAddress)) - return SK_RESOLVE; - else if (isVTableCallStub(stubStartAddress)) - return SK_VTABLECALL; - - return SK_UNKNOWN; - } - - inline BOOL isStub(PCODE stubStartAddress) - { - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - return (getStubKind(stubStartAddress) != SK_UNKNOWN); - } - - BOOL isDispatchingStub(PCODE stubStartAddress) - { - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - return GetDispatchRangeList()->IsInRange(stubStartAddress); - } - - BOOL isResolvingStub(PCODE stubStartAddress) - { - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - return GetResolveRangeList()->IsInRange(stubStartAddress); - } - - BOOL isLookupStub(PCODE stubStartAddress) - { - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - return GetLookupRangeList()->IsInRange(stubStartAddress); - } - - BOOL isVTableCallStub(PCODE stubStartAddress) - { - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - return GetVTableCallRangeList()->IsInRange(stubStartAddress); + return sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB || + sk == STUB_CODE_BLOCK_VSD_LOOKUP_STUB || + sk == STUB_CODE_BLOCK_VSD_RESOLVE_STUB || + sk == STUB_CODE_BLOCK_VSD_VTABLE_STUB; } static BOOL isDispatchingStubStatic(PCODE addr) { WRAPPER_NO_CONTRACT; - StubKind stubKind; - FindStubManager(addr, &stubKind); - return stubKind == SK_DISPATCH; + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(addr); + + return sk == STUB_CODE_BLOCK_VSD_DISPATCH_STUB; } static BOOL isResolvingStubStatic(PCODE addr) { WRAPPER_NO_CONTRACT; - StubKind stubKind; - FindStubManager(addr, &stubKind); - return stubKind == SK_RESOLVE; + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(addr); + + return sk == STUB_CODE_BLOCK_VSD_RESOLVE_STUB; } static BOOL isLookupStubStatic(PCODE addr) { WRAPPER_NO_CONTRACT; - StubKind stubKind; - FindStubManager(addr, &stubKind); - return stubKind == SK_LOOKUP; + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(addr); + + return sk == STUB_CODE_BLOCK_VSD_LOOKUP_STUB; } static BOOL isVtableCallStubStatic(PCODE addr) { WRAPPER_NO_CONTRACT; - StubKind stubKind; - FindStubManager(addr, &stubKind); - return stubKind == SK_VTABLECALL; + StubCodeBlockKind sk = RangeSectionStubManager::GetStubKind(addr); + + return sk == STUB_CODE_BLOCK_VSD_VTABLE_STUB; } //use range lists to track the chunks of memory that are part of each heap - LockedRangeList lookup_rangeList; - LockedRangeList resolve_rangeList; - LockedRangeList dispatch_rangeList; LockedRangeList cache_entry_rangeList; - LockedRangeList vtable_rangeList; // Get dac-ized pointers to rangelist. - RangeList* GetLookupRangeList() - { - SUPPORTS_DAC; - - TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, lookup_rangeList); - return PTR_RangeList(addr); - } - RangeList* GetResolveRangeList() - { - SUPPORTS_DAC; - - TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, resolve_rangeList); - return PTR_RangeList(addr); - } - RangeList* GetDispatchRangeList() - { - SUPPORTS_DAC; - - TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, dispatch_rangeList); - return PTR_RangeList(addr); - } RangeList* GetCacheEntryRangeList() { SUPPORTS_DAC; TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, cache_entry_rangeList); return PTR_RangeList(addr); } - RangeList* GetVTableCallRangeList() - { - SUPPORTS_DAC; - TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, vtable_rangeList); - return PTR_RangeList(addr); - } private: @@ -508,17 +378,6 @@ class VirtualCallStubManager : public StubManager VTableCallHolder* GenerateVTableCallStub(DWORD slot); - template - void AddToCollectibleVSDRangeList(STUB_HOLDER *holder) - { - if (m_loaderAllocator->IsCollectible()) - { - parentDomain->GetCollectibleVSDRanges()->AddRange(reinterpret_cast(holder->stub()), - reinterpret_cast(holder->stub()) + holder->stub()->size(), - this); - } - } - // The resolve cache is static across all AppDomains ResolveCacheElem *GenerateResolveCacheElem(void *addrOfCode, void *pMTExpected, @@ -551,7 +410,7 @@ class VirtualCallStubManager : public StubManager static size_t GetTokenFromStub(PCODE stub); //This is used to get the token out of a stub and we know the stub manager and stub kind - static size_t GetTokenFromStubQuick(VirtualCallStubManager * pMgr, PCODE stub, StubKind kind); + static size_t GetTokenFromStubQuick(VirtualCallStubManager * pMgr, PCODE stub, StubCodeBlockKind kind); // General utility functions // Quick lookup in the cache. NOTHROW, GC_NOTRIGGER @@ -595,7 +454,7 @@ class VirtualCallStubManager : public StubManager static void STDCALL BackPatchWorkerStatic(PCODE returnAddr, TADDR siteAddrForRegisterIndirect); public: - PCODE ResolveWorker(StubCallSite* pCallSite, OBJECTREF *protectedObj, DispatchToken token, StubKind stubKind); + PCODE ResolveWorker(StubCallSite* pCallSite, OBJECTREF *protectedObj, DispatchToken token, StubCodeBlockKind stubKind); void BackPatchWorker(StubCallSite* pCallSite); //Change the callsite to point to stub @@ -617,12 +476,6 @@ class VirtualCallStubManager : public StubManager retval+=indcell_heap->GetSize(); if(cache_entry_heap) retval+=cache_entry_heap->GetSize(); - if(lookup_heap) - retval+=lookup_heap->GetSize(); - if(dispatch_heap) - retval+=dispatch_heap->GetSize(); - if(resolve_heap) - retval+=resolve_heap->GetSize(); return retval; }; @@ -720,10 +573,10 @@ class VirtualCallStubManager : public StubManager PTR_LoaderHeap indcell_heap; // indirection cells go here PTR_LoaderHeap cache_entry_heap; // resolve cache elem entries go here - PTR_LoaderHeap lookup_heap; // lookup stubs go here - PTR_LoaderHeap dispatch_heap; // dispatch stubs go here - PTR_LoaderHeap resolve_heap; // resolve stubs go here - PTR_LoaderHeap vtable_heap; // vtable-based jump stubs go here + PTR_CodeFragmentHeap lookup_heap; // lookup stubs go here + PTR_CodeFragmentHeap dispatch_heap; // dispatch stubs go here + PTR_CodeFragmentHeap resolve_heap; // resolve stubs go here + PTR_CodeFragmentHeap vtable_heap; // vtable-based jump stubs go here #ifdef TARGET_AMD64 // When we layout the stub heaps, we put them close together in a sequential order @@ -770,8 +623,7 @@ class VirtualCallStubManager : public StubManager public: // Given a stub address, find the VCSManager that owns it. static VirtualCallStubManager *FindStubManager(PCODE addr, - StubKind* wbStubKind = NULL, - BOOL usePredictStubKind = TRUE); + StubCodeBlockKind* wbStubKind = NULL); #ifndef DACCESS_COMPILE // insert a linked list of indirection cells at the beginning of m_RecycledIndCellList @@ -818,19 +670,7 @@ class VirtualCallStubManager : public StubManager WRAPPER_NO_CONTRACT; CONSISTENCY_CHECK(isStub(addr)); - if (isLookupStub(addr)) - { - return W("VSD_LookupStub"); - } - else if (isDispatchingStub(addr)) - { - return W("VSD_DispatchStub"); - } - else - { - CONSISTENCY_CHECK(isResolvingStub(addr)); - return W("VSD_ResolveStub"); - } + return W("Unexpected. RangeSectionStubManager should report the name"); } #endif };