From b0a10f69a85404bcc9c377c80dc2950f927f8731 Mon Sep 17 00:00:00 2001 From: Konstantin Baladurin Date: Fri, 12 Jan 2018 18:55:10 +0300 Subject: UMEntryThunk: store freed thunks into FIFO free list Use free list to delay reusing deleted thunks. It improves collected delegate calls diagnostic. --- src/vm/dllimportcallback.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++-- src/vm/dllimportcallback.h | 10 ++++- 2 files changed, 91 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/vm/dllimportcallback.cpp b/src/vm/dllimportcallback.cpp index c3e6a4e62d..fe03f47388 100644 --- a/src/vm/dllimportcallback.cpp +++ b/src/vm/dllimportcallback.cpp @@ -33,6 +33,79 @@ struct UM2MThunk_Args int argLen; }; +class UMEntryThunkFreeList +{ +public: + UMEntryThunkFreeList(size_t threshold) : + m_threshold(threshold), + m_count(0), + m_pHead(NULL), + m_pTail(NULL) + { + WRAPPER_NO_CONTRACT; + + m_crst.Init(CrstLeafLock, CRST_UNSAFE_ANYMODE); + } + + UMEntryThunk *GetUMEntryThunk() + { + WRAPPER_NO_CONTRACT; + + if (m_count < m_threshold) + return NULL; + + CrstHolder ch(&m_crst); + + UMEntryThunk *pThunk = m_pHead; + + if (pThunk == NULL) + return NULL; + + m_pHead = m_pHead->m_pNextFreeThunk; + --m_count; + + return pThunk; + } + + void AddToList(UMEntryThunk *pThunk) + { + CONTRACTL + { + NOTHROW; + } + CONTRACTL_END; + + CrstHolder ch(&m_crst); + + if (m_pHead == NULL) + { + m_pHead = pThunk; + m_pTail = pThunk; + } + else + { + m_pTail->m_pNextFreeThunk = pThunk; + m_pTail = pThunk; + } + + pThunk->m_pNextFreeThunk = NULL; + + ++m_count; + } + +private: + // Used to delay reusing freed thunks + size_t m_threshold; + size_t m_count; + UMEntryThunk *m_pHead; + UMEntryThunk *m_pTail; + CrstStatic m_crst; +}; + +#define DEFAULT_THUNK_FREE_LIST_THRESHOLD 64 + +static UMEntryThunkFreeList s_thunkFreeList(DEFAULT_THUNK_FREE_LIST_THRESHOLD); + EXTERN_C void STDCALL UM2MThunk_WrapperHelper(void *pThunkArgs, int argLen, void *pAddr, @@ -1111,20 +1184,26 @@ UMEntryThunk* UMEntryThunk::CreateUMEntryThunk() UMEntryThunk * p; - // On the phone, use loader heap to save memory commit of regular executable heap - p = (UMEntryThunk *)(void *)SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(sizeof(UMEntryThunk))); + p = s_thunkFreeList.GetUMEntryThunk(); + + if (p == NULL) + p = (UMEntryThunk *)(void *)SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(sizeof(UMEntryThunk))); RETURN p; } void UMEntryThunk::Terminate() { - WRAPPER_NO_CONTRACT; + CONTRACTL + { + NOTHROW; + } + CONTRACTL_END; _ASSERTE(!SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->IsZeroInit()); m_code.Poison(); - SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->BackoutMem(this, sizeof(UMEntryThunk)); + s_thunkFreeList.AddToList(this); } VOID UMEntryThunk::FreeUMEntryThunk(UMEntryThunk* p) diff --git a/src/vm/dllimportcallback.h b/src/vm/dllimportcallback.h index 5838e49566..d820a766bf 100644 --- a/src/vm/dllimportcallback.h +++ b/src/vm/dllimportcallback.h @@ -250,6 +250,7 @@ class UMEntryThunk { friend class CheckAsmOffsets; friend class NDirectStubLinker; + friend class UMEntryThunkFreeList; private: #ifdef _DEBUG @@ -526,8 +527,13 @@ private: // Field is NULL for a static method. OBJECTHANDLE m_pObjectHandle; - // Pointer to the shared structure containing everything else - PTR_UMThunkMarshInfo m_pUMThunkMarshInfo; + union + { + // Pointer to the shared structure containing everything else + PTR_UMThunkMarshInfo m_pUMThunkMarshInfo; + // Pointer to the next UMEntryThunk in the free list. Used when it is freed. + UMEntryThunk *m_pNextFreeThunk; + }; ADID m_dwDomainId; // appdomain of module (cached for fast access) #ifdef _DEBUG -- cgit v1.2.3