From caab7ad6ab35cbfe456f0fecd354663e0dd569d9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Aug 2026 20:49:44 +0000 Subject: [PATCH 01/17] Unify StubLinker stub memory management with JIT code allocator Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/debug/daccess/request.cpp | 5 ++- src/coreclr/vm/appdomain.hpp | 1 - src/coreclr/vm/appdomain.inl | 7 ---- src/coreclr/vm/assembly.cpp | 7 ---- src/coreclr/vm/assembly.hpp | 2 -- src/coreclr/vm/class.h | 2 +- src/coreclr/vm/codeman.h | 6 ++++ src/coreclr/vm/comdelegate.cpp | 6 ++-- src/coreclr/vm/comdelegate.h | 2 +- .../vm/datadescriptor/datadescriptor.inc | 1 - src/coreclr/vm/loaderallocator.cpp | 32 ++----------------- src/coreclr/vm/loaderallocator.hpp | 10 ------ src/coreclr/vm/prestub.cpp | 8 ++--- src/coreclr/vm/stubcache.cpp | 12 ++----- src/coreclr/vm/stubcache.h | 4 +-- src/coreclr/vm/stublink.cpp | 26 +++++++-------- src/coreclr/vm/stublink.h | 7 ++-- src/coreclr/vm/stubmgr.cpp | 13 ++++++-- src/coreclr/vm/stubmgr.h | 14 +------- 19 files changed, 52 insertions(+), 113 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 7e5fb6b3d93476..6d89324756ad6c 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -2453,7 +2453,7 @@ ClrDataAccess::GetAppDomainData(CLRDATA_ADDRESS addr, struct DacpAppDomainData * PTR_LoaderAllocator pLoaderAllocator = SystemDomain::GetGlobalLoaderAllocator(); appdomainData->pHighFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetHighFrequencyHeap()); appdomainData->pLowFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetLowFrequencyHeap()); - appdomainData->pStubHeap = HOST_CDADDR(pLoaderAllocator->GetStubHeap()); + appdomainData->pStubHeap = HOST_CDADDR(pLoaderAllocator->GetExecutableHeap()); appdomainData->appDomainStage = STAGE_OPEN; appdomainData->dwId = DefaultADID; @@ -3681,7 +3681,7 @@ static const char *LoaderAllocatorLoaderHeapNames[] = "LowFrequencyHeap", "HighFrequencyHeap", "StaticsHeap", - "StubHeap", + "ExecutableStubHeap", "ExecutableHeap", "FixupPrecodeHeap", "NewStubPrecodeHeap", @@ -3721,7 +3721,6 @@ HRESULT ClrDataAccess::GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocatorAd pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetLowFrequencyHeap()); pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetHighFrequencyHeap()); pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetStaticsHeap()); - pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetStubHeap()); pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetExecutableHeap()); pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetFixupPrecodeHeap()); pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetNewStubPrecodeHeap()); diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 655f295fa7055f..a0f28899e54cc0 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1297,7 +1297,6 @@ class AppDomain final } #endif // FEATURE_COMINTEROP - PTR_LoaderHeap GetStubHeap(); PTR_LoaderHeap GetLowFrequencyHeap(); PTR_LoaderHeap GetHighFrequencyHeap(); diff --git a/src/coreclr/vm/appdomain.inl b/src/coreclr/vm/appdomain.inl index 899bc9a2153922..cdb8ec6127de92 100644 --- a/src/coreclr/vm/appdomain.inl +++ b/src/coreclr/vm/appdomain.inl @@ -54,11 +54,4 @@ inline PTR_LoaderHeap AppDomain::GetLowFrequencyHeap() return GetLoaderAllocator()->GetLowFrequencyHeap(); } -inline PTR_LoaderHeap AppDomain::GetStubHeap() -{ - WRAPPER_NO_CONTRACT; - return GetLoaderAllocator()->GetStubHeap(); -} - #endif // _APPDOMAIN_I - diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index c5e4f3d78961df..bc6ef3b21f7e3e 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -557,13 +557,6 @@ PTR_LoaderHeap Assembly::GetHighFrequencyHeap() } -PTR_LoaderHeap Assembly::GetStubHeap() -{ - WRAPPER_NO_CONTRACT; - - return GetLoaderAllocator()->GetStubHeap(); -} - Module *Assembly::FindModuleByExportedType(mdExportedType mdType, Loader::LoadFlag loadFlag, mdTypeDef mdNested, diff --git a/src/coreclr/vm/assembly.hpp b/src/coreclr/vm/assembly.hpp index 177972e82294a9..15f4617cc5dce7 100644 --- a/src/coreclr/vm/assembly.hpp +++ b/src/coreclr/vm/assembly.hpp @@ -249,8 +249,6 @@ class Assembly PTR_LoaderHeap GetLowFrequencyHeap(); PTR_LoaderHeap GetHighFrequencyHeap(); - PTR_LoaderHeap GetStubHeap(); - PTR_Module GetModule() { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 165ccdaac5c289..7afd07b5bc3bab 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -1922,7 +1922,7 @@ class DelegateEEClass : public EEClass } // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer - LoaderHeap *GetStubHeap(); + LoaderAllocator *GetStubHeap(); #endif // !DACCESS_COMPILE }; diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 787b448aa27922..6a69bfc7536698 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -102,6 +102,8 @@ enum StubCodeBlockKind : int STUB_CODE_BLOCK_DYNAMICHELPER = 3, STUB_CODE_BLOCK_STUBPRECODE = 4, STUB_CODE_BLOCK_FIXUPPRECODE = 5, + STUB_CODE_BLOCK_STUBLINK = 0xB, + STUB_CODE_BLOCK_SHUFFLE_THUNK = 0xC, #ifdef FEATURE_VIRTUAL_STUB_DISPATCH STUB_CODE_BLOCK_VSD_DISPATCH_STUB = 6, STUB_CODE_BLOCK_VSD_RESOLVE_STUB = 7, @@ -129,6 +131,10 @@ inline const char *GetStubCodeBlockKindString(StubCodeBlockKind kind) case STUB_CODE_BLOCK_CALLCOUNTING: return "CallCountingStub"; #endif + case STUB_CODE_BLOCK_STUBLINK: + return "StubLink"; + case STUB_CODE_BLOCK_SHUFFLE_THUNK: + return "ShuffleThunk"; case STUB_CODE_BLOCK_DYNAMICHELPER: return "MethodCallThunk"; case STUB_CODE_BLOCK_FIXUPPRECODE: diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 95e4edf4dd9779..826884119a29d7 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -783,7 +783,7 @@ void COMDelegate::Init() } CONTRACTL_END; #if defined(FEATURE_PORTABLE_SHUFFLE_THUNKS) || defined(TARGET_X86) - s_pShuffleThunkCache = new ShuffleThunkCache(SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap()); + s_pShuffleThunkCache = new ShuffleThunkCache(SystemDomain::GetGlobalLoaderAllocator()); #endif } @@ -821,9 +821,9 @@ CLRToCOMCallInfo * COMDelegate::PopulateCLRToCOMCallInfo(MethodTable * pDelMT) #endif // FEATURE_COMINTEROP // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer -LoaderHeap *DelegateEEClass::GetStubHeap() +LoaderAllocator *DelegateEEClass::GetStubHeap() { - return GetInvokeMethod()->GetLoaderAllocator()->GetStubHeap(); + return GetInvokeMethod()->GetLoaderAllocator(); } static Stub* CreateILDelegateShuffleThunk(MethodDesc* pDelegateMD, bool callTargetWithThis) diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index 263027c2bbc789..4bc2679229e00b 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -175,7 +175,7 @@ struct ShuffleEntry class ShuffleThunkCache : public StubCacheBase { public: - ShuffleThunkCache(LoaderHeap* heap) : StubCacheBase(heap) + ShuffleThunkCache(LoaderAllocator* pLoaderAllocator) : StubCacheBase(pLoaderAllocator) { } private: diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 3bb39cac9bacb3..a1bb2214a1194a 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -403,7 +403,6 @@ CDAC_TYPE_FIELD(LoaderAllocator, T_UINT32, ReferenceCount, cdac_data::HighFrequencyHeap) CDAC_TYPE_FIELD(LoaderAllocator, T_POINTER, LowFrequencyHeap, cdac_data::LowFrequencyHeap) CDAC_TYPE_FIELD(LoaderAllocator, T_POINTER, StaticsHeap, cdac_data::StaticsHeap) -CDAC_TYPE_FIELD(LoaderAllocator, T_POINTER, StubHeap, cdac_data::StubHeap) CDAC_TYPE_FIELD(LoaderAllocator, T_POINTER, ExecutableHeap, cdac_data::ExecutableHeap) #ifdef HAS_FIXUP_PRECODE CDAC_TYPE_FIELD(LoaderAllocator, T_POINTER, FixupPrecodeHeap, cdac_data::FixupPrecodeHeap) diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 04fbbe48029808..e427a3d7ab45de 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -23,8 +23,6 @@ //#define ENABLE_LOG_LOADER_ALLOCATOR_CLEANUP 1 -#define STUBMANAGER_RANGELIST(stubManager) (stubManager::g_pManager->GetRangeList()) - UINT64 LoaderAllocator::cLoaderAllocatorsCreated = 1; LoaderAllocator::LoaderAllocator(bool collectible) : @@ -40,7 +38,6 @@ LoaderAllocator::LoaderAllocator(bool collectible) : m_InitialReservedMemForLoaderHeaps = NULL; m_pLowFrequencyHeap = NULL; m_pHighFrequencyHeap = NULL; - m_pStubHeap = NULL; m_pExecutableHeap = NULL; #ifdef FEATURE_READYTORUN #ifndef FEATURE_STUBPRECODE_DYNAMIC_HELPERS @@ -1122,7 +1119,6 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) DWORD dwLowFrequencyHeapReserveSize; DWORD dwHighFrequencyHeapReserveSize; DWORD dwStaticsHeapReserveSize; - DWORD dwStubHeapReserveSize; DWORD dwExecutableHeapReserveSize; DWORD dwCodeHeapReserveSize; DWORD dwVSDHeapReserveSize; @@ -1133,7 +1129,6 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) { dwLowFrequencyHeapReserveSize = COLLECTIBLE_LOW_FREQUENCY_HEAP_SIZE; dwHighFrequencyHeapReserveSize = COLLECTIBLE_HIGH_FREQUENCY_HEAP_SIZE; - dwStubHeapReserveSize = COLLECTIBLE_STUB_HEAP_SIZE; dwCodeHeapReserveSize = COLLECTIBLE_CODEHEAP_SIZE; dwVSDHeapReserveSize = COLLECTIBLE_VIRTUALSTUBDISPATCH_HEAP_SPACE; dwStaticsHeapReserveSize = 0; @@ -1142,7 +1137,6 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) { dwLowFrequencyHeapReserveSize = LOW_FREQUENCY_HEAP_RESERVE_SIZE; dwHighFrequencyHeapReserveSize = HIGH_FREQUENCY_HEAP_RESERVE_SIZE; - dwStubHeapReserveSize = STUB_HEAP_RESERVE_SIZE; dwStaticsHeapReserveSize = STATIC_FIELD_HEAP_RESERVE_SIZE; // Non-collectible assemblies do not reserve space for these heaps. @@ -1163,7 +1157,6 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) DWORD dwTotalReserveMemSize = dwLowFrequencyHeapReserveSize + dwHighFrequencyHeapReserveSize + dwStaticsHeapReserveSize - + dwStubHeapReserveSize + dwCodeHeapReserveSize + dwVSDHeapReserveSize + dwExecutableHeapReserveSize; @@ -1238,15 +1231,6 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) m_pStaticsHeap = m_pHighFrequencyHeap; } - m_pStubHeap = new (&m_StubHeapInstance) LoaderHeap(STUB_HEAP_RESERVE_SIZE, - STUB_HEAP_COMMIT_SIZE, - initReservedMem, - dwStubHeapReserveSize, - STUBMANAGER_RANGELIST(StubLinkStubManager), - LoaderHeapImplementationKind::Executable); - - initReservedMem += dwStubHeapReserveSize; - #ifndef FEATURE_PORTABLE_ENTRYPOINTS m_pNewStubPrecodeHeap = new (&m_NewStubPrecodeHeapInstance) InterleavedLoaderHeap( &m_stubPrecodeRangeList, @@ -1452,12 +1436,6 @@ void LoaderAllocator::Terminate() m_pHighFrequencyHeap = NULL; } - if (m_pStubHeap != NULL) - { - m_pStubHeap->~LoaderHeap(); - m_pStubHeap = NULL; - } - #ifdef HAS_FIXUP_PRECODE if (m_pFixupPrecodeHeap != NULL) { @@ -1544,10 +1522,6 @@ void LoaderAllocator::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) { m_pStaticsHeap->EnumMemoryRegions(flags); } - if (m_pStubHeap.IsValid()) - { - m_pStubHeap->EnumMemoryRegions(flags); - } if (m_pExecutableHeap.IsValid()) { m_pExecutableHeap->EnumMemoryRegions(flags); @@ -1590,8 +1564,6 @@ SIZE_T LoaderAllocator::EstimateSize() retval+=m_pStaticsHeap->GetSize(); if(m_pLowFrequencyHeap) retval+=m_pLowFrequencyHeap->GetSize(); - if(m_pStubHeap) - retval+=m_pStubHeap->GetSize(); if(m_pStringLiteralMap) retval+=m_pStringLiteralMap->GetSize(); if(m_pVirtualCallStubManager) @@ -1791,11 +1763,11 @@ void AssemblyLoaderAllocator::Init() #ifndef FEATURE_PORTABLE_ENTRYPOINTS if (IsCollectible()) { - // TODO: the ShuffleThunkCache should really be using the m_pStubHeap, however the unloadability support + // TODO: the ShuffleThunkCache should really be using collectible stub-linked executable memory, however the unloadability support // doesn't track the stubs or the related delegate classes and so we get crashes when a stub is used after // the AssemblyLoaderAllocator is gone (the stub memory is unmapped). // https://github.com/dotnet/runtime/issues/55697 tracks this issue. - m_pShuffleThunkCache = new ShuffleThunkCache(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()); + m_pShuffleThunkCache = new ShuffleThunkCache(SystemDomain::GetGlobalLoaderAllocator()); } #endif // !FEATURE_PORTABLE_ENTRYPOINTS } diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 525eb06d5ddb8f..0ddffcd79ec57f 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -320,7 +320,6 @@ class LoaderAllocator BYTE * m_InitialReservedMemForLoaderHeaps; BYTE m_LowFreqHeapInstance[sizeof(LoaderHeap)]; BYTE m_HighFreqHeapInstance[sizeof(LoaderHeap)]; - BYTE m_StubHeapInstance[sizeof(LoaderHeap)]; #ifdef HAS_FIXUP_PRECODE BYTE m_FixupPrecodeHeapInstance[sizeof(InterleavedLoaderHeap)]; #endif // HAS_FIXUP_PRECODE @@ -336,7 +335,6 @@ class LoaderAllocator PTR_LoaderHeap m_pLowFrequencyHeap; PTR_LoaderHeap m_pHighFrequencyHeap; PTR_LoaderHeap m_pStaticsHeap; - PTR_LoaderHeap m_pStubHeap; // stubs for PInvoke, remoting, etc PTR_LoaderHeap m_pExecutableHeap; #ifdef FEATURE_READYTORUN #ifdef FEATURE_STUBPRECODE_DYNAMIC_HELPERS @@ -657,12 +655,6 @@ class LoaderAllocator return m_pStaticsHeap; } - PTR_LoaderHeap GetStubHeap() - { - LIMITED_METHOD_CONTRACT; - return m_pStubHeap; - } - #ifndef FEATURE_PORTABLE_ENTRYPOINTS PTR_InterleavedLoaderHeap GetNewStubPrecodeHeap() { @@ -950,7 +942,6 @@ struct cdac_data static constexpr size_t HighFrequencyHeap = offsetof(LoaderAllocator, m_pHighFrequencyHeap); static constexpr size_t LowFrequencyHeap = offsetof(LoaderAllocator, m_pLowFrequencyHeap); static constexpr size_t StaticsHeap = offsetof(LoaderAllocator, m_pStaticsHeap); - static constexpr size_t StubHeap = offsetof(LoaderAllocator, m_pStubHeap); static constexpr size_t ExecutableHeap = offsetof(LoaderAllocator, m_pExecutableHeap); #ifdef HAS_FIXUP_PRECODE static constexpr size_t FixupPrecodeHeap = offsetof(LoaderAllocator, m_pFixupPrecodeHeap); @@ -1115,4 +1106,3 @@ class LOADERHANDLEHolder #include "loaderallocator.inl" #endif // __LoaderAllocator_h__ - diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 31231bc4d4b0ab..f37bea0be0e23d 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -1743,13 +1743,13 @@ Stub * MakeUnboxingStubWorker(MethodDesc *pMD) sl.EmitComputedInstantiatingMethodStub(pUnboxedMD, &portableShuffle[0], NULL); - return sl.Link(pMD->GetLoaderAllocator()->GetStubHeap(), NEWSTUB_FL_INSTANTIATING_METHOD, "UnboxingStub"); + return sl.Link(pMD->GetLoaderAllocator(), NEWSTUB_FL_INSTANTIATING_METHOD, "UnboxingStub"); } #elif defined(TARGET_X86) CPUSTUBLINKER sl; if (sl.EmitUnboxMethodStub(pUnboxedMD)) { - return sl.Link(pMD->GetLoaderAllocator()->GetStubHeap(), NEWSTUB_FL_NONE, "UnboxingStub"); + return sl.Link(pMD->GetLoaderAllocator(), NEWSTUB_FL_NONE, "UnboxingStub"); } #endif // FEATURE_PORTABLE_SHUFFLE_THUNKS || TARGET_X86 @@ -1798,13 +1798,13 @@ Stub * MakeInstantiatingStubWorker(MethodDesc *pMD) _ASSERTE(pSharedMD != NULL && pSharedMD != pMD); sl.EmitComputedInstantiatingMethodStub(pSharedMD, &portableShuffle[0], extraArg); - return sl.Link(pMD->GetLoaderAllocator()->GetStubHeap(), NEWSTUB_FL_INSTANTIATING_METHOD, "InstantiatingStub"); + return sl.Link(pMD->GetLoaderAllocator(), NEWSTUB_FL_INSTANTIATING_METHOD, "InstantiatingStub"); } #elif defined(TARGET_X86) CPUSTUBLINKER sl; if (sl.EmitInstantiatingMethodStub(pSharedMD, extraArg)) { - return sl.Link(pMD->GetLoaderAllocator()->GetStubHeap(), NEWSTUB_FL_NONE, "InstantiatingStub"); + return sl.Link(pMD->GetLoaderAllocator(), NEWSTUB_FL_NONE, "InstantiatingStub"); } #endif // FEATURE_PORTABLE_SHUFFLE_THUNKS || TARGET_X86 diff --git a/src/coreclr/vm/stubcache.cpp b/src/coreclr/vm/stubcache.cpp index 265058e2e6ddef..de15b6ef6f3f48 100644 --- a/src/coreclr/vm/stubcache.cpp +++ b/src/coreclr/vm/stubcache.cpp @@ -18,7 +18,7 @@ //--------------------------------------------------------- // Constructor //--------------------------------------------------------- -StubCacheBase::StubCacheBase(LoaderHeap *pHeap) : +StubCacheBase::StubCacheBase(LoaderAllocator *pLoaderAllocator) : CClosedHashBase( #ifdef _DEBUG 3, @@ -30,15 +30,9 @@ StubCacheBase::StubCacheBase(LoaderHeap *pHeap) : FALSE ), m_crst(CrstStubCache), - m_heap(pHeap) + m_pLoaderAllocator(pLoaderAllocator) { WRAPPER_NO_CONTRACT; - -#ifdef TARGET_UNIX - if (m_heap == NULL) - m_heap = SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap(); -#endif - } @@ -112,7 +106,7 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) // and link up the stub. CodeLabel *plabel = psl->EmitNewCodeLabel(); psl->EmitBytes(pRawStub, Length(pRawStub)); - pstub = psl->Link(m_heap, linkFlags, stubType); + pstub = psl->Link(m_pLoaderAllocator, linkFlags, stubType); UINT32 offset = psl->GetLabelOffset(plabel); if (offset > 0xffff) diff --git a/src/coreclr/vm/stubcache.h b/src/coreclr/vm/stubcache.h index 0eeebdfb6c0b89..24b38b8f113a7e 100644 --- a/src/coreclr/vm/stubcache.h +++ b/src/coreclr/vm/stubcache.h @@ -44,7 +44,7 @@ class StubCacheBase : private CClosedHashBase //--------------------------------------------------------- // Constructor //--------------------------------------------------------- - StubCacheBase(LoaderHeap *heap = 0); + StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL); //--------------------------------------------------------- // Destructor @@ -127,7 +127,7 @@ class StubCacheBase : private CClosedHashBase private: Crst m_crst; - LoaderHeap* m_heap; + LoaderAllocator* m_pLoaderAllocator; }; diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index 36450b365f7bea..c2778b679d80e2 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -544,22 +544,21 @@ static BOOL LabelCanReach(LabelRef *pLabelRef) // // Throws exception on failure. //--------------------------------------------------------------- -Stub *StubLinker::Link(LoaderHeap *pHeap, DWORD flags, const char *stubType) +Stub *StubLinker::Link(LoaderAllocator *pLoaderAllocator, DWORD flags, const char *stubType) { STANDARD_VM_CONTRACT; int globalsize = 0; int size = CalculateSize(&globalsize); - _ASSERTE(!pHeap || pHeap->IsExecutable()); - StubHolder pStub{ Stub::NewStub( - pHeap, + pLoaderAllocator, + ((flags & NEWSTUB_FL_SHUFFLE_THUNK) != 0) ? STUB_CODE_BLOCK_SHUFFLE_THUNK : STUB_CODE_BLOCK_STUBLINK, size, flags) }; ASSERT(pStub != NULL); - EmitStub(pStub, globalsize, size, pHeap); + EmitStub(pStub, globalsize, size); PerfMap::LogStubs(__FUNCTION__, stubType, pStub->GetEntryPoint(), pStub->GetNumCodeBytes(), PerfMapStubType::Individual); @@ -698,7 +697,7 @@ int StubLinker::CalculateSize(int* pGlobalSize) return globalsize + datasize; } -void StubLinker::EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap) +void StubLinker::EmitStub(Stub* pStub, int globalsize, int totalSize) { STANDARD_VM_CONTRACT; @@ -888,7 +887,7 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) } CONTRACTL_END; - Stub* pStub = NewStub(NULL, 0, flags | NEWSTUB_FL_EXTERNAL); + Stub* pStub = NewStub(NULL, STUB_CODE_BLOCK_UNKNOWN, 0, flags | NEWSTUB_FL_EXTERNAL); // Passing NEWSTUB_FL_EXTERNAL requests the stub struct be // expanded in size by a single pointer. Insert the code point at this @@ -902,7 +901,8 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) // Stub allocation done here. //------------------------------------------------------------------- /*static*/ Stub* Stub::NewStub( - LoaderHeap *pHeap, + LoaderAllocator *pLoaderAllocator, + StubCodeBlockKind kind, UINT numCodeBytes, DWORD flags) { @@ -925,7 +925,7 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) if (flags & NEWSTUB_FL_EXTERNAL) { - _ASSERTE(pHeap == NULL); + _ASSERTE(pLoaderAllocator == NULL); _ASSERTE(numCodeBytes == 0); size += sizeof(PTR_PCODE); } @@ -941,14 +941,13 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) size_t totalSize = size.Value(); BYTE *pBlock; - if (pHeap == NULL) + if (pLoaderAllocator == NULL) { pBlock = new BYTE[totalSize]; } else { - TaggedMemAllocPtr ptr = pHeap->AllocAlignedMem(totalSize, CODE_SIZE_ALIGN); - pBlock = (BYTE*)(void*)ptr; + pBlock = reinterpret_cast(ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock(totalSize, CODE_SIZE_ALIGN, pLoaderAllocator, kind)); flags |= NEWSTUB_FL_LOADERHEAP; } @@ -957,7 +956,7 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) Stub* pStubRW; ExecutableWriterHolderNoLog stubWriterHolder; - if (pHeap == NULL) + if (pLoaderAllocator == NULL) { pStubRW = pStubRX; } @@ -1015,4 +1014,3 @@ void Stub::SetupStub(int numCodeBytes, DWORD flags) } #endif // #ifndef DACCESS_COMPILE - diff --git a/src/coreclr/vm/stublink.h b/src/coreclr/vm/stublink.h index 334ae6d43d7ee5..91cd7eda8e55f8 100644 --- a/src/coreclr/vm/stublink.h +++ b/src/coreclr/vm/stublink.h @@ -53,6 +53,7 @@ #include "crst.h" #include "util.hpp" #include "eecontract.h" +enum StubCodeBlockKind : int; //------------------------------------------------------------------------- // Forward refs @@ -177,7 +178,7 @@ class StubLinker // // Throws exception on failure. //--------------------------------------------------------------- - Stub *Link(LoaderHeap *heap, DWORD flags, const char *stubType); + Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, const char *stubType); private: CodeElement *m_pCodeElements; // stored in *reverse* order @@ -213,7 +214,7 @@ class StubLinker // Writes out the code element into memory following the // stub object. - void EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap); + void EmitStub(Stub* pStub, int globalsize, int totalSize); CodeRun *GetLastCodeRunIfAny(); }; @@ -489,7 +490,7 @@ class Stub //------------------------------------------------------------------- // This creates stubs. //------------------------------------------------------------------- - static Stub* NewStub(LoaderHeap *pLoaderHeap, UINT numCodeBytes, + static Stub* NewStub(LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind, UINT numCodeBytes, DWORD flags = NEWSTUB_FL_NONE); static Stub* NewStub(PTR_VOID pCode, DWORD flags = NEWSTUB_FL_NONE); diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 1c36ecffbc3d36..76f5ea3046e9d0 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1259,7 +1259,8 @@ BOOL StubLinkStubManager::CheckIsStub_Internal(PCODE stubStartAddress) { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; - return GetRangeList()->IsInRange(stubStartAddress) ? TRUE : FALSE; + StubCodeBlockKind kind = RangeSectionStubManager::GetStubKind(stubStartAddress); + return (kind == STUB_CODE_BLOCK_STUBLINK) || (kind == STUB_CODE_BLOCK_SHUFFLE_THUNK); } BOOL StubLinkStubManager::DoTraceStub(PCODE stubStartAddress, @@ -1437,6 +1438,8 @@ BOOL RangeSectionStubManager::CheckIsStub_Internal(PCODE stubStartAddress) { case STUB_CODE_BLOCK_JUMPSTUB: case STUB_CODE_BLOCK_METHOD_CALL_THUNK: + case STUB_CODE_BLOCK_STUBLINK: + case STUB_CODE_BLOCK_SHUFFLE_THUNK: #ifdef FEATURE_TIERED_COMPILATION case STUB_CODE_BLOCK_CALLCOUNTING: #endif // FEATURE_TIERED_COMPILATION @@ -1476,6 +1479,9 @@ BOOL RangeSectionStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestinati return TRUE; } #endif // FEATURE_DYNAMIC_CODE_COMPILED + case STUB_CODE_BLOCK_STUBLINK: + case STUB_CODE_BLOCK_SHUFFLE_THUNK: + return StubLinkStubManager::g_pManager->DoTraceStub(stubStartAddress, trace); #ifdef FEATURE_TIERED_COMPILATION case STUB_CODE_BLOCK_CALLCOUNTING: { @@ -1518,6 +1524,10 @@ LPCWSTR RangeSectionStubManager::GetStubManagerName(PCODE addr) return W("JumpStub"); case STUB_CODE_BLOCK_METHOD_CALL_THUNK: return W("MethodCallThunk"); + case STUB_CODE_BLOCK_STUBLINK: + return W("StubLinkStub"); + case STUB_CODE_BLOCK_SHUFFLE_THUNK: + return W("ShuffleThunk"); #ifdef FEATURE_TIERED_COMPILATION case STUB_CODE_BLOCK_CALLCOUNTING: return W("CallCountingStub"); @@ -2252,7 +2262,6 @@ StubLinkStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) WRAPPER_NO_CONTRACT; DAC_ENUM_VTHIS(); EMEM_OUT(("MEM: %p StubLinkStubManager\n", dac_cast(this))); - GetRangeList()->EnumMemoryRegions(flags); } void diff --git a/src/coreclr/vm/stubmgr.h b/src/coreclr/vm/stubmgr.h index da04e1f11dbe63..8418ca5f1e7681 100644 --- a/src/coreclr/vm/stubmgr.h +++ b/src/coreclr/vm/stubmgr.h @@ -469,22 +469,10 @@ class StubLinkStubManager : public StubManager #endif // DACCESS_COMPILE #if !defined(DACCESS_COMPILE) - StubLinkStubManager() : StubManager(), m_rangeList() {LIMITED_METHOD_CONTRACT;} + StubLinkStubManager() : StubManager() {LIMITED_METHOD_CONTRACT;} ~StubLinkStubManager() {WRAPPER_NO_CONTRACT;} #endif // DACCESS_COMPILE - protected: - LockedRangeList m_rangeList; - public: - // Get dac-ized pointer to rangelist. - PTR_RangeList GetRangeList() - { - SUPPORTS_DAC; - - TADDR addr = PTR_HOST_MEMBER_TADDR(StubLinkStubManager, this, m_rangeList); - return PTR_RangeList(addr); - } - virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress); virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace); From 761fa633ce62010a1d1e00cb250ff4e0c38550ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Aug 2026 21:27:07 +0000 Subject: [PATCH 02/17] Remove COLLECTIBLE_STUB_HEAP_SIZE, rename STUB_HEAP_* to EXECUTABLE_HEAP_* Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/appdomain.hpp | 4 ++-- src/coreclr/vm/loaderallocator.cpp | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index a0f28899e54cc0..bfec31617debff 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -208,8 +208,8 @@ FORCEINLINE void PinnedHeapHandleBlockHolder__StaticFree(PinnedHeapHandleBlockH #define HIGH_FREQUENCY_HEAP_RESERVE_SIZE (8 * minipal_getpagesize()) #define HIGH_FREQUENCY_HEAP_COMMIT_SIZE (1 * minipal_getpagesize()) -#define STUB_HEAP_RESERVE_SIZE (3 * minipal_getpagesize()) -#define STUB_HEAP_COMMIT_SIZE (1 * minipal_getpagesize()) +#define EXECUTABLE_HEAP_RESERVE_SIZE (3 * minipal_getpagesize()) +#define EXECUTABLE_HEAP_COMMIT_SIZE (1 * minipal_getpagesize()) #define STATIC_FIELD_HEAP_RESERVE_SIZE (2 * minipal_getpagesize()) #define STATIC_FIELD_HEAP_COMMIT_SIZE (1 * minipal_getpagesize()) diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index e427a3d7ab45de..96f59fc2cbde2f 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -1095,7 +1095,6 @@ void LoaderAllocator::ActivateManagedTracking() // This is carefully tuned to sum up to 16 pages to reduce waste. #define COLLECTIBLE_LOW_FREQUENCY_HEAP_SIZE 0 #define COLLECTIBLE_HIGH_FREQUENCY_HEAP_SIZE (3 * minipal_getpagesize()) -#define COLLECTIBLE_STUB_HEAP_SIZE minipal_getpagesize() #define COLLECTIBLE_CODEHEAP_SIZE (10 * minipal_getpagesize()) #define COLLECTIBLE_VIRTUALSTUBDISPATCH_HEAP_SPACE (2 * minipal_getpagesize()) @@ -1198,8 +1197,8 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) { _ASSERTE(!IsCollectible()); - m_pExecutableHeap = new (pExecutableHeapMemory) LoaderHeap(STUB_HEAP_RESERVE_SIZE, - STUB_HEAP_COMMIT_SIZE, + m_pExecutableHeap = new (pExecutableHeapMemory) LoaderHeap(EXECUTABLE_HEAP_RESERVE_SIZE, + EXECUTABLE_HEAP_COMMIT_SIZE, initReservedMem, dwExecutableHeapReserveSize, NULL, From 9b2ac94184899fa5bc120ba89f54798538fbea4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Aug 2026 21:42:31 +0000 Subject: [PATCH 03/17] Drop StubHeap from DAC/cDAC, reorder and rename stub code block kinds Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- docs/design/datacontracts/Loader.md | 9 --------- docs/design/datacontracts/RuntimeTypeSystem.md | 1 - .../design/datacontracts/data-descriptor-meanings.json | 1 - src/coreclr/debug/daccess/request.cpp | 2 -- src/coreclr/vm/codeman.h | 8 ++++---- src/coreclr/vm/stublink.cpp | 2 +- src/coreclr/vm/stubmgr.cpp | 10 +++++----- .../Contracts/ILoader.cs | 2 -- .../Contracts/Loader_1.cs | 7 ------- .../Data/LoaderAllocator.cs | 1 - .../SOSDacImpl.cs | 2 -- .../cdac/tests/DumpTests/ISOSDacInterface13Tests.cs | 1 - src/native/managed/cdac/tests/UnitTests/LoaderTests.cs | 2 -- 13 files changed, 10 insertions(+), 38 deletions(-) diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index cfb3cf1f288807..53f5210f854147 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -63,7 +63,6 @@ enum LoaderAllocatorHeapType LowFrequencyHeap, HighFrequencyHeap, StaticsHeap, - StubHeap, ExecutableHeap, FixupPrecodeHeap, NewStubPrecodeHeap, @@ -112,7 +111,6 @@ TargetPointer GetGlobalLoaderAllocator(); TargetPointer GetSystemAssembly(); TargetPointer GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer); TargetPointer GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer); -TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer); TargetPointer GetObjectHandle(TargetPointer loaderAllocatorPointer); TargetPointer GetILHeader(ModuleHandle handle, uint token); TargetPointer GetDynamicIL(ModuleHandle handle, uint token); @@ -193,7 +191,6 @@ enum ClrModifiableAssemblies : uint | `LoaderAllocator` | `ObjectHandle` | `ObjectHandle` | Handle to the managed loader allocator object | | `LoaderAllocator` | `ReferenceCount` | `uint32` | Reference count of the loader allocator | | `LoaderAllocator` | `StaticsHeap` | `pointer` | Heap containing statics-related allocations | -| `LoaderAllocator` | `StubHeap` | `pointer` | Heap containing runtime stubs | | `LoaderAllocator` | `VirtualCallStubManager` | `pointer` | Pointer to the virtual-call stub manager | | `LoaderHeap` | `FirstBlock` | `pointer` | Pointer to the first loader-heap block | | `LoaderHeapBlock` | `Next` | `pointer` | Pointer to the next loader-heap block | @@ -850,11 +847,6 @@ TargetPointer GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer) return target.ReadPointer(loaderAllocatorPointer + /* LoaderAllocator::LowFrequencyHeap offset */); } -TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer) -{ - return target.ReadPointer(loaderAllocatorPointer + /* LoaderAllocator::StubHeap offset */); -} - TargetPointer GetObjectHandle(TargetPointer loaderAllocatorPointer) { return target.ReadPointer(loaderAllocatorPointer + /* LoaderAllocator::ObjectHandle offset */); @@ -870,7 +862,6 @@ IReadOnlyDictionary GetLoaderAllocatorHe [LoaderAllocatorHeapType.LowFrequencyHeap] = la.LowFrequencyHeap, [LoaderAllocatorHeapType.HighFrequencyHeap] = la.HighFrequencyHeap, [LoaderAllocatorHeapType.StaticsHeap] = la.StaticsHeap, - [LoaderAllocatorHeapType.StubHeap] = la.StubHeap, [LoaderAllocatorHeapType.ExecutableHeap] = la.ExecutableHeap, }; diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index a57877760e47ef..2b7ac2cdccf518 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -585,7 +585,6 @@ static class RuntimeTypeSystem_1_Helpers | `LoaderAllocator` | `ObjectHandle` | `ObjectHandle` | Handle to the managed loader allocator object | | `LoaderAllocator` | `ReferenceCount` | `uint32` | Reference count of the loader allocator | | `LoaderAllocator` | `StaticsHeap` | `pointer` | Heap containing statics-related allocations | -| `LoaderAllocator` | `StubHeap` | `pointer` | Heap containing runtime stubs | | `LoaderAllocator` | `VirtualCallStubManager` | `pointer` | Pointer to the virtual-call stub manager | | `MethodDesc` | *(type size)* | `uint32` | Base size for mcIL classification | | `MethodDesc` | `ChunkIndex` | `uint8` | Offset of this MethodDesc relative to the end of its containing MethodDescChunk - in multiples of MethodDescAlignment | diff --git a/docs/design/datacontracts/data-descriptor-meanings.json b/docs/design/datacontracts/data-descriptor-meanings.json index 5ac9114612c194..b9ead4f0b972d4 100644 --- a/docs/design/datacontracts/data-descriptor-meanings.json +++ b/docs/design/datacontracts/data-descriptor-meanings.json @@ -330,7 +330,6 @@ "LoaderAllocator.ObjectHandle": "Handle to the managed loader allocator object", "LoaderAllocator.ReferenceCount": "Reference count of the loader allocator", "LoaderAllocator.StaticsHeap": "Heap containing statics-related allocations", - "LoaderAllocator.StubHeap": "Heap containing runtime stubs", "LoaderAllocator.VirtualCallStubManager": "Pointer to the virtual-call stub manager", "LoaderCodeHeap.LoaderHeap": "Offset of the embedded `ExplicitControlLoaderHeap` within the `LoaderCodeHeap` object; adding this to the object's base address yields the loader heap address", "LoaderHeap.FirstBlock": "Pointer to the first loader-heap block", diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 6d89324756ad6c..a206ea3db232ea 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -2453,7 +2453,6 @@ ClrDataAccess::GetAppDomainData(CLRDATA_ADDRESS addr, struct DacpAppDomainData * PTR_LoaderAllocator pLoaderAllocator = SystemDomain::GetGlobalLoaderAllocator(); appdomainData->pHighFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetHighFrequencyHeap()); appdomainData->pLowFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetLowFrequencyHeap()); - appdomainData->pStubHeap = HOST_CDADDR(pLoaderAllocator->GetExecutableHeap()); appdomainData->appDomainStage = STAGE_OPEN; appdomainData->dwId = DefaultADID; @@ -3681,7 +3680,6 @@ static const char *LoaderAllocatorLoaderHeapNames[] = "LowFrequencyHeap", "HighFrequencyHeap", "StaticsHeap", - "ExecutableStubHeap", "ExecutableHeap", "FixupPrecodeHeap", "NewStubPrecodeHeap", diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 6a69bfc7536698..f7bb70c8f5d59e 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -102,8 +102,6 @@ enum StubCodeBlockKind : int STUB_CODE_BLOCK_DYNAMICHELPER = 3, STUB_CODE_BLOCK_STUBPRECODE = 4, STUB_CODE_BLOCK_FIXUPPRECODE = 5, - STUB_CODE_BLOCK_STUBLINK = 0xB, - STUB_CODE_BLOCK_SHUFFLE_THUNK = 0xC, #ifdef FEATURE_VIRTUAL_STUB_DISPATCH STUB_CODE_BLOCK_VSD_DISPATCH_STUB = 6, STUB_CODE_BLOCK_VSD_RESOLVE_STUB = 7, @@ -113,6 +111,8 @@ enum StubCodeBlockKind : int #ifdef FEATURE_TIERED_COMPILATION STUB_CODE_BLOCK_CALLCOUNTING = 0xA, #endif // FEATURE_TIERED_COMPILATION + STUB_CODE_BLOCK_WRAPPER_STUB = 0xB, + STUB_CODE_BLOCK_SHUFFLE_THUNK = 0xC, // Last valid value. Note that the definition is duplicated in debug\daccess\fntableaccess.cpp STUB_CODE_BLOCK_LAST = 0xF, // Placeholder used by ReadyToRun images @@ -131,8 +131,8 @@ inline const char *GetStubCodeBlockKindString(StubCodeBlockKind kind) case STUB_CODE_BLOCK_CALLCOUNTING: return "CallCountingStub"; #endif - case STUB_CODE_BLOCK_STUBLINK: - return "StubLink"; + case STUB_CODE_BLOCK_WRAPPER_STUB: + return "WrapperStub"; case STUB_CODE_BLOCK_SHUFFLE_THUNK: return "ShuffleThunk"; case STUB_CODE_BLOCK_DYNAMICHELPER: diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index c2778b679d80e2..5f599740a3ad20 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -553,7 +553,7 @@ Stub *StubLinker::Link(LoaderAllocator *pLoaderAllocator, DWORD flags, const cha StubHolder pStub{ Stub::NewStub( pLoaderAllocator, - ((flags & NEWSTUB_FL_SHUFFLE_THUNK) != 0) ? STUB_CODE_BLOCK_SHUFFLE_THUNK : STUB_CODE_BLOCK_STUBLINK, + ((flags & NEWSTUB_FL_SHUFFLE_THUNK) != 0) ? STUB_CODE_BLOCK_SHUFFLE_THUNK : STUB_CODE_BLOCK_WRAPPER_STUB, size, flags) }; ASSERT(pStub != NULL); diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 76f5ea3046e9d0..666d19ad82aca1 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1260,7 +1260,7 @@ BOOL StubLinkStubManager::CheckIsStub_Internal(PCODE stubStartAddress) WRAPPER_NO_CONTRACT; SUPPORTS_DAC; StubCodeBlockKind kind = RangeSectionStubManager::GetStubKind(stubStartAddress); - return (kind == STUB_CODE_BLOCK_STUBLINK) || (kind == STUB_CODE_BLOCK_SHUFFLE_THUNK); + return (kind == STUB_CODE_BLOCK_WRAPPER_STUB) || (kind == STUB_CODE_BLOCK_SHUFFLE_THUNK); } BOOL StubLinkStubManager::DoTraceStub(PCODE stubStartAddress, @@ -1438,7 +1438,7 @@ BOOL RangeSectionStubManager::CheckIsStub_Internal(PCODE stubStartAddress) { case STUB_CODE_BLOCK_JUMPSTUB: case STUB_CODE_BLOCK_METHOD_CALL_THUNK: - case STUB_CODE_BLOCK_STUBLINK: + case STUB_CODE_BLOCK_WRAPPER_STUB: case STUB_CODE_BLOCK_SHUFFLE_THUNK: #ifdef FEATURE_TIERED_COMPILATION case STUB_CODE_BLOCK_CALLCOUNTING: @@ -1479,7 +1479,7 @@ BOOL RangeSectionStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestinati return TRUE; } #endif // FEATURE_DYNAMIC_CODE_COMPILED - case STUB_CODE_BLOCK_STUBLINK: + case STUB_CODE_BLOCK_WRAPPER_STUB: case STUB_CODE_BLOCK_SHUFFLE_THUNK: return StubLinkStubManager::g_pManager->DoTraceStub(stubStartAddress, trace); #ifdef FEATURE_TIERED_COMPILATION @@ -1524,8 +1524,8 @@ LPCWSTR RangeSectionStubManager::GetStubManagerName(PCODE addr) return W("JumpStub"); case STUB_CODE_BLOCK_METHOD_CALL_THUNK: return W("MethodCallThunk"); - case STUB_CODE_BLOCK_STUBLINK: - return W("StubLinkStub"); + case STUB_CODE_BLOCK_WRAPPER_STUB: + return W("WrapperStub"); case STUB_CODE_BLOCK_SHUFFLE_THUNK: return W("ShuffleThunk"); #ifdef FEATURE_TIERED_COMPILATION diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs index 282cfb12ee7beb..42da5b04d49d59 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs @@ -42,7 +42,6 @@ public enum LoaderAllocatorHeapType LowFrequencyHeap, HighFrequencyHeap, StaticsHeap, - StubHeap, ExecutableHeap, FixupPrecodeHeap, NewStubPrecodeHeap, @@ -128,7 +127,6 @@ public interface ILoader : IContract TargetPointer GetSystemAssembly() => throw new NotImplementedException(); TargetPointer GetHighFrequencyHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); TargetPointer GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); - TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); TargetPointer GetILHeader(ModuleHandle handle, uint token) => throw new NotImplementedException(); TargetPointer GetObjectHandle(TargetPointer loaderAllocatorPointer) => throw new NotImplementedException(); TargetPointer GetDynamicIL(ModuleHandle handle, uint token) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index c4bff95296e78b..ee8939779b4301 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -694,12 +694,6 @@ TargetPointer ILoader.GetLowFrequencyHeap(TargetPointer loaderAllocatorPointer) return loaderAllocator.LowFrequencyHeap; } - TargetPointer ILoader.GetStubHeap(TargetPointer loaderAllocatorPointer) - { - Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd(loaderAllocatorPointer); - return loaderAllocator.StubHeap; - } - TargetPointer ILoader.GetObjectHandle(TargetPointer loaderAllocatorPointer) { Data.LoaderAllocator loaderAllocator = _target.ProcessedData.GetOrAdd(loaderAllocatorPointer); @@ -795,7 +789,6 @@ IReadOnlyDictionary ILoader.GetLoaderAll [LoaderAllocatorHeapType.LowFrequencyHeap] = loaderAllocator.LowFrequencyHeap, [LoaderAllocatorHeapType.HighFrequencyHeap] = loaderAllocator.HighFrequencyHeap, [LoaderAllocatorHeapType.StaticsHeap] = loaderAllocator.StaticsHeap, - [LoaderAllocatorHeapType.StubHeap] = loaderAllocator.StubHeap, [LoaderAllocatorHeapType.ExecutableHeap] = loaderAllocator.ExecutableHeap, }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs index 8456d4768b6c37..aa66b3e3684679 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs @@ -10,7 +10,6 @@ internal sealed partial class LoaderAllocator : IData [Field] public partial TargetPointer HighFrequencyHeap { get; } [Field] public partial TargetPointer LowFrequencyHeap { get; } [Field] public partial TargetPointer StaticsHeap { get; } - [Field] public partial TargetPointer StubHeap { get; } [Field] public partial TargetPointer ExecutableHeap { get; } [Field] public partial TargetPointer? FixupPrecodeHeap { get; } [Field] public partial TargetPointer? NewStubPrecodeHeap { get; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 35b59f759c1e2d..bb0ab68fe89ee3 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -125,7 +125,6 @@ int ISOSDacInterface.GetAppDomainData(ClrDataAddress addr, DacpAppDomainData* da TargetPointer globalLoaderAllocator = loader.GetGlobalLoaderAllocator(); data->pHighFrequencyHeap = loader.GetHighFrequencyHeap(globalLoaderAllocator).ToClrDataAddress(_target); data->pLowFrequencyHeap = loader.GetLowFrequencyHeap(globalLoaderAllocator).ToClrDataAddress(_target); - data->pStubHeap = loader.GetStubHeap(globalLoaderAllocator).ToClrDataAddress(_target); data->appDomainStage = DacpAppDomainDataStage.STAGE_OPEN; data->dwId = DefaultAppDomainId; @@ -6483,7 +6482,6 @@ private static (LoaderAllocatorHeapType heapType, nint AnsiPtr)[] InitializeHeap LoaderAllocatorHeapType.LowFrequencyHeap, LoaderAllocatorHeapType.HighFrequencyHeap, LoaderAllocatorHeapType.StaticsHeap, - LoaderAllocatorHeapType.StubHeap, LoaderAllocatorHeapType.ExecutableHeap, LoaderAllocatorHeapType.FixupPrecodeHeap, LoaderAllocatorHeapType.NewStubPrecodeHeap, diff --git a/src/native/managed/cdac/tests/DumpTests/ISOSDacInterface13Tests.cs b/src/native/managed/cdac/tests/DumpTests/ISOSDacInterface13Tests.cs index 997d5d2d73e21f..9715eb1da1aacf 100644 --- a/src/native/managed/cdac/tests/DumpTests/ISOSDacInterface13Tests.cs +++ b/src/native/managed/cdac/tests/DumpTests/ISOSDacInterface13Tests.cs @@ -50,7 +50,6 @@ public unsafe void GetLoaderAllocatorHeapNames_MatchExpectedOrder(TestConfigurat "LowFrequencyHeap", "HighFrequencyHeap", "StaticsHeap", - "StubHeap", "ExecutableHeap", "FixupPrecodeHeap", "NewStubPrecodeHeap", diff --git a/src/native/managed/cdac/tests/UnitTests/LoaderTests.cs b/src/native/managed/cdac/tests/UnitTests/LoaderTests.cs index 6a6776dc56072b..ebe837202cc955 100644 --- a/src/native/managed/cdac/tests/UnitTests/LoaderTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/LoaderTests.cs @@ -197,7 +197,6 @@ public void GetSimpleName_InvalidUtf8(MockTarget.Architecture arch) [LoaderAllocatorHeapType.LowFrequencyHeap] = new(0x1000), [LoaderAllocatorHeapType.HighFrequencyHeap] = new(0x2000), [LoaderAllocatorHeapType.StaticsHeap] = new(0x3000), - [LoaderAllocatorHeapType.StubHeap] = new(0x4000), [LoaderAllocatorHeapType.ExecutableHeap] = new(0x5000), [LoaderAllocatorHeapType.FixupPrecodeHeap] = new(0x6000), [LoaderAllocatorHeapType.NewStubPrecodeHeap] = new(0x7000), @@ -232,7 +231,6 @@ private static ISOSDacInterface13 CreateSOSDacInterface13ForHeapTests(MockTarget ["LowFrequencyHeap"] = dummyField, ["HighFrequencyHeap"] = dummyField, ["StaticsHeap"] = dummyField, - ["StubHeap"] = dummyField, ["ExecutableHeap"] = dummyField, ["FixupPrecodeHeap"] = dummyField, ["NewStubPrecodeHeap"] = dummyField, From 76a92eb36dbf4eb2cec82b48858d5ce8b0bd9b6b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Aug 2026 21:59:41 +0000 Subject: [PATCH 04/17] Address StubLinker review feedback Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/class.cpp | 10 +- src/coreclr/vm/comdelegate.cpp | 10 +- src/coreclr/vm/comdelegate.h | 6 +- src/coreclr/vm/prestub.cpp | 19 +-- src/coreclr/vm/stubcache.cpp | 13 +- src/coreclr/vm/stubcache.h | 7 +- src/coreclr/vm/stublink.cpp | 119 ++++++------------ src/coreclr/vm/stublink.h | 59 +++------ .../ExecutionManager/ExecutionManagerCore.cs | 2 + 9 files changed, 72 insertions(+), 173 deletions(-) diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 5eda34f8ce5e94..4577bd036285e3 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -92,15 +92,7 @@ void EEClass::Destruct() _ASSERTE(pThunk->IsShuffleThunk()); - if (pThunk->HasExternalEntryPoint()) // IL thunk - { - pThunk->DecRef(); - } - else - { - ExecutableWriterHolder stubWriterHolder(pThunk, sizeof(Stub)); - stubWriterHolder.GetRW()->DecRef(); - } + pThunk->DecRef(); } } diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 826884119a29d7..f54ebf12620a0b 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -941,15 +941,7 @@ static PCODE SetupShuffleThunk(MethodTable * pDelMT, MethodDesc *pTargetMeth) Stub* pExistingThunk = InterlockedCompareExchangeT(ppThunk, pShuffleThunk, NULL); if (pExistingThunk != NULL) { - if (pShuffleThunk->HasExternalEntryPoint()) // IL thunk - { - pShuffleThunk->DecRef(); - } - else - { - ExecutableWriterHolder shuffleThunkWriterHolder(pShuffleThunk, sizeof(Stub)); - shuffleThunkWriterHolder.GetRW()->DecRef(); - } + pShuffleThunk->DecRef(); pShuffleThunk = pExistingThunk; } diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index 4bc2679229e00b..380f4eb94b37cb 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -183,13 +183,13 @@ class ShuffleThunkCache : public StubCacheBase // Compile a static delegate shufflethunk. Always returns // STANDALONE since we don't interpret these things. //--------------------------------------------------------- - virtual DWORD CompileStub(const BYTE *pRawStub, - StubLinker *pstublinker) + virtual StubCodeBlockKind CompileStub(const BYTE *pRawStub, + StubLinker *pstublinker) { STANDARD_VM_CONTRACT; ((CPUSTUBLINKER*)pstublinker)->EmitShuffleThunk((ShuffleEntry*)pRawStub); - return NEWSTUB_FL_SHUFFLE_THUNK; + return STUB_CODE_BLOCK_SHUFFLE_THUNK; } //--------------------------------------------------------- diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index f37bea0be0e23d..1ba3740b27031a 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -1743,13 +1743,13 @@ Stub * MakeUnboxingStubWorker(MethodDesc *pMD) sl.EmitComputedInstantiatingMethodStub(pUnboxedMD, &portableShuffle[0], NULL); - return sl.Link(pMD->GetLoaderAllocator(), NEWSTUB_FL_INSTANTIATING_METHOD, "UnboxingStub"); + return sl.Link(pMD->GetLoaderAllocator(), STUB_CODE_BLOCK_WRAPPER_STUB, "UnboxingStub"); } #elif defined(TARGET_X86) CPUSTUBLINKER sl; if (sl.EmitUnboxMethodStub(pUnboxedMD)) { - return sl.Link(pMD->GetLoaderAllocator(), NEWSTUB_FL_NONE, "UnboxingStub"); + return sl.Link(pMD->GetLoaderAllocator(), STUB_CODE_BLOCK_WRAPPER_STUB, "UnboxingStub"); } #endif // FEATURE_PORTABLE_SHUFFLE_THUNKS || TARGET_X86 @@ -1798,13 +1798,13 @@ Stub * MakeInstantiatingStubWorker(MethodDesc *pMD) _ASSERTE(pSharedMD != NULL && pSharedMD != pMD); sl.EmitComputedInstantiatingMethodStub(pSharedMD, &portableShuffle[0], extraArg); - return sl.Link(pMD->GetLoaderAllocator(), NEWSTUB_FL_INSTANTIATING_METHOD, "InstantiatingStub"); + return sl.Link(pMD->GetLoaderAllocator(), STUB_CODE_BLOCK_WRAPPER_STUB, "InstantiatingStub"); } #elif defined(TARGET_X86) CPUSTUBLINKER sl; if (sl.EmitInstantiatingMethodStub(pSharedMD, extraArg)) { - return sl.Link(pMD->GetLoaderAllocator(), NEWSTUB_FL_NONE, "InstantiatingStub"); + return sl.Link(pMD->GetLoaderAllocator(), STUB_CODE_BLOCK_WRAPPER_STUB, "InstantiatingStub"); } #endif // FEATURE_PORTABLE_SHUFFLE_THUNKS || TARGET_X86 @@ -2615,16 +2615,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo #else // !FEATURE_PORTABLE_ENTRYPOINTS if (!GetOrCreatePrecode()->SetTargetInterlocked(pStub->GetEntryPoint())) { - if (pStub->HasExternalEntryPoint()) - { - // Stubs with external entry point are allocated from regular heap and so they are always writeable - pStub->DecRef(); - } - else - { - ExecutableWriterHolder stubWriterHolder(pStub, sizeof(Stub)); - stubWriterHolder.GetRW()->DecRef(); - } + pStub->DecRef(); } else if (pStub->HasExternalEntryPoint()) { diff --git a/src/coreclr/vm/stubcache.cpp b/src/coreclr/vm/stubcache.cpp index de15b6ef6f3f48..1901a2fb18d35c 100644 --- a/src/coreclr/vm/stubcache.cpp +++ b/src/coreclr/vm/stubcache.cpp @@ -53,8 +53,7 @@ StubCacheBase::~StubCacheBase() while (phe) { _ASSERTE(NULL != phe->m_pStub); - ExecutableWriterHolder stubWriterHolder(phe->m_pStub, sizeof(Stub)); - stubWriterHolder.GetRW()->DecRef(); + phe->m_pStub->DecRef(); phe = (STUBHASHENTRY*)GetNext((BYTE*)phe); } } @@ -89,9 +88,8 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) { pstub = phe->m_pStub; - ExecutableWriterHolder stubWriterHolder(pstub, sizeof(Stub)); // IncRef as we're returning a reference to our caller. - stubWriterHolder.GetRW()->IncRef(); + pstub->IncRef(); return pstub.Detach(); } @@ -100,13 +98,13 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) // Couldn't find it, let's try to compile it. CPUSTUBLINKER sl; CPUSTUBLINKER *psl = &sl; - DWORD linkFlags = CompileStub(pRawStub, psl); + StubCodeBlockKind kind = CompileStub(pRawStub, psl); // Append the raw stub to the native stub // and link up the stub. CodeLabel *plabel = psl->EmitNewCodeLabel(); psl->EmitBytes(pRawStub, Length(pRawStub)); - pstub = psl->Link(m_pLoaderAllocator, linkFlags, stubType); + pstub = psl->Link(m_pLoaderAllocator, kind, stubType); UINT32 offset = psl->GetLabelOffset(plabel); if (offset > 0xffff) @@ -142,8 +140,7 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) pstub = phe->m_pStub; } // IncRef so that caller has firm ownership of stub. - ExecutableWriterHolder stubWriterHolder(pstub, sizeof(Stub)); - stubWriterHolder.GetRW()->IncRef(); + pstub->IncRef(); } } diff --git a/src/coreclr/vm/stubcache.h b/src/coreclr/vm/stubcache.h index 24b38b8f113a7e..22d5b1361fc76e 100644 --- a/src/coreclr/vm/stubcache.h +++ b/src/coreclr/vm/stubcache.h @@ -19,6 +19,7 @@ class Stub; class StubLinker; +enum StubCodeBlockKind : int; class StubCacheBase : private CClosedHashBase { @@ -67,10 +68,10 @@ class StubCacheBase : private CClosedHashBase // This method should compile into the provided stublinker (but // not call the Link method.) // - // It can return flags that will be passed to StubLinker::Link(). + // It can return the kind passed to StubLinker::Link(). //--------------------------------------------------------- - virtual DWORD CompileStub(const BYTE *pRawStub, - StubLinker *psl) = 0; + virtual StubCodeBlockKind CompileStub(const BYTE *pRawStub, + StubLinker *psl) = 0; //--------------------------------------------------------- // OVERRIDE diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index 5f599740a3ad20..f344d25c5539d0 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -544,21 +544,25 @@ static BOOL LabelCanReach(LabelRef *pLabelRef) // // Throws exception on failure. //--------------------------------------------------------------- -Stub *StubLinker::Link(LoaderAllocator *pLoaderAllocator, DWORD flags, const char *stubType) +Stub *StubLinker::Link(LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind, const char *stubType) { STANDARD_VM_CONTRACT; int globalsize = 0; int size = CalculateSize(&globalsize); + DWORD flags = (m_pTargetMethod != NULL) ? NEWSTUB_FL_INSTANTIATING_METHOD : NEWSTUB_FL_NONE; + if (kind == STUB_CODE_BLOCK_SHUFFLE_THUNK) + { + flags |= NEWSTUB_FL_SHUFFLE_THUNK; + } StubHolder pStub{ Stub::NewStub( pLoaderAllocator, - ((flags & NEWSTUB_FL_SHUFFLE_THUNK) != 0) ? STUB_CODE_BLOCK_SHUFFLE_THUNK : STUB_CODE_BLOCK_WRAPPER_STUB, size, flags) }; ASSERT(pStub != NULL); - EmitStub(pStub, globalsize, size); + EmitStub(pStub, pLoaderAllocator, kind, globalsize, size); PerfMap::LogStubs(__FUNCTION__, stubType, pStub->GetEntryPoint(), pStub->GetNumCodeBytes(), PerfMapStubType::Individual); @@ -697,16 +701,29 @@ int StubLinker::CalculateSize(int* pGlobalSize) return globalsize + datasize; } -void StubLinker::EmitStub(Stub* pStub, int globalsize, int totalSize) +void StubLinker::EmitStub(Stub* pStub, LoaderAllocator* pLoaderAllocator, StubCodeBlockKind kind, int globalsize, int totalSize) { STANDARD_VM_CONTRACT; - BYTE *pCode = (BYTE*)(pStub->GetBlob()); + S_SIZE_T allocationSize(totalSize); + allocationSize += CODE_SIZE_ALIGN; + if (allocationSize.IsOverflow()) + COMPlusThrowArithmetic(); + + BYTE* pBlock = reinterpret_cast(ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock( + allocationSize.Value(), + CODE_SIZE_ALIGN, + pLoaderAllocator, + kind)); + size_t codeOffset = ALIGN_UP(reinterpret_cast(pBlock) + sizeof(PTR_Stub), CODE_SIZE_ALIGN) - reinterpret_cast(pBlock); + BYTE* pCode = pBlock + codeOffset; + pStub->m_entryPoint = pCode; - ExecutableWriterHolder stubWriterHolder(pStub, sizeof(Stub) + totalSize); - Stub *pStubRW = stubWriterHolder.GetRW(); + ExecutableWriterHolder stubWriterHolder(pBlock, allocationSize.Value()); + BYTE* pBlockRW = stubWriterHolder.GetRW(); + BYTE* pCodeRW = pBlockRW + codeOffset; + SET_UNALIGNED_PTR(pCodeRW - sizeof(PTR_Stub), reinterpret_cast(pStub)); - BYTE *pCodeRW = (BYTE*)(pStubRW->GetBlob()); BYTE *pDataRW = pCodeRW+globalsize; // start of data area { int lastCodeOffset = 0; @@ -772,10 +789,10 @@ void StubLinker::EmitStub(Stub* pStub, int globalsize, int totalSize) } // Fill in the target method for the Instantiating stub. - if (pStubRW->IsInstantiatingStub()) + if (pStub->IsInstantiatingStub()) { _ASSERTE(m_pTargetMethod != NULL); - pStubRW->SetInstantiatedMethodDesc(m_pTargetMethod); + pStub->SetInstantiatedMethodDesc(m_pTargetMethod); LOG((LF_CORDB, LL_INFO100, "SL::ES: InstantiatedMethod fd:0x%x\n", pStub->GetInstantiatedMethodDesc())); @@ -793,13 +810,6 @@ void StubLinker::EmitStub(Stub* pStub, int globalsize, int totalSize) #ifndef DACCESS_COMPILE -// Redeclaring the Stub type here and assert its size. -// The size assertion is done here because of where CODE_SIZE_ALIGN -// is defined - it is not included in all places where stublink.h -// is consumed. -class Stub; -static_assert((sizeof(Stub) % CODE_SIZE_ALIGN) == 0); - //------------------------------------------------------------------- // Inc the refcount. //------------------------------------------------------------------- @@ -850,34 +860,13 @@ VOID Stub::DeleteStub() { #ifdef _DEBUG m_signature = kFreedStub; - FillMemory(this+1, GetNumCodeBytes(), 0xcc); + FillMemory(this, sizeof(*this), 0xcc); #endif - delete [] (BYTE*)GetAllocationBase(); + delete [] reinterpret_cast(this); } } -TADDR Stub::GetAllocationBase() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - FORBID_FAULT; - } - CONTRACTL_END - - TADDR info = dac_cast(this); - SIZE_T cbPrefix = 0; - - if (!HasExternalEntryPoint()) - { - cbPrefix = ALIGN_UP(cbPrefix + sizeof(Stub), CODE_SIZE_ALIGN) - sizeof(Stub); - } - - return info - cbPrefix; -} - Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) { CONTRACTL @@ -887,12 +876,8 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) } CONTRACTL_END; - Stub* pStub = NewStub(NULL, STUB_CODE_BLOCK_UNKNOWN, 0, flags | NEWSTUB_FL_EXTERNAL); - - // Passing NEWSTUB_FL_EXTERNAL requests the stub struct be - // expanded in size by a single pointer. Insert the code point at this - // location. - *(PTR_VOID *)(pStub + 1) = pCode; + Stub* pStub = NewStub(NULL, 0, flags | NEWSTUB_FL_EXTERNAL); + pStub->m_entryPoint = reinterpret_cast(pCode); return pStub; } @@ -902,7 +887,6 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) //------------------------------------------------------------------- /*static*/ Stub* Stub::NewStub( LoaderAllocator *pLoaderAllocator, - StubCodeBlockKind kind, UINT numCodeBytes, DWORD flags) { @@ -913,26 +897,12 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) } CONTRACTL_END; - // The memory layout of the allocated memory for the Stub instance is as follows: - // Offset: - // - 0 - // optional: unwind info - see nUnwindInfoSize usage. - // - stubPayloadOffset - // Stub instance - // optional: external pointer | padding + code - size_t stubPayloadOffset = 0; S_SIZE_T size = S_SIZE_T(sizeof(Stub)); if (flags & NEWSTUB_FL_EXTERNAL) { _ASSERTE(pLoaderAllocator == NULL); _ASSERTE(numCodeBytes == 0); - size += sizeof(PTR_PCODE); - } - else - { - size.AlignUp(CODE_SIZE_ALIGN); - size += numCodeBytes; } if (size.IsOverflow()) @@ -947,31 +917,15 @@ Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) } else { - pBlock = reinterpret_cast(ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock(totalSize, CODE_SIZE_ALIGN, pLoaderAllocator, kind)); + TaggedMemAllocPtr ptr = pLoaderAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(totalSize)); + pBlock = static_cast(static_cast(ptr)); flags |= NEWSTUB_FL_LOADERHEAP; } - _ASSERTE((stubPayloadOffset % CODE_SIZE_ALIGN) == 0); - Stub* pStubRX = (Stub*)(pBlock + stubPayloadOffset); - Stub* pStubRW; - ExecutableWriterHolderNoLog stubWriterHolder; + Stub* pStub = reinterpret_cast(pBlock); + pStub->SetupStub(numCodeBytes, flags); - if (pLoaderAllocator == NULL) - { - pStubRW = pStubRX; - } - else - { - stubWriterHolder.AssignExecutableWriterHolder(pStubRX, sizeof(Stub)); - pStubRW = stubWriterHolder.GetRW(); - } - pStubRW->SetupStub( - numCodeBytes, - flags); - - _ASSERTE((BYTE *)pStubRX->GetAllocationBase() == pBlock); - - return pStubRX; + return pStub; } void Stub::SetupStub(int numCodeBytes, DWORD flags) @@ -997,6 +951,7 @@ void Stub::SetupStub(int numCodeBytes, DWORD flags) m_numCodeBytesAndFlags = numCodeBytes; + m_entryPoint = NULL; m_refcount = 1; m_data = {}; diff --git a/src/coreclr/vm/stublink.h b/src/coreclr/vm/stublink.h index 91cd7eda8e55f8..6fbed06a055d74 100644 --- a/src/coreclr/vm/stublink.h +++ b/src/coreclr/vm/stublink.h @@ -178,7 +178,7 @@ class StubLinker // // Throws exception on failure. //--------------------------------------------------------------- - Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, const char *stubType); + Stub *Link(LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind, const char *stubType); private: CodeElement *m_pCodeElements; // stored in *reverse* order @@ -206,15 +206,12 @@ class StubLinker VOID AppendCodeElement(CodeElement *pCodeElement); - // Calculates the size of the stub code that is allocate - // immediately after the stub object. Returns the - // total size. GlobalSize contains the size without - // that data part. + // Calculates the size of the stub code. Returns the total size. + // GlobalSize contains the size without that data part. virtual int CalculateSize(int* globalsize); - // Writes out the code element into memory following the - // stub object. - void EmitStub(Stub* pStub, int globalsize, int totalSize); + // Writes out the code element into a code fragment. + void EmitStub(Stub* pStub, LoaderAllocator* pLoaderAllocator, StubCodeBlockKind kind, int globalsize, int totalSize); CodeRun *GetLastCodeRunIfAny(); }; @@ -276,6 +273,7 @@ class Stub { friend class CheckDuplicatedStructLayouts; friend class CheckAsmOffsets; + friend class StubLinker; protected: enum @@ -358,10 +356,6 @@ class Stub } //------------------------------------------------------------------- - // Returns pointer to the start of the allocation containing this Stub. - //------------------------------------------------------------------- - TADDR GetAllocationBase(); - //------------------------------------------------------------------- // Return executable entrypoint after checking the ref count. //------------------------------------------------------------------- @@ -396,7 +390,7 @@ class Stub } //------------------------------------------------------------------- - // Return start of the stub blob + // Return start of the stub code //------------------------------------------------------------------- PTR_CBYTE GetBlob() { @@ -410,10 +404,7 @@ class Stub } //------------------------------------------------------------------- - // Return the Stub as in GetEntryPoint and size of the stub+code in bytes - // WARNING: Depending on the stub kind this may be just Stub size as - // not all stubs have the info about the code size. - // It's the caller responsibility to determine that + // Return the Stub and code size. //------------------------------------------------------------------- static Stub* RecoverStubAndSize(PCODE pEntryPoint, DWORD *pSize) { @@ -428,25 +419,10 @@ class Stub CONTRACTL_END; Stub *pStub = Stub::RecoverStub(pEntryPoint); - *pSize = sizeof(Stub) + pStub->GetNumCodeBytes(); + *pSize = pStub->GetNumCodeBytes(); return pStub; } - HRESULT CloneStub(BYTE *pBuffer, DWORD dwBufferSize) - { - LIMITED_METHOD_CONTRACT; - if ((pBuffer == NULL) || - (dwBufferSize < (sizeof(*this) + GetNumCodeBytes()))) - { - return E_INVALIDARG; - } - - memcpyNoGCRefs(pBuffer, this, sizeof(*this) + GetNumCodeBytes()); - reinterpret_cast(pBuffer)->m_refcount = 1; - - return S_OK; - } - //------------------------------------------------------------------- // Reverse GetEntryPoint. //------------------------------------------------------------------- @@ -457,7 +433,7 @@ class Stub TADDR pStubData = PCODEToPINSTR(pEntryPoint); - Stub *pStub = PTR_Stub(pStubData - sizeof(*pStub)); + Stub *pStub = *dac_cast(pStubData - sizeof(PTR_Stub)); #if !defined(DACCESS_COMPILE) _ASSERTE(pStub->m_signature == kUsedStub); @@ -488,9 +464,9 @@ class Stub } //------------------------------------------------------------------- - // This creates stubs. + // This creates stub metadata. //------------------------------------------------------------------- - static Stub* NewStub(LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind, UINT numCodeBytes, + static Stub* NewStub(LoaderAllocator *pLoaderAllocator, UINT numCodeBytes, DWORD flags = NEWSTUB_FL_NONE); static Stub* NewStub(PTR_VOID pCode, DWORD flags = NEWSTUB_FL_NONE); @@ -514,17 +490,10 @@ class Stub _ASSERTE(m_signature == kUsedStub); - if (HasExternalEntryPoint()) - { - return dac_cast(*dac_cast(dac_cast(this) + sizeof(*this))); - } - else - { - // StubLink always puts the entrypoint first. - return dac_cast(this) + sizeof(*this); - } + return m_entryPoint; } + PTR_CBYTE m_entryPoint; UINT32 m_refcount; UINT32 m_numCodeBytesAndFlags; union diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs index b679dbce6a1e6e..6f5ef1f2e57d34 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs @@ -102,6 +102,8 @@ private enum StubKind : int VSDLookupStub = 8, VSDVTableStub = 9, CallCountingStub = 10, + WrapperStub = 11, + ShuffleThunk = 12, } private abstract class JitManager From c650d98429c86c38086b8bd76331eaa338f84803 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Aug 2026 22:26:02 +0000 Subject: [PATCH 05/17] Delete DelegateEEClass::GetStubHeap and stop double-recognizing stub kinds Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/class.h | 3 --- src/coreclr/vm/comdelegate.cpp | 6 ------ src/coreclr/vm/stubmgr.cpp | 5 +++-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 7afd07b5bc3bab..4c457d8e9c1fb0 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -1920,9 +1920,6 @@ class DelegateEEClass : public EEClass LIMITED_METHOD_CONTRACT; // Note: Memory allocated on loader heap is zero filled } - - // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer - LoaderAllocator *GetStubHeap(); #endif // !DACCESS_COMPILE }; diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index f54ebf12620a0b..5de44d8308ecee 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -820,12 +820,6 @@ CLRToCOMCallInfo * COMDelegate::PopulateCLRToCOMCallInfo(MethodTable * pDelMT) } #endif // FEATURE_COMINTEROP -// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer -LoaderAllocator *DelegateEEClass::GetStubHeap() -{ - return GetInvokeMethod()->GetLoaderAllocator(); -} - static Stub* CreateILDelegateShuffleThunk(MethodDesc* pDelegateMD, bool callTargetWithThis) { SigTypeContext typeContext(pDelegateMD); diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 666d19ad82aca1..798512431309bd 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1259,8 +1259,9 @@ BOOL StubLinkStubManager::CheckIsStub_Internal(PCODE stubStartAddress) { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; - StubCodeBlockKind kind = RangeSectionStubManager::GetStubKind(stubStartAddress); - return (kind == STUB_CODE_BLOCK_WRAPPER_STUB) || (kind == STUB_CODE_BLOCK_SHUFFLE_THUNK); + + // Forwarded to from RangeSectionStubManager + return FALSE; } BOOL StubLinkStubManager::DoTraceStub(PCODE stubStartAddress, From c38e9d02dd951495cedbf0167152fb14a1e234a2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 01:41:09 +0000 Subject: [PATCH 06/17] Remove obsolete Stub wrapper Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/inc/holder.h | 47 ----- src/coreclr/vm/array.cpp | 4 +- src/coreclr/vm/array.h | 2 +- src/coreclr/vm/cgensys.h | 1 - src/coreclr/vm/class.cpp | 9 - src/coreclr/vm/class.h | 5 +- src/coreclr/vm/classcompat.h | 1 - src/coreclr/vm/comdelegate.cpp | 21 ++- src/coreclr/vm/comdelegate.h | 3 +- src/coreclr/vm/eventtrace.cpp | 3 +- src/coreclr/vm/interpexec.cpp | 4 +- src/coreclr/vm/jitinterface.h | 1 - src/coreclr/vm/loaderallocator.cpp | 2 +- src/coreclr/vm/methodtable.h | 1 - src/coreclr/vm/prestub.cpp | 30 +--- src/coreclr/vm/stubcache.cpp | 49 ++--- src/coreclr/vm/stubcache.h | 9 +- src/coreclr/vm/stubgen.h | 2 - src/coreclr/vm/stublink.cpp | 232 +++--------------------- src/coreclr/vm/stublink.h | 279 +---------------------------- src/coreclr/vm/stubmgr.cpp | 30 ++-- 21 files changed, 99 insertions(+), 636 deletions(-) diff --git a/src/coreclr/inc/holder.h b/src/coreclr/inc/holder.h index 6e474b1eb1e9ad..4943b4b8fb89c2 100644 --- a/src/coreclr/inc/holder.h +++ b/src/coreclr/inc/holder.h @@ -1128,53 +1128,6 @@ struct CoTaskMemTraits final template using CoTaskMemHolder = LifetimeHolder>; -//----------------------------------------------------------------------------- -// StubHolder : holder for runtime-emitted Stub-like objects. -// On scope exit, calls DecRef through the executable-memory -// writer-holder so the refcount field can be written. -// -// Note: StubHolder does NOT call IncRef on assignment - the caller owns -// matching IncRef/DecRef pairing on the value it hands to the holder. -// -// Usage example: -// -// { -// StubHolder foo; -// foo = new Stub(); -// foo->AddRef(); -// } // foo->DecRef() on out of scope -//----------------------------------------------------------------------------- -template -class ExecutableWriterHolderNoLog; - -class ExecutableAllocator; - -template -struct StubTraits final -{ - using Type = T*; - static constexpr Type Default() { return nullptr; } - static void Free(Type value) - { - STATIC_CONTRACT_WRAPPER; - if (value != nullptr) - { -#ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS -#ifdef HOST_UNIX - ExecutableAllocator::LogUsage(__FILE__, __LINE__, __PRETTY_FUNCTION__); -#else - ExecutableAllocator::LogUsage(__FILE__, __LINE__, __FUNCTION__); -#endif -#endif // LOG_EXECUTABLE_ALLOCATOR_STATISTICS - ExecutableWriterHolderNoLog stubWriterHolder(value, sizeof(T)); - stubWriterHolder.GetRW()->DecRef(); - } - } -}; - -template -using StubHolder = LifetimeHolder>; - // // We need the following methods to have volatile arguments, so that they can accept // raw pointers in addition to the results of the & operator on Volatile. diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index fba06cfb5a8840..e27e2e46d75685 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -864,7 +864,7 @@ class ArrayOpLinker : public ILStubLinker } }; -Stub *GenerateArrayOpStub(ArrayMethodDesc* pMD) +PCODE GenerateArrayOpStub(ArrayMethodDesc* pMD) { STANDARD_VM_CONTRACT; @@ -908,7 +908,7 @@ Stub *GenerateArrayOpStub(ArrayMethodDesc* pMD) NULL, &sl); - return Stub::NewStub(JitILStub(pStubMD)); + return JitILStub(pStubMD); } diff --git a/src/coreclr/vm/array.h b/src/coreclr/vm/array.h index 1f687f140eef3b..c1043aefc31a17 100644 --- a/src/coreclr/vm/array.h +++ b/src/coreclr/vm/array.h @@ -14,7 +14,7 @@ class MethodTable; -Stub *GenerateArrayOpStub(ArrayMethodDesc* pMD); +PCODE GenerateArrayOpStub(ArrayMethodDesc* pMD); diff --git a/src/coreclr/vm/cgensys.h b/src/coreclr/vm/cgensys.h index 3f32aca5cdcecb..9f0a24383f8ff5 100644 --- a/src/coreclr/vm/cgensys.h +++ b/src/coreclr/vm/cgensys.h @@ -11,7 +11,6 @@ #define __cgensys_h__ class MethodDesc; -class Stub; class Thread; class CrawlFrame; struct EE_ILEXCEPTION_CLAUSE; diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 4577bd036285e3..5d033d0e089613 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -85,15 +85,6 @@ void EEClass::Destruct() if (IsDelegate()) { DelegateEEClass* pDelegateEEClass = (DelegateEEClass*)this; - for (Stub* pThunk : {pDelegateEEClass->m_pStaticCallStub, pDelegateEEClass->m_pInstRetBuffCallStub}) - { - if (pThunk == nullptr) - continue; - - _ASSERTE(pThunk->IsShuffleThunk()); - - pThunk->DecRef(); - } } #ifdef FEATURE_COMINTEROP diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 4c457d8e9c1fb0..b6d307eb011ef2 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -77,7 +77,6 @@ class MethodDescChunk; class MethodTable; class Module; class Object; -class Stub; enum class AsyncMethodFlags; class Substitution; class SystemDomain; @@ -1898,8 +1897,8 @@ class DelegateEEClass : public EEClass { public: DAC_ALIGNAS(EEClass) // Align the first member to the alignment of the base class - PTR_Stub m_pStaticCallStub; - PTR_Stub m_pInstRetBuffCallStub; + PCODE m_pStaticCallStub; + PCODE m_pInstRetBuffCallStub; PTR_MethodDesc m_pInvokeMethod; PCODE m_pMultiCastInvokeStub; UMThunkMarshInfo* m_pUMThunkMarshInfo; diff --git a/src/coreclr/vm/classcompat.h b/src/coreclr/vm/classcompat.h index 5bd0c7e7e33467..176257d77c8a17 100644 --- a/src/coreclr/vm/classcompat.h +++ b/src/coreclr/vm/classcompat.h @@ -48,7 +48,6 @@ class MethodNameHash; class MethodTable; class Module; class Object; -class Stub; class Substitution; class SystemDomain; class TypeHandle; diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 5de44d8308ecee..a60a97875a5c5b 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -820,7 +820,7 @@ CLRToCOMCallInfo * COMDelegate::PopulateCLRToCOMCallInfo(MethodTable * pDelMT) } #endif // FEATURE_COMINTEROP -static Stub* CreateILDelegateShuffleThunk(MethodDesc* pDelegateMD, bool callTargetWithThis) +static PCODE CreateILDelegateShuffleThunk(MethodDesc* pDelegateMD, bool callTargetWithThis) { SigTypeContext typeContext(pDelegateMD); MetaSig sig(pDelegateMD); @@ -877,7 +877,7 @@ static Stub* CreateILDelegateShuffleThunk(MethodDesc* pDelegateMD, bool callTarg ILStubResolver* pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver(); pResolver->SetStubTargetMethodSig(pTargetSig, cbTargetSig); - return Stub::NewStub(JitILStub(pStubMD), NEWSTUB_FL_SHUFFLE_THUNK); + return JitILStub(pStubMD); } static PCODE SetupShuffleThunk(MethodTable * pDelMT, MethodDesc *pTargetMeth) @@ -896,9 +896,9 @@ static PCODE SetupShuffleThunk(MethodTable * pDelMT, MethodDesc *pTargetMeth) // Look for a thunk cached on the delegate class first. Note we need a different thunk for instance methods with a // hidden return buffer argument because the extra argument switches place with the target when coming from the caller. - Stub* pShuffleThunk = isInstRetBuff ? pClass->m_pInstRetBuffCallStub : pClass->m_pStaticCallStub; + PCODE pShuffleThunk = isInstRetBuff ? pClass->m_pInstRetBuffCallStub : pClass->m_pStaticCallStub; if (pShuffleThunk) - return pShuffleThunk->GetEntryPoint(); + return pShuffleThunk; GCX_PREEMP(); @@ -931,15 +931,14 @@ static PCODE SetupShuffleThunk(MethodTable * pDelMT, MethodDesc *pTargetMeth) } // Cache the shuffle thunk - Stub** ppThunk = isInstRetBuff ? &pClass->m_pInstRetBuffCallStub : &pClass->m_pStaticCallStub; - Stub* pExistingThunk = InterlockedCompareExchangeT(ppThunk, pShuffleThunk, NULL); - if (pExistingThunk != NULL) + PCODE* ppThunk = isInstRetBuff ? &pClass->m_pInstRetBuffCallStub : &pClass->m_pStaticCallStub; + PCODE pExistingThunk = InterlockedCompareExchangeT(ppThunk, pShuffleThunk, PCODE(0)); + if (pExistingThunk != 0) { - pShuffleThunk->DecRef(); pShuffleThunk = pExistingThunk; } - return pShuffleThunk->GetEntryPoint(); + return pShuffleThunk; } extern "C" PCODE CID_VirtualOpenDelegateDispatch(TransitionBlock * pTransitionBlock); @@ -1817,7 +1816,7 @@ BOOL COMDelegate::HasSingleTarget(DELEGATEREF delegate) } // Get the cpu stub for a delegate invoke. -Stub* COMDelegate::GetInvokeMethodStub(EEImplMethodDesc* pMD) +PCODE COMDelegate::GetInvokeMethodStub(EEImplMethodDesc* pMD) { STANDARD_VM_CONTRACT; @@ -1872,7 +1871,7 @@ Stub* COMDelegate::GetInvokeMethodStub(EEImplMethodDesc* pMD) NULL, &sl); - return Stub::NewStub(JitILStub(pStubMD)); + return JitILStub(pStubMD); } else { diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index 380f4eb94b37cb..e4cd1902e9cfed 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -10,7 +10,6 @@ #ifndef _COMDELEGATE_H_ #define _COMDELEGATE_H_ -class Stub; class ShuffleThunkCache; #include "cgensys.h" @@ -65,7 +64,7 @@ class COMDelegate static BOOL IsDelegate(MethodTable *pMT); // Get the cpu stub for a delegate invoke. - static Stub* GetInvokeMethodStub(EEImplMethodDesc* pMD); + static PCODE GetInvokeMethodStub(EEImplMethodDesc* pMD); static MethodDesc* GetMethodDesc(OBJECTREF obj); static MethodDesc* GetMethodDescForOpenVirtualDelegate(DELEGATEREF delegate); diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index f6bebafdc0f358..c60e96e66391e0 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -3623,8 +3623,7 @@ VOID ETW::MethodLog::StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pH TRACE_LEVEL_INFORMATION, CLR_JIT_KEYWORD)) { - DWORD dwHelperSize=0; - Stub::RecoverStubAndSize((TADDR)ullHelperStartAddress, &dwHelperSize); + DWORD dwHelperSize = 0; ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName); } } EX_CATCH { } EX_END_CATCH diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 9a1ff7bbb5739f..ae2b5d51edc5e1 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -3409,8 +3409,8 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr NULL_CHECK(*delegateObj); PCODE targetAddress = (*delegateObj)->GetMethodPtr(); DelegateEEClass *pDelClass = (DelegateEEClass*)(*delegateObj)->GetMethodTable()->GetClass(); - if ((pDelClass->m_pInstRetBuffCallStub != NULL && pDelClass->m_pInstRetBuffCallStub->GetEntryPoint() == targetAddress) || - (pDelClass->m_pStaticCallStub != NULL && pDelClass->m_pStaticCallStub->GetEntryPoint() == targetAddress)) + if (pDelClass->m_pInstRetBuffCallStub == targetAddress || + pDelClass->m_pStaticCallStub == targetAddress) { // This implies that we're using a delegate shuffle thunk to strip off the first parameter to the method // and call the actual underlying method. We allow for tail-calls to work and for greater efficiency in the diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 42c2847edb8b49..7727e7d8114832 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -39,7 +39,6 @@ enum SignatureKind SK_STATIC_VIRTUAL_CODEPOINTER_CALLSITE, }; -class Stub; class MethodDesc; class NativeCodeVersion; class FieldDesc; diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 96f59fc2cbde2f..5d5e94f6ed0278 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -1762,7 +1762,7 @@ void AssemblyLoaderAllocator::Init() #ifndef FEATURE_PORTABLE_ENTRYPOINTS if (IsCollectible()) { - // TODO: the ShuffleThunkCache should really be using collectible stub-linked executable memory, however the unloadability support + // TODO: the ShuffleThunkCache should really be using collectible executable memory, however the unloadability support // doesn't track the stubs or the related delegate classes and so we get crashes when a stub is used after // the AssemblyLoaderAllocator is gone (the stub memory is unmapped). // https://github.com/dotnet/runtime/issues/55697 tracks this issue. diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index beb1567a81fef1..5b0763d3189915 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -45,7 +45,6 @@ class MethodDescChunk; class MethodTable; class Module; class Object; -class Stub; class Substitution; class TypeHandle; class Dictionary; diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 1ba3740b27031a..74342132dbc679 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -1517,7 +1517,7 @@ void MethodDesc::CreateDerivedTargetSig(MetaSig& msig, SigBuilder *stubSigBuilde } } -Stub * CreateUnboxingILStubForValueTypeMethods(MethodDesc* pTargetMD) +PCODE CreateUnboxingILStubForValueTypeMethods(MethodDesc* pTargetMD) { CONTRACTL @@ -1603,11 +1603,11 @@ Stub * CreateUnboxingILStubForValueTypeMethods(MethodDesc* pTargetMD) pResolver->SetStubTargetMethodSig(pTargetSig, cbTargetSig); pResolver->SetStubTargetMethodDesc(pTargetMD); - return Stub::NewStub(JitILStub(pStubMD)); + return JitILStub(pStubMD); } -Stub * CreateInstantiatingILStub(MethodDesc* pTargetMD, void* pHiddenArg) +PCODE CreateInstantiatingILStub(MethodDesc* pTargetMD, void* pHiddenArg) { CONTRACTL @@ -1696,11 +1696,11 @@ Stub * CreateInstantiatingILStub(MethodDesc* pTargetMD, void* pHiddenArg) pResolver->SetStubTargetMethodSig(pTargetSig, cbTargetSig); pResolver->SetStubTargetMethodDesc(pTargetMD); - return Stub::NewStub(JitILStub(pStubMD)); + return JitILStub(pStubMD); } /* Make a stub that for a value class method that expects a BOXed this pointer */ -Stub * MakeUnboxingStubWorker(MethodDesc *pMD) +PCODE MakeUnboxingStubWorker(MethodDesc *pMD) { CONTRACTL { @@ -1708,8 +1708,6 @@ Stub * MakeUnboxingStubWorker(MethodDesc *pMD) } CONTRACTL_END; - Stub *pstub = NULL; - _ASSERTE (pMD->GetMethodTable()->IsValueType()); _ASSERTE(!pMD->ContainsGenericVariables()); MethodDesc *pUnboxedMD = pMD->GetWrappedMethodDesc(); @@ -1757,7 +1755,7 @@ Stub * MakeUnboxingStubWorker(MethodDesc *pMD) } #if defined(FEATURE_SHARE_GENERIC_CODE) -Stub * MakeInstantiatingStubWorker(MethodDesc *pMD) +PCODE MakeInstantiatingStubWorker(MethodDesc *pMD) { CONTRACTL { @@ -2362,7 +2360,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo } CONTRACTL_END; - Stub *pStub = NULL; + PCODE pStub = NULL; PCODE pCode = (PCODE)NULL; Thread *pThread = GetThread(); @@ -2600,8 +2598,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo else { #ifdef FEATURE_PORTABLE_ENTRYPOINTS - pCode = pStub->GetEntryPoint(); - pStub->DecRef(); + pCode = pStub; void* ilStubInterpData = PortableEntryPoint::GetInterpreterData(pCode); _ASSERTE(ilStubInterpData != NULL); @@ -2613,16 +2610,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo PortableEntryPoint::SetInterpreterData(pCode, (PCODE)(TADDR)ilStubInterpData); SetCodeEntryPoint(pCode); #else // !FEATURE_PORTABLE_ENTRYPOINTS - if (!GetOrCreatePrecode()->SetTargetInterlocked(pStub->GetEntryPoint())) - { - pStub->DecRef(); - } - else if (pStub->HasExternalEntryPoint()) - { - // If the Stub wraps code that is outside of the Stub allocation, then we - // need to free the Stub allocation now. - pStub->DecRef(); - } + GetOrCreatePrecode()->SetTargetInterlocked(pStub); #if defined(FEATURE_INTERPRETER) && defined(HAS_FIXUP_PRECODE) if (GetOrCreatePrecode()->GetType() == PRECODE_FIXUP) { diff --git a/src/coreclr/vm/stubcache.cpp b/src/coreclr/vm/stubcache.cpp index 1901a2fb18d35c..e444a1df7cac38 100644 --- a/src/coreclr/vm/stubcache.cpp +++ b/src/coreclr/vm/stubcache.cpp @@ -52,8 +52,7 @@ StubCacheBase::~StubCacheBase() STUBHASHENTRY *phe = (STUBHASHENTRY*)GetFirst(); while (phe) { - _ASSERTE(NULL != phe->m_pStub); - phe->m_pStub->DecRef(); + _ASSERTE(NULL != phe->m_pCode); phe = (STUBHASHENTRY*)GetNext((BYTE*)phe); } } @@ -61,14 +60,10 @@ StubCacheBase::~StubCacheBase() //--------------------------------------------------------- -// Returns the equivalent hashed Stub, creating a new hash +// Returns the equivalent hashed code, creating a new hash // entry if necessary. If the latter, will call out to CompileStub. -// -// Refcounting: -// The caller is responsible for DecRef'ing the returned stub in -// order to avoid leaks. //--------------------------------------------------------- -Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) +PCODE StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) { CONTRACTL { @@ -78,7 +73,7 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) STUBHASHENTRY *phe = NULL; - StubHolder pstub; + PCODE pCode = NULL; { CrstHolder ch(&m_crst); @@ -86,12 +81,7 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) phe = (STUBHASHENTRY*)Find((LPVOID)pRawStub); if (phe) { - pstub = phe->m_pStub; - - // IncRef as we're returning a reference to our caller. - pstub->IncRef(); - - return pstub.Detach(); + return phe->m_pCode; } } @@ -104,7 +94,7 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) // and link up the stub. CodeLabel *plabel = psl->EmitNewCodeLabel(); psl->EmitBytes(pRawStub, Length(pRawStub)); - pstub = psl->Link(m_pLoaderAllocator, kind, stubType); + pCode = psl->Link(m_pLoaderAllocator, kind, stubType); UINT32 offset = psl->GetLabelOffset(plabel); if (offset > 0xffff) @@ -119,10 +109,10 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) { if (bNew) { - phe->m_pStub = pstub; + phe->m_pCode = pCode; phe->m_offsetOfRawStub = (UINT16)offset; - AddStub(pRawStub, pstub); + AddStub(pRawStub, pCode); } else { @@ -135,12 +125,9 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) // toggling between inlined TLSGetValue and api TLSGetValue. //_ASSERTE(phe->m_offsetOfRawStub == (UINT16)offset); - //Use the previously created stub - // This will DecRef the new stub for us. - pstub = phe->m_pStub; + // Use the previously created stub + pCode = phe->m_pCode; } - // IncRef so that caller has firm ownership of stub. - pstub->IncRef(); } } @@ -150,11 +137,11 @@ Stub *StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) COMPlusThrowOM(); } - return pstub.Detach(); + return pCode; } -void StubCacheBase::AddStub(const BYTE* pRawStub, Stub* pNewStub) +void StubCacheBase::AddStub(const BYTE* pRawStub, PCODE pNewStub) { LIMITED_METHOD_CONTRACT; @@ -235,11 +222,11 @@ CClosedHashBase::ELEMENTSTATUS StubCacheBase::Status( // The status of } CONTRACTL_END; - Stub *pStub = ((STUBHASHENTRY*)pElement)->m_pStub; + PCODE pCode = ((STUBHASHENTRY*)pElement)->m_pCode; - if (pStub == NULL) + if (pCode == NULL) return FREE; - else if (pStub == (Stub*)(-1)) + else if (pCode == (PCODE)-1) return DELETED; else return USED; @@ -264,8 +251,8 @@ void StubCacheBase::SetStatus( switch (eStatus) { - case FREE: phe->m_pStub = NULL; break; - case DELETED: phe->m_pStub = (Stub*)(-1); break; + case FREE: phe->m_pCode = NULL; break; + case DELETED: phe->m_pCode = (PCODE)-1; break; default: _ASSERTE(!"MLCacheEntry::SetStatus(): Bad argument."); } @@ -286,5 +273,5 @@ void *StubCacheBase::GetKey( // The data to hash on. CONTRACTL_END; STUBHASHENTRY *phe = (STUBHASHENTRY*)pElement; - return (void *)(phe->m_pStub->GetBlob() + phe->m_offsetOfRawStub); + return (void *)(PCODEToPINSTR(phe->m_pCode) + phe->m_offsetOfRawStub); } diff --git a/src/coreclr/vm/stubcache.h b/src/coreclr/vm/stubcache.h index 22d5b1361fc76e..5e91714934da40 100644 --- a/src/coreclr/vm/stubcache.h +++ b/src/coreclr/vm/stubcache.h @@ -17,7 +17,6 @@ #include "util.hpp" #include "crst.h" -class Stub; class StubLinker; enum StubCodeBlockKind : int; @@ -33,7 +32,7 @@ class StubCacheBase : private CClosedHashBase // NULL = free // -1 = deleted // other = used - Stub *m_pStub; + PCODE m_pCode; // Offset where the RawStub begins (the RawStub can be // preceded by native stub code.) @@ -53,12 +52,12 @@ class StubCacheBase : private CClosedHashBase virtual ~StubCacheBase(); //--------------------------------------------------------- - // Returns the equivalent hashed Stub, creating a new hash + // Returns the equivalent hashed code, creating a new hash // entry if necessary. If the latter, will call out to CompileStub. // // Throws on out of memory or other fatal error. //--------------------------------------------------------- - Stub *Canonicalize(const BYTE *pRawStub, const char *stubType); + PCODE Canonicalize(const BYTE *pRawStub, const char *stubType); protected: //--------------------------------------------------------- @@ -83,7 +82,7 @@ class StubCacheBase : private CClosedHashBase // OVERRIDE (OPTIONAL) // Notifies the various derived classes that a new stub has been created //--------------------------------------------------------- - virtual void AddStub(const BYTE* pRawStub, Stub* pNewStub); + virtual void AddStub(const BYTE* pRawStub, PCODE pNewStub); private: diff --git a/src/coreclr/vm/stubgen.h b/src/coreclr/vm/stubgen.h index 59b0020ca75393..f04b0ec05382a4 100644 --- a/src/coreclr/vm/stubgen.h +++ b/src/coreclr/vm/stubgen.h @@ -770,8 +770,6 @@ class ILStubLinker BOOL StubHasVoidReturnType(); - Stub *Link(LoaderHeap *pHeap, UINT *pcbSize /* = NULL*/, BOOL fMC); - size_t Link(UINT* puMaxStack); size_t GetNumEHClauses(); diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index f344d25c5539d0..b676df552fdae0 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -112,6 +112,18 @@ StubLinker::StubLinker() m_fDataOnly = FALSE; } +void StubLinker::SetTargetMethod(PTR_MethodDesc pMD) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + PRECONDITION(pMD != NULL); + } + CONTRACTL_END; + m_pTargetMethod = pMD; +} + //--------------------------------------------------------------- @@ -392,22 +404,6 @@ CodeLabel* StubLinker::NewExternalCodeLabel(LPVOID pExternalAddress) return pCodeLabel; } -//--------------------------------------------------------------- -// Set the target method for Instantiating stubs. -//--------------------------------------------------------------- -void StubLinker::SetTargetMethod(PTR_MethodDesc pMD) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - PRECONDITION(pMD != NULL); - } - CONTRACTL_END; - m_pTargetMethod = pMD; -} - - //--------------------------------------------------------------- // Append an instruction containing a reference to a label. // @@ -538,35 +534,23 @@ static BOOL LabelCanReach(LabelRef *pLabelRef) } //--------------------------------------------------------------- -// Generate the actual stub. The returned stub has a refcount of 1. +// Generate the actual stub. // No other methods (other than the destructor) should be called // after calling Link(). // // Throws exception on failure. //--------------------------------------------------------------- -Stub *StubLinker::Link(LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind, const char *stubType) +PCODE StubLinker::Link(LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind, const char *stubType) { STANDARD_VM_CONTRACT; int globalsize = 0; int size = CalculateSize(&globalsize); - DWORD flags = (m_pTargetMethod != NULL) ? NEWSTUB_FL_INSTANTIATING_METHOD : NEWSTUB_FL_NONE; - if (kind == STUB_CODE_BLOCK_SHUFFLE_THUNK) - { - flags |= NEWSTUB_FL_SHUFFLE_THUNK; - } - - StubHolder pStub{ Stub::NewStub( - pLoaderAllocator, - size, - flags) }; - ASSERT(pStub != NULL); - - EmitStub(pStub, pLoaderAllocator, kind, globalsize, size); + PCODE pCode = EmitStub(pLoaderAllocator, kind, globalsize, size); - PerfMap::LogStubs(__FUNCTION__, stubType, pStub->GetEntryPoint(), pStub->GetNumCodeBytes(), PerfMapStubType::Individual); + PerfMap::LogStubs(__FUNCTION__, stubType, pCode, size, PerfMapStubType::Individual); - return pStub.Detach(); + return pCode; } int StubLinker::CalculateSize(int* pGlobalSize) @@ -701,12 +685,12 @@ int StubLinker::CalculateSize(int* pGlobalSize) return globalsize + datasize; } -void StubLinker::EmitStub(Stub* pStub, LoaderAllocator* pLoaderAllocator, StubCodeBlockKind kind, int globalsize, int totalSize) +PCODE StubLinker::EmitStub(LoaderAllocator* pLoaderAllocator, StubCodeBlockKind kind, int globalsize, int totalSize) { STANDARD_VM_CONTRACT; S_SIZE_T allocationSize(totalSize); - allocationSize += CODE_SIZE_ALIGN; + allocationSize += sizeof(PTR_MethodDesc) + CODE_SIZE_ALIGN - 1; if (allocationSize.IsOverflow()) COMPlusThrowArithmetic(); @@ -715,14 +699,13 @@ void StubLinker::EmitStub(Stub* pStub, LoaderAllocator* pLoaderAllocator, StubCo CODE_SIZE_ALIGN, pLoaderAllocator, kind)); - size_t codeOffset = ALIGN_UP(reinterpret_cast(pBlock) + sizeof(PTR_Stub), CODE_SIZE_ALIGN) - reinterpret_cast(pBlock); + size_t codeOffset = ALIGN_UP(reinterpret_cast(pBlock) + sizeof(PTR_MethodDesc), CODE_SIZE_ALIGN) - reinterpret_cast(pBlock); BYTE* pCode = pBlock + codeOffset; - pStub->m_entryPoint = pCode; ExecutableWriterHolder stubWriterHolder(pBlock, allocationSize.Value()); BYTE* pBlockRW = stubWriterHolder.GetRW(); BYTE* pCodeRW = pBlockRW + codeOffset; - SET_UNALIGNED_PTR(pCodeRW - sizeof(PTR_Stub), reinterpret_cast(pStub)); + SET_UNALIGNED_PTR(pCodeRW - sizeof(PTR_MethodDesc), reinterpret_cast(m_pTargetMethod)); BYTE *pDataRW = pCodeRW+globalsize; // start of data area { @@ -788,184 +771,23 @@ void StubLinker::EmitStub(Stub* pStub, LoaderAllocator* pLoaderAllocator, StubCo ZeroMemory(pCodeRW + lastCodeOffset, globalsize - lastCodeOffset); } - // Fill in the target method for the Instantiating stub. - if (pStub->IsInstantiatingStub()) - { - _ASSERTE(m_pTargetMethod != NULL); - pStub->SetInstantiatedMethodDesc(m_pTargetMethod); - - LOG((LF_CORDB, LL_INFO100, "SL::ES: InstantiatedMethod fd:0x%x\n", - pStub->GetInstantiatedMethodDesc())); - } - if (!m_fDataOnly) { FlushInstructionCache(GetCurrentProcess(), pCode, globalsize); } _ASSERTE(m_fDataOnly || DbgIsExecutable(pCode, globalsize)); -} - -#endif // #ifndef DACCESS_COMPILE - -#ifndef DACCESS_COMPILE -//------------------------------------------------------------------- -// Inc the refcount. -//------------------------------------------------------------------- -VOID Stub::IncRef() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; +#ifdef TARGET_ARM - _ASSERTE(m_signature == kUsedStub); - InterlockedIncrement((LONG*)&m_refcount); -} - -//------------------------------------------------------------------- -// Dec the refcount. -//------------------------------------------------------------------- -BOOL Stub::DecRef() -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - - _ASSERTE(m_signature == kUsedStub); - int count = InterlockedDecrement((LONG*)&m_refcount); - if (count <= 0) { - DeleteStub(); - return TRUE; - } - return FALSE; -} - -VOID Stub::DeleteStub() -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - - if ((m_numCodeBytesAndFlags & LOADER_HEAP_BIT) == 0) - { -#ifdef _DEBUG - m_signature = kFreedStub; - FillMemory(this, sizeof(*this), 0xcc); +#ifndef THUMB_CODE +#define THUMB_CODE 1 #endif - delete [] reinterpret_cast(this); - } -} - -Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END; - - Stub* pStub = NewStub(NULL, 0, flags | NEWSTUB_FL_EXTERNAL); - pStub->m_entryPoint = reinterpret_cast(pCode); - - return pStub; -} - -//------------------------------------------------------------------- -// Stub allocation done here. -//------------------------------------------------------------------- -/*static*/ Stub* Stub::NewStub( - LoaderAllocator *pLoaderAllocator, - UINT numCodeBytes, - DWORD flags) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END; - - S_SIZE_T size = S_SIZE_T(sizeof(Stub)); - - if (flags & NEWSTUB_FL_EXTERNAL) - { - _ASSERTE(pLoaderAllocator == NULL); - _ASSERTE(numCodeBytes == 0); - } - - if (size.IsOverflow()) - COMPlusThrowArithmetic(); - - size_t totalSize = size.Value(); - - BYTE *pBlock; - if (pLoaderAllocator == NULL) - { - pBlock = new BYTE[totalSize]; - } - else - { - TaggedMemAllocPtr ptr = pLoaderAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(totalSize)); - pBlock = static_cast(static_cast(ptr)); - flags |= NEWSTUB_FL_LOADERHEAP; - } - - Stub* pStub = reinterpret_cast(pBlock); - pStub->SetupStub(numCodeBytes, flags); - - return pStub; -} - -void Stub::SetupStub(int numCodeBytes, DWORD flags) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END; - -#ifdef _DEBUG - m_signature = kUsedStub; -#ifdef HOST_64BIT - m_pad_code_bytes1 = 0; - m_pad_code_bytes2 = 0; - m_pad_code_bytes3 = 0; -#endif + return (PCODE)(reinterpret_cast(pCode) | THUMB_CODE); +#else + return (PCODE)pCode; #endif - - if (((DWORD)numCodeBytes) >= MAX_CODEBYTES) - COMPlusThrowHR(COR_E_OVERFLOW); - - m_numCodeBytesAndFlags = numCodeBytes; - - m_entryPoint = NULL; - m_refcount = 1; - m_data = {}; - - if (flags != NEWSTUB_FL_NONE) - { - if((flags & NEWSTUB_FL_LOADERHEAP) != 0) - m_numCodeBytesAndFlags |= LOADER_HEAP_BIT; - if ((flags & NEWSTUB_FL_EXTERNAL) != 0) - m_numCodeBytesAndFlags |= EXTERNAL_ENTRY_BIT; - if ((flags & NEWSTUB_FL_INSTANTIATING_METHOD) != 0) - m_numCodeBytesAndFlags |= INSTANTIATING_STUB_BIT; - if ((flags & NEWSTUB_FL_SHUFFLE_THUNK) != 0) - m_numCodeBytesAndFlags |= SHUFFLE_THUNK_BIT; - } } #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/stublink.h b/src/coreclr/vm/stublink.h index 6fbed06a055d74..ea362c0e9e59bd 100644 --- a/src/coreclr/vm/stublink.h +++ b/src/coreclr/vm/stublink.h @@ -59,7 +59,6 @@ enum StubCodeBlockKind : int; // Forward refs //------------------------------------------------------------------------- class InstructionFormat; -class Stub; class CheckDuplicatedStructLayouts; class CodeBasedStubCache; struct CodeLabel; @@ -146,9 +145,6 @@ class StubLinker return NewExternalCodeLabel((LPVOID)pExternalAddress); } - //--------------------------------------------------------------- - // Set the target method for Instantiating stubs. - //--------------------------------------------------------------- void SetTargetMethod(PTR_MethodDesc pMD); //--------------------------------------------------------------- @@ -172,13 +168,13 @@ class StubLinker public: //--------------------------------------------------------------- - // Generate the actual stub. The returned stub has a refcount of 1. + // Generate the actual stub. // No other methods (other than the destructor) should be called // after calling Link(). // // Throws exception on failure. //--------------------------------------------------------------- - Stub *Link(LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind, const char *stubType); + PCODE Link(LoaderAllocator *pLoaderAllocator, StubCodeBlockKind kind, const char *stubType); private: CodeElement *m_pCodeElements; // stored in *reverse* order @@ -211,7 +207,7 @@ class StubLinker virtual int CalculateSize(int* globalsize); // Writes out the code element into a code fragment. - void EmitStub(Stub* pStub, LoaderAllocator* pLoaderAllocator, StubCodeBlockKind kind, int globalsize, int totalSize); + PCODE EmitStub(LoaderAllocator* pLoaderAllocator, StubCodeBlockKind kind, int globalsize, int totalSize); CodeRun *GetLastCodeRunIfAny(); }; @@ -251,275 +247,6 @@ struct CodeLabel }; }; -enum NewStubFlags -{ - NEWSTUB_FL_NONE = 0x00000000, - NEWSTUB_FL_INSTANTIATING_METHOD = 0x00000001, - NEWSTUB_FL_EXTERNAL = 0x00000002, - NEWSTUB_FL_LOADERHEAP = 0x00000004, - NEWSTUB_FL_SHUFFLE_THUNK = 0x00000008 -}; - - -//------------------------------------------------------------------------- -// An executable stub. These can only be created by the StubLinker(). -// Each stub has a reference count (which is maintained in a thread-safe -// manner.) When the ref-count goes to zero, the stub automatically -// cleans itself up. -//------------------------------------------------------------------------- -typedef DPTR(class Stub) PTR_Stub; -typedef DPTR(PTR_Stub) PTR_PTR_Stub; -class Stub -{ - friend class CheckDuplicatedStructLayouts; - friend class CheckAsmOffsets; - friend class StubLinker; - - protected: - enum - { - EXTERNAL_ENTRY_BIT = 0x80000000, - LOADER_HEAP_BIT = 0x40000000, - INSTANTIATING_STUB_BIT = 0x20000000, - SHUFFLE_THUNK_BIT = 0x10000000, - - CODEBYTES_MASK = SHUFFLE_THUNK_BIT - 1, - MAX_CODEBYTES = CODEBYTES_MASK + 1, - }; - static_assert(CODEBYTES_MASK < SHUFFLE_THUNK_BIT); - - public: - //------------------------------------------------------------------- - // Inc the refcount. - //------------------------------------------------------------------- - VOID IncRef(); - - //------------------------------------------------------------------- - // Dec the refcount. - // Returns true if the count went to zero and the stub was deleted - //------------------------------------------------------------------- - BOOL DecRef(); - - //------------------------------------------------------------------- - // Used for throwing out unused stubs from stub caches. This - // method cannot be 100% accurate due to race conditions. This - // is ok because stub cache management is robust in the face - // of missed or premature cleanups. - //------------------------------------------------------------------- - BOOL HeuristicLooksOrphaned() - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(m_signature == kUsedStub); - return m_refcount == 1; - } - - //------------------------------------------------------------------- - // Used by the debugger to help step through stubs - //------------------------------------------------------------------- - BOOL IsInstantiatingStub() - { - LIMITED_METHOD_CONTRACT; - return (m_numCodeBytesAndFlags & INSTANTIATING_STUB_BIT) != 0; - } - - //------------------------------------------------------------------- - // Used by the debugger to help step through stubs - //------------------------------------------------------------------- - BOOL IsShuffleThunk() - { - LIMITED_METHOD_CONTRACT; - return (m_numCodeBytesAndFlags & SHUFFLE_THUNK_BIT) != 0; - } - - //------------------------------------------------------------------- - // For instantiating methods, the target MethodDesc needs to be set - // to tell the debugger where to step through the instantiating method - // stub. - //------------------------------------------------------------------- - void SetInstantiatedMethodDesc(PTR_MethodDesc pMD) - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(IsInstantiatingStub()); - m_data.InstantiatedMethod = pMD; - } - - //------------------------------------------------------------------- - // For instantiating methods, the target MethodDesc needs to be set - // to tell the debugger where to step through the instantiating method - // stub. - //------------------------------------------------------------------- - PTR_MethodDesc GetInstantiatedMethodDesc() - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(IsInstantiatingStub()); - return m_data.InstantiatedMethod; - } - - //------------------------------------------------------------------- - //------------------------------------------------------------------- - // Return executable entrypoint after checking the ref count. - //------------------------------------------------------------------- - PCODE GetEntryPoint() - { - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - _ASSERTE(m_signature == kUsedStub); - _ASSERTE(m_refcount > 0); - - TADDR pEntryPoint = dac_cast(GetEntryPointInternal()); - -#ifdef TARGET_ARM - -#ifndef THUMB_CODE -#define THUMB_CODE 1 -#endif - - pEntryPoint |= THUMB_CODE; -#endif - - return pEntryPoint; - } - - UINT GetNumCodeBytes() - { - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - return m_numCodeBytesAndFlags & CODEBYTES_MASK; - } - - //------------------------------------------------------------------- - // Return start of the stub code - //------------------------------------------------------------------- - PTR_CBYTE GetBlob() - { - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - _ASSERTE(m_signature == kUsedStub); - _ASSERTE(m_refcount > 0); - - return GetEntryPointInternal(); - } - - //------------------------------------------------------------------- - // Return the Stub and code size. - //------------------------------------------------------------------- - static Stub* RecoverStubAndSize(PCODE pEntryPoint, DWORD *pSize) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - - PRECONDITION(pEntryPoint && pSize); - } - CONTRACTL_END; - - Stub *pStub = Stub::RecoverStub(pEntryPoint); - *pSize = pStub->GetNumCodeBytes(); - return pStub; - } - - //------------------------------------------------------------------- - // Reverse GetEntryPoint. - //------------------------------------------------------------------- - static Stub* RecoverStub(PCODE pEntryPoint) - { - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - - TADDR pStubData = PCODEToPINSTR(pEntryPoint); - - Stub *pStub = *dac_cast(pStubData - sizeof(PTR_Stub)); - -#if !defined(DACCESS_COMPILE) - _ASSERTE(pStub->m_signature == kUsedStub); - _ASSERTE(pStub->GetEntryPoint() == pEntryPoint); -#elif defined(_DEBUG) - // If this isn't really a stub we don't want - // to continue with it. - // TODO: This should be removed once IsStub - // can adverstise whether it's safe to call - // further StubManager methods. - if (pStub->m_signature != kUsedStub || - pStub->GetEntryPoint() != pEntryPoint) - { - DacError(E_INVALIDARG); - } -#endif - return pStub; - } - - //------------------------------------------------------------------- - // Returns TRUE if entry point is not inside the Stub allocation. - //------------------------------------------------------------------- - BOOL HasExternalEntryPoint() const - { - LIMITED_METHOD_CONTRACT; - - return (m_numCodeBytesAndFlags & EXTERNAL_ENTRY_BIT) != 0; - } - - //------------------------------------------------------------------- - // This creates stub metadata. - //------------------------------------------------------------------- - static Stub* NewStub(LoaderAllocator *pLoaderAllocator, UINT numCodeBytes, - DWORD flags = NEWSTUB_FL_NONE); - - static Stub* NewStub(PTR_VOID pCode, DWORD flags = NEWSTUB_FL_NONE); - static Stub* NewStub(PCODE pCode, DWORD flags = NEWSTUB_FL_NONE) - { - return NewStub((PTR_VOID)pCode, flags); - } - - protected: - void SetupStub(int numCodeBytes, DWORD flags); - void DeleteStub(); - - //------------------------------------------------------------------- - // Return executable entrypoint without checking the ref count. - //------------------------------------------------------------------- - inline PTR_CBYTE GetEntryPointInternal() - { - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - - _ASSERTE(m_signature == kUsedStub); - - - return m_entryPoint; - } - - PTR_CBYTE m_entryPoint; - UINT32 m_refcount; - UINT32 m_numCodeBytesAndFlags; - union - { - // Stub kind specific data - PTR_MethodDesc InstantiatedMethod; // Valid for IsInstantiatingStub() only - } m_data; - -#ifdef _DEBUG - enum { - kUsedStub = 0x42555453, // 'STUB' - kFreedStub = 0x46555453, // 'STUF' - }; - - UINT32 m_signature; -#ifdef HOST_64BIT - //README ALIGNMENT: Enusure code after the Stub struct align to 16-bytes. - UINT32 m_pad_code_bytes1; - UINT32 m_pad_code_bytes2; - UINT32 m_pad_code_bytes3; -#endif // HOST_64BIT -#endif // _DEBUG - - Stub() = delete; // Stubs are created by NewStub(), not "new". -}; - //------------------------------------------------------------------------- // Each platform encodes the "branch" instruction in a different // way. We use objects derived from InstructionFormat to abstract this diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 798512431309bd..76acef4775942a 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1264,6 +1264,17 @@ BOOL StubLinkStubManager::CheckIsStub_Internal(PCODE stubStartAddress) return FALSE; } +typedef DPTR(PTR_MethodDesc) PTR_PTR_MethodDesc; + +static PTR_MethodDesc GetStubTargetMethod(PCODE stubStartAddress) +{ + STATIC_CONTRACT_NOTHROW; + STATIC_CONTRACT_GC_NOTRIGGER; + + TADDR pStubData = PCODEToPINSTR(stubStartAddress); + return *dac_cast(pStubData - sizeof(PTR_MethodDesc)); +} + BOOL StubLinkStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestination *trace) { @@ -1280,19 +1291,14 @@ BOOL StubLinkStubManager::DoTraceStub(PCODE stubStartAddress, "StubLinkStubManager::DoTraceStub: stubStartAddress=%p\n", stubStartAddress)); - Stub *stub = Stub::RecoverStub(stubStartAddress); - - LOG((LF_CORDB, LL_INFO10000, - "StubLinkStubManager::DoTraceStub: stub=%p\n", stub)); - - TADDR pRealAddr = 0; - if (stub->IsInstantiatingStub()) + StubCodeBlockKind kind = RangeSectionStubManager::GetStubKind(stubStartAddress); + if (kind == STUB_CODE_BLOCK_WRAPPER_STUB && GetStubTargetMethod(stubStartAddress) != NULL) { trace->InitForManagerPush(stubStartAddress, this); LOG_TRACE_DESTINATION(trace, stubStartAddress, "StubLinkStubManager(InstantiatingMethod)::DoTraceStub"); return TRUE; } - else if (stub->IsShuffleThunk()) + else if (kind == STUB_CODE_BLOCK_SHUFFLE_THUNK) { trace->InitForManagerPush(stubStartAddress, this); LOG_TRACE_DESTINATION(trace, stubStartAddress, "StubLinkStubManager(ShuffleThunk)::DoTraceStub"); @@ -1374,11 +1380,11 @@ BOOL StubLinkStubManager::TraceManager(Thread *thread, *pRetAddr = (BYTE *)StubManagerHelpers::GetReturnAddress(pContext); LOG((LF_CORDB,LL_INFO10000, "SLSM:TM %p, retAddr is %p\n", pc, (*pRetAddr))); - Stub *stub = Stub::RecoverStub((PCODE)pc); - if (stub->IsInstantiatingStub()) + StubCodeBlockKind kind = RangeSectionStubManager::GetStubKind((PCODE)pc); + if (kind == STUB_CODE_BLOCK_WRAPPER_STUB) { LOG((LF_CORDB,LL_INFO10000, "SLSM:TM Instantiating method stub\n")); - PTR_MethodDesc pMD = stub->GetInstantiatedMethodDesc(); + PTR_MethodDesc pMD = GetStubTargetMethod((PCODE)pc); _ASSERTE(pMD != NULL); PCODE target = GetStubTarget(pMD); @@ -1392,7 +1398,7 @@ BOOL StubLinkStubManager::TraceManager(Thread *thread, trace->InitForManaged(target); return TRUE; } - else if (stub->IsShuffleThunk()) + else if (kind == STUB_CODE_BLOCK_SHUFFLE_THUNK) { LOG((LF_CORDB,LL_INFO10000, "SLSM:TM ShuffleThunk\n")); return TraceShuffleThunk(trace, pContext, pRetAddr); From ce2ada8b99e02f193bf0a867e9c263ed12fad3fa Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 5 Aug 2026 18:58:16 -0700 Subject: [PATCH 07/17] Update src/coreclr/vm/eventtrace.cpp --- src/coreclr/vm/eventtrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index c60e96e66391e0..8c1242ea4eccdf 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -3623,7 +3623,7 @@ VOID ETW::MethodLog::StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pH TRACE_LEVEL_INFORMATION, CLR_JIT_KEYWORD)) { - DWORD dwHelperSize = 0; + DWORD dwHelperSize = 1; ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName); } } EX_CATCH { } EX_END_CATCH From c6c56d39f8697b149b5232d98c5fcb8069d3ae78 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 02:20:08 +0000 Subject: [PATCH 08/17] Remove unused delegate destruction block Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/class.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 5d033d0e089613..0fa9beba441e8b 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -81,12 +81,6 @@ void EEClass::Destruct() #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION #endif // FEATURE_COMINTEROP - - if (IsDelegate()) - { - DelegateEEClass* pDelegateEEClass = (DelegateEEClass*)this; - } - #ifdef FEATURE_COMINTEROP if (GetSparseCOMInteropVTableMap() != NULL) delete GetSparseCOMInteropVTableMap(); From 30617da7499d43e6a8a79f44fdbdeb95ab858525 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 02:32:18 +0000 Subject: [PATCH 09/17] Reserve MethodDesc slot only when set; restore SetTargetMethod location Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/i386/stublinkerx86.cpp | 2 ++ src/coreclr/vm/stublink.cpp | 42 +++++++++++++++++---------- src/coreclr/vm/stubmgr.cpp | 2 +- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index 39b04902f1385b..9b8a394f87238e 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -871,6 +871,7 @@ bool StubLinkerCPU::EmitUnboxMethodStub(MethodDesc* pUnboxMD) // X86EmitAddReg(THIS_kREG, sizeof(void*)); EmitTailJumpToMethod(pUnboxMD); + SetTargetMethod(pUnboxMD); return true; } @@ -944,6 +945,7 @@ bool StubLinkerCPU::EmitInstantiatingMethodStub(MethodDesc* pMD, void* extra) } EmitTailJumpToMethod(pMD); + SetTargetMethod(pMD); return true; #endif // UNIX_X86_ABI diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index b676df552fdae0..c221b822e09bdd 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -112,18 +112,6 @@ StubLinker::StubLinker() m_fDataOnly = FALSE; } -void StubLinker::SetTargetMethod(PTR_MethodDesc pMD) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - PRECONDITION(pMD != NULL); - } - CONTRACTL_END; - m_pTargetMethod = pMD; -} - //--------------------------------------------------------------- @@ -404,6 +392,22 @@ CodeLabel* StubLinker::NewExternalCodeLabel(LPVOID pExternalAddress) return pCodeLabel; } +//--------------------------------------------------------------- +// Set the target method for Instantiating stubs. +//--------------------------------------------------------------- +void StubLinker::SetTargetMethod(PTR_MethodDesc pMD) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + PRECONDITION(pMD != NULL); + } + CONTRACTL_END; + m_pTargetMethod = pMD; +} + + //--------------------------------------------------------------- // Append an instruction containing a reference to a label. // @@ -689,8 +693,13 @@ PCODE StubLinker::EmitStub(LoaderAllocator* pLoaderAllocator, StubCodeBlockKind { STANDARD_VM_CONTRACT; + // The target method is stored right before the code of the stub. It is used by the debugger + // to trace through the stub. + size_t headerSize = (m_pTargetMethod != NULL) ? sizeof(PTR_MethodDesc) : 0; + _ASSERTE((kind == STUB_CODE_BLOCK_WRAPPER_STUB) == (m_pTargetMethod != NULL)); + S_SIZE_T allocationSize(totalSize); - allocationSize += sizeof(PTR_MethodDesc) + CODE_SIZE_ALIGN - 1; + allocationSize += headerSize + CODE_SIZE_ALIGN - 1; if (allocationSize.IsOverflow()) COMPlusThrowArithmetic(); @@ -699,13 +708,16 @@ PCODE StubLinker::EmitStub(LoaderAllocator* pLoaderAllocator, StubCodeBlockKind CODE_SIZE_ALIGN, pLoaderAllocator, kind)); - size_t codeOffset = ALIGN_UP(reinterpret_cast(pBlock) + sizeof(PTR_MethodDesc), CODE_SIZE_ALIGN) - reinterpret_cast(pBlock); + size_t codeOffset = ALIGN_UP(reinterpret_cast(pBlock) + headerSize, CODE_SIZE_ALIGN) - reinterpret_cast(pBlock); BYTE* pCode = pBlock + codeOffset; ExecutableWriterHolder stubWriterHolder(pBlock, allocationSize.Value()); BYTE* pBlockRW = stubWriterHolder.GetRW(); BYTE* pCodeRW = pBlockRW + codeOffset; - SET_UNALIGNED_PTR(pCodeRW - sizeof(PTR_MethodDesc), reinterpret_cast(m_pTargetMethod)); + if (m_pTargetMethod != NULL) + { + SET_UNALIGNED_PTR(pCodeRW - sizeof(PTR_MethodDesc), reinterpret_cast(m_pTargetMethod)); + } BYTE *pDataRW = pCodeRW+globalsize; // start of data area { diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 76acef4775942a..4c188502cf758e 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1292,7 +1292,7 @@ BOOL StubLinkStubManager::DoTraceStub(PCODE stubStartAddress, stubStartAddress)); StubCodeBlockKind kind = RangeSectionStubManager::GetStubKind(stubStartAddress); - if (kind == STUB_CODE_BLOCK_WRAPPER_STUB && GetStubTargetMethod(stubStartAddress) != NULL) + if (kind == STUB_CODE_BLOCK_WRAPPER_STUB) { trace->InitForManagerPush(stubStartAddress, this); LOG_TRACE_DESTINATION(trace, stubStartAddress, "StubLinkStubManager(InstantiatingMethod)::DoTraceStub"); From e970986f4bef93768ed131ac646c5d3bb57ca439 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 02:58:24 +0000 Subject: [PATCH 10/17] Address StubLinker review feedback Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/codeman.h | 20 +++++++------- src/coreclr/vm/stublink.cpp | 11 +------- src/coreclr/vm/stublink.h | 3 +++ src/coreclr/vm/stubmgr.cpp | 54 ++++++++++++++++++------------------- 4 files changed, 40 insertions(+), 48 deletions(-) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index f7bb70c8f5d59e..5128c0429c4e26 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -125,16 +125,6 @@ inline const char *GetStubCodeBlockKindString(StubCodeBlockKind kind) { case STUB_CODE_BLOCK_JUMPSTUB: return "JumpStub"; - case STUB_CODE_BLOCK_METHOD_CALL_THUNK: - return "MethodCallThunk"; -#ifdef FEATURE_TIERED_COMPILATION - case STUB_CODE_BLOCK_CALLCOUNTING: - return "CallCountingStub"; -#endif - case STUB_CODE_BLOCK_WRAPPER_STUB: - return "WrapperStub"; - case STUB_CODE_BLOCK_SHUFFLE_THUNK: - return "ShuffleThunk"; case STUB_CODE_BLOCK_DYNAMICHELPER: return "MethodCallThunk"; case STUB_CODE_BLOCK_FIXUPPRECODE: @@ -149,6 +139,16 @@ inline const char *GetStubCodeBlockKindString(StubCodeBlockKind kind) case STUB_CODE_BLOCK_VSD_VTABLE_STUB: return "VSD_VTableStub"; #endif // FEATURE_VIRTUAL_STUB_DISPATCH +#ifdef FEATURE_TIERED_COMPILATION + case STUB_CODE_BLOCK_CALLCOUNTING: + return "CallCountingStub"; +#endif // FEATURE_TIERED_COMPILATION + case STUB_CODE_BLOCK_WRAPPER_STUB: + return "WrapperStub"; + case STUB_CODE_BLOCK_SHUFFLE_THUNK: + return "ShuffleThunk"; + case STUB_CODE_BLOCK_METHOD_CALL_THUNK: + return "MethodCallThunk"; default: return "Unknown"; } diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index c221b822e09bdd..43b2e513e21dfd 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -790,16 +790,7 @@ PCODE StubLinker::EmitStub(LoaderAllocator* pLoaderAllocator, StubCodeBlockKind _ASSERTE(m_fDataOnly || DbgIsExecutable(pCode, globalsize)); -#ifdef TARGET_ARM - -#ifndef THUMB_CODE -#define THUMB_CODE 1 -#endif - - return (PCODE)(reinterpret_cast(pCode) | THUMB_CODE); -#else - return (PCODE)pCode; -#endif + return PINSTRToPCODE(reinterpret_cast(pCode)); } #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/stublink.h b/src/coreclr/vm/stublink.h index ea362c0e9e59bd..012abe2a74d9d1 100644 --- a/src/coreclr/vm/stublink.h +++ b/src/coreclr/vm/stublink.h @@ -145,6 +145,9 @@ class StubLinker return NewExternalCodeLabel((LPVOID)pExternalAddress); } + //--------------------------------------------------------------- + // Set the target method for wrapper stubs. + //--------------------------------------------------------------- void SetTargetMethod(PTR_MethodDesc pMD); //--------------------------------------------------------------- diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 4c188502cf758e..87c559554f2ec0 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1444,18 +1444,18 @@ BOOL RangeSectionStubManager::CheckIsStub_Internal(PCODE stubStartAddress) switch (GetStubKind(stubStartAddress)) { case STUB_CODE_BLOCK_JUMPSTUB: - case STUB_CODE_BLOCK_METHOD_CALL_THUNK: - case STUB_CODE_BLOCK_WRAPPER_STUB: - case STUB_CODE_BLOCK_SHUFFLE_THUNK: -#ifdef FEATURE_TIERED_COMPILATION - case STUB_CODE_BLOCK_CALLCOUNTING: -#endif // FEATURE_TIERED_COMPILATION #ifdef FEATURE_VIRTUAL_STUB_DISPATCH 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: #endif // FEATURE_VIRTUAL_STUB_DISPATCH +#ifdef FEATURE_TIERED_COMPILATION + case STUB_CODE_BLOCK_CALLCOUNTING: +#endif // FEATURE_TIERED_COMPILATION + case STUB_CODE_BLOCK_WRAPPER_STUB: + case STUB_CODE_BLOCK_SHUFFLE_THUNK: + case STUB_CODE_BLOCK_METHOD_CALL_THUNK: return TRUE; default: break; @@ -1486,17 +1486,6 @@ BOOL RangeSectionStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestinati return TRUE; } #endif // FEATURE_DYNAMIC_CODE_COMPILED - case STUB_CODE_BLOCK_WRAPPER_STUB: - case STUB_CODE_BLOCK_SHUFFLE_THUNK: - return StubLinkStubManager::g_pManager->DoTraceStub(stubStartAddress, trace); -#ifdef FEATURE_TIERED_COMPILATION - case STUB_CODE_BLOCK_CALLCOUNTING: - { - trace->InitForStub(CallCountingManager::GetTargetForMethod(stubStartAddress)); - return TRUE; - } -#endif // FEATURE_TIERED_COMPILATION - #ifdef FEATURE_VIRTUAL_STUB_DISPATCH case STUB_CODE_BLOCK_VSD_DISPATCH_STUB: case STUB_CODE_BLOCK_VSD_RESOLVE_STUB: @@ -1504,6 +1493,16 @@ BOOL RangeSectionStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestinati case STUB_CODE_BLOCK_VSD_VTABLE_STUB: return VirtualCallStubManagerManager::GlobalManager()->DoTraceStub(stubStartAddress, trace); #endif // FEATURE_VIRTUAL_STUB_DISPATCH +#ifdef FEATURE_TIERED_COMPILATION + case STUB_CODE_BLOCK_CALLCOUNTING: + { + trace->InitForStub(CallCountingManager::GetTargetForMethod(stubStartAddress)); + return TRUE; + } +#endif // FEATURE_TIERED_COMPILATION + case STUB_CODE_BLOCK_WRAPPER_STUB: + case STUB_CODE_BLOCK_SHUFFLE_THUNK: + return StubLinkStubManager::g_pManager->DoTraceStub(stubStartAddress, trace); case STUB_CODE_BLOCK_METHOD_CALL_THUNK: #ifdef DACCESS_COMPILE @@ -1529,17 +1528,6 @@ LPCWSTR RangeSectionStubManager::GetStubManagerName(PCODE addr) { case STUB_CODE_BLOCK_JUMPSTUB: return W("JumpStub"); - case STUB_CODE_BLOCK_METHOD_CALL_THUNK: - return W("MethodCallThunk"); - case STUB_CODE_BLOCK_WRAPPER_STUB: - return W("WrapperStub"); - case STUB_CODE_BLOCK_SHUFFLE_THUNK: - return W("ShuffleThunk"); -#ifdef FEATURE_TIERED_COMPILATION - case STUB_CODE_BLOCK_CALLCOUNTING: - return W("CallCountingStub"); -#endif // FEATURE_TIERED_COMPILATION - #ifdef FEATURE_VIRTUAL_STUB_DISPATCH case STUB_CODE_BLOCK_VSD_DISPATCH_STUB: return W("VSD_DispatchStub"); @@ -1553,6 +1541,16 @@ LPCWSTR RangeSectionStubManager::GetStubManagerName(PCODE addr) case STUB_CODE_BLOCK_VSD_VTABLE_STUB: return W("VSD_VTableStub"); #endif // FEATURE_VIRTUAL_STUB_DISPATCH +#ifdef FEATURE_TIERED_COMPILATION + case STUB_CODE_BLOCK_CALLCOUNTING: + return W("CallCountingStub"); +#endif // FEATURE_TIERED_COMPILATION + case STUB_CODE_BLOCK_WRAPPER_STUB: + return W("WrapperStub"); + case STUB_CODE_BLOCK_SHUFFLE_THUNK: + return W("ShuffleThunk"); + case STUB_CODE_BLOCK_METHOD_CALL_THUNK: + return W("MethodCallThunk"); default: break; From ee6640b2403738c27c0790176471130eb86dd5c8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 05:23:26 +0000 Subject: [PATCH 11/17] Fix PCODE/NULL comparisons that broke the build Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/prestub.cpp | 4 ++-- src/coreclr/vm/stubcache.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 74342132dbc679..cb032e1536029d 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2360,7 +2360,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo } CONTRACTL_END; - PCODE pStub = NULL; + PCODE pStub = (PCODE)NULL; PCODE pCode = (PCODE)NULL; Thread *pThread = GetThread(); @@ -2574,7 +2574,7 @@ PCODE MethodDesc::DoPrestub(MethodTable *pDispatchingMT, CallerGCMode callerGCMo // At this point we must have either a pointer to managed code or to a stub. All of the above code // should have thrown an exception if it couldn't make a stub. - _ASSERTE((pStub != NULL) ^ (pCode != (PCODE)NULL)); + _ASSERTE((pStub != (PCODE)NULL) ^ (pCode != (PCODE)NULL)); #if defined(TARGET_X86) || defined(TARGET_AMD64) // diff --git a/src/coreclr/vm/stubcache.cpp b/src/coreclr/vm/stubcache.cpp index e444a1df7cac38..bcca028666463b 100644 --- a/src/coreclr/vm/stubcache.cpp +++ b/src/coreclr/vm/stubcache.cpp @@ -52,7 +52,7 @@ StubCacheBase::~StubCacheBase() STUBHASHENTRY *phe = (STUBHASHENTRY*)GetFirst(); while (phe) { - _ASSERTE(NULL != phe->m_pCode); + _ASSERTE((PCODE)NULL != phe->m_pCode); phe = (STUBHASHENTRY*)GetNext((BYTE*)phe); } } @@ -73,7 +73,7 @@ PCODE StubCacheBase::Canonicalize(const BYTE * pRawStub, const char *stubType) STUBHASHENTRY *phe = NULL; - PCODE pCode = NULL; + PCODE pCode = (PCODE)NULL; { CrstHolder ch(&m_crst); @@ -224,7 +224,7 @@ CClosedHashBase::ELEMENTSTATUS StubCacheBase::Status( // The status of PCODE pCode = ((STUBHASHENTRY*)pElement)->m_pCode; - if (pCode == NULL) + if (pCode == (PCODE)NULL) return FREE; else if (pCode == (PCODE)-1) return DELETED; @@ -251,7 +251,7 @@ void StubCacheBase::SetStatus( switch (eStatus) { - case FREE: phe->m_pCode = NULL; break; + case FREE: phe->m_pCode = (PCODE)NULL; break; case DELETED: phe->m_pCode = (PCODE)-1; break; default: _ASSERTE(!"MLCacheEntry::SetStatus(): Bad argument."); From 152f79267b9aad6413ddc4e779c46b6779ffa6be Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 05:40:25 +0000 Subject: [PATCH 12/17] Assert pointer alignment and use direct assignment for target method write Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/stublink.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index 43b2e513e21dfd..36a2b18508912c 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -716,7 +716,8 @@ PCODE StubLinker::EmitStub(LoaderAllocator* pLoaderAllocator, StubCodeBlockKind BYTE* pCodeRW = pBlockRW + codeOffset; if (m_pTargetMethod != NULL) { - SET_UNALIGNED_PTR(pCodeRW - sizeof(PTR_MethodDesc), reinterpret_cast(m_pTargetMethod)); + _ASSERTE(IS_ALIGNED(pCodeRW - sizeof(PTR_MethodDesc), sizeof(PTR_MethodDesc))); + *reinterpret_cast(pCodeRW - sizeof(PTR_MethodDesc)) = m_pTargetMethod; } BYTE *pDataRW = pCodeRW+globalsize; // start of data area From aa58970e9e9932a3e6c58128cbedfc624585f2f4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 14:33:55 +0000 Subject: [PATCH 13/17] Renumber stub code block kinds Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/codeman.h | 21 +++++++++---------- src/coreclr/vm/loaderallocator.cpp | 2 +- .../ExecutionManager/ExecutionManagerCore.cs | 20 +++++++++--------- .../ExecutionManager/ExecutionManagerTests.cs | 2 +- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 5128c0429c4e26..41d59626f5216f 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -98,21 +98,20 @@ enum StubCodeBlockKind : int { STUB_CODE_BLOCK_UNKNOWN = 0, STUB_CODE_BLOCK_JUMPSTUB = 1, - UNUSED = 2, - STUB_CODE_BLOCK_DYNAMICHELPER = 3, - STUB_CODE_BLOCK_STUBPRECODE = 4, - STUB_CODE_BLOCK_FIXUPPRECODE = 5, + STUB_CODE_BLOCK_DYNAMICHELPER = 2, + STUB_CODE_BLOCK_STUBPRECODE = 3, + STUB_CODE_BLOCK_FIXUPPRECODE = 4, #ifdef FEATURE_VIRTUAL_STUB_DISPATCH - STUB_CODE_BLOCK_VSD_DISPATCH_STUB = 6, - STUB_CODE_BLOCK_VSD_RESOLVE_STUB = 7, - STUB_CODE_BLOCK_VSD_LOOKUP_STUB = 8, - STUB_CODE_BLOCK_VSD_VTABLE_STUB = 9, + STUB_CODE_BLOCK_VSD_DISPATCH_STUB = 5, + STUB_CODE_BLOCK_VSD_RESOLVE_STUB = 6, + STUB_CODE_BLOCK_VSD_LOOKUP_STUB = 7, + STUB_CODE_BLOCK_VSD_VTABLE_STUB = 8, #endif // FEATURE_VIRTUAL_STUB_DISPATCH #ifdef FEATURE_TIERED_COMPILATION - STUB_CODE_BLOCK_CALLCOUNTING = 0xA, + STUB_CODE_BLOCK_CALLCOUNTING = 9, #endif // FEATURE_TIERED_COMPILATION - STUB_CODE_BLOCK_WRAPPER_STUB = 0xB, - STUB_CODE_BLOCK_SHUFFLE_THUNK = 0xC, + STUB_CODE_BLOCK_WRAPPER_STUB = 0xA, + STUB_CODE_BLOCK_SHUFFLE_THUNK = 0xB, // Last valid value. Note that the definition is duplicated in debug\daccess\fntableaccess.cpp STUB_CODE_BLOCK_LAST = 0xF, // Placeholder used by ReadyToRun images diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 5d5e94f6ed0278..0ee2d101573278 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -1094,7 +1094,7 @@ void LoaderAllocator::ActivateManagedTracking() // We don't actually allocate a low frequency heap for collectible types. // This is carefully tuned to sum up to 16 pages to reduce waste. #define COLLECTIBLE_LOW_FREQUENCY_HEAP_SIZE 0 -#define COLLECTIBLE_HIGH_FREQUENCY_HEAP_SIZE (3 * minipal_getpagesize()) +#define COLLECTIBLE_HIGH_FREQUENCY_HEAP_SIZE (4 * minipal_getpagesize()) #define COLLECTIBLE_CODEHEAP_SIZE (10 * minipal_getpagesize()) #define COLLECTIBLE_VIRTUALSTUBDISPATCH_HEAP_SPACE (2 * minipal_getpagesize()) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs index 6f5ef1f2e57d34..ad634f444d5914 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs @@ -94,16 +94,16 @@ private enum StubKind : int { Unknown = 0, JumpStub = 1, - DynamicHelper = 3, - StubPrecode = 4, - FixupPrecode = 5, - VSDDispatchStub = 6, - VSDResolveStub = 7, - VSDLookupStub = 8, - VSDVTableStub = 9, - CallCountingStub = 10, - WrapperStub = 11, - ShuffleThunk = 12, + DynamicHelper = 2, + StubPrecode = 3, + FixupPrecode = 4, + VSDDispatchStub = 5, + VSDResolveStub = 6, + VSDLookupStub = 7, + VSDVTableStub = 8, + CallCountingStub = 9, + WrapperStub = 10, + ShuffleThunk = 11, } private abstract class JitManager diff --git a/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs index 933835d5441caa..fe2ab616e3fe7b 100644 --- a/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs @@ -773,7 +773,7 @@ public void GetStubKind_RangeListStubs(string version, MockTarget.Architecture a const ulong codeRangeStart = 0x0a0a_0000u; const uint codeRangeSize = 0x4000u; const ulong jitManagerAddress = 0x000b_ff00; - const int stubCodeBlockKindPrecode = 4; // STUB_CODE_BLOCK_STUBPRECODE + const int stubCodeBlockKindPrecode = 3; // STUB_CODE_BLOCK_STUBPRECODE IExecutionManager em = CreateExecutionManagerContract( version, From 74e6e7aa05dda0bfd7f352a480e854514498632f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 14:40:15 +0000 Subject: [PATCH 14/17] Remove obsolete AppDomain comment Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/appdomain.hpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index bfec31617debff..f779665ccc6eed 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -188,20 +188,6 @@ FORCEINLINE void PinnedHeapHandleBlockHolder__StaticFree(PinnedHeapHandleBlockH pHolder->FreeData(); }; -//-------------------------------------------------------------------------------------- -// Base class for domains. It provides an abstract way of finding the first assembly and -// for creating assemblies in the domain. The system domain only has one assembly, it -// contains the classes that are logically shared between domains. All other domains can -// have multiple assemblies. Iteration is done be getting the first assembly and then -// calling the Next() method on the assembly. -// -// The system domain should be as small as possible, it includes object, exceptions, etc. -// which are the basic classes required to load other assemblies. All other classes -// should be loaded into the domain. Of coarse there is a trade off between loading the -// same classes multiple times, requiring all domains to load certain assemblies (working -// set) and being able to specify specific versions. -// - #define LOW_FREQUENCY_HEAP_RESERVE_SIZE (3 * minipal_getpagesize()) #define LOW_FREQUENCY_HEAP_COMMIT_SIZE (1 * minipal_getpagesize()) From 4767ff179194e5570b3cc2b87769066c44e4db6a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 15:33:29 +0000 Subject: [PATCH 15/17] Remove obsolete shuffle thunk comment Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/comdelegate.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index e4cd1902e9cfed..f571ecb9daf8f2 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -178,10 +178,6 @@ class ShuffleThunkCache : public StubCacheBase { } private: - //--------------------------------------------------------- - // Compile a static delegate shufflethunk. Always returns - // STANDALONE since we don't interpret these things. - //--------------------------------------------------------- virtual StubCodeBlockKind CompileStub(const BYTE *pRawStub, StubLinker *pstublinker) { From 6b1d87d03a755c64a3d46bff9e20a04d7ffb269f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Aug 2026 00:41:07 +0000 Subject: [PATCH 16/17] Pass actual write barrier sizes to ETW Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/inc/eventtracebase.h | 4 ++-- src/coreclr/vm/eventtrace.cpp | 6 +++--- src/coreclr/vm/threads.cpp | 24 +++++++++++++++++++++--- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/coreclr/inc/eventtracebase.h b/src/coreclr/inc/eventtracebase.h index 16cb14bf278228..97b439c976771d 100644 --- a/src/coreclr/inc/eventtracebase.h +++ b/src/coreclr/inc/eventtracebase.h @@ -960,7 +960,7 @@ namespace ETW static VOID MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, PCODE pNativeCodeStartAddress, PrepareCodeConfig *pConfig); static VOID SendMethodDetailsEvent(MethodDesc *pMethodDesc); static VOID SendNonDuplicateMethodDetailsEvent(MethodDesc* pMethodDesc, MethodDescSet* set); - static VOID StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pHelperName); + static VOID StubInitialized(ULONGLONG ullHelperStartAddress, ULONG ulHelperSize, LPCWSTR pHelperName); static VOID MethodRestored(MethodDesc * pMethodDesc); static VOID DynamicMethodDestroyed(MethodDesc *pMethodDesc); static VOID LogMethodInstrumentationData(MethodDesc* method, uint32_t cbData, BYTE *data, TypeHandle* pTypeHandles, uint32_t numTypeHandles, MethodDesc** pMethods, uint32_t numMethods); @@ -970,7 +970,7 @@ namespace ETW static VOID GetR2RGetEntryPoint(MethodDesc *pMethodDesc, PCODE pEntryPoint) {}; static VOID MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); static VOID MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, PCODE pNativeCodeStartAddress, PrepareCodeConfig *pConfig); - static VOID StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pHelperName) {}; + static VOID StubInitialized(ULONGLONG ullHelperStartAddress, ULONG ulHelperSize, LPCWSTR pHelperName) {}; static VOID MethodRestored(MethodDesc * pMethodDesc) {}; static VOID DynamicMethodDestroyed(MethodDesc *pMethodDesc) {}; static VOID LogMethodInstrumentationData(MethodDesc* method, uint32_t cbData, BYTE *data, TypeHandle* pTypeHandles, uint32_t numTypeHandles, MethodDesc** pMethods, uint32_t numMethods) {}; diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index 8c1242ea4eccdf..7be0af69ca6541 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -3609,12 +3609,13 @@ VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER /**********************************************************************/ /* This is called by the runtime when a single jit helper method with stub is initialized */ /**********************************************************************/ -VOID ETW::MethodLog::StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pHelperName) +VOID ETW::MethodLog::StubInitialized(ULONGLONG ullHelperStartAddress, ULONG ulHelperSize, LPCWSTR pHelperName) { CONTRACTL { NOTHROW; GC_TRIGGERS; PRECONDITION(ullHelperStartAddress != 0); + PRECONDITION(ulHelperSize != 0); } CONTRACTL_END; EX_TRY @@ -3623,8 +3624,7 @@ VOID ETW::MethodLog::StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pH TRACE_LEVEL_INFORMATION, CLR_JIT_KEYWORD)) { - DWORD dwHelperSize = 1; - ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName); + ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, ulHelperSize, pHelperName); } } EX_CATCH { } EX_END_CATCH } diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index 1d1d589970687b..4519b127bb3250 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -958,9 +958,24 @@ DWORD_PTR Thread::OBJREF_HASH = OBJREF_TABSIZE; extern "C" void STDCALL JIT_PatchedCodeStart(); extern "C" void STDCALL JIT_PatchedCodeLast(); +#ifndef TARGET_X86 +extern "C" void STDCALL JIT_WriteBarrier_End(); +#endif // !TARGET_X86 +#if defined(TARGET_ARM64) || defined(TARGET_ARM) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) +extern "C" void STDCALL JIT_CheckedWriteBarrier_End(); +#endif // TARGET_ARM64 || TARGET_ARM || TARGET_LOONGARCH64 || TARGET_RISCV64 static void* s_barrierCopy = NULL; +static DWORD GetCodeSize(VOID* codeStart, VOID* codeEnd) +{ + LIMITED_METHOD_CONTRACT; + + ptrdiff_t codeSize = (BYTE*)codeEnd - (BYTE*)codeStart; + _ASSERTE(codeSize > 0); + return (DWORD)codeSize; +} + BYTE* GetWriteBarrierCodeLocation(VOID* barrier) { if (IsWriteBarrierCopyEnabled()) @@ -1089,11 +1104,12 @@ void InitThreadManager() // can jump to it. #ifdef TARGET_X86 JIT_WriteBarrierEAX_Loc = GetWriteBarrierCodeLocation((void*)JIT_WriteBarrierEAX); + DWORD dwWriteBarrierSize = GetCodeSize((void*)JIT_WriteBarrierEBP, (void*)JIT_PatchedWriteBarrierGroup_End); #define X86_WRITE_BARRIER_REGISTER(reg) \ SetJitHelperFunction(CORINFO_HELP_ASSIGN_REF_##reg, GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier##reg)); \ SetAuxiliarySymbol(GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier##reg), "JIT_WriteBarrier" #reg); \ - ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier##reg), W("@WriteBarrier" #reg)); + ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier##reg), dwWriteBarrierSize, W("@WriteBarrier" #reg)); ENUM_X86_WRITE_BARRIER_REGISTERS() @@ -1101,10 +1117,11 @@ void InitThreadManager() #else // TARGET_X86 JIT_WriteBarrier_Loc = GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier); + DWORD dwWriteBarrierSize = GetCodeSize((void*)JIT_WriteBarrier, (void*)JIT_WriteBarrier_End); #endif // TARGET_X86 SetJitHelperFunction(CORINFO_HELP_ASSIGN_REF, GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier)); SetAuxiliarySymbol(GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier), "JIT_WriteBarrier"); - ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier), W("@WriteBarrier")); + ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier), dwWriteBarrierSize, W("@WriteBarrier")); #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) // Store the JIT_WriteBarrier_Table copy location to a global variable so that it can be updated. @@ -1112,9 +1129,10 @@ void InitThreadManager() #endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64 #if defined(TARGET_ARM64) || defined(TARGET_ARM) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + DWORD dwCheckedWriteBarrierSize = GetCodeSize((void*)JIT_CheckedWriteBarrier, (void*)JIT_CheckedWriteBarrier_End); SetJitHelperFunction(CORINFO_HELP_CHECKED_ASSIGN_REF, GetWriteBarrierCodeLocation((void*)JIT_CheckedWriteBarrier)); SetAuxiliarySymbol(GetWriteBarrierCodeLocation((void*)JIT_CheckedWriteBarrier), "JIT_CheckedWriteBarrier"); - ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_CheckedWriteBarrier), W("@CheckedWriteBarrier")); + ETW::MethodLog::StubInitialized((ULONGLONG)GetWriteBarrierCodeLocation((void*)JIT_CheckedWriteBarrier), dwCheckedWriteBarrierSize, W("@CheckedWriteBarrier")); #endif // TARGET_ARM64 || TARGET_ARM || TARGET_LOONGARCH64 || TARGET_RISCV64 #if defined(TARGET_AMD64) From bb70c03b305a8f424e9924bb2defc66bcd7424b1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Aug 2026 01:08:08 +0000 Subject: [PATCH 17/17] Map cDAC wrapper and shuffle stub kinds Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- docs/design/datacontracts/ExecutionManager.md | 4 +++- .../Contracts/IExecutionManager.cs | 4 +++- .../ExecutionManager/ExecutionManagerCore.cs | 2 ++ .../ExecutionManager/ExecutionManagerTests.cs | 24 +++++++++++++++---- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/docs/design/datacontracts/ExecutionManager.md b/docs/design/datacontracts/ExecutionManager.md index a21886b71e7a45..9529f28b4f755a 100644 --- a/docs/design/datacontracts/ExecutionManager.md +++ b/docs/design/datacontracts/ExecutionManager.md @@ -144,7 +144,9 @@ public enum CodeKind : uint Jitted = 11, ReadyToRun = 12, Interpreter = 13, - ThePreStub = 14 + ThePreStub = 14, + WrapperStub = 15, + ShuffleThunk = 16 } ``` diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs index ef0a13cbce4d7b..e37ab8ef879c70 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs @@ -58,7 +58,9 @@ public enum CodeKind : uint Jitted = 11, ReadyToRun = 12, Interpreter = 13, - ThePreStub = 14 + ThePreStub = 14, + WrapperStub = 15, + ShuffleThunk = 16 } public interface ICodeHeapInfo diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs index ad634f444d5914..1e7fad5357992c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs @@ -661,6 +661,8 @@ private static CodeKind GetStubKind(StubKind stubKind) StubKind.VSDLookupStub => CodeKind.VSD_LookupStub, StubKind.VSDVTableStub => CodeKind.VSD_VTableStub, StubKind.CallCountingStub => CodeKind.CallCountingStub, + StubKind.WrapperStub => CodeKind.WrapperStub, + StubKind.ShuffleThunk => CodeKind.ShuffleThunk, _ => CodeKind.Unknown, }; } diff --git a/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs b/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs index fe2ab616e3fe7b..18ed39cc0d01e6 100644 --- a/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/ExecutionManager/ExecutionManagerTests.cs @@ -798,7 +798,14 @@ public void GetStubKind_CodeHeapStubs(string version, MockTarget.Architecture ar const uint stubSize = 0x20; const ulong jitManagerAddress = 0x000b_ff00; const int stubCodeBlockKindJumpStub = 1; // STUB_CODE_BLOCK_JUMPSTUB - ulong stubCodeAddress = 0; + const int stubCodeBlockKindWrapperStub = 10; // STUB_CODE_BLOCK_WRAPPER_STUB + const int stubCodeBlockKindShuffleThunk = 11; // STUB_CODE_BLOCK_SHUFFLE_THUNK + (int StubCodeBlockKind, CodeKind CodeKind, ulong CodeAddress)[] stubs = + [ + (stubCodeBlockKindJumpStub, CodeKind.JumpStub, 0), + (stubCodeBlockKindWrapperStub, CodeKind.WrapperStub, 0), + (stubCodeBlockKindShuffleThunk, CodeKind.ShuffleThunk, 0), + ]; IExecutionManager em = CreateExecutionManagerContract( version, @@ -806,18 +813,25 @@ public void GetStubKind_CodeHeapStubs(string version, MockTarget.Architecture ar emBuilder => { var jittedCode = emBuilder.AllocateJittedCodeRange(codeRangeStart, codeRangeSize); - stubCodeAddress = emBuilder.AddStubCodeBlock(jittedCode, stubSize, stubCodeBlockKindJumpStub).CodeAddress; NibbleMapTestBuilderBase nibBuilder = emBuilder.CreateNibbleMap(codeRangeStart, codeRangeSize); - nibBuilder.AllocateCodeChunk(new TargetCodePointer(stubCodeAddress), stubSize); + for (int i = 0; i < stubs.Length; i++) + { + MockJittedMethod stub = emBuilder.AddStubCodeBlock(jittedCode, stubSize, stubs[i].StubCodeBlockKind); + stubs[i].CodeAddress = stub.CodeAddress; + nibBuilder.AllocateCodeChunk(new TargetCodePointer(stub.CodeAddress), stubSize); + } MockCodeHeapListNode codeHeapListNode = emBuilder.AddCodeHeapListNode(0, codeRangeStart, codeRangeStart + codeRangeSize, codeRangeStart, nibBuilder.NibbleMapFragment.Address); MockRangeSection rangeSection = emBuilder.AddRangeSection(jittedCode, jitManagerAddress, codeHeapListNode.Address); _ = emBuilder.AddRangeSectionFragment(jittedCode, rangeSection.Address); }); - CodeKind kind = em.GetCodeKind(new TargetCodePointer(stubCodeAddress)); - Assert.Equal(CodeKind.JumpStub, kind); + foreach ((_, CodeKind expected, ulong codeAddress) in stubs) + { + CodeKind kind = em.GetCodeKind(new TargetCodePointer(codeAddress)); + Assert.Equal(expected, kind); + } } [Theory]