summaryrefslogtreecommitdiff
path: root/src/vm/listlock.h
diff options
context:
space:
mode:
authornoahfalk <noahfalk@microsoft.com>2017-07-24 17:38:30 -0700
committernoahfalk <noahfalk@microsoft.com>2017-07-24 17:38:30 -0700
commitfd1998903d5eef356f27c54e5a9d490711cbc9e7 (patch)
treeb1d3d7ff1978483060a0f7c879b22006edd417b4 /src/vm/listlock.h
parent39cd3cfcb078154f9b595ae476f2c5fb7b445e18 (diff)
downloadcoreclr-fd1998903d5eef356f27c54e5a9d490711cbc9e7.tar.gz
coreclr-fd1998903d5eef356f27c54e5a9d490711cbc9e7.tar.bz2
coreclr-fd1998903d5eef356f27c54e5a9d490711cbc9e7.zip
Add the runtime code versioning feature
This makes tiered compilation work properly with profiler ReJIT, and positions the runtime to integrate other versioning related features together in the future. See the newly added code-versioning design-doc in this commit for more information. Breaking changes for profilers: See code-versioning-profiler-breaking-changes.md for more details.
Diffstat (limited to 'src/vm/listlock.h')
-rw-r--r--src/vm/listlock.h179
1 files changed, 147 insertions, 32 deletions
diff --git a/src/vm/listlock.h b/src/vm/listlock.h
index e16741a7d7..db953c8b55 100644
--- a/src/vm/listlock.h
+++ b/src/vm/listlock.h
@@ -17,7 +17,8 @@
#include "threads.h"
#include "crst.h"
-class ListLock;
+template < typename ELEMENT >
+class ListLockBase;
// This structure is used for running class init methods or JITing methods
// (m_pData points to a FunctionDesc). This class cannot have a destructor since it is used
// in function that also have EX_TRY's and the VC compiler doesn't allow classes with destructors
@@ -25,9 +26,14 @@ class ListLock;
// <TODO>@FUTURE Keep a pool of these (e.g. an array), so we don't have to allocate on the fly</TODO>
// m_hInitException contains a handle to the exception thrown by the class init. This
// allows us to throw this information to the caller on subsequent class init attempts.
-class ListLockEntry
+template < typename ELEMENT >
+class ListLockEntryBase
{
- friend class ListLock;
+ friend class ListLockBase<ELEMENT>;
+ typedef ListLockEntryBase<ELEMENT> Entry_t;
+ typedef ListLockBase<ELEMENT> List_t;
+ typedef typename List_t::LockHolder ListLockHolder;
+
public:
#ifdef _DEBUG
@@ -40,11 +46,11 @@ public:
#endif // DEBUG
DeadlockAwareLock m_deadlock;
- ListLock * m_pList;
- void * m_pData;
+ List_t * m_pList;
+ ELEMENT m_data;
Crst m_Crst;
const char * m_pszDescription;
- ListLockEntry * m_pNext;
+ Entry_t * m_pNext;
DWORD m_dwRefCount;
HRESULT m_hrResultCode;
LOADERHANDLE m_hInitException;
@@ -54,9 +60,27 @@ public:
CorruptionSeverity m_CorruptionSeverity;
#endif // FEATURE_CORRUPTING_EXCEPTIONS
- ListLockEntry(ListLock *pList, void *pData, const char *description = NULL);
+ ListLockEntryBase(List_t *pList, ELEMENT data, const char *description = NULL)
+ : m_deadlock(description),
+ m_pList(pList),
+ m_data(data),
+ m_Crst(CrstListLock,
+ (CrstFlags)(CRST_REENTRANCY | (pList->IsHostBreakable() ? CRST_HOST_BREAKABLE : 0))),
+ m_pszDescription(description),
+ m_pNext(NULL),
+ m_dwRefCount(1),
+ m_hrResultCode(S_FALSE),
+ m_hInitException(NULL),
+ m_pLoaderAllocator(dac_cast<PTR_LoaderAllocator>(nullptr))
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ ,
+ m_CorruptionSeverity(NotCorrupting)
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ {
+ WRAPPER_NO_CONTRACT;
+ }
- virtual ~ListLockEntry()
+ virtual ~ListLockEntryBase()
{
}
@@ -102,10 +126,65 @@ public:
m_Crst.Leave();
}
- static ListLockEntry *Find(ListLock* pLock, LPVOID pPointer, const char *description = NULL) DAC_EMPTY_RET(NULL);
+ static Entry_t *Find(List_t* pLock, ELEMENT data, const char *description = NULL)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(pLock->HasLock());
+
+ Entry_t *pEntry = pLock->Find(data);
+ if (pEntry == NULL)
+ {
+ pEntry = new Entry_t(pLock, data, description);
+ pLock->AddElement(pEntry);
+ }
+ else
+ pEntry->AddRef();
+
+ return pEntry;
+ };
+
+
+ void AddRef()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(this));
+ }
+ CONTRACTL_END;
+
+ FastInterlockIncrement((LONG*)&m_dwRefCount);
+ }
+
+ void Release()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(this));
+ }
+ CONTRACTL_END;
- void AddRef() DAC_EMPTY_ERR();
- void Release() DAC_EMPTY_ERR();
+ ListLockHolder lock(m_pList);
+
+ if (FastInterlockDecrement((LONG*)&m_dwRefCount) == 0)
+ {
+ // Remove from list
+ m_pList->Unlink(this);
+ delete this;
+ }
+ };
#ifdef _DEBUG
BOOL HasLock()
@@ -117,14 +196,14 @@ public:
// LockHolder holds the lock of the element, not the element itself
- DEBUG_NOINLINE static void LockHolderEnter(ListLockEntry *pThis) PUB
+ DEBUG_NOINLINE static void LockHolderEnter(Entry_t *pThis) PUB
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
pThis->Enter();
}
- DEBUG_NOINLINE static void LockHolderLeave(ListLockEntry *pThis) PUB
+ DEBUG_NOINLINE static void LockHolderLeave(Entry_t *pThis) PUB
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
@@ -139,7 +218,7 @@ public:
m_deadlock.EndEnterLock();
}
- typedef Wrapper<ListLockEntry *, ListLockEntry::LockHolderEnter, ListLockEntry::LockHolderLeave> LockHolderBase;
+ typedef Wrapper<Entry_t *, LockHolderEnter, LockHolderLeave> LockHolderBase;
class LockHolder : public LockHolderBase
{
@@ -150,32 +229,36 @@ public:
{
}
- LockHolder(ListLockEntry *value, BOOL take = TRUE)
+ LockHolder(Entry_t *value, BOOL take = TRUE)
: LockHolderBase(value, take)
{
}
BOOL DeadlockAwareAcquire()
{
- if (!m_acquired && m_value != NULL)
+ if (!this->m_acquired && this->m_value != NULL)
{
- if (!m_value->m_deadlock.TryBeginEnterLock())
+ if (!this->m_value->m_deadlock.TryBeginEnterLock())
return FALSE;
- m_value->FinishDeadlockAwareEnter();
- m_acquired = TRUE;
+ this->m_value->FinishDeadlockAwareEnter();
+ this->m_acquired = TRUE;
}
return TRUE;
}
};
};
-class ListLock
+template < typename ELEMENT >
+class ListLockBase
{
+ typedef ListLockBase<ELEMENT> List_t;
+ typedef ListLockEntryBase<ELEMENT> Entry_t;
+
protected:
CrstStatic m_Crst;
BOOL m_fInited;
BOOL m_fHostBreakable; // Lock can be broken by a host for deadlock detection
- ListLockEntry * m_pHead;
+ Entry_t * m_pHead;
public:
@@ -219,7 +302,7 @@ class ListLock
return m_fHostBreakable;
}
- void AddElement(ListLockEntry* pElement)
+ void AddElement(Entry_t* pElement)
{
WRAPPER_NO_CONTRACT;
pElement->m_pNext = m_pHead;
@@ -257,10 +340,39 @@ class ListLock
// Must own the lock before calling this or is ok if the debugger has
// all threads stopped
- ListLockEntry *Find(void *pData);
+ inline Entry_t *Find(ELEMENT data)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+#ifdef DEBUGGING_SUPPORTED
+ PRECONDITION(m_Crst.OwnedByCurrentThread() ||
+ CORDebuggerAttached()
+ // This condition should be true, but it is awkward to assert it because adding dbginterface.h creates lots of cycles in the includes
+ // It didn't seem valuable enough to refactor out a wrapper just to preserve it
+ /* && g_pDebugInterface->IsStopped() */);
+#else
+ PRECONDITION(m_Crst.OwnedByCurrentThread());
+#endif // DEBUGGING_SUPPORTED
+
+ }
+ CONTRACTL_END;
+
+ Entry_t *pSearch;
+
+ for (pSearch = m_pHead; pSearch != NULL; pSearch = pSearch->m_pNext)
+ {
+ if (pSearch->m_data == data)
+ return pSearch;
+ }
+
+ return NULL;
+ }
// Must own the lock before calling this!
- ListLockEntry* Pop(BOOL unloading = FALSE)
+ Entry_t* Pop(BOOL unloading = FALSE)
{
LIMITED_METHOD_CONTRACT;
#ifdef _DEBUG
@@ -269,13 +381,13 @@ class ListLock
#endif
if(m_pHead == NULL) return NULL;
- ListLockEntry* pEntry = m_pHead;
+ Entry_t* pEntry = m_pHead;
m_pHead = m_pHead->m_pNext;
return pEntry;
}
// Must own the lock before calling this!
- ListLockEntry* Peek()
+ Entry_t* Peek()
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(m_Crst.OwnedByCurrentThread());
@@ -283,12 +395,12 @@ class ListLock
}
// Must own the lock before calling this!
- BOOL Unlink(ListLockEntry *pItem)
+ BOOL Unlink(Entry_t *pItem)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(m_Crst.OwnedByCurrentThread());
- ListLockEntry *pSearch;
- ListLockEntry *pPrev;
+ Entry_t *pSearch;
+ Entry_t *pPrev;
pPrev = NULL;
@@ -320,21 +432,21 @@ class ListLock
}
#endif
- DEBUG_NOINLINE static void HolderEnter(ListLock *pThis)
+ DEBUG_NOINLINE static void HolderEnter(List_t *pThis)
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
pThis->Enter();
}
- DEBUG_NOINLINE static void HolderLeave(ListLock *pThis)
+ DEBUG_NOINLINE static void HolderLeave(List_t *pThis)
{
WRAPPER_NO_CONTRACT;
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
pThis->Leave();
}
- typedef Wrapper<ListLock*, ListLock::HolderEnter, ListLock::HolderLeave> LockHolder;
+ typedef Wrapper<List_t*, List_t::HolderEnter, List_t::HolderLeave> LockHolder;
};
class WaitingThreadListElement
@@ -344,6 +456,9 @@ public:
WaitingThreadListElement * m_pNext;
};
+typedef class ListLockBase<void*> ListLock;
+typedef class ListLockEntryBase<void*> ListLockEntry;
+
// Holds the lock of the ListLock
typedef ListLock::LockHolder ListLockHolder;