diff --git a/docs/design/datacontracts/SyncBlock.md b/docs/design/datacontracts/SyncBlock.md index 2a81318db644f3..ea51bb4503fc44 100644 --- a/docs/design/datacontracts/SyncBlock.md +++ b/docs/design/datacontracts/SyncBlock.md @@ -24,7 +24,7 @@ Data descriptors used: | `SyncTableEntry` | `SyncBlock` | Pointer to the sync block for a sync table entry | | `SyncTableEntry` | `Object` | Pointer to the object associated with a sync table entry | | `SyncBlockCache` | `FreeSyncTableIndex` | One past the highest sync table entry index allocated | -| `SyncBlockCache` | `CleanupBlockList` | Head of the `SLink` cleanup list (points into `SyncBlock.m_Link`) | +| `SyncBlockCache` | `CleanupBlockList` | Head of the cleanup list (points to the first `SyncBlock` in the chain) | | `SyncBlock` | `Lock` | Optional pointer to a `System.Threading.Lock` object payload | | `SyncBlock` | `ThinLock` | Thin-lock state bits | | `SyncBlock` | `LinkNext` | Head pointer for cleanup list link | @@ -149,7 +149,7 @@ TargetPointer GetSyncBlockFromCleanupList() TargetPointer cleanupBlockList = target.ReadPointer(syncBlockCache + /* SyncBlockCache::CleanupBlockList offset */); if (cleanupBlockList == TargetPointer.Null) return TargetPointer.Null; - return cleanupBlockList - /* SyncBlock::LinkNext offset */; + return cleanupBlockList; } // Returns the next sync block in the cleanup list after syncBlock, or TargetPointer.Null if there is none. @@ -158,7 +158,7 @@ TargetPointer GetNextSyncBlock(TargetPointer syncBlock) TargetPointer linkNext = target.ReadPointer(syncBlock + /* SyncBlock::LinkNext offset */); if (linkNext == TargetPointer.Null) return TargetPointer.Null; - return linkNext - /* SyncBlock::LinkNext offset */; + return linkNext; } // Gets the built-in COM interop data directly from a sync block. diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 9e72098dd863bb..0d5ae0fc298036 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -3822,9 +3822,9 @@ ClrDataAccess::GetSyncBlockData(unsigned int SBNumber, struct DacpSyncBlockData // TODO: Microsoft, implement the wait list pSyncBlockData->AdditionalThreadCount = 0; - if (pBlock->m_Link.m_pNext != NULL) + if (pBlock->m_pNext != NULL) { - PTR_SLink pLink = pBlock->m_Link.m_pNext; + PTR_SyncBlock pLink = pBlock->m_pNext; do { pSyncBlockData->AdditionalThreadCount++; @@ -3855,7 +3855,7 @@ ClrDataAccess::GetSyncBlockCleanupData(CLRDATA_ADDRESS syncBlock, struct DacpSyn if (syncBlock == (CLRDATA_ADDRESS)NULL && SyncBlockCache::s_pSyncBlockCache->m_pCleanupBlockList) { pBlock = (SyncBlock *) PTR_SyncBlock( - PTR_HOST_TO_TADDR(SyncBlockCache::s_pSyncBlockCache->m_pCleanupBlockList) - offsetof(SyncBlock, m_Link)); + PTR_HOST_TO_TADDR(SyncBlockCache::s_pSyncBlockCache->m_pCleanupBlockList)); } else { @@ -3865,10 +3865,10 @@ ClrDataAccess::GetSyncBlockCleanupData(CLRDATA_ADDRESS syncBlock, struct DacpSyn if (pBlock) { syncBlockCData->SyncBlockPointer = HOST_CDADDR(pBlock); - if (pBlock->m_Link.m_pNext) + if (pBlock->m_pNext) { syncBlockCData->nextSyncBlock = (CLRDATA_ADDRESS) - (PTR_HOST_TO_TADDR(pBlock->m_Link.m_pNext) - offsetof(SyncBlock, m_Link)); + PTR_HOST_TO_TADDR(pBlock->m_pNext); } #ifdef FEATURE_COMINTEROP diff --git a/src/coreclr/inc/daccess.h b/src/coreclr/inc/daccess.h index 9870093d1bca57..b3f97772c24ef3 100644 --- a/src/coreclr/inc/daccess.h +++ b/src/coreclr/inc/daccess.h @@ -238,20 +238,10 @@ // instance pointers should be held across a Flush(). // // Accessing into an object can lead to some unusual behavior. For -// example, the SList class relies on objects to contain an SLink -// instance that it uses for list maintenance. This SLink can be -// embedded anywhere in the larger object. The SList access is always -// purely to an SLink, so when using the access layer it will only -// retrieve an SLink's worth of data. The SList template will then -// do some address arithmetic to determine the start of the real -// object and cast the resulting pointer to the final object type. -// When using the access layer this results in a new ?PTR being -// created and used, so a new instance will result. The internal -// SLink instance will have no relation to the new object instance -// even though in target address terms one is embedded in the other. -// The assumption of data stability means that this won't cause -// a problem, but care must be taken with the address arithmetic, -// as laid out in rules #2 and #3. +// example, the SList class uses an intrusive m_pNext pointer +// embedded in each object for list maintenance. The SList access is +// always to the object itself, so when using the access layer it will +// retrieve the full object's data. // // 4. Global address references cannot be used. Any reference to a // global piece of code or data, such as a function address, global diff --git a/src/coreclr/inc/profilepriv.h b/src/coreclr/inc/profilepriv.h index 004a3ab6c85f8e..1f63f517d4040c 100644 --- a/src/coreclr/inc/profilepriv.h +++ b/src/coreclr/inc/profilepriv.h @@ -158,10 +158,11 @@ struct StoredProfilerNode { CLSID guid; SString path; - SLink m_Link; + // Next pointer for SList linkage. + DPTR(StoredProfilerNode) m_pNext; }; -typedef SList STOREDPROFILERLIST; +typedef SList STOREDPROFILERLIST; // --------------------------------------------------------------------------------------- // Global struct that lets the EE see the load status of the profiler, and provides a // pointer (pProfInterface) through which profiler calls can be made diff --git a/src/coreclr/inc/slist.h b/src/coreclr/inc/slist.h index 487c5dca382553..d746f8d3f46158 100644 --- a/src/coreclr/inc/slist.h +++ b/src/coreclr/inc/slist.h @@ -3,339 +3,397 @@ //----------------------------------------------------------------------------- // @File: slist.h // - -// -// @commn: Bunch of utility classes -// -// HISTORY: -// 02/03/98: created helper classes -// SLink, link node for singly linked list, every class that is intrusively -// linked should have a data member of this type -// SList, template linked list class, contains only inline -// methods for fast list operations, with proper type checking -// -// see below for futher info. on how to use these template classes +// Unified singly linked list template shared between CoreCLR VM and +// NativeAOT Runtime. // //----------------------------------------------------------------------------- -//#ifndef _H_UTIL -//#error "I am a part of util.hpp Please don't include me alone !" -//#endif - - #ifndef _H_SLIST_ #define _H_SLIST_ -#include "cdacdata.h" +// --------------------------------------------------------------------------- +// Environment compatibility — define CoreCLR macros as no-ops for NativeAOT. +// --------------------------------------------------------------------------- +#if defined(FEATURE_NATIVEAOT) + #define LIMITED_METHOD_CONTRACT + #define LIMITED_METHOD_DAC_CONTRACT + #define WRAPPER_NO_CONTRACT +#endif -//------------------------------------------------------------------ -// struct SLink, to use a singly linked list -// have a data member m_Link of type SLink in your class -// and instantiate the template SList class -//-------------------------------------------------------------------- +#include "cdacdata.h" +#include // std::forward (used by SListElem) -struct SLink; -typedef DPTR(struct SLink) PTR_SLink; +// --------------------------------------------------------------------------- +// SListMode — controls which SList operations are permitted. +// --------------------------------------------------------------------------- +enum class SListMode +{ + Thin, // Head-only: InsertHead, RemoveHead, no tail. + Tail, // Adds InsertTail/GetTail for O(1) tail insertion. +}; -struct SLink +// --------------------------------------------------------------------------- +// SListTraits +// +// T must have a pointer-sized m_pNext field. +// --------------------------------------------------------------------------- +template +struct SListTraits { - PTR_SLink m_pNext; - SLink() - { - LIMITED_METHOD_CONTRACT; + typedef DPTR(T) PTR_T; + typedef DPTR(PTR_T) PTR_PTR_T; - m_pNext = NULL; - } + static constexpr bool HasTail = (Mode == SListMode::Tail); - void InsertAfter(SLink* pLinkToInsert) + static inline PTR_PTR_T GetNextPtr(PTR_T pT) { - LIMITED_METHOD_CONTRACT; - PRECONDITION_MSG(NULL == pLinkToInsert->m_pNext, "This method does not support inserting lists"); - - PTR_SLink pTemp = m_pNext; - - m_pNext = PTR_SLink(pLinkToInsert); - pLinkToInsert->m_pNext = pTemp; + LIMITED_METHOD_DAC_CONTRACT; + _ASSERTE(pT != NULL); + return dac_cast(dac_cast(pT) + offsetof(T, m_pNext)); } - // find pLink within the list starting at pHead - // if found remove the link from the list and return the link - // otherwise return NULL - static SLink* FindAndRemove(SLink *pHead, SLink* pLink, SLink ** ppPrior) + static inline bool Equals(PTR_T pA, PTR_T pB) { LIMITED_METHOD_CONTRACT; + return pA == pB; + } +}; - _ASSERTE(pHead != NULL); - _ASSERTE(pLink != NULL); - - SLink* pFreeLink = NULL; - *ppPrior = NULL; +// --------------------------------------------------------------------------- +// SListTailBase — conditionally holds m_pTail when Traits::HasTail is true. +// --------------------------------------------------------------------------- +template +struct SListTailBase { }; - while (pHead->m_pNext != NULL) - { - if (pHead->m_pNext == pLink) - { - pFreeLink = pLink; - pHead->m_pNext = pLink->m_pNext; - *ppPrior = pHead; - break; - } - pHead = pHead->m_pNext; - } - - return pFreeLink; - } +template +struct SListTailBase +{ + PTR_T m_pTail = NULL; }; -//------------------------------------------------------------------ -// class SList. Intrusive singly linked list. -// -// To use SList with the default instantiation, your class should -// define a data member of type SLink and named 'm_Link'. To use a -// different field name, you need to provide an explicit LinkPtr -// template argument. For example: -// 'SList' -// -// SList has two different behaviours depending on boolean -// fHead variable, +// --------------------------------------------------------------------------- +// SList // -// if fHead is true, then the list allows only InsertHead operations -// if fHead is false, then the list allows only InsertTail operations -// the code is optimized to perform these operations -// all methods are inline, and conditional compiled based on template -// argument 'fHead' -// so there is no actual code size increase -//-------------------------------------------------------------- -template -class SList +// Intrusive singly linked list. Elements must have a pointer-sized m_pNext +// field. Use SListTraits for O(1) tail insertion. +// --------------------------------------------------------------------------- +template > +struct SList : public Traits, private SListTailBase { -public: - // typedef used by the Queue class below - typedef T ENTRY_TYPE; - -protected: - - // used as sentinel - SLink m_link; // slink.m_pNext == Null - PTR_SLink m_pHead; - PTR_SLink m_pTail; + typedef typename Traits::PTR_T PTR_T; + typedef typename Traits::PTR_PTR_T PTR_PTR_T; // as a generic data structure, friend to all specializations of cdac_data template friend struct ::cdac_data; - // get the list node within the object - static SLink* GetLink (T* pLink) + PTR_T m_pHead = NULL; + +public: + + bool IsEmpty() { - LIMITED_METHOD_DAC_CONTRACT; - return &(pLink->*LinkPtr); + LIMITED_METHOD_CONTRACT; + return m_pHead == NULL; } - // move to the beginning of the object given the pointer within the object - static T* GetObject (SLink* pLink) + PTR_T GetHead() { LIMITED_METHOD_DAC_CONTRACT; - if (pLink == NULL) - { - return NULL; - } - else - { -#if 1 - // Newer compilers define offsetof to be __builtin_offsetof, which doesn't use the - // old-school memory model trick to determine offset. - const UINT_PTR offset = (((UINT_PTR)&(((T *)0x1000)->*LinkPtr))-0x1000); - return (T*)__PTR(dac_cast(pLink) - offset); -#else - return (T*)__PTR(dac_cast(pLink) - offsetof(T, *LinkPtr)); -#endif - } + return m_pHead; } -public: - - SList() + static T* GetNext(T* pObj) { - WRAPPER_NO_CONTRACT; -#ifndef DACCESS_COMPILE - Init(); -#endif // !defined(DACCESS_COMPILE) + LIMITED_METHOD_DAC_CONTRACT; + if (pObj == NULL) + return NULL; + + return *Traits::GetNextPtr(dac_cast(pObj)); } - void Init() + // --------------------------------------------------------------------------- + // Pointer-to-pointer iterator — supports Insert and Remove at the current + // position. Used via Begin()/End(). + // --------------------------------------------------------------------------- + class Iterator { - LIMITED_METHOD_CONTRACT; - m_pHead = PTR_SLink(&m_link); - // NOTE :: fHead variable is template argument - // the following code is a compiled in, only if the fHead flag - // is set to false, - if (!fHead) + friend struct SList; + + public: + Iterator(Iterator const &it) + : m_ppCur(it.m_ppCur) +#ifdef _DEBUG + , m_fIsValid(it.m_fIsValid) +#endif + { } + + Iterator& operator=(Iterator const &it) { - m_pTail = PTR_SLink(&m_link); + m_ppCur = it.m_ppCur; +#ifdef _DEBUG + m_fIsValid = it.m_fIsValid; +#endif + return *this; } - } - bool IsEmpty() - { - LIMITED_METHOD_CONTRACT; - return m_pHead->m_pNext == NULL; - } + PTR_T operator->() + { _Validate(e_HasValue); return _Value(); } -#ifndef DACCESS_COMPILE + PTR_T operator*() + { _Validate(e_HasValue); return _Value(); } - void InsertTail(T *pObj) - { - LIMITED_METHOD_CONTRACT; - // NOTE : conditional compilation on fHead template variable - if (!fHead) + Iterator & operator++() { - _ASSERTE(pObj != NULL); - SLink *pLink = GetLink(pObj); + _Validate(e_HasValue); + m_ppCur = Traits::GetNextPtr(_Value()); + return *this; + } - m_pTail->m_pNext = pLink; - m_pTail = pLink; + Iterator operator++(int) + { + _Validate(e_HasValue); + PTR_PTR_T ppRet = m_ppCur; + ++(*this); + return Iterator(ppRet); } - else - {// you instantiated this class asking only for InsertHead operations - _ASSERTE(0); + + bool operator==(Iterator const &rhs) + { + _Validate(e_CanCompare); + rhs._Validate(e_CanCompare); + return Traits::Equals(_Value(), rhs._Value()); } - } - void InsertHead(T *pObj) - { - LIMITED_METHOD_CONTRACT; - // NOTE : conditional compilation on fHead template variable - if (fHead) + bool operator==(PTR_T pT) { - _ASSERTE(pObj != NULL); - SLink *pLink = GetLink(pObj); + _Validate(e_CanCompare); + return Traits::Equals(_Value(), pT); + } + + bool operator!=(Iterator const &rhs) + { return !operator==(rhs); } - pLink->m_pNext = m_pHead->m_pNext; - m_pHead->m_pNext = pLink; + private: + Iterator(PTR_PTR_T ppItem) + : m_ppCur(ppItem) +#ifdef _DEBUG + , m_fIsValid(true) +#endif + { } + + Iterator Insert(PTR_T pItem) + { + _Validate(e_CanInsert); + *Traits::GetNextPtr(pItem) = *m_ppCur; + *m_ppCur = pItem; + Iterator itRet(m_ppCur); + ++(*this); + return itRet; } - else - {// you instantiated this class asking only for InsertTail operations - _ASSERTE(0); + + Iterator Remove() + { + _Validate(e_HasValue); + *m_ppCur = *Traits::GetNextPtr(*m_ppCur); + PTR_PTR_T ppRet = m_ppCur; + *this = End(); + return Iterator(ppRet); } - } - T* RemoveHead() - { - LIMITED_METHOD_CONTRACT; - SLink* pLink = m_pHead->m_pNext; - if (pLink != NULL) + static Iterator End() + { return Iterator(NULL); } + + PTR_PTR_T m_ppCur; +#ifdef _DEBUG + mutable bool m_fIsValid; +#endif + + PTR_T _Value() const { - m_pHead->m_pNext = pLink->m_pNext; +#ifdef _DEBUG + _ASSERTE(m_fIsValid); +#endif + return dac_cast(m_ppCur == NULL ? NULL : *m_ppCur); } - // conditionally compiled, if the instantiated class - // uses Insert Tail operations - if (!fHead) + + enum e_ValidateOperation + { + e_CanCompare, + e_CanInsert, + e_HasValue, + }; + + void _Validate(e_ValidateOperation op) const { - if(m_pTail == pLink) +#ifdef _DEBUG + _ASSERTE(m_fIsValid); +#endif + if ((op != e_CanCompare && m_ppCur == NULL) || + (op == e_HasValue && *m_ppCur == NULL)) { - m_pTail = m_pHead; + _ASSERTE(!"Invalid SList::Iterator use."); +#ifdef _DEBUG + m_fIsValid = false; +#endif } } + }; - return GetObject(pLink); + Iterator Begin() + { + typedef SList T_THIS; + return Iterator(dac_cast( + dac_cast(this) + offsetof(T_THIS, m_pHead))); } -#endif // !DACCESS_COMPILE + Iterator End() + { return Iterator::End(); } - T* GetHead() + Iterator FindFirst(PTR_T pItem) { - WRAPPER_NO_CONTRACT; - return GetObject(m_pHead->m_pNext); + Iterator it = Begin(); + for (; it != End(); ++it) + { + if (Traits::Equals(*it, pItem)) + break; + } + return it; } - T* GetTail() + // Inserts pItem *before* it. Returns iterator pointing to inserted item. + Iterator Insert(Iterator & it, PTR_T pItem) { - WRAPPER_NO_CONTRACT; - - // conditional compile - if (fHead) - { // you instantiated this class asking only for InsertHead operations - // you need to walk the list yourself to find the tail - _ASSERTE(0); - } - return (m_pHead != m_pTail) ? GetObject(m_pTail) : NULL; + static_assert(!Traits::HasTail, "Iterator Insert cannot maintain m_pTail"); + return it.Insert(pItem); } - static T *GetNext(T *pObj) + // Removes item pointed to by it. Returns iterator to following item. + Iterator Remove(Iterator & it) { - WRAPPER_NO_CONTRACT; - - _ASSERTE(pObj != NULL); - return GetObject(GetLink(pObj)->m_pNext); + static_assert(!Traits::HasTail, "Iterator Remove cannot maintain m_pTail"); + return it.Remove(); } - T* FindAndRemove(T *pObj) - { - WRAPPER_NO_CONTRACT; +#ifndef DACCESS_COMPILE - _ASSERTE(pObj != NULL); + void InsertHead(PTR_T pItem) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(pItem != NULL); + if constexpr (Traits::HasTail) + { + if (m_pHead == NULL) + this->m_pTail = pItem; + } + *Traits::GetNextPtr(pItem) = m_pHead; + m_pHead = pItem; + } - SLink *prior; - SLink *ret = SLink::FindAndRemove(m_pHead, GetLink(pObj), &prior); + PTR_T RemoveHead() + { + LIMITED_METHOD_CONTRACT; + PTR_T pRet = m_pHead; + if (pRet != NULL) + { + m_pHead = *Traits::GetNextPtr(pRet); + if constexpr (Traits::HasTail) + { + if (m_pHead == NULL) + this->m_pTail = NULL; + } + } - if (ret == m_pTail) - m_pTail = PTR_SLink(prior); + return pRet; + } - return GetObject(ret); + void InsertTail(PTR_T pItem) + { + static_assert(Traits::HasTail, "InsertTail requires Traits::HasTail to be true"); + LIMITED_METHOD_CONTRACT; + _ASSERTE(pItem != NULL); + *Traits::GetNextPtr(pItem) = NULL; + if (this->m_pTail != NULL) + *Traits::GetNextPtr(this->m_pTail) = pItem; + else + m_pHead = pItem; + this->m_pTail = pItem; } - class Iterator + PTR_T GetTail() { - friend class SList; + static_assert(Traits::HasTail, "GetTail requires Traits::HasTail to be true"); + LIMITED_METHOD_DAC_CONTRACT; - public: - Iterator & operator++() - { _ASSERTE(m_cur != NULL); m_cur = SList::GetNext(m_cur); return *this; } + return this->m_pTail; + } - Iterator operator++(int) - { Iterator it(m_cur); ++(*this); return it; } + bool RemoveFirst(PTR_T pItem) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(pItem != NULL); - bool operator==(Iterator const & other) const + PTR_T prev = NULL; + PTR_T cur = m_pHead; + while (cur != NULL) { - return m_cur == other.m_cur || - (m_cur != NULL && other.m_cur != NULL && *m_cur == *other.m_cur); + if (Traits::Equals(cur, pItem)) + { + PTR_T next = *Traits::GetNextPtr(cur); + if (prev == NULL) + m_pHead = next; + else + *Traits::GetNextPtr(prev) = next; + + if constexpr (Traits::HasTail) + { + if (cur == this->m_pTail) + this->m_pTail = prev; + } + + return true; + } + prev = cur; + cur = *Traits::GetNextPtr(cur); } - bool operator!=(Iterator const & other) const - { return !(*this == other); } - - T & operator*() - { _ASSERTE(m_cur != NULL); return *m_cur; } - - T * operator->() const - { return m_cur; } - - private: - Iterator(SList * pList) - : m_cur(pList->GetHead()) - { } - - Iterator(T* pObj) - : m_cur(pObj) - { } + return false; + } - Iterator() - : m_cur(NULL) - { } + // Alias for RemoveFirst, for API compatibility. + bool FindAndRemove(PTR_T pItem) + { + WRAPPER_NO_CONTRACT; - T* m_cur; - }; + return RemoveFirst(pItem); + } - Iterator begin() - { return Iterator(GetHead()); } + // Inserts pNewItem immediately after pAfter in the list. + static void InsertAfter(PTR_T pAfter, PTR_T pNewItem) + { + static_assert(!Traits::HasTail, "InsertAfter cannot maintain m_pTail"); + LIMITED_METHOD_CONTRACT; + _ASSERTE(pAfter != NULL && pNewItem != NULL); + _ASSERTE(*Traits::GetNextPtr(pNewItem) == NULL); + *Traits::GetNextPtr(pNewItem) = *Traits::GetNextPtr(pAfter); + *Traits::GetNextPtr(pAfter) = pNewItem; + } - Iterator end() - { return Iterator(); } +#endif // !DACCESS_COMPILE }; +// --------------------------------------------------------------------------- +// Convenience alias for tail-tracking SList. +// --------------------------------------------------------------------------- +template using SListTail = SList>; + +// --------------------------------------------------------------------------- +// SListElem — non-intrusive list element wrapper. +// --------------------------------------------------------------------------- template struct SListElem { - SLink m_Link; + typedef DPTR(SListElem) PTR_SListElem; + PTR_SListElem m_pNext; ElemT m_Value; operator ElemT const &() const @@ -357,35 +415,33 @@ struct SListElem { return m_Value; } SListElem() - : m_Link() + : m_pNext(NULL) , m_Value() { } template SListElem(T1&& val) - : m_Link() + : m_pNext(NULL) , m_Value(std::forward(val)) { } template SListElem(T1&& val1, T2&& val2) - : m_Link() + : m_pNext(NULL) , m_Value(std::forward(val1), std::forward(val2)) { } template SListElem(T1&& val1, T2&& val2, T3&& val3) - : m_Link() + : m_pNext(NULL) , m_Value(std::forward(val1), std::forward(val2), std::forward(val3)) { } template SListElem(T1&& val1, T2&& val2, T3&& val3, T4&& val4) - : m_Link() + : m_pNext(NULL) , m_Value(std::forward(val1), std::forward(val2), std::forward(val3), std::forward(val4)) { } }; #endif // _H_SLIST_ - -// End of file: list.h diff --git a/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp b/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp index 2050eb1216d9c2..4c19087fa577df 100644 --- a/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp @@ -28,7 +28,6 @@ #include "TypeManager.h" #include "MethodTable.h" #include "ObjectLayout.h" -#include "slist.inl" #include "MethodTable.inl" #include "CommonMacros.inl" #include "volatile.h" diff --git a/src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp b/src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp index 919a99a7148f2e..74a930a0e9bdc8 100644 --- a/src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp +++ b/src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp @@ -24,7 +24,6 @@ #include "MethodTable.h" #include "CommonMacros.inl" -#include "slist.inl" #include "MethodTable.inl" #include "../../inc/clrversion.h" @@ -268,7 +267,7 @@ bool RuntimeInstance::RegisterTypeManager(TypeManager * pTypeManager) return false; pEntry->m_pTypeManager = pTypeManager; - m_TypeManagerList.PushHeadInterlocked(pEntry); + m_TypeManagerList.InsertHead(pEntry); return true; } @@ -290,7 +289,7 @@ FCIMPL1(void*, RhpRegisterOsModule, HANDLE hOsModule) pEntry->m_osModule = hOsModule; RuntimeInstance *pRuntimeInstance = GetRuntimeInstance(); - pRuntimeInstance->GetOsModuleList()->PushHeadInterlocked(pEntry); + pRuntimeInstance->GetOsModuleList()->InsertHead(pEntry); return hOsModule; // Return non-null on success } diff --git a/src/coreclr/nativeaot/Runtime/RuntimeInstance.h b/src/coreclr/nativeaot/Runtime/RuntimeInstance.h index 7f6b7ac6195c8e..349bf1dbc7b578 100644 --- a/src/coreclr/nativeaot/Runtime/RuntimeInstance.h +++ b/src/coreclr/nativeaot/Runtime/RuntimeInstance.h @@ -10,6 +10,7 @@ class ICodeManager; class TypeManager; enum GenericVarianceType : uint8_t; +#include "forward_declarations.h" #include "ICodeManager.h" extern "C" void PopulateDebugHeaders(); @@ -17,7 +18,6 @@ extern "C" void PopulateDebugHeaders(); class RuntimeInstance { friend class AsmOffsets; - friend struct DefaultSListTraits; friend class Thread; friend void PopulateDebugHeaders(); @@ -29,10 +29,8 @@ class RuntimeInstance typedef DPTR(OsModuleEntry) PTR_OsModuleEntry; struct OsModuleEntry { - // os Module list is add-only, so we can use PushHeadInterlocked and iterate without synchronization. - // m_pNext is volatile - to make sure there are no re-reading optimizations when iterating. - PTR_OsModuleEntry volatile m_pNext; - HANDLE m_osModule; + PTR_OsModuleEntry m_pNext; + HANDLE m_osModule; }; typedef SList OsModuleList; @@ -48,10 +46,8 @@ class RuntimeInstance public: struct TypeManagerEntry { - // TypeManager list is add-only, so we can use PushHeadInterlocked and iterate without synchronization. - // m_pNext is volatile - to make sure there are no re-reading optimizations when iterating. - TypeManagerEntry* volatile m_pNext; - TypeManager* m_pTypeManager; + TypeManagerEntry* m_pNext; + TypeManager* m_pTypeManager; }; typedef SList TypeManagerList; diff --git a/src/coreclr/nativeaot/Runtime/allocheap.cpp b/src/coreclr/nativeaot/Runtime/allocheap.cpp index be924529ce5d59..e7ad1a9ed3b3d6 100644 --- a/src/coreclr/nativeaot/Runtime/allocheap.cpp +++ b/src/coreclr/nativeaot/Runtime/allocheap.cpp @@ -14,7 +14,6 @@ #include "allocheap.h" #include "CommonMacros.inl" -#include "slist.inl" //------------------------------------------------------------------------------------------------- AllocHeap::AllocHeap() @@ -39,7 +38,7 @@ void AllocHeap::Destroy() { while (!m_blockList.IsEmpty()) { - BlockListElem *pCur = m_blockList.PopHead(); + BlockListElem *pCur = m_blockList.RemoveHead(); delete[] (uint8_t*)pCur; } m_lock.Destroy(); @@ -88,7 +87,7 @@ bool AllocHeap::_AllocNewBlock(uintptr_t cbMem, uintptr_t alignment) BlockListElem *pBlockListElem = reinterpret_cast(pbMem); pBlockListElem->m_cbMem = cbBlockSize; - m_blockList.PushHead(pBlockListElem); + m_blockList.InsertHead(pBlockListElem); m_cbCurBlockUsed = sizeof(BlockListElem); return true; diff --git a/src/coreclr/nativeaot/Runtime/slist.h b/src/coreclr/nativeaot/Runtime/slist.h index 9c67d1b9bf40dc..cf077c3c71be20 100644 --- a/src/coreclr/nativeaot/Runtime/slist.h +++ b/src/coreclr/nativeaot/Runtime/slist.h @@ -1,126 +1,4 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#ifndef __slist_h__ -#define __slist_h__ - -#include "forward_declarations.h" - -MSVC_SAVE_WARNING_STATE() -MSVC_DISABLE_WARNING(4127) // conditional expression is constant -- it's intentionally constant - -struct DoNothingFailFastPolicy -{ - static inline void FailFast(); -}; - -template -struct DefaultSListTraits : public FailFastPolicy -{ - typedef DPTR(T) PTR_T; - typedef DPTR(PTR_T) PTR_PTR_T; - - static inline PTR_PTR_T GetNextPtr(PTR_T pT); - static inline bool Equals(PTR_T pA, PTR_T pB); -}; - -//------------------------------------------------------------------------------------------------------------ -// class SList, to use a singly linked list. -// -// To use, either expose a field DPTR(T) m_pNext by adding DefaultSListTraits as a friend class, or -// define a new Traits class derived from DefaultSListTraits and override the GetNextPtr function. -// -// SList supports lockless head insert and Remove methods. However, PushHeadInterlocked and -// PopHeadInterlocked must be used very carefully, as the rest of the mutating methods are not -// interlocked. In general, code must be careful to ensure that it will never use more than one -// synchronization mechanism at any given time to control access to a resource, and this is no -// exception. In particular, if synchronized access to other SList operations (such as FindAndRemove) -// are required, than a separate synchronization mechanism (such as a critical section) must be used. -//------------------------------------------------------------------------------------------------------------ -template > -class SList : public Traits -{ -protected: - typedef typename Traits::PTR_T PTR_T; - typedef typename Traits::PTR_PTR_T PTR_PTR_T; - -public: - SList(); - - // Returns true if there are no entries in the list. - bool IsEmpty(); - - // Returns the value of (but does not remove) the first element in the list. - PTR_T GetHead(); - - // Inserts pItem at the front of the list. See class header for more information. - void PushHead(PTR_T pItem); - void PushHeadInterlocked(PTR_T pItem); - - // Removes and returns the first entry in the list. See class header for more information. - PTR_T PopHead(); - - class Iterator - { - friend SList; - - public: - Iterator(Iterator const &it); - Iterator& operator=(Iterator const &it); - - PTR_T operator->(); - PTR_T operator*(); - - Iterator & operator++(); - Iterator operator++(int); - - bool operator==(Iterator const &rhs); - bool operator==(PTR_T pT); - bool operator!=(Iterator const &rhs); - - private: - Iterator(PTR_PTR_T ppItem); - - Iterator Insert(PTR_T pItem); - Iterator Remove(); - - static Iterator End(); - PTR_PTR_T m_ppCur; -#ifdef _DEBUG - mutable bool m_fIsValid; -#endif - - PTR_T _Value() const; - - enum e_ValidateOperation - { - e_CanCompare, // Will assert in debug if m_fIsValid == false. - e_CanInsert, // i.e., not the fake End() value of m_ppCur == NULL - e_HasValue, // i.e., m_ppCur != NULL && *m_ppCur != NULL - }; - void _Validate(e_ValidateOperation op) const; - }; - - Iterator Begin(); - Iterator End(); - - // Returns iterator to first list item matching pItem - Iterator FindFirst(PTR_T pItem); - bool RemoveFirst(PTR_T pItem); - - // Inserts pItem *before* it. Returns iterator pointing to inserted item. - Iterator Insert(Iterator & it, PTR_T pItem); - - // Removes item pointed to by it from the list. Returns iterator pointing - // to following item. - Iterator Remove(Iterator & it); - -private: - // when using PushHeadInterlocked, the head may be inserted concurrently. - // m_pHead is volatile - to make sure there are no re-reading optimizations when iterating. - PTR_T volatile m_pHead; -}; - -MSVC_RESTORE_WARNING_STATE() - -#endif // __slist_h__ +#include "../../inc/slist.h" diff --git a/src/coreclr/nativeaot/Runtime/slist.inl b/src/coreclr/nativeaot/Runtime/slist.inl deleted file mode 100644 index a9fb5989875473..00000000000000 --- a/src/coreclr/nativeaot/Runtime/slist.inl +++ /dev/null @@ -1,376 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -MSVC_SAVE_WARNING_STATE() -MSVC_DISABLE_WARNING(4127) // conditional expression is constant -- - // while (true) loops and compile time template constants cause this. - - -//------------------------------------------------------------------------------------------------- -namespace rh { namespace std -{ - template - inline - uintptr_t count(_InIt _First, _InIt _Last, const _Ty& _Val) - { - uintptr_t _Ret = 0; - for (; _First != _Last; _First++) - if (*_First == _Val) - ++_Ret; - return _Ret; - } - - template - inline - _InIt find(_InIt _First, _InIt _Last, const _Ty& _Val) - { // find first matching _Val - for (; _First != _Last; ++_First) - if (*_First == _Val) - break; - return (_First); - } - - // Specialize rh::std::find for SList iterators so that it will use _Traits::Equals. - template - inline - typename SList<_Tx, _Traits>::Iterator find( - typename SList<_Tx, _Traits>::Iterator _First, - typename SList<_Tx, _Traits>::Iterator _Last, - const _Ty& _Val) - { // find first matching _Val - for (; _First != _Last; ++_First) - if (_Traits::Equals(*_First, _Val)) - break; - return (_First); - } -} // namespace std -} // namespace rh - -//------------------------------------------------------------------------------------------------- -inline -void DoNothingFailFastPolicy::FailFast() -{ - // Intentionally a no-op. -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename DefaultSListTraits::PTR_PTR_T DefaultSListTraits::GetNextPtr( - PTR_T pT) -{ - ASSERT(pT != NULL); - return dac_cast(dac_cast(pT) + offsetof(T, m_pNext)); -} - -//------------------------------------------------------------------------------------------------- -template -inline -bool DefaultSListTraits::Equals( - PTR_T pA, - PTR_T pB) -{ // Default is pointer comparison - return pA == pB; -} - -//------------------------------------------------------------------------------------------------- -template -inline -SList::SList() - : m_pHead(NULL) -{ -} - -//------------------------------------------------------------------------------------------------- -template -inline -bool SList::IsEmpty() -{ - return Begin() == End(); -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::PTR_T SList::GetHead() -{ - return m_pHead; -} - -//------------------------------------------------------------------------------------------------- -template -inline -void SList::PushHead( - PTR_T pItem) -{ - Begin().Insert(pItem); -} - -//------------------------------------------------------------------------------------------------- -template -inline -void SList::PushHeadInterlocked( - PTR_T pItem) -{ - ASSERT(pItem != NULL); - ASSERT(IS_ALIGNED(&m_pHead, sizeof(void*))); - - while (true) - { - *Traits::GetNextPtr(pItem) = *reinterpret_cast(&m_pHead); - if (PalInterlockedCompareExchangePointer( - reinterpret_cast(&m_pHead), - reinterpret_cast(pItem), - reinterpret_cast(*Traits::GetNextPtr(pItem))) == reinterpret_cast(*Traits::GetNextPtr(pItem))) - { - break; - } - } -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::PTR_T SList::PopHead() -{ - PTR_T pRet = *Begin(); - Begin().Remove(); - return pRet; -} - -//------------------------------------------------------------------------------------------------- -template -inline -SList::Iterator::Iterator( - Iterator const &it) - : m_ppCur(it.m_ppCur) -#ifdef _DEBUG - , m_fIsValid(it.m_fIsValid) -#endif -{ -} - -//------------------------------------------------------------------------------------------------- -template -inline -SList::Iterator::Iterator( - PTR_PTR_T ppItem) - : m_ppCur(ppItem) -#ifdef _DEBUG - , m_fIsValid(true) -#endif -{ -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator& SList::Iterator::operator=( - Iterator const &it) -{ - m_ppCur = it.m_ppCur; -#ifdef _DEBUG - m_fIsValid = it.m_fIsValid; -#endif - return *this; -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::PTR_T SList::Iterator::operator->() -{ - _Validate(e_HasValue); - return _Value(); -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::PTR_T SList::Iterator::operator*() -{ - _Validate(e_HasValue); - return _Value(); -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator & SList::Iterator::operator++() -{ - _Validate(e_HasValue); // Having a value means we're not at the end. - m_ppCur = Traits::GetNextPtr(_Value()); - return *this; -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator SList::Iterator::operator++( - int) -{ - _Validate(e_HasValue); // Having a value means we're not at the end. - PTR_PTR_T ppRet = m_ppCur; - ++(*this); - return Iterator(ppRet); -} - -//------------------------------------------------------------------------------------------------- -template -inline -bool SList::Iterator::operator==( - Iterator const &rhs) -{ - _Validate(e_CanCompare); - rhs._Validate(e_CanCompare); - return Traits::Equals(_Value(), rhs._Value()); -} - -//------------------------------------------------------------------------------------------------- -template -inline -bool SList::Iterator::operator==( - PTR_T pT) -{ - _Validate(e_CanCompare); - return Traits::Equals(_Value(), pT); -} - -//------------------------------------------------------------------------------------------------- -template -inline -bool SList::Iterator::operator!=( - Iterator const &rhs) -{ - return !operator==(rhs); -} - -//------------------------------------------------------------------------------------------------- -template -inline /*static*/ -typename SList::Iterator SList::Iterator::End() -{ - return Iterator(NULL); -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator SList::Iterator::Insert( - PTR_T pItem) -{ - _Validate(e_CanInsert); - *Traits::GetNextPtr(pItem) = *m_ppCur; - *m_ppCur = pItem; - Iterator itRet(m_ppCur); - ++(*this); - return itRet; -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator SList::Iterator::Remove() -{ - _Validate(e_HasValue); - *m_ppCur = *Traits::GetNextPtr(*m_ppCur); - PTR_PTR_T ppRet = m_ppCur; - // Set it to End, so that subsequent misuse of this iterator will - // result in an AV rather than possible memory corruption. - *this = End(); - return Iterator(ppRet); -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::PTR_T SList::Iterator::_Value() const -{ - ASSERT(m_fIsValid); - return dac_cast(m_ppCur == NULL ? NULL : *m_ppCur); -} - -//------------------------------------------------------------------------------------------------- -template -inline -void SList::Iterator::_Validate(e_ValidateOperation op) const -{ - ASSERT(m_fIsValid); - ASSERT(op == e_CanCompare || op == e_CanInsert || op == e_HasValue); - - if ((op != e_CanCompare && m_ppCur == NULL) || - (op == e_HasValue && *m_ppCur == NULL)) - { - // NOTE: Default of DoNothingFailFastPolicy is a no-op, and so this function will be - // eliminated in retail builds. This is ok, as the subsequent operation will cause - // an AV, which will itself trigger a FailFast. Provide a different policy to get - // different behavior. - ASSERT_MSG(false, "Invalid SList::Iterator use."); - Traits::FailFast(); -#ifdef _DEBUG - m_fIsValid = false; -#endif - } -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator SList::Begin() -{ - typedef SList T_THIS; - return Iterator(dac_cast( - dac_cast(this) + offsetof(T_THIS, m_pHead))); -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator SList::End() -{ - return Iterator::End(); -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator SList::FindFirst(PTR_T pItem) -{ - return rh::std::find(Begin(), End(), pItem); -} - -//------------------------------------------------------------------------------------------------- -template -inline -bool SList::RemoveFirst(PTR_T pItem) -{ - Iterator it = FindFirst(pItem); - if (it != End()) - { - it.Remove(); - return true; - } - else - { - return false; - } -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator SList::Insert(Iterator & it, PTR_T pItem) -{ - return it.Insert(pItem); -} - -//------------------------------------------------------------------------------------------------- -template -inline -typename SList::Iterator SList::Remove(Iterator & it) -{ - return it.Remove(); -} - - -MSVC_RESTORE_WARNING_STATE() - diff --git a/src/coreclr/nativeaot/Runtime/thread.h b/src/coreclr/nativeaot/Runtime/thread.h index c93556e59ebb67..a910894ec968df 100644 --- a/src/coreclr/nativeaot/Runtime/thread.h +++ b/src/coreclr/nativeaot/Runtime/thread.h @@ -5,7 +5,7 @@ #define __thread_h__ #include "StackFrameIterator.h" -#include "slist.h" // DefaultSListTraits +#include "slist.h" // SListTraits #include struct gc_alloc_context; @@ -179,7 +179,7 @@ struct ReversePInvokeFrame class Thread : private RuntimeThreadLocals { friend class AsmOffsets; - friend struct DefaultSListTraits; + friend struct SListTraits; friend class ThreadStore; IN_DAC(friend class ClrDataAccess;) diff --git a/src/coreclr/nativeaot/Runtime/threadstore.cpp b/src/coreclr/nativeaot/Runtime/threadstore.cpp index 3059d1ca8750d0..0439f0c76058ab 100644 --- a/src/coreclr/nativeaot/Runtime/threadstore.cpp +++ b/src/coreclr/nativeaot/Runtime/threadstore.cpp @@ -25,8 +25,6 @@ #include #include "SignalSafeThreadMap.h" -#include "slist.inl" - EXTERN_C volatile uint32_t RhpTrapThreads; volatile uint32_t RhpTrapThreads = (uint32_t)TrapThreadsFlags::None; @@ -144,7 +142,7 @@ void ThreadStore::AttachCurrentThread(bool fAcquireThreadStoreLock) ASSERT(pAttachingThread->m_ThreadStateFlags == Thread::TSF_Unknown); pAttachingThread->m_ThreadStateFlags = Thread::TSF_Attached; - pTS->m_ThreadList.PushHead(pAttachingThread); + pTS->m_ThreadList.InsertHead(pAttachingThread); #if defined(TARGET_UNIX) && !defined(TARGET_WASM) if (!InsertThreadIntoSignalSafeMap(pAttachingThread->m_threadId, pAttachingThread)) @@ -193,9 +191,9 @@ void ThreadStore::DetachCurrentThread() // Note that when process is shutting down, the threads may be rudely terminated, // possibly while holding the threadstore lock. That is ok, since the process is being torn down. CrstHolder threadStoreLock(&pTS->m_Lock); - ASSERT(rh::std::count(pTS->m_ThreadList.Begin(), pTS->m_ThreadList.End(), pDetachingThread) == 1); // remove the thread from the list of managed threads. - pTS->m_ThreadList.RemoveFirst(pDetachingThread); + bool removed = pTS->m_ThreadList.RemoveFirst(pDetachingThread); + ASSERT(removed); // tidy up GC related stuff (release allocation context, etc..) pDetachingThread->Detach(); #if defined(TARGET_UNIX) && !defined(TARGET_WASM) diff --git a/src/coreclr/vm/cachelinealloc.cpp b/src/coreclr/vm/cachelinealloc.cpp index 4c32903c6de399..e7dadaf044a1e7 100644 --- a/src/coreclr/vm/cachelinealloc.cpp +++ b/src/coreclr/vm/cachelinealloc.cpp @@ -39,10 +39,6 @@ CCacheLineAllocator::CCacheLineAllocator() MODE_ANY; } CONTRACTL_END; - - m_freeList32.Init(); - m_freeList64.Init(); - m_registryList.Init(); } /////////////////////////////////////////////////////// diff --git a/src/coreclr/vm/cachelinealloc.h b/src/coreclr/vm/cachelinealloc.h index 4ea26c1bbf006e..d9daacd4bd29c4 100644 --- a/src/coreclr/vm/cachelinealloc.h +++ b/src/coreclr/vm/cachelinealloc.h @@ -46,7 +46,8 @@ class CacheLine }; // store next pointer and the entries - total of 16 pointers - SLink m_Link; + // Next pointer for SList linkage. + DPTR(CacheLine) m_pNext; union { void* m_pAddr[numEntries]; @@ -64,7 +65,7 @@ class CacheLine CONTRACTL_END; // initialize cacheline - m_Link = {}; + m_pNext = NULL; memset(m_xxx,0,numValidBytes); } }; @@ -80,9 +81,9 @@ typedef CacheLine* LPCacheLine; /////////////////////////////////////////////////////// class CCacheLineAllocator { - typedef SList REGISTRYLIST; - typedef SList FREELIST32; - typedef SList FREELIST64; + typedef SList REGISTRYLIST; + typedef SList FREELIST32; + typedef SList FREELIST64; public: diff --git a/src/coreclr/vm/callcounting.cpp b/src/coreclr/vm/callcounting.cpp index ee053d81052275..1d5ca8b40bf00e 100644 --- a/src/coreclr/vm/callcounting.cpp +++ b/src/coreclr/vm/callcounting.cpp @@ -383,7 +383,7 @@ CallCountingManager::MethodDescForwarderStubHashTraits::Hash(const key_t &k) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CallCountingManager -SList CallCountingManager::s_callCountingManagers; +CallCountingManager::CallCountingManagerList CallCountingManager::s_callCountingManagers; COUNT_T CallCountingManager::s_callCountingStubCount = 0; COUNT_T CallCountingManager::s_activeCallCountingStubCount = 0; COUNT_T CallCountingManager::s_completedCallCountingStubCount = 0; @@ -729,7 +729,7 @@ COUNT_T CallCountingManager::GetCountOfCodeVersionsPendingCompletion() CodeVersionManager::LockHolder codeVersioningLockHolder; - for (CallCountingManager *callCountingManager = s_callCountingManagers.GetHead(); callCountingManager != nullptr; callCountingManager = SList::GetNext(callCountingManager)) + for (CallCountingManager *callCountingManager = s_callCountingManagers.GetHead(); callCountingManager != nullptr; callCountingManager = CallCountingManagerList::GetNext(callCountingManager)) { count += callCountingManager->m_callCountingInfosPendingCompletion.GetCount(); } @@ -756,7 +756,7 @@ void CallCountingManager::CompleteCallCounting() MethodDescBackpatchInfoTracker::ConditionalLockHolder slotBackpatchLockHolder; CodeVersionManager::LockHolder codeVersioningLockHolder; - for (CallCountingManager *callCountingManager = s_callCountingManagers.GetHead(); callCountingManager != nullptr; callCountingManager = SList::GetNext(callCountingManager)) + for (CallCountingManager *callCountingManager = s_callCountingManagers.GetHead(); callCountingManager != nullptr; callCountingManager = CallCountingManagerList::GetNext(callCountingManager)) { SArray &callCountingInfosPendingCompletion = callCountingManager->m_callCountingInfosPendingCompletion; @@ -916,7 +916,7 @@ void CallCountingManager::StopAllCallCounting(TieredCompilationManager *tieredCo _ASSERTE(CodeVersionManager::IsLockOwnedByCurrentThread()); _ASSERTE(tieredCompilationManager != nullptr); - for (CallCountingManager *callCountingManager = s_callCountingManagers.GetHead(); callCountingManager != nullptr; callCountingManager = SList::GetNext(callCountingManager)) + for (CallCountingManager *callCountingManager = s_callCountingManagers.GetHead(); callCountingManager != nullptr; callCountingManager = CallCountingManagerList::GetNext(callCountingManager)) { CallCountingInfoByCodeVersionHash &callCountingInfoByCodeVersionHash = callCountingManager->m_callCountingInfoByCodeVersionHash; @@ -1002,7 +1002,7 @@ void CallCountingManager::DeleteAllCallCountingStubs() s_callCountingStubCount = 0; s_completedCallCountingStubCount = 0; - for (CallCountingManager *callCountingManager = s_callCountingManagers.GetHead(); callCountingManager != nullptr; callCountingManager = SList::GetNext(callCountingManager)) + for (CallCountingManager *callCountingManager = s_callCountingManagers.GetHead(); callCountingManager != nullptr; callCountingManager = CallCountingManagerList::GetNext(callCountingManager)) { _ASSERTE(callCountingManager->m_callCountingInfosPendingCompletion.IsEmpty()); diff --git a/src/coreclr/vm/callcounting.h b/src/coreclr/vm/callcounting.h index a9600c883cc0ae..ceb20fc76485c3 100644 --- a/src/coreclr/vm/callcounting.h +++ b/src/coreclr/vm/callcounting.h @@ -300,10 +300,13 @@ class CallCountingManager // CallCountingManager members public: - SLink m_Link; + // Next pointer for SList linkage. + DPTR(CallCountingManager) m_pNext; private: - static SList s_callCountingManagers; + typedef SListTail CallCountingManagerList; + + static CallCountingManagerList s_callCountingManagers; static COUNT_T s_callCountingStubCount; static COUNT_T s_activeCallCountingStubCount; static COUNT_T s_completedCallCountingStubCount; diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index 1f28d1ff6e8ee3..f4c60e20ea451e 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -595,7 +595,7 @@ void ConnectionPoint::InsertWithLock(ConnectionCookie* pConCookie) fDone = true; } - if (!fDone && ((NULL != m_pLastInserted->m_Link.m_pNext) || (idUpperLimit == m_pLastInserted->m_id))) + if (!fDone && ((NULL != CONNECTIONCOOKIELIST::GetNext(m_pLastInserted)) || (idUpperLimit == m_pLastInserted->m_id))) { // // Special case 2: Last inserted is somewhere in the middle of the list or we last @@ -621,7 +621,7 @@ void ConnectionPoint::InsertWithLock(ConnectionCookie* pConCookie) ConnectionCookie* pLocationToStartSearchForInsertPoint = NULL; ConnectionCookie* pInsertionPoint = NULL; - if (NULL == m_pLastInserted->m_Link.m_pNext) + if (NULL == CONNECTIONCOOKIELIST::GetNext(m_pLastInserted)) { if (idUpperLimit == m_pLastInserted->m_id) { @@ -656,7 +656,7 @@ void ConnectionPoint::InsertWithLock(ConnectionCookie* pConCookie) // while (true) { - if (NULL == pCurrentNode->m_Link.m_pNext) + if (NULL == CONNECTIONCOOKIELIST::GetNext(pCurrentNode)) { if (pCurrentNode->m_id < idUpperLimit) { @@ -667,7 +667,7 @@ void ConnectionPoint::InsertWithLock(ConnectionCookie* pConCookie) } else { - ConnectionCookie* pNext = CONTAINING_RECORD(pCurrentNode->m_Link.m_pNext, ConnectionCookie, m_Link); + ConnectionCookie* pNext = CONNECTIONCOOKIELIST::GetNext(pCurrentNode); if ((pCurrentNode->m_id + 1) < pNext->m_id) { break; @@ -691,7 +691,7 @@ void ConnectionPoint::InsertWithLock(ConnectionCookie* pConCookie) CONSISTENCY_CHECK(idUpperLimit != pInsertionPoint->m_id); #ifdef _DEBUG - ConnectionCookie* pNextCookieNode = CONTAINING_RECORD(pInsertionPoint->m_Link.m_pNext, ConnectionCookie, m_Link); + ConnectionCookie* pNextCookieNode = CONNECTIONCOOKIELIST::GetNext(pInsertionPoint); DWORD idNew = pInsertionPoint->m_id + 1; CONSISTENCY_CHECK(NULL == pNextCookieNode || ((pInsertionPoint->m_id < idNew) && @@ -699,7 +699,7 @@ void ConnectionPoint::InsertWithLock(ConnectionCookie* pConCookie) #endif // _DEBUG pConCookie->m_id = pInsertionPoint->m_id + 1; - pInsertionPoint->m_Link.InsertAfter(&pConCookie->m_Link); + CONNECTIONCOOKIELIST::InsertAfter(pInsertionPoint, pConCookie); } m_pLastInserted = pConCookie; @@ -718,7 +718,7 @@ ConnectionCookie* ConnectionPoint::FindWithLock(DWORD idOfCookie) while (pCurrentNode && (pCurrentNode->m_id != idOfCookie)) { - pCurrentNode = CONTAINING_RECORD(pCurrentNode->m_Link.m_pNext, ConnectionCookie, m_Link); + pCurrentNode = CONNECTIONCOOKIELIST::GetNext(pCurrentNode); } } @@ -1105,7 +1105,6 @@ HRESULT __stdcall ConnectionEnum::Next(ULONG cConnections, CONNECTDATA* rgcd, UL HRESULT hr = S_OK; UINT cFetched; - CONNECTIONCOOKIELIST *pConnectionList = m_pConnectionPoint->GetCookieList(); // Acquire the connection point's lock before we start traversing the connection list. { @@ -1122,7 +1121,7 @@ HRESULT __stdcall ConnectionEnum::Next(ULONG cConnections, CONNECTDATA* rgcd, UL rgcd[cFetched].pUnk = GetComIPFromObjectRef((OBJECTREF*)(OBJECTHANDLE)m_CurrCookie->m_hndEventProvObj, ComIpType_Unknown, NULL); rgcd[cFetched].dwCookie = m_CurrCookie->m_id; } - m_CurrCookie = pConnectionList->GetNext(m_CurrCookie); + m_CurrCookie = CONNECTIONCOOKIELIST::GetNext(m_CurrCookie); } } @@ -1149,7 +1148,6 @@ HRESULT __stdcall ConnectionEnum::Skip(ULONG cConnections) SetupForComCallHR(); HRESULT hr = S_FALSE; - CONNECTIONCOOKIELIST *pConnectionList = m_pConnectionPoint->GetCookieList(); { ConnectionPoint::LockHolder lh(m_pConnectionPoint); @@ -1157,7 +1155,7 @@ HRESULT __stdcall ConnectionEnum::Skip(ULONG cConnections) // Try and skip the requested number of connections. while (m_CurrCookie && cConnections) { - m_CurrCookie = pConnectionList->GetNext(m_CurrCookie); + m_CurrCookie = CONNECTIONCOOKIELIST::GetNext(m_CurrCookie); cConnections--; } // Leave the lock now that we are done traversing the list. diff --git a/src/coreclr/vm/comconnectionpoints.h b/src/coreclr/vm/comconnectionpoints.h index 97311c4ade04f6..88535dd0fff6e5 100644 --- a/src/coreclr/vm/comconnectionpoints.h +++ b/src/coreclr/vm/comconnectionpoints.h @@ -35,7 +35,7 @@ struct EventMethodInfo // Structure passed out as a cookie when Advise is called. struct ConnectionCookie { - ConnectionCookie(OBJECTHANDLEHolder hndEventProvObj) : m_hndEventProvObj(std::move(hndEventProvObj)) + ConnectionCookie(OBJECTHANDLEHolder hndEventProvObj) : m_pNext(NULL), m_hndEventProvObj(std::move(hndEventProvObj)) { CONTRACTL { @@ -65,8 +65,8 @@ struct ConnectionCookie RETURN (new ConnectionCookie(std::move(hndEventProvObj))); } - - SLink m_Link; + // Next pointer for SList linkage. + DPTR(ConnectionCookie) m_pNext; OBJECTHANDLEHolder m_hndEventProvObj; DWORD m_id; }; @@ -75,7 +75,7 @@ struct ConnectionCookie using ConnectionCookieHolder = NewHolder; // List of connection cookies. -typedef SList CONNECTIONCOOKIELIST; +typedef SList CONNECTIONCOOKIELIST; // ConnectionPoint class. This class implements IConnectionPoint and does the mapping // from a CP handler to a TCE provider. diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index a13b9b275ce31c..0769a5b7d7495d 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -196,10 +196,6 @@ CDAC_TYPE_FIELD(SyncBlock, T_POINTER, LinkNext, cdac_data::LinkNext) CDAC_TYPE_FIELD(SyncBlock, T_UINT32, HashCode, cdac_data::HashCode) CDAC_TYPE_END(SyncBlock) -CDAC_TYPE_BEGIN(SLink) -CDAC_TYPE_INDETERMINATE(SLink) -CDAC_TYPE_FIELD(SLink, T_POINTER, Next, offsetof(SLink, m_pNext)) -CDAC_TYPE_END(SLink) #ifdef FEATURE_COMWRAPPERS CDAC_TYPE_BEGIN(NativeObjectWrapperObject) diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 545e2cc7dd4539..7cf751d3260593 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -1962,7 +1962,7 @@ void AssemblyLoaderAllocator::UnregisterHandleFromCleanup(OBJECTHANDLE objHandle // FindAndRemove must be protected by a lock. Just use the loader allocator lock CrstHolder ch(&m_crstLoaderAllocator); - for (HandleCleanupListItem* item = m_handleCleanupList.GetHead(); item != NULL; item = SList::GetNext(item)) + for (HandleCleanupListItem* item = m_handleCleanupList.GetHead(); item != NULL; item = SListTail::GetNext(item)) { if (item->m_handle == objHandle) { diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 68c372185b4723..15ad9c726db0ef 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -452,16 +452,18 @@ class LoaderAllocator struct FailedTypeInitCleanupListItem { - SLink m_Link; + // Next pointer for SList linkage. + DPTR(FailedTypeInitCleanupListItem) m_pNext; ListLockEntry *m_pListLockEntry; explicit FailedTypeInitCleanupListItem(ListLockEntry *pListLockEntry) : + m_pNext(PTR_NULL), m_pListLockEntry(pListLockEntry) { } }; - SList m_failedTypeInitCleanupList; + SListTail m_failedTypeInitCleanupList; SegmentedHandleIndexStack m_freeHandleIndexesStack; #ifdef FEATURE_COMINTEROP @@ -1013,16 +1015,18 @@ class AssemblyLoaderAllocator : public LoaderAllocator private: struct HandleCleanupListItem { - SLink m_Link; + // Next pointer for SList linkage. + DPTR(HandleCleanupListItem) m_pNext; OBJECTHANDLE m_handle; explicit HandleCleanupListItem(OBJECTHANDLE handle) : + m_pNext(PTR_NULL), m_handle(handle) { } }; - SList m_handleCleanupList; + SListTail m_handleCleanupList; #if !defined(DACCESS_COMPILE) CustomAssemblyBinder* m_binderToRelease; #endif diff --git a/src/coreclr/vm/syncblk.cpp b/src/coreclr/vm/syncblk.cpp index d81973bf4e2980..27501d6c2f1232 100644 --- a/src/coreclr/vm/syncblk.cpp +++ b/src/coreclr/vm/syncblk.cpp @@ -524,8 +524,8 @@ void SyncBlockCache::InsertCleanupSyncBlock(SyncBlock* psb) // we don't need to lock here //EnterCacheLock(); - psb->m_Link.m_pNext = m_pCleanupBlockList; - m_pCleanupBlockList = &psb->m_Link; + psb->m_pNext = m_pCleanupBlockList; + m_pCleanupBlockList = psb; // we don't need a lock here //LeaveCacheLock(); @@ -542,7 +542,7 @@ SyncBlock* SyncBlockCache::GetNextCleanupSyncBlock() if (m_pCleanupBlockList) { // get the actual sync block pointer - psb = (SyncBlock *) (((BYTE *) m_pCleanupBlockList) - offsetof(SyncBlock, m_Link)); + psb = m_pCleanupBlockList; m_pCleanupBlockList = m_pCleanupBlockList->m_pNext; } return psb; @@ -567,7 +567,7 @@ SyncBlock *SyncBlockCache::GetNextFreeSyncBlock() #endif SyncBlock *psb; - SLink *plst = m_FreeBlockList; + SyncBlock *plst = m_FreeBlockList; m_ActiveCount++; @@ -579,7 +579,7 @@ SyncBlock *SyncBlockCache::GetNextFreeSyncBlock() m_FreeCount--; // get the actual sync block pointer - psb = (SyncBlock *) (((BYTE *) plst) - offsetof(SyncBlock, m_Link)); + psb = plst; return psb; } @@ -823,8 +823,8 @@ void SyncBlockCache::DeleteSyncBlockMemory(SyncBlock *psb) m_ActiveCount--; m_FreeCount++; - psb->m_Link.m_pNext = m_FreeBlockList; - m_FreeBlockList = &psb->m_Link; + psb->m_pNext = m_FreeBlockList; + m_FreeBlockList = psb; } @@ -847,8 +847,8 @@ void SyncBlockCache::GCDeleteSyncBlock(SyncBlock *psb) m_ActiveCount--; m_FreeCount++; - psb->m_Link.m_pNext = m_FreeBlockList; - m_FreeBlockList = &psb->m_Link; + psb->m_pNext = m_FreeBlockList; + m_FreeBlockList = psb; } void SyncBlockCache::GCWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2) diff --git a/src/coreclr/vm/syncblk.h b/src/coreclr/vm/syncblk.h index 43c46739a5154f..e995eeea2282bc 100644 --- a/src/coreclr/vm/syncblk.h +++ b/src/coreclr/vm/syncblk.h @@ -418,19 +418,15 @@ class SyncBlock // If this object is exposed to unmanaged code, we keep some extra info here. PTR_InteropSyncBlockInfo m_pInteropInfo; + // Next pointer for linked-list linkage (SyncBlockCache free and cleanup lists). + PTR_SyncBlock m_pNext; + protected: #ifdef FEATURE_METADATA_UPDATER // And if the object has new fields added via EnC, this is a list of them PTR_EnCSyncBlockInfo m_pEnCInfo; #endif // FEATURE_METADATA_UPDATER - // When the SyncBlock is released (we recycle them), - // the SyncBlockCache maintains a free list of SyncBlocks here. - // - // We can't afford to use an SList<> here because we only want to burn - // space for the minimum, which is the pointer within an SLink. - SLink m_Link; - // This is the hash code for the object. It can either have been transferred // from the header dword, in which case it will be limited to 26 bits, or // have been generated right into this member variable here, when it will @@ -447,6 +443,7 @@ class SyncBlock : m_Lock((OBJECTHANDLE)NULL) , m_thinLock() , m_dwSyncIndex(indx) + , m_pNext(PTR_NULL) #ifdef FEATURE_METADATA_UPDATER , m_pEnCInfo(PTR_NULL) #endif // FEATURE_METADATA_UPDATER @@ -604,7 +601,7 @@ struct cdac_data static constexpr size_t InteropInfo = offsetof(SyncBlock, m_pInteropInfo); static constexpr size_t Lock = offsetof(SyncBlock, m_Lock); static constexpr size_t ThinLock = offsetof(SyncBlock, m_thinLock); - static constexpr size_t LinkNext = offsetof(SyncBlock, m_Link) + offsetof(SLink, m_pNext); + static constexpr size_t LinkNext = offsetof(SyncBlock, m_pNext); static constexpr size_t HashCode = offsetof(SyncBlock, m_dwHashCode); }; @@ -646,8 +643,8 @@ class SyncBlockCache private: - PTR_SLink m_pCleanupBlockList; // list of sync blocks that need cleanup - SLink* m_FreeBlockList; // list of free sync blocks + PTR_SyncBlock m_pCleanupBlockList; // list of sync blocks that need cleanup + PTR_SyncBlock m_FreeBlockList; // list of free sync blocks CrstStatic m_CacheLock; // cache lock DWORD m_FreeCount; // count of active sync blocks DWORD m_ActiveCount; // number active diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index d10279bbe0c7d3..292e5621b2e373 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -3941,7 +3941,6 @@ BOOL ThreadStore::RemoveThread(Thread *target) CONTRACTL_END; BOOL found; - Thread *ret; #if 0 // This assert is not valid when failing to create background GC thread. // Main GC thread holds the TS lock. @@ -3951,9 +3950,8 @@ BOOL ThreadStore::RemoveThread(Thread *target) _ASSERTE(s_pThreadStore->m_Crst.GetEnterCount() > 0 || IsAtProcessExit()); _ASSERTE(s_pThreadStore->DbgFindThread(target)); - ret = s_pThreadStore->m_ThreadList.FindAndRemove(target); - _ASSERTE(ret && ret == target); - found = (ret != NULL); + found = s_pThreadStore->m_ThreadList.FindAndRemove(target); + _ASSERTE(found); if (found) { diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index bb17344a8fe625..ade9b6ad804998 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -2224,10 +2224,9 @@ class Thread { return m_PreventAbort != 0; } - // The ThreadStore manages a list of all the threads in the system. I - // can't figure out how to expand the ThreadList template type without - // making m_Link public. - SLink m_Link; + // The ThreadStore manages a list of all the threads in the system. + // Next pointer for SList linkage (ThreadStore::m_ThreadList). + PTR_Thread m_pNext = NULL; // Debugger per-thread flag for enabling notification on "manual" // method calls, for stepping logic @@ -3761,7 +3760,7 @@ struct cdac_data static constexpr size_t ExposedObject = offsetof(Thread, m_ExposedObject); static constexpr size_t LastThrownObject = offsetof(Thread, m_LastThrownObjectHandle); static constexpr size_t LastThrownObjectIsUnhandled = offsetof(Thread, m_ltoIsUnhandled); - static constexpr size_t Link = offsetof(Thread, m_Link); + static constexpr size_t Link = offsetof(Thread, m_pNext); static constexpr size_t ThreadLocalDataPtr = offsetof(Thread, m_ThreadLocalDataPtr); static constexpr size_t CurrentCustomDebuggerNotification = offsetof(Thread, m_hCurrNotification); @@ -3795,7 +3794,7 @@ void UndoRevert(BOOL bReverted, HANDLE hToken); // ThreadStore::m_pThreadStore. // --------------------------------------------------------------------------- -typedef SList ThreadList; +typedef SListTail ThreadList; // The ThreadStore is a singleton class @@ -4034,7 +4033,7 @@ class ThreadStore template<> struct cdac_data { - static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList) + offsetof(ThreadList, m_link); + static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList) + offsetof(ThreadList, m_pHead); static constexpr size_t ThreadCount = offsetof(ThreadStore, m_ThreadCount); static constexpr size_t UnstartedCount = offsetof(ThreadStore, m_UnstartedThreadCount); static constexpr size_t BackgroundCount = offsetof(ThreadStore, m_BackgroundThreadCount); diff --git a/src/coreclr/vm/tieredcompilation.h b/src/coreclr/vm/tieredcompilation.h index 775240e8193a2c..09dacde317d20b 100644 --- a/src/coreclr/vm/tieredcompilation.h +++ b/src/coreclr/vm/tieredcompilation.h @@ -128,7 +128,9 @@ class TieredCompilationManager #endif // !DACCESS_COMPILE private: - SList> m_methodsToOptimize; + typedef SListTail> OptimizationQueue; + + OptimizationQueue m_methodsToOptimize; UINT32 m_countOfMethodsToOptimize; UINT32 m_countOfNewMethodsCalledDuringDelay; SArray* m_methodsPendingCountingForTier1; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SyncBlock_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SyncBlock_1.cs index d1eb3f83b9b478..f19648ed6459a3 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SyncBlock_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SyncBlock_1.cs @@ -15,13 +15,11 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; private const string LockNamespace = "System.Threading"; private readonly Target _target; private readonly TargetPointer _syncTableEntries; - private readonly ulong _syncBlockLinkOffset; internal SyncBlock_1(Target target) { _target = target; _syncTableEntries = target.ReadPointer(target.ReadGlobalPointer(Constants.Globals.SyncTableEntries)); - _syncBlockLinkOffset = (ulong)target.GetTypeInfo(DataType.SyncBlock).Fields[nameof(Data.SyncBlock.LinkNext)].Offset; } public TargetPointer GetSyncBlock(uint index) @@ -108,7 +106,7 @@ public TargetPointer GetSyncBlockFromCleanupList() TargetPointer cleanupBlockList = cache.CleanupBlockList; if (cleanupBlockList == TargetPointer.Null) return TargetPointer.Null; - return new TargetPointer(cleanupBlockList.Value - _syncBlockLinkOffset); + return cleanupBlockList; } public TargetPointer GetNextSyncBlock(TargetPointer syncBlock) @@ -116,7 +114,7 @@ public TargetPointer GetNextSyncBlock(TargetPointer syncBlock) Data.SyncBlock sb = _target.ProcessedData.GetOrAdd(syncBlock); if (sb.LinkNext == TargetPointer.Null) return TargetPointer.Null; - return new TargetPointer(sb.LinkNext.Value - _syncBlockLinkOffset); + return sb.LinkNext; } public bool GetBuiltInComData(TargetPointer syncBlock, out TargetPointer rcw, out TargetPointer ccw, out TargetPointer ccf) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Thread_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Thread_1.cs index b811041fb1a856..52bb2f30419e81 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Thread_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Thread_1.cs @@ -9,7 +9,6 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; { private readonly Target _target; private readonly TargetPointer _threadStoreAddr; - private readonly ulong _threadLinkOffset; [Flags] private enum TLSIndexType @@ -41,11 +40,6 @@ internal Thread_1(Target target) { _target = target; _threadStoreAddr = target.ReadPointer(target.ReadGlobalPointer(Constants.Globals.ThreadStore)); - - // Get the offset into Thread of the SLink. We use this to find the actual - // first thread from the linked list node contained by the first thread. - Target.TypeInfo type = _target.GetTypeInfo(DataType.Thread); - _threadLinkOffset = (ulong)type.Fields[nameof(Data.Thread.LinkNext)].Offset; } ThreadStoreData IThread.GetThreadStoreData() @@ -53,7 +47,7 @@ ThreadStoreData IThread.GetThreadStoreData() Data.ThreadStore threadStore = _target.ProcessedData.GetOrAdd(_threadStoreAddr); return new ThreadStoreData( threadStore.ThreadCount, - GetThreadFromLink(threadStore.FirstThreadLink), + threadStore.FirstThreadLink, _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.FinalizerThread)), _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.GCThread))); } @@ -124,7 +118,7 @@ ThreadData IThread.GetThreadData(TargetPointer threadPointer) thread.CurrentCustomDebuggerNotification, thread.LastThrownObjectIsUnhandled != 0, hasUnhandledException, - GetThreadFromLink(thread.LinkNext)); + thread.LinkNext); } void IThread.GetThreadAllocContext(TargetPointer threadPointer, out long allocBytes, out long allocBytesLoh) @@ -157,15 +151,6 @@ TargetPointer IThread.IdToThread(uint id) return threadPtr; } - private TargetPointer GetThreadFromLink(TargetPointer threadLink) - { - if (threadLink == TargetPointer.Null) - return TargetPointer.Null; - - // Get the address of the thread containing the link - return new TargetPointer(threadLink - _threadLinkOffset); - } - TargetPointer IThread.GetThreadLocalStaticBase(TargetPointer threadPointer, TargetPointer tlsIndexPtr) { // Get the thread's TLS base address diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.SyncBlock.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.SyncBlock.cs index 83cd34b76cd32e..69e4da037e6637 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.SyncBlock.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.SyncBlock.cs @@ -86,8 +86,6 @@ public ulong LinkNext set => WritePointerField(LinkNextFieldName, value); } - public ulong CleanupLinkAddress - => GetFieldAddress(LinkNextFieldName); } internal sealed class MockSyncBlockBuilder @@ -193,7 +191,7 @@ internal MockSyncBlock AddSyncBlockToCleanupList( MockSyncBlock syncBlock = AddSyncBlock(rcw, ccw, ccf, hasInteropInfo, "SyncBlock (cleanup)"); syncBlock.LinkNext = _cleanupListHeadAddress; - _cleanupListHeadAddress = syncBlock.CleanupLinkAddress; + _cleanupListHeadAddress = syncBlock.Address; _syncBlockCache.CleanupBlockList = _cleanupListHeadAddress; return syncBlock; } diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.Thread.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.Thread.cs index 6f9760394731e6..bfa7b2a8b5416b 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.Thread.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.Thread.cs @@ -279,8 +279,6 @@ public ulong CurrentCustomDebuggerNotification } public ulong FrameAddress => GetFieldAddress(FrameFieldName); - - public ulong LinkAddress => GetFieldAddress(LinkNextFieldName); } internal sealed class MockThreadBuilder @@ -361,11 +359,11 @@ internal MockThread AddThread(uint id, ulong osId, long allocBytes, long allocBy if (_previousThread is not null) { - _previousThread.LinkNext = thread.LinkAddress; + _previousThread.LinkNext = thread.Address; } else { - _threadStore.FirstThreadLink = thread.LinkAddress; + _threadStore.FirstThreadLink = thread.Address; } _previousThread = thread;