UMEntryThunk: store freed thunks into FIFO free list
authorKonstantin Baladurin <k.baladurin@partner.samsung.com>
Fri, 12 Jan 2018 15:55:10 +0000 (18:55 +0300)
committerJan Kotas <jkotas@microsoft.com>
Fri, 12 Jan 2018 20:40:37 +0000 (12:40 -0800)
Use free list to delay reusing deleted thunks. It improves
collected delegate calls diagnostic.

Commit migrated from https://github.com/dotnet/coreclr/commit/b0a10f69a85404bcc9c377c80dc2950f927f8731

src/coreclr/src/vm/dllimportcallback.cpp
src/coreclr/src/vm/dllimportcallback.h

index c3e6a4e..fe03f47 100644 (file)
@@ -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)
index 5838e49..d820a76 100644 (file)
@@ -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