Replace manually managed TLS slots with regular thread_local statics (#33597)
authorJan Kotas <jkotas@microsoft.com>
Mon, 16 Mar 2020 17:54:49 +0000 (10:54 -0700)
committerGitHub <noreply@github.com>
Mon, 16 Mar 2020 17:54:49 +0000 (10:54 -0700)
* Delete TlsIdx_XXX

* Delete EnableTerminationOnHeapCorruption

* Delete redundant cant stop tracking

* Workaround compiler bug

56 files changed:
src/coreclr/src/debug/di/cordb.cpp
src/coreclr/src/debug/di/eventredirectionpipeline.cpp
src/coreclr/src/debug/di/process.cpp
src/coreclr/src/debug/di/rspriv.h
src/coreclr/src/debug/di/rsthread.cpp
src/coreclr/src/debug/ee/rcthread.cpp
src/coreclr/src/debug/inc/dbgipcevents.h
src/coreclr/src/gc/env/gcenv.base.h
src/coreclr/src/inc/check.h
src/coreclr/src/inc/check.inl
src/coreclr/src/inc/clrhost.h
src/coreclr/src/inc/clrinternal.idl
src/coreclr/src/inc/contract.h
src/coreclr/src/inc/formattype.cpp
src/coreclr/src/inc/predeftlsslot.h
src/coreclr/src/inc/stresslog.h
src/coreclr/src/inc/utilcode.h
src/coreclr/src/pal/prebuilt/inc/clrinternal.h
src/coreclr/src/utilcode/check.cpp
src/coreclr/src/utilcode/clrhost.cpp
src/coreclr/src/utilcode/clrhost_nodependencies.cpp
src/coreclr/src/utilcode/debug.cpp
src/coreclr/src/utilcode/ex.cpp
src/coreclr/src/utilcode/hostimpl.cpp
src/coreclr/src/utilcode/hostimpl.h
src/coreclr/src/utilcode/log.cpp
src/coreclr/src/utilcode/securityutil.cpp
src/coreclr/src/utilcode/stresslog.cpp
src/coreclr/src/utilcode/util.cpp
src/coreclr/src/vm/arm/stubs.cpp
src/coreclr/src/vm/ceemain.cpp
src/coreclr/src/vm/ceemain.h
src/coreclr/src/vm/codeversion.cpp
src/coreclr/src/vm/codeversion.h
src/coreclr/src/vm/common.h
src/coreclr/src/vm/comsynchronizable.cpp
src/coreclr/src/vm/corhost.cpp
src/coreclr/src/vm/crossgencompile.cpp
src/coreclr/src/vm/crst.cpp
src/coreclr/src/vm/crst.h
src/coreclr/src/vm/eedbginterface.h
src/coreclr/src/vm/eedbginterfaceimpl.cpp
src/coreclr/src/vm/eedbginterfaceimpl.h
src/coreclr/src/vm/excep.cpp
src/coreclr/src/vm/hosting.cpp
src/coreclr/src/vm/hosting.h
src/coreclr/src/vm/i386/stublinkerx86.cpp
src/coreclr/src/vm/method.cpp
src/coreclr/src/vm/proftoeeinterfaceimpl.cpp
src/coreclr/src/vm/stackwalk.cpp
src/coreclr/src/vm/threads.cpp
src/coreclr/src/vm/threads.h
src/coreclr/src/vm/threads.inl
src/coreclr/src/vm/threadsuspend.cpp
src/coreclr/src/vm/util.cpp
src/coreclr/src/vm/util.hpp

index ad304fb..df66790 100644 (file)
@@ -246,7 +246,7 @@ BOOL WINAPI DbgDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
         case DLL_THREAD_DETACH:
         {
 #ifdef STRESS_LOG
-            StressLog::ThreadDetach((ThreadStressLog*) ClrFlsGetValue(TlsIdx_StressLog));
+            StressLog::ThreadDetach();
 #endif
 
 #ifdef RSCONTRACTS
index 92d6fd9..c8e3c16 100644 (file)
@@ -126,7 +126,7 @@ HRESULT EventRedirectionPipeline::AttachDebuggerToTarget(LPCWSTR szOptions, DWOR
 
         fRemap = true;
     }EX_CATCH {}
-    EX_END_CATCH(RethrowTerminalExceptions);
+    EX_END_CATCH(SwallowAllExceptions)
 
     if (!fRemap)
     {
index d42010a..37a19da 100644 (file)
@@ -7678,8 +7678,6 @@ HRESULT CordbProcess::GetRuntimeOffsets()
          m_runtimeOffsets.m_EEMaxFrameValue));
     LOG((LF_CORDB, LL_INFO10000, "    m_EEThreadDebuggerFilterContextOffset= 0x%08x\n",
          m_runtimeOffsets.m_EEThreadDebuggerFilterContextOffset));
-    LOG((LF_CORDB, LL_INFO10000, "    m_EEThreadCantStopOffset=         0x%08x\n",
-         m_runtimeOffsets.m_EEThreadCantStopOffset));
     LOG((LF_CORDB, LL_INFO10000, "    m_EEFrameNextOffset=              0x%08x\n",
          m_runtimeOffsets.m_EEFrameNextOffset));
     LOG((LF_CORDB, LL_INFO10000, "    m_EEIsManagedExceptionStateMask=  0x%08x\n",
index 7b4ff27..5c5f98a 100644 (file)
@@ -10608,18 +10608,16 @@ private:
 #endif
 
     HRESULT EnableSSAfterBP();
-    bool GetEEThreadCantStopHelper();
 
     HRESULT GetTlsSlot(DWORD slot, REMOTE_PTR *pValue);
     HRESULT SetTlsSlot(DWORD slot, REMOTE_PTR value);
-    REMOTE_PTR GetPreDefTlsSlot(SIZE_T slot, bool * pRead);
+    REMOTE_PTR GetPreDefTlsSlot(SIZE_T slot);
 
     void * m_pPatchSkipAddress;
 
     UINT m_continueCountCached;
 
     DWORD_PTR GetEEThreadValue();
-    REMOTE_PTR GetEETlsDataBlock();
     HRESULT GetClrModuleTlsDataAddress(REMOTE_PTR* pAddress);
 
 public:
index 3645cc7..e4da07d 100644 (file)
@@ -2992,41 +2992,30 @@ HRESULT CordbUnmanagedThread::RestoreLeafSeh()
 //    return value of data in the slot, *pRead = true
 // 2) On failure to read block (block doens't exist yet, any other failure)
 //    return value == 0 (assumed default, *pRead = false
-REMOTE_PTR CordbUnmanagedThread::GetPreDefTlsSlot(SIZE_T slot, bool * pRead)
+REMOTE_PTR CordbUnmanagedThread::GetPreDefTlsSlot(SIZE_T offset)
 {
-    REMOTE_PTR pBlock = (REMOTE_PTR) GetEETlsDataBlock();
-
-    REMOTE_PTR data = 0;
-
-    // We don't have a maximum size, but we know it's less than ~200. This assert
-    // will catch if we're just passsing Garbage.
-    _ASSERTE(slot < 200);
-
-    bool dummy;
-    if (pRead == NULL)
+    REMOTE_PTR tlsDataAddress;
+    HRESULT hr = GetClrModuleTlsDataAddress(&tlsDataAddress);
+    if (FAILED(hr))
     {
-        pRead = &dummy;
+        LOG((LF_CORDB, LL_INFO1000, "CUT::GEETV: GetClrModuleTlsDataAddress FAILED %x for 0x%x\n", hr, m_id));
+        return NULL;
     }
 
-    if (pBlock != NULL)
-    {
-        REMOTE_PTR p = ((BYTE*) pBlock) + slot * sizeof(data);
-
-        // Now read the "special" status out of the PreDef block.
-        HRESULT hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(p), &data);
-
-        // The predef block should be valid at this point, so the ReadProcessMemory ought to work.
-        SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
+    REMOTE_PTR data = 0;
 
-        if (SUCCEEDED(hr))
-        {
-            *pRead = true;
-            return data;
-        }
+    // Read the thread's TLS value.
+    REMOTE_PTR slotAddr = (BYTE*)tlsDataAddress + offset;
+    hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(slotAddr), &data);
+    if (FAILED(hr))
+    {
+        LOG((LF_CORDB, LL_INFO1000, "CUT::GEETV: failed to get TLS value: tlsData=0x%p offset=%d, err=%x\n",
+            tlsDataAddress, offset, hr));
+        return NULL;
     }
 
-    *pRead = false;
-    return 0;
+    LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETV: EE Thread TLS value is 0x%x for 0x%x\n", data, m_id));
+    return data;
 }
 
 // Read the contents from a LS threads's TLS slot.
@@ -3072,7 +3061,7 @@ HRESULT CordbUnmanagedThread::GetTlsSlot(DWORD slot, REMOTE_PTR * pValue)
     hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pEEThreadTLS), pValue);
     if (FAILED(hr))
     {
-        LOG((LF_CORDB, LL_INFO1000, "CUT::GTS: failed to read TLS value: computed addr=0x%p index=%d, err=%x\n",
+        LOG((LF_CORDB, LL_INFO1000, "CUT::GTS: failed to read TLS value: computed addr=0x%p slot=%d, err=%x\n",
            pEEThreadTLS, slot, hr));
         return hr;
     }
@@ -3165,7 +3154,7 @@ DWORD_PTR CordbUnmanagedThread::GetEEThreadValue()
     }
 
     // Read the thread's TLS value.
-    REMOTE_PTR EEThreadAddr = (BYTE*)tlsDataAddress + OFFSETOF__TLS__tls_CurrentThread;
+    REMOTE_PTR EEThreadAddr = (BYTE*)tlsDataAddress + GetProcess()->m_runtimeOffsets.m_TLSEEThreadOffset + OFFSETOF__TLS__tls_CurrentThread;
     hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(EEThreadAddr), &ret);
     if (FAILED(hr))
     {
@@ -3196,10 +3185,8 @@ HRESULT CordbUnmanagedThread::GetClrModuleTlsDataAddress(REMOTE_PTR* pAddress)
         return E_FAIL;
     }
 
-    DWORD slot = (DWORD)(GetProcess()->m_runtimeOffsets.m_TLSIndex);
-
     REMOTE_PTR clrModuleTlsDataAddr;
-    hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)tlsArrayAddr + (slot & 0xFFFF) * sizeof(void*)), &clrModuleTlsDataAddr);
+    hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)tlsArrayAddr + GetProcess()->m_runtimeOffsets.m_TLSIndex * sizeof(void*)), &clrModuleTlsDataAddr);
     if (FAILED(hr))
     {
         return hr;
@@ -3211,36 +3198,10 @@ HRESULT CordbUnmanagedThread::GetClrModuleTlsDataAddress(REMOTE_PTR* pAddress)
         return E_FAIL;
     }
 
-    *pAddress = (BYTE*) clrModuleTlsDataAddr + ((slot & 0x7FFF0000) >> 16);
+    *pAddress = (BYTE*) clrModuleTlsDataAddr;
     return S_OK;
 }
 
-// Gets the value of gCurrentThreadInfo.m_EETlsData
-REMOTE_PTR CordbUnmanagedThread::GetEETlsDataBlock()
-{
-    REMOTE_PTR ret;
-
-    REMOTE_PTR tlsDataAddress;
-    HRESULT hr = GetClrModuleTlsDataAddress(&tlsDataAddress);
-    if (FAILED(hr))
-    {
-        LOG((LF_CORDB, LL_INFO1000, "CUT::GEETDB: GetClrModuleTlsDataAddress FAILED %x for 0x%x\n", hr, m_id));
-        return NULL;
-    }
-
-    REMOTE_PTR blockAddr = (BYTE*)tlsDataAddress + OFFSETOF__TLS__tls_EETlsData;
-    hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(blockAddr), &ret);
-    if (FAILED(hr))
-    {
-        LOG((LF_CORDB, LL_INFO1000, "CUT::GEETDB: failed to read EETlsData address: computed addr=0x%p offset=%d, err=%x\n",
-             blockAddr, OFFSETOF__TLS__tls_EETlsData, hr));
-        return NULL;
-    }
-
-    LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETDB: EETlsData address value is 0x%p for 0x%x\n", ret, m_id));
-    return ret;
-}
-
 /*
  * GetEEDebuggerWord
  *
@@ -3341,46 +3302,6 @@ void CordbUnmanagedThread::GetEEState(bool *threadStepping, bool *specialManaged
     return;
 }
 
-// Currently, the EE manually tracks its "can't-stop" regions. This retrieves that manual tracking value.
-// @todo - This should eventually become deprecated since the Entire EE will be a can't-stop region.
-bool CordbUnmanagedThread::GetEEThreadCantStopHelper()
-{
-    // Note: any failure to read memory is okay for this method. We simply say that the thread is not is a can't stop
-    // state, and that's okay.
-
-    REMOTE_PTR pEEThread;
-
-    HRESULT hr = GetEEThreadPtr(&pEEThread);
-
-    _ASSERTE(SUCCEEDED(hr));
-    _ASSERTE(pEEThread != NULL);
-
-    // Compute the address of the thread's debugger word #1
-    DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
-    void *pEEThreadCantStop = (BYTE*) pEEThread + pRO->m_EEThreadCantStopOffset;
-
-    // Grab the debugger word #1 out of the EE Thread.
-    DWORD EEThreadCantStop;
-    hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pEEThreadCantStop), &EEThreadCantStop);
-
-    if (FAILED(hr))
-    {
-        LOG((LF_CORDB, LL_INFO1000, "CUT::GEETS: failed to read thread cant stop: 0x%08x + 0x%x = 0x%08x, err=%d\n",
-             pEEThread, pRO->m_EEThreadCantStopOffset, pEEThreadCantStop, GetLastError()));
-
-        return false;
-    }
-
-    LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETS: EE Thread cant stop is 0x%08x\n", EEThreadCantStop));
-
-    // Looks like we've got it.
-    if (EEThreadCantStop != 0)
-        return true;
-    else
-        return false;
-}
-
-
 // Is the thread in a "can't stop" region?
 // "Can't-Stop" regions include anything that's "inside" the runtime; ie, the runtime has some
 // synchronization mechanism that will halt this thread, and so we don't need to suspend it.
@@ -3433,8 +3354,7 @@ bool CordbUnmanagedThread::IsCantStop()
     // them, they may be holding a lock that blocks the helper thread.
     // The helper thread is marked as "special".
     {
-        SIZE_T idx = pRO->m_TLSIsSpecialIndex;
-        REMOTE_PTR special = GetPreDefTlsSlot(idx, NULL);
+        REMOTE_PTR special = GetPreDefTlsSlot(pRO->m_TLSIsSpecialOffset);
 
         // If it's a special thread
         if ((special != 0) && (pEEThread == NULL))
@@ -3448,8 +3368,7 @@ bool CordbUnmanagedThread::IsCantStop()
     // (or when we don't have a thread object).
     // If a LS thread takes a debugger lock, it will increment the Can't-Stop count.
     {
-        SIZE_T idx = pRO->m_TLSCantStopIndex;
-        REMOTE_PTR count = (REMOTE_PTR) GetPreDefTlsSlot(idx, NULL);
+        REMOTE_PTR count = GetPreDefTlsSlot(pRO->m_TLSCantStopOffset);
 
         // Just a sanity check here. There's nothing special about 1000, but if the
         // stop-count gets this big, 99% chance it's:
@@ -3497,10 +3416,10 @@ bool CordbUnmanagedThread::IsCantStop()
 
     // This checks for an explicit "can't" stop region.
     // Eventually, these explicit regions should become a complete subset of the other checks.
-    if (GetEEThreadCantStopHelper())
+    REMOTE_PTR count = GetPreDefTlsSlot(GetProcess()->m_runtimeOffsets.m_TLSCantStopOffset);
+    if (count > 0)
         return true;
 
-
     // If we're in cooperative mode (either managed code or parts inside the runtime), then don't stop.
     // Note we could remove this since the check is made in side of the DAC request below,
     // but it's faster to look here.
index 0096728..8711140 100644 (file)
@@ -543,8 +543,9 @@ HRESULT DebuggerRCThread::SetupRuntimeOffsets(DebuggerIPCControlBlock * pDebugge
 
     // @dbgtodo  inspection - this should all go away or be obtained from DacDbi Primitives.
     g_pEEInterface->GetRuntimeOffsets(&pDebuggerRuntimeOffsets->m_TLSIndex,
-                                      &pDebuggerRuntimeOffsets->m_TLSIsSpecialIndex,
-                                      &pDebuggerRuntimeOffsets->m_TLSCantStopIndex,
+                                      &pDebuggerRuntimeOffsets->m_TLSEEThreadOffset,
+                                      &pDebuggerRuntimeOffsets->m_TLSIsSpecialOffset,
+                                      &pDebuggerRuntimeOffsets->m_TLSCantStopOffset,
                                       &pDebuggerRuntimeOffsets->m_EEThreadStateOffset,
                                       &pDebuggerRuntimeOffsets->m_EEThreadStateNCOffset,
                                       &pDebuggerRuntimeOffsets->m_EEThreadPGCDisabledOffset,
@@ -554,7 +555,6 @@ HRESULT DebuggerRCThread::SetupRuntimeOffsets(DebuggerIPCControlBlock * pDebugge
                                       &pDebuggerRuntimeOffsets->m_EEThreadSteppingStateMask,
                                       &pDebuggerRuntimeOffsets->m_EEMaxFrameValue,
                                       &pDebuggerRuntimeOffsets->m_EEThreadDebuggerFilterContextOffset,
-                                      &pDebuggerRuntimeOffsets->m_EEThreadCantStopOffset,
                                       &pDebuggerRuntimeOffsets->m_EEFrameNextOffset,
                                       &pDebuggerRuntimeOffsets->m_EEIsManagedExceptionStateMask);
 
index 5a78835..e9c095e 100644 (file)
@@ -131,9 +131,10 @@ struct MSLAYOUT DebuggerIPCRuntimeOffsets
     void   *m_raiseExceptionAddr;                       // The address of kernel32!RaiseException in the debuggee
     DWORD   m_debuggerWordTLSIndex;                     // The TLS slot for the debugger word used in the debugger hijack functions
 #endif // FEATURE_INTEROP_DEBUGGING
-    SIZE_T  m_TLSIndex;                                 // The TLS index the CLR is using to hold Thread objects
-    SIZE_T  m_TLSIsSpecialIndex;                        // The index into the Predef block of the the "IsSpecial" status for a thread.
-    SIZE_T  m_TLSCantStopIndex;                         // The index into the Predef block of the the Can't-Stop count.
+    SIZE_T  m_TLSIndex;                                 // The TLS index of the thread-local storage for coreclr.dll
+    SIZE_T  m_TLSEEThreadOffset;                        // TLS Offset of the Thread pointer.
+    SIZE_T  m_TLSIsSpecialOffset;                       // TLS Offset of the "IsSpecial" status for a thread.
+    SIZE_T  m_TLSCantStopOffset;                        // TLS Offset of the Can't-Stop count.
     SIZE_T  m_EEThreadStateOffset;                      // Offset of m_state in a Thread
     SIZE_T  m_EEThreadStateNCOffset;                    // Offset of m_stateNC in a Thread
     SIZE_T  m_EEThreadPGCDisabledOffset;                // Offset of the bit for whether PGC is disabled or not in a Thread
@@ -143,7 +144,6 @@ struct MSLAYOUT DebuggerIPCRuntimeOffsets
     DWORD   m_EEThreadSteppingStateMask;                // Mask for Thread::TSNC_DebuggerIsStepping
     DWORD   m_EEMaxFrameValue;                          // The max Frame value
     SIZE_T  m_EEThreadDebuggerFilterContextOffset;      // Offset of debugger's filter context within a Thread Object.
-    SIZE_T  m_EEThreadCantStopOffset;                   // Offset of the can't stop count in a Thread
     SIZE_T  m_EEFrameNextOffset;                        // Offset of the next ptr in a Frame
     DWORD   m_EEIsManagedExceptionStateMask;            // Mask for Thread::TSNC_DebuggerIsManagedException
     void   *m_pPatches;                                 // Addr of patch table
index 45774e8..b8fd086 100644 (file)
@@ -515,8 +515,6 @@ inline bool dbgOnly_IsSpecialEEThread()
     return false;
 }
 
-#define ClrFlsSetThreadType(type)
-
 //
 // Performance logging
 //
index ca335bd..9e012de 100644 (file)
@@ -80,6 +80,8 @@ protected:
     // Keep leakage counters.
     static  size_t s_cLeakedBytes;
     static  size_t s_cNumFailures;
+
+    static thread_local LONG t_count;
 #endif
 
     static BOOL s_neverEnforceAsserts;
@@ -144,10 +146,7 @@ public: // !!! NOTE: Called from macros only!!!
 
     static void SetAssertEnforcement(BOOL value);
 
-    static void ReleaseTls(void* pCountTLS);
-
   private:
-    static LONG* InitTls();
 #ifdef _DEBUG
     static LPCSTR AllocateDynamicMessage(const SString &s);
 #endif
index 7e36b18..84a9be2 100644 (file)
 #include "debugmacros.h"
 #include "clrtypes.h"
 
-inline LONG *CHECK::InitTls()
-{
-#pragma push_macro("HeapAlloc")
-#pragma push_macro("GetProcessHeap")
-#undef HeapAlloc
-#undef GetProcessHeap
-
-    LONG *pCount = (LONG *)::HeapAlloc(GetProcessHeap(), 0, sizeof(LONG));
-    if (pCount)
-        *pCount = 0;
-
-#pragma pop_macro("HeapAlloc")
-#pragma pop_macro("GetProcessHeap")
-    ClrFlsSetValue(TlsIdx_Check, pCount);
-    ClrFlsAssociateCallback(TlsIdx_Check, ReleaseCheckTls);
-    return pCount;
-}
-
-inline void CHECK::ReleaseTls(void* pCountTLS)
-{
-#pragma push_macro("HeapFree")
-#pragma push_macro("GetProcessHeap")
-#undef HeapFree
-#undef GetProcessHeap
-        LONG* pCount = (LONG*) pCountTLS;
-        if (pCount)
-            ::HeapFree(GetProcessHeap(), 0, pCount);
-
-#pragma pop_macro("HeapFree")
-#pragma pop_macro("GetProcessHeap")
-}
-
 FORCEINLINE BOOL CHECK::EnterAssert()
 {
     if (s_neverEnforceAsserts)
         return FALSE;
 
 #ifdef _DEBUG_IMPL
-    m_pCount = (LONG *)ClrFlsGetValue(TlsIdx_Check);
-    if (!m_pCount)
-    {
-        m_pCount = InitTls();
-        if (!m_pCount)
-            return FALSE;
-    }
+    m_pCount = &t_count;
 
     if (!*m_pCount)
     {
@@ -81,12 +43,9 @@ FORCEINLINE BOOL CHECK::IsInAssert()
 {
 #ifdef _DEBUG_IMPL
     if (!m_pCount)
-        m_pCount = (LONG *)ClrFlsGetValue(TlsIdx_Check);
+        m_pCount = &t_count;
 
-    if (!m_pCount)
-        return FALSE;
-    else
-        return *m_pCount;
+    return *m_pCount;
 #else
     return FALSE;
 #endif
index cf0a587..1292446 100644 (file)
@@ -77,111 +77,6 @@ HANDLE ClrGetProcessExecutableHeap();
 extern int RFS_HashStack();
 #endif
 
-
-void ClrFlsAssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback);
-
-typedef LPVOID* (*CLRFLSGETBLOCK)();
-extern CLRFLSGETBLOCK __ClrFlsGetBlock;
-
-// Combining getter/setter into a single call
-inline void ClrFlsIncrementValue(DWORD slot, int increment)
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
-
-    _ASSERTE(increment != 0);
-
-    void **block = (*__ClrFlsGetBlock)();
-    size_t value;
-
-    if (block != NULL)
-    {
-        value = (size_t) block[slot];
-
-        _ASSERTE((increment > 0) || (value + increment < value));
-        block[slot] = (void *) (value + increment);
-    }
-    else
-    {
-        BEGIN_PRESERVE_LAST_ERROR;
-
-        IExecutionEngine * pEngine = GetExecutionEngine();
-        value = (size_t) pEngine->TLS_GetValue(slot);
-
-        _ASSERTE((increment > 0) || (value + increment < value));
-        pEngine->TLS_SetValue(slot, (void *) (value + increment));
-
-        END_PRESERVE_LAST_ERROR;
-    }
-}
-
-
-inline void * ClrFlsGetValue (DWORD slot)
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
-
-       void **block = (*__ClrFlsGetBlock)();
-       if (block != NULL)
-    {
-        return block[slot];
-    }
-    else
-    {
-        void * value = GetExecutionEngine()->TLS_GetValue(slot);
-        return value;
-    }
-}
-
-
-inline BOOL ClrFlsCheckValue(DWORD slot, void ** pValue)
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-
-#ifdef _DEBUG
-    *pValue = ULongToPtr(0xcccccccc);
-#endif //_DEBUG
-       void **block = (*__ClrFlsGetBlock)();
-       if (block != NULL)
-    {
-        *pValue = block[slot];
-        return TRUE;
-    }
-    else
-    {
-        BOOL result = GetExecutionEngine()->TLS_CheckValue(slot, pValue);
-        return result;
-    }
-}
-
-inline void ClrFlsSetValue(DWORD slot, void *pData)
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
-
-    void **block = (*__ClrFlsGetBlock)();
-    if (block != NULL)
-    {
-        block[slot] = pData;
-    }
-    else
-    {
-        BEGIN_PRESERVE_LAST_ERROR;
-
-        GetExecutionEngine()->TLS_SetValue(slot, pData);
-
-        END_PRESERVE_LAST_ERROR;
-    }
-}
-
 #ifndef SELF_NO_HOST
 LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes);
 BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem);
@@ -358,8 +253,17 @@ private:
 
 HMODULE GetCLRModule ();
 
-extern void IncCantAllocCount();
-extern void DecCantAllocCount();
+extern thread_local int t_CantAllocCount;
+
+inline void IncCantAllocCount()
+{
+    t_CantAllocCount++;
+}
+
+inline void DecCantAllocCount()
+{
+    t_CantAllocCount--;
+}
 
 class CantAllocHolder
 {
@@ -375,18 +279,13 @@ public:
 };
 
 // At places where want to allocate stress log, we need to first check if we are allowed to do so.
-// If ClrTlsInfo doesn't exist for this thread, we take it as can alloc
 inline bool IsInCantAllocRegion ()
 {
-    size_t count = 0;
-    if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
-    {
-        _ASSERTE (count >= 0);
-        return count > 0;
-    }
-    return false;
+    return t_CantAllocCount != 0;
+}
+inline BOOL IsInCantAllocStressLogRegion()
+{
+    return t_CantAllocCount != 0;
 }
-// for stress log the rule is more restrict, we have to check the global counter too
-extern BOOL IsInCantAllocStressLogRegion();
 
 #endif
index a332fba..19fc708 100644 (file)
@@ -128,30 +128,6 @@ typedef VOID (__stdcall *PTLS_CALLBACK_FUNCTION)(PVOID);
 ]
 interface IExecutionEngine : IUnknown
 {
-    // Thread Local Storage is based on logical threads.  The underlying
-    // implementation could be threads, fibers, or something more exotic.
-    // Slot numbers are predefined.  This is not a general extensibility
-    // mechanism.
-
-    // Associate a callback function for releasing TLS on thread/fiber death.
-    // This can be NULL.
-    void TLS_AssociateCallback([in] DWORD slot, [in] PTLS_CALLBACK_FUNCTION callback);
-
-    // Get the TLS block for fast Get/Set operations
-    PVOID* TLS_GetDataBlock();
-
-    // Get the value at a slot
-    PVOID TLS_GetValue([in] DWORD slot);
-
-    // Get the value at a slot, return FALSE if TLS info block doesn't exist
-    BOOL TLS_CheckValue([in] DWORD slot, [out] PVOID * pValue);
-
-    // Set the value at a slot
-    void TLS_SetValue([in] DWORD slot, [in] PVOID pData);
-
-    // Free TLS memory block and make callback
-    void TLS_ThreadDetaching();
-
     // Critical Sections are sometimes exposed to the host and therefore need to be
     // reflected from all CLR DLLs to the EE.
     //
index 156685e..082d41d 100644 (file)
@@ -409,8 +409,6 @@ public:
 #define CONTRACT_BITMASK_RESET(whichbit)     (m_flags &= ~(whichbit))
 #define CONTRACT_BITMASK_UPDATE(whichbit, value)  ((value)?CONTRACT_BITMASK_SET(whichbit):CONTRACT_BITMASK_RESET(whichbit))
 
-
-// Stored in the FLS under TlsIdx_ClrDebugState.
 struct ClrDebugState
 {
 private:
@@ -744,13 +742,13 @@ public:
 ClrDebugState *CLRInitDebugState();
 ClrDebugState *GetClrDebugState(BOOL fAlloc = TRUE);
 
+extern thread_local ClrDebugState* t_pClrDebugState;
 
 // This function returns a ClrDebugState if one has been created, but will not create one itself.
 inline ClrDebugState *CheckClrDebugState()
 {
     STATIC_CONTRACT_LIMITED_METHOD;
-    ClrDebugState *ret = (ClrDebugState*)ClrFlsGetValue(TlsIdx_ClrDebugState);
-    return ret;
+    return t_pClrDebugState;
 }
 
 void CONTRACT_ASSERT(const char *szElaboration,
index 7384d25..24da3ae 100644 (file)
@@ -149,12 +149,6 @@ const char* PrettyPrintSig(
 {
     STATIC_CONTRACT_THROWS;
 
-    // This had a _try/__except handler earlier that would swallow exceptions like
-    // SO and breakpoint. Obviously, swallowing any of them is not the right thing to do.
-    //
-    // Thus, we replace it with EX_TRY/EX_CATCH that automatically kicks in with SO
-    // handling if it sees any SO going past it. Also, C++ catch will not swallow
-    // the breakpoint exception (which is what we want).
     EX_TRY
     {
         PrettyPrintSignature(typePtr,
@@ -170,12 +164,7 @@ const char* PrettyPrintSig(
         out->Shrink(0);
         appendStr(out,"ERROR PARSING THE SIGNATURE");
     }
-#if defined(__ILDASM__)
-    // Dont allow ildasm to swallow bad SEH exceptions
-    EX_END_CATCH(RethrowCorruptingExceptions);
-#else // __ILDASM__
     EX_END_CATCH(SwallowAllExceptions);
-#endif // __ILDASM__
 
     return(asString(out));
 }
index a3eb5ae..eba2dc1 100644 (file)
 // See: https://github.com/dotnet/diagnostics/blob/master/src/inc/predeftlsslot.h
 // ******************************************************************************
 
-// And here are the predefined slots for accessing TLS from various DLLs of the CLR.
-// Note that we want to support combinations of Debug and Retail DLLs for testing
-// purposes, so we burn the slots into the retail EE even if a debug CLR dll needs
-// them.
+// The historic location of ThreadType slot kept for compatibility with SOS
+// TODO: Introduce DAC API to make this hack unnecessary
 enum PredefinedTlsSlots
 {
-    TlsIdx_OwnedCrstsChain, // slot to store the Crsts owned by this thread
-    TlsIdx_Unused1,
-    TlsIdx_Unused2,
-    TlsIdx_Unused3,
-    TlsIdx_AssertDlgStatus, // Whether the thread is displaying an assert dialog
-    TlsIdx_StressLog,
-    TlsIdx_CantStopCount, // Can't-stop counter for any thread
-    TlsIdx_Check,
-    TlsIdx_ForbidGCLoaderUseCount,
-    TlsIdx_ClrDebugState,         // Pointer to ClrDebugState* structure
-    TlsIdx_Unused10,
-
-    // Add more indices here.
-    TlsIdx_ThreadType, // bit flags to indicate special thread's type
-    TlsIdx_CantAllocCount, //Can't allocate memory on heap in this thread
-
-    // A transient thread value that indicates this thread is currently walking its stack
-    // or the stack of another thread. This value is useful to help short-circuit
-    // some problematic checks in the loader, guarantee that types & assemblies
-    // encountered during the walk must already be loaded, and provide information to control
-    // assembly loading behavior during stack walks.
-    //
-    // This value is set around the main portions of the stack walk (as those portions may
-    // enter the type & assembly loaders). This is also explicitly cleared while the
-    // walking thread calls the stackwalker callback or needs to execute managed code, as
-    // such calls may execute arbitrary code unrelated to the actual stack walking, and
-    // may never return, in the case of exception stackwalk callbacks.
-    TlsIdx_StackWalkerWalkingThread, // Thread* that the stack walker is currently walking.
-
-    // Save the last exception info.  Sometimes we need this info in our EX_CATCH, such as for SO.
-    // It will be better if VC can supply this in catch(...) block.
-    // !!! These data may become stale.  Use it only inside exception handling code.
-    // !!! Please access these fields through GetCurrentExceptionPointers which validates the data to some level.
-    TlsIdx_EXCEPTION_CODE,
-    TlsIdx_PEXCEPTION_RECORD,
-    TlsIdx_PCONTEXT,
-
-    MAX_PREDEFINED_TLS_SLOT
+    TlsIdx_ThreadType = 11 // bit flags to indicate special thread's type
 };
 
 enum TlsThreadTypeFlag // flag used for thread type in Tls data
@@ -79,7 +40,5 @@ enum TlsThreadTypeFlag // flag used for thread type in Tls data
     ThreadType_GenericInstantiationCompare= 0x00020000, // Used to indicate that the thread is determining if a generic instantiation in an ngen image matches a lookup.
 };
 
-static_assert(TlsIdx_ThreadType == 11, "SOS in diagnostics repo has a dependency on this value.");
-
 #endif
 
index e3c16fb..fe7b91a 100644 (file)
@@ -266,7 +266,7 @@ public:
     static void Initialize(unsigned facilities, unsigned level, unsigned maxBytesPerThread,
                     unsigned maxBytesTotal, HMODULE hMod);
     static void Terminate(BOOL fProcessDetach=FALSE);
-    static void ThreadDetach(ThreadStressLog *msgs);         // call at DllMain  THREAD_DETACH if you want to recycle thread logs
+    static void ThreadDetach();         // call at DllMain  THREAD_DETACH if you want to recycle thread logs
     static int NewChunk ()
     {
         return InterlockedIncrement (&theLog.totalChunk);
@@ -302,7 +302,7 @@ public:
     unsigned MaxSizeTotal;               //maximum memory allowed for stress log
     Volatile<LONG> totalChunk;              //current number of total chunks allocated
     Volatile<ThreadStressLog*> logs;        // the list of logs for every thread.
-    Volatile<unsigned> TLSslot;             // Each thread gets a log this is used to fetch each threads log
+    unsigned padding;                       // Preserve the layout for SOS
     Volatile<LONG> deadCount;               // count of dead threads in the log
     CRITSEC_COOKIE lock;                    // lock
     unsigned __int64 tickFrequency;         // number of ticks per second
@@ -310,6 +310,8 @@ public:
     FILETIME startTime;                     // time the application started
     SIZE_T   moduleOffset;                  // Used to compute format strings.
 
+    static thread_local ThreadStressLog* t_pCurrentThreadLog;
+
 // private:
     static void Enter(CRITSEC_COOKIE dummy = NULL);
     static void Leave(CRITSEC_COOKIE dummy = NULL);
index 286c13f..45b5c4c 100644 (file)
@@ -4338,6 +4338,8 @@ public:
 
 #if !defined(DACCESS_COMPILE)
 
+extern thread_local size_t t_ThreadType;
+
 // check if current thread is a GC thread (concurrent or server)
 inline BOOL IsGCSpecialThread ()
 {
@@ -4346,7 +4348,7 @@ inline BOOL IsGCSpecialThread ()
     STATIC_CONTRACT_MODE_ANY;
     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_GC);
+    return !!(t_ThreadType & ThreadType_GC);
 }
 
 // check if current thread is a Gate thread
@@ -4356,7 +4358,7 @@ inline BOOL IsGateSpecialThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Gate);
+    return !!(t_ThreadType & ThreadType_Gate);
 }
 
 // check if current thread is a Timer thread
@@ -4366,7 +4368,7 @@ inline BOOL IsTimerSpecialThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Timer);
+    return !!(t_ThreadType & ThreadType_Timer);
 }
 
 // check if current thread is a debugger helper thread
@@ -4376,7 +4378,7 @@ inline BOOL IsDbgHelperSpecialThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_DbgHelper);
+    return !!(t_ThreadType & ThreadType_DbgHelper);
 }
 
 // check if current thread is a debugger helper thread
@@ -4386,7 +4388,7 @@ inline BOOL IsETWRundownSpecialThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ETWRundownThread);
+    return !!(t_ThreadType & ThreadType_ETWRundownThread);
 }
 
 // check if current thread is a generic instantiation lookup compare thread
@@ -4396,7 +4398,7 @@ inline BOOL IsGenericInstantiationLookupCompareThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_GenericInstantiationCompare);
+    return !!(t_ThreadType & ThreadType_GenericInstantiationCompare);
 }
 
 // check if current thread is a thread which is performing shutdown
@@ -4406,7 +4408,7 @@ inline BOOL IsShutdownSpecialThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Shutdown);
+    return !!(t_ThreadType & ThreadType_Shutdown);
 }
 
 inline BOOL IsThreadPoolIOCompletionSpecialThread ()
@@ -4415,7 +4417,7 @@ inline BOOL IsThreadPoolIOCompletionSpecialThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Threadpool_IOCompletion);
+    return !!(t_ThreadType & ThreadType_Threadpool_IOCompletion);
 }
 
 inline BOOL IsThreadPoolWorkerSpecialThread ()
@@ -4424,7 +4426,7 @@ inline BOOL IsThreadPoolWorkerSpecialThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Threadpool_Worker);
+    return !!(t_ThreadType & ThreadType_Threadpool_Worker);
 }
 
 inline BOOL IsWaitSpecialThread ()
@@ -4433,7 +4435,7 @@ inline BOOL IsWaitSpecialThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Wait);
+    return !!(t_ThreadType & ThreadType_Wait);
 }
 
 // check if current thread is a thread which is performing shutdown
@@ -4443,7 +4445,7 @@ inline BOOL IsSuspendEEThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_DynamicSuspendEE);
+    return !!(t_ThreadType & ThreadType_DynamicSuspendEE);
 }
 
 inline BOOL IsFinalizerThread ()
@@ -4452,7 +4454,7 @@ inline BOOL IsFinalizerThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Finalizer);
+    return !!(t_ThreadType & ThreadType_Finalizer);
 }
 
 inline BOOL IsShutdownHelperThread ()
@@ -4461,7 +4463,7 @@ inline BOOL IsShutdownHelperThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ShutdownHelper);
+    return !!(t_ThreadType & ThreadType_ShutdownHelper);
 }
 
 inline BOOL IsProfilerAttachThread ()
@@ -4470,55 +4472,17 @@ inline BOOL IsProfilerAttachThread ()
     STATIC_CONTRACT_GC_NOTRIGGER;
     STATIC_CONTRACT_MODE_ANY;
 
-    return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ProfAPI_Attach);
-}
-
-// set specical type for current thread
-inline void ClrFlsSetThreadType (TlsThreadTypeFlag flag)
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-
-    ClrFlsSetValue (TlsIdx_ThreadType, (LPVOID)(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) |flag));
+    return !!(t_ThreadType & ThreadType_ProfAPI_Attach);
 }
 
-// clear specical type for current thread
-inline void ClrFlsClearThreadType (TlsThreadTypeFlag flag)
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-
-    ClrFlsSetValue (TlsIdx_ThreadType, (LPVOID)(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ~flag));
-}
+// set special type for current thread
+void ClrFlsSetThreadType(TlsThreadTypeFlag flag);
+void ClrFlsClearThreadType(TlsThreadTypeFlag flag);
 
 #endif //!DACCESS_COMPILE
 
-#ifdef DACCESS_COMPILE
-#define SET_THREAD_TYPE_STACKWALKER(pThread)
-#define CLEAR_THREAD_TYPE_STACKWALKER()
-#else   // DACCESS_COMPILE
-#define SET_THREAD_TYPE_STACKWALKER(pThread)   ClrFlsSetValue(TlsIdx_StackWalkerWalkingThread, pThread)
-#define CLEAR_THREAD_TYPE_STACKWALKER() ClrFlsSetValue(TlsIdx_StackWalkerWalkingThread, NULL)
-#endif  // DACCESS_COMPILE
-
 HRESULT SetThreadName(HANDLE hThread, PCWSTR lpThreadDescription);
 
-inline BOOL IsStackWalkerThread()
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
-
-#if defined(DACCESS_COMPILE)
-    return FALSE;
-#else
-    return ClrFlsGetValue (TlsIdx_StackWalkerWalkingThread) != NULL;
-#endif
-}
-
 inline BOOL IsGCThread ()
 {
     STATIC_CONTRACT_NOTHROW;
@@ -4544,11 +4508,11 @@ public:
 
 #ifndef DACCESS_COMPILE
         m_flag = flag;
-        m_fPreviouslySet = (((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & flag);
+        m_fPreviouslySet = (t_ThreadType & flag);
 
         // In debug builds, remember the full group of flags that were set at the time
         // the constructor was called.  This will be used in ASSERTs in the destructor
-        INDEBUG(m_nPreviousFlagGroup = (size_t)ClrFlsGetValue (TlsIdx_ThreadType));
+        INDEBUG(m_nPreviousFlagGroup = t_ThreadType);
 
         if (!m_fPreviouslySet)
         {
@@ -4573,7 +4537,7 @@ public:
         // The expression below says that the only difference between the previous flag
         // group and the current flag group should be m_flag (or no difference at all, if
         // m_flag's state didn't actually change).
-        _ASSERTE(((m_nPreviousFlagGroup ^ (size_t) ClrFlsGetValue(TlsIdx_ThreadType)) | (size_t) m_flag) == (size_t) m_flag);
+        _ASSERTE(((m_nPreviousFlagGroup ^ t_ThreadType) | (size_t) m_flag) == (size_t) m_flag);
 
         if (m_fPreviouslySet)
         {
@@ -4592,81 +4556,6 @@ private:
     INDEBUG(size_t m_nPreviousFlagGroup);
 };
 
-class ClrFlsValueSwitch
-{
-public:
-    ClrFlsValueSwitch (PredefinedTlsSlots slot, PVOID value)
-    {
-        STATIC_CONTRACT_NOTHROW;
-        STATIC_CONTRACT_GC_NOTRIGGER;
-        STATIC_CONTRACT_MODE_ANY;
-
-#ifndef DACCESS_COMPILE
-        m_slot = slot;
-        m_PreviousValue = ClrFlsGetValue(slot);
-        ClrFlsSetValue(slot, value);
-#endif // DACCESS_COMPILE
-    }
-
-    ~ClrFlsValueSwitch ()
-    {
-        STATIC_CONTRACT_NOTHROW;
-        STATIC_CONTRACT_GC_NOTRIGGER;
-        STATIC_CONTRACT_MODE_ANY;
-
-#ifndef DACCESS_COMPILE
-        ClrFlsSetValue(m_slot, m_PreviousValue);
-#endif // DACCESS_COMPILE
-    }
-
-private:
-    PVOID m_PreviousValue;
-    PredefinedTlsSlots m_slot;
-};
-
-//*********************************************************************************
-
-// When we're hosted, operations called by the host (such as Thread::YieldTask)
-// may not cause calls back into the host, as the host needs not be reentrant.
-// Use the following holder for code in which calls into the host are forbidden.
-// (If a call into the host is attempted nevertheless, an assert will fire.)
-
-class ForbidCallsIntoHostOnThisThread
-{
-private:
-    static Volatile<PVOID> s_pvOwningFiber;
-
-    FORCEINLINE static BOOL Enter(BOOL)
-    {
-        WRAPPER_NO_CONTRACT;
-        return InterlockedCompareExchangePointer(
-            &s_pvOwningFiber, ClrTeb::GetFiberPtrId(), NULL) == NULL;
-    }
-
-    FORCEINLINE static void Leave(BOOL)
-    {
-        LIMITED_METHOD_CONTRACT;
-        s_pvOwningFiber = NULL;
-    }
-
-public:
-    typedef ConditionalStateHolder<BOOL, ForbidCallsIntoHostOnThisThread::Enter, ForbidCallsIntoHostOnThisThread::Leave> Holder;
-
-    FORCEINLINE static BOOL CanThisThreadCallIntoHost()
-    {
-        WRAPPER_NO_CONTRACT;
-        return s_pvOwningFiber != ClrTeb::GetFiberPtrId();
-    }
-};
-
-typedef ForbidCallsIntoHostOnThisThread::Holder ForbidCallsIntoHostOnThisThreadHolder;
-
-FORCEINLINE BOOL CanThisThreadCallIntoHost()
-{
-    WRAPPER_NO_CONTRACT;
-    return ForbidCallsIntoHostOnThisThread::CanThisThreadCallIntoHost();
-}
-
 //*********************************************************************************
 
 #include "contract.inl"
@@ -5072,13 +4961,6 @@ typedef void* (__cdecl *LocalizedFileHandler)(LPCWSTR);
 void* FindLocalizedFile(_In_z_ LPCWSTR wzResourceDllName, LocalizedFileHandler lfh, _In_opt_z_ LPCWSTR modulePath=NULL);
 
 
-
-// Helper to support termination due to heap corruption
-// It's not supported on Win2K, so we have to manually delay load it
-void EnableTerminationOnHeapCorruption();
-
-
-
 namespace Clr { namespace Util
 {
 
index 647b899..1afbb75 100644 (file)
@@ -165,25 +165,6 @@ EXTERN_C const IID IID_IExecutionEngine;
     IExecutionEngine : public IUnknown
     {
     public:
-        virtual void STDMETHODCALLTYPE TLS_AssociateCallback( 
-            /* [in] */ DWORD slot,
-            /* [in] */ PTLS_CALLBACK_FUNCTION callback) = 0;
-        
-        virtual PVOID *STDMETHODCALLTYPE TLS_GetDataBlock( void) = 0;
-        
-        virtual PVOID STDMETHODCALLTYPE TLS_GetValue( 
-            /* [in] */ DWORD slot) = 0;
-        
-        virtual BOOL STDMETHODCALLTYPE TLS_CheckValue( 
-            /* [in] */ DWORD slot,
-            /* [out] */ PVOID *pValue) = 0;
-        
-        virtual void STDMETHODCALLTYPE TLS_SetValue( 
-            /* [in] */ DWORD slot,
-            /* [in] */ PVOID pData) = 0;
-        
-        virtual void STDMETHODCALLTYPE TLS_ThreadDetaching( void) = 0;
-        
         virtual CRITSEC_COOKIE STDMETHODCALLTYPE CreateLock( 
             /* [in] */ LPCSTR szTag,
             /* [in] */ LPCSTR level,
@@ -285,31 +266,6 @@ EXTERN_C const IID IID_IExecutionEngine;
         ULONG ( STDMETHODCALLTYPE *Release )( 
             IExecutionEngine * This);
         
-        void ( STDMETHODCALLTYPE *TLS_AssociateCallback )( 
-            IExecutionEngine * This,
-            /* [in] */ DWORD slot,
-            /* [in] */ PTLS_CALLBACK_FUNCTION callback);
-        
-        PVOID *( STDMETHODCALLTYPE *TLS_GetDataBlock )( 
-            IExecutionEngine * This);
-        
-        PVOID ( STDMETHODCALLTYPE *TLS_GetValue )( 
-            IExecutionEngine * This,
-            /* [in] */ DWORD slot);
-        
-        BOOL ( STDMETHODCALLTYPE *TLS_CheckValue )( 
-            IExecutionEngine * This,
-            /* [in] */ DWORD slot,
-            /* [out] */ PVOID *pValue);
-        
-        void ( STDMETHODCALLTYPE *TLS_SetValue )( 
-            IExecutionEngine * This,
-            /* [in] */ DWORD slot,
-            /* [in] */ PVOID pData);
-        
-        void ( STDMETHODCALLTYPE *TLS_ThreadDetaching )( 
-            IExecutionEngine * This);
-        
         CRITSEC_COOKIE ( STDMETHODCALLTYPE *CreateLock )( 
             IExecutionEngine * This,
             /* [in] */ LPCSTR szTag,
@@ -434,25 +390,6 @@ EXTERN_C const IID IID_IExecutionEngine;
 #define IExecutionEngine_Release(This) \
     ( (This)->lpVtbl -> Release(This) ) 
 
-
-#define IExecutionEngine_TLS_AssociateCallback(This,slot,callback)     \
-    ( (This)->lpVtbl -> TLS_AssociateCallback(This,slot,callback) ) 
-
-#define IExecutionEngine_TLS_GetDataBlock(This)        \
-    ( (This)->lpVtbl -> TLS_GetDataBlock(This) ) 
-
-#define IExecutionEngine_TLS_GetValue(This,slot)       \
-    ( (This)->lpVtbl -> TLS_GetValue(This,slot) ) 
-
-#define IExecutionEngine_TLS_CheckValue(This,slot,pValue)      \
-    ( (This)->lpVtbl -> TLS_CheckValue(This,slot,pValue) ) 
-
-#define IExecutionEngine_TLS_SetValue(This,slot,pData) \
-    ( (This)->lpVtbl -> TLS_SetValue(This,slot,pData) ) 
-
-#define IExecutionEngine_TLS_ThreadDetaching(This)     \
-    ( (This)->lpVtbl -> TLS_ThreadDetaching(This) ) 
-
 #define IExecutionEngine_CreateLock(This,szTag,level,flags)    \
     ( (This)->lpVtbl -> CreateLock(This,szTag,level,flags) ) 
 
index f6eb909..e06743d 100644 (file)
@@ -15,6 +15,8 @@
 #ifdef _DEBUG
 size_t CHECK::s_cLeakedBytes = 0;
 size_t CHECK::s_cNumFailures = 0;
+
+thread_local LONG CHECK::t_count;
 #endif
 
 BOOL CHECK::s_neverEnforceAsserts = 0;
@@ -277,9 +279,4 @@ LPCSTR CHECK::AllocateDynamicMessage(const SString &s)
     return p;
 }
 
-void WINAPI ReleaseCheckTls(LPVOID pTlsData)
-{
-    CHECK::ReleaseTls(pTlsData);
-}
-
 #endif
index 9440b17..090b533 100644 (file)
 
 CoreClrCallbacks g_CoreClrCallbacks;
 
-
-// In some cirumstance (e.g, the thread suspecd another thread), allocation on heap
-// could cause dead lock. We use a counter in TLS to indicate the current thread is not allowed
-// to do heap allocation.
-//In cases where CLRTlsInfo doesn't exist and we still want to track CantAlloc info (this is important to
-//stress log), We use a global counter. This introduces the problem where one thread could disable allocation
-//for another thread, but the cases should be rare (we limit the use to stress log for now) and the period
-//should (MUST) be short
-//only stress log check this counter
-
-struct CantAllocThread
-{
-    PVOID m_fiberId;
-    LONG  m_CantCount;
-};
-
-#define MaxCantAllocThreadNum 100
-static CantAllocThread g_CantAllocThreads[MaxCantAllocThreadNum] = {};
-static Volatile<LONG> g_CantAllocStressLogCount = 0;
-
-void IncCantAllocCount()
-{
-    size_t count = 0;
-    if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
-    {
-        _ASSERTE (count >= 0);
-        ClrFlsSetValue(TlsIdx_CantAllocCount,  (LPVOID)(count+1));
-        return;
-    }
-    PVOID fiberId = ClrTeb::GetFiberPtrId();
-    for (int i = 0; i < MaxCantAllocThreadNum; i ++)
-    {
-        if (g_CantAllocThreads[i].m_fiberId == fiberId)
-        {
-            g_CantAllocThreads[i].m_CantCount ++;
-            return;
-        }
-    }
-    for (int i = 0; i < MaxCantAllocThreadNum; i ++)
-    {
-        if (g_CantAllocThreads[i].m_fiberId == NULL)
-        {
-            if (InterlockedCompareExchangeT(&g_CantAllocThreads[i].m_fiberId, fiberId, NULL) == NULL)
-            {
-                _ASSERTE(g_CantAllocThreads[i].m_CantCount == 0);
-                g_CantAllocThreads[i].m_CantCount = 1;
-                return;
-            }
-        }
-    }
-    count = InterlockedIncrement (&g_CantAllocStressLogCount);
-    _ASSERTE (count >= 1);
-    return;
-}
-
-void DecCantAllocCount()
-{
-    size_t count = 0;
-    if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
-    {
-        if (count > 0)
-        {
-            ClrFlsSetValue(TlsIdx_CantAllocCount,  (LPVOID)(count-1));
-            return;
-        }
-    }
-    PVOID fiberId = ClrTeb::GetFiberPtrId();
-    for (int i = 0; i < MaxCantAllocThreadNum; i ++)
-    {
-        if (g_CantAllocThreads[i].m_fiberId == fiberId)
-        {
-            _ASSERTE (g_CantAllocThreads[i].m_CantCount > 0);
-            g_CantAllocThreads[i].m_CantCount --;
-            if (g_CantAllocThreads[i].m_CantCount == 0)
-            {
-                g_CantAllocThreads[i].m_fiberId = NULL;
-            }
-            return;
-        }
-    }
-    _ASSERTE (g_CantAllocStressLogCount > 0);
-    InterlockedDecrement (&g_CantAllocStressLogCount);
-    return;
-
-}
-
-// for stress log the rule is more restrict, we have to check the global counter too
-BOOL IsInCantAllocStressLogRegion()
-{
-    size_t count = 0;
-    if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
-    {
-        if (count > 0)
-        {
-            return true;
-        }
-    }
-    PVOID fiberId = ClrTeb::GetFiberPtrId();
-    for (int i = 0; i < MaxCantAllocThreadNum; i ++)
-    {
-        if (g_CantAllocThreads[i].m_fiberId == fiberId)
-        {
-            _ASSERTE (g_CantAllocThreads[i].m_CantCount > 0);
-            return true;
-        }
-    }
-
-    return g_CantAllocStressLogCount > 0;
-
-}
-
+thread_local int t_CantAllocCount;
 
 #ifdef FAILPOINTS_ENABLED
 typedef int (*FHashStack) ();
index 9d9c624..d531182 100644 (file)
@@ -65,6 +65,8 @@ static void RealCLRThrowsExceptionWorker(__in_z const char *szFunction,
 
 #if defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
 
+thread_local ClrDebugState* t_pClrDebugState;
+
 // Fls callback to deallocate ClrDebugState when our FLS block goes away.
 void FreeClrDebugState(LPVOID pTlsData)
 {
@@ -147,25 +149,6 @@ static VOID ShutoffContracts()
 //=============================================================================================
 ClrDebugState *CLRInitDebugState()
 {
-    // workaround!
-    //
-    // The existing Fls apis didn't provide the support we need and adding support cleanly is
-    // messy because of the brittleness of IExecutionEngine.
-    //
-    // To understand this function, you need to know that the Fls routines have special semantics
-    // for the TlsIdx_ClrDebugState slot:
-    //
-    //  - FlsSetValue will never throw. If it fails due to OOM on creation of the slot storage,
-    //    it will silently bail. Thus, we must do a confirming FlsGetValue before we can conclude
-    //    that the SetValue succeeded.
-    //
-    //  - FlsAssociateCallback will not complain about multiple sets of the callback.
-    //
-    //  - The mscorwks implemention of FlsAssociateCallback will ignore the passed in value
-    //    and use the version of FreeClrDebugState compiled into mscorwks. This is needed to
-    //    avoid dangling pointer races on shutdown.
-
-
     // This is our global "bad" debug state that thread use when they OOM on CLRInitDebugState.
     // We really only need to initialize it once but initializing each time is convenient
     // and has low perf impact.
@@ -177,12 +160,6 @@ ClrDebugState *CLRInitDebugState()
     ClrDebugState *pClrDebugState    = NULL;
     DbgStateLockData    *pNewLockData      = NULL;
 
-    // We call this first partly to force a CheckThreadState. We've hopefully chased out all the
-    // recursive contract calls inside here but if we haven't, it's best to get them out of the way
-    // early.
-    ClrFlsAssociateCallback(TlsIdx_ClrDebugState, FreeClrDebugState);
-
-
     if (AreContractsShutoff())
     {
         pNewClrDebugState = NULL;
@@ -227,7 +204,7 @@ ClrDebugState *CLRInitDebugState()
     //
     // So we must make one last check to see if the ClrDebugState still needs creating.
     //
-    ClrDebugState *pTmp = (ClrDebugState*)(ClrFlsGetValue(TlsIdx_ClrDebugState));
+    ClrDebugState *pTmp = t_pClrDebugState;
     if (pTmp != NULL)
     {
         // Recursive call set up ClrDebugState for us
@@ -251,27 +228,7 @@ ClrDebugState *CLRInitDebugState()
 
     _ASSERTE(pClrDebugState != NULL);
 
-
-    ClrFlsSetValue(TlsIdx_ClrDebugState, (LPVOID)pClrDebugState);
-
-    // For the ClrDebugState index, ClrFlsSetValue does *not* throw on OOM.
-    // Instead, it silently throws away the value. So we must now do a confirming
-    // FlsGet to learn if our Set succeeded.
-    if (ClrFlsGetValue(TlsIdx_ClrDebugState) == NULL)
-    {
-        // Our FlsSet didn't work. That means it couldn't allocate the master FLS block for our thread.
-        // Now we're a bad state because not only can't we succeed, we can't record that we didn't succeed.
-        // And it's invalid to return a BadClrDebugState here only to return a good debug state later.
-        //
-        // So we now take the drastic step of forcing all future ClrInitDebugState calls to return the OOM state.
-        ShutoffContracts();
-        pClrDebugState = &gBadClrDebugState;
-
-        // Try once more time to set the FLS (if it doesn't work, the next call will keep cycling through here
-        // until it does succeed.)
-        ClrFlsSetValue(TlsIdx_ClrDebugState, &gBadClrDebugState);
-    }
-
+    t_pClrDebugState = pClrDebugState;
 
 #if defined(_DEBUG)
     // The ClrDebugState we allocated above made it into FLS iff
@@ -669,22 +626,6 @@ void SetExecutionEngine(IExecutionEngine *pExecutionEngine)
     }
 }
 
-void ClrFlsAssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
-{
-    WRAPPER_NO_CONTRACT;
-
-    GetExecutionEngine()->TLS_AssociateCallback(slot, callback);
-}
-
-LPVOID *ClrFlsGetBlockGeneric()
-{
-    WRAPPER_NO_CONTRACT;
-
-    return (LPVOID *) GetExecutionEngine()->TLS_GetDataBlock();
-}
-
-CLRFLSGETBLOCK __ClrFlsGetBlock = ClrFlsGetBlockGeneric;
-
 CRITSEC_COOKIE ClrCreateCriticalSection(CrstType crstType, CrstFlags flags)
 {
     WRAPPER_NO_CONTRACT;
index 8fd814d..4833b9c 100644 (file)
@@ -183,29 +183,7 @@ VOID TerminateOnAssert()
     RaiseFailFastException(NULL, NULL, 0);
 }
 
-// Whether this thread is already displaying an assert dialog.
-BOOL IsDisplayingAssertDlg()
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_DEBUG_ONLY;
-
-    size_t flag = 0;
-    if (ClrFlsCheckValue(TlsIdx_AssertDlgStatus, (LPVOID *)&flag))
-    {
-        return (flag != 0);
-    }
-    return FALSE;
-}
-
-void SetDisplayingAssertDlg(BOOL value)
-{
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_DEBUG_ONLY;
-
-    ClrFlsSetValue(TlsIdx_AssertDlgStatus, (LPVOID)(size_t)value);
-}
+thread_local bool f_bDisplayingAssertDlg;
 
 VOID LogAssert(
     LPCSTR      szFile,
@@ -440,7 +418,7 @@ bool _DbgBreakCheck(
         TerminateOnAssert();
     }
 
-    if (IsDisplayingAssertDlg())
+    if (f_bDisplayingAssertDlg)
     {
         // We are already displaying an assert dialog box on this thread. The reason why we came here is
         // the message loop run by the API we call to display the UI. A message was dispatched and execution
@@ -450,7 +428,7 @@ bool _DbgBreakCheck(
         return false;
     }
 
-    SetDisplayingAssertDlg(TRUE);
+    f_bDisplayingAssertDlg = true;
 
     // Tell user there was an error.
     _DbgBreakCount++;
@@ -467,7 +445,7 @@ bool _DbgBreakCheck(
     }
     --_DbgBreakCount;
 
-    SetDisplayingAssertDlg(FALSE);
+    f_bDisplayingAssertDlg = false;
 
     switch(ret)
     {
index c970326..d669055 100644 (file)
@@ -1214,35 +1214,6 @@ void GenerateTopLevelHRExceptionMessage(HRESULT hresult, SString &result)
     GetHRMsg(hresult, result);
 }
 
-#if !defined(DACCESS_COMPILE)
-
-void GetCurrentExceptionPointers(PEXCEPTION_POINTERS pExceptionInfo DEBUG_ARG(bool checkExceptionRecordLocation))
-{
-    WRAPPER_NO_CONTRACT;
-
-    PEXCEPTION_RECORD pRecord = (PEXCEPTION_RECORD)ClrFlsGetValue(TlsIdx_PEXCEPTION_RECORD);
-    PCONTEXT pContext = (PCONTEXT)ClrFlsGetValue(TlsIdx_PCONTEXT);
-
-    pExceptionInfo->ContextRecord = pContext;
-    pExceptionInfo->ExceptionRecord = pRecord;
-
-#ifdef _DEBUG
-    if (pRecord != NULL && checkExceptionRecordLocation)
-    {
-        _ASSERTE ((PVOID)(pRecord) > (PVOID)(&pRecord));
-    }
-#endif
-}
-#endif // !defined(DACCESS_COMPILE)
-
-DWORD GetCurrentExceptionCode()
-{
-    WRAPPER_NO_CONTRACT;
-    SUPPORTS_DAC_HOST_ONLY;
-
-    return (DWORD)(size_t)ClrFlsGetValue(TlsIdx_EXCEPTION_CODE);
-}
-
 //===========================================================================================
 // These abstractions hide the difference between legacy desktop CLR's (that don't support
 // side-by-side-inproc and rely on a fixed SEH code to identify managed exceptions) and
index 60c6aca..2354d18 100644 (file)
 #include "mscoree.h"
 #include "clrinternal.h"
 #include "hostimpl.h"
-#include "predeftlsslot.h"
 
 // to avoid to include clrhost.h in this file
 #ifdef FAILPOINTS_ENABLED
 extern int RFS_HashStack();
 #endif
 
-#ifndef __GNUC__
-static __declspec(thread) void** t_pBlock;
-#else  // !__GNUC__
-static thread_local void** t_pBlock;
-#endif // !__GNUC__
-
-static PTLS_CALLBACK_FUNCTION Callbacks[MAX_PREDEFINED_TLS_SLOT];
-
 #ifdef SELF_NO_HOST
 HANDLE (*g_fnGetExecutableHeapHandle)();
 #endif
 
-extern LPVOID* (*__ClrFlsGetBlock)();
-
-//
-// FLS getter to avoid unnecessary indirection via execution engine.
-//
-LPVOID* ClrFlsGetBlockDirect()
-{
-    return t_pBlock;
-}
-
-//
-// utility functions for tls functionality
-//
-static void **CheckThreadState(DWORD slot, BOOL force = TRUE)
-{
-    // Treat as a runtime assertion, since the invariant spans many DLLs.
-    _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
-
-    if (__ClrFlsGetBlock != ClrFlsGetBlockDirect)
-    {
-        // Switch to faster TLS getter now that the TLS slot is initialized
-        __ClrFlsGetBlock = ClrFlsGetBlockDirect;
-    }
-
-    void **pTlsData = t_pBlock;
-
-    if (pTlsData == 0 && force) {
-
-        // !!! Contract uses our TLS support.  Contract may be used before our host support is set up.
-        // !!! To better support contract, we call into OS for memory allocation.
-        pTlsData = (void**) ::HeapAlloc(GetProcessHeap(),0,MAX_PREDEFINED_TLS_SLOT*sizeof(void*));
-
-
-        if (pTlsData == NULL)
-        {
-            // workaround! We don't want exceptions being thrown during ClrInitDebugState. Just return NULL out of TlsSetValue.
-            // ClrInitDebugState will do a confirming FlsGet to see if the value stuck.
-
-            // If this is for the stack probe, and we failed to allocate memory for it, we won't
-            // put in a guard page.
-            if (slot == TlsIdx_ClrDebugState)
-            {
-                return NULL;
-            }
-            RaiseException(STATUS_NO_MEMORY, 0, 0, NULL);
-        }
-        for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
-            pTlsData[i] = 0;
-        t_pBlock = pTlsData;
-    }
-
-    return pTlsData;
-} // CheckThreadState
+thread_local size_t t_ThreadType;
 
 HRESULT STDMETHODCALLTYPE UtilExecutionEngine::QueryInterface(REFIID id, void **pInterface)
 {
@@ -122,69 +61,6 @@ ULONG STDMETHODCALLTYPE UtilExecutionEngine::Release()
     return 1;
 }
 
-VOID  STDMETHODCALLTYPE UtilExecutionEngine::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
-{
-    CheckThreadState(slot);
-
-    // They can toggle between a callback and no callback.  But anything else looks like
-    // confusion on their part.
-    //
-    // (TlsIdx_ClrDebugState associates its callback from utilcode.lib - which can be replicated. But
-    // all the callbacks are equally good.)
-    _ASSERTE(slot == TlsIdx_ClrDebugState || Callbacks[slot] == 0 || Callbacks[slot] == callback || callback == 0);
-    Callbacks[slot] = callback;
-}
-
-LPVOID* STDMETHODCALLTYPE UtilExecutionEngine::TLS_GetDataBlock()
-{
-    return t_pBlock;
-}
-
-LPVOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_GetValue(DWORD slot)
-{
-    void **pTlsData = CheckThreadState(slot, FALSE);
-    if (pTlsData)
-        return pTlsData[slot];
-    else
-        return NULL;
-}
-
-BOOL STDMETHODCALLTYPE UtilExecutionEngine::TLS_CheckValue(DWORD slot, LPVOID * pValue)
-{
-    void **pTlsData = CheckThreadState(slot, FALSE);
-    if (pTlsData)
-    {
-        *pValue = pTlsData[slot];
-        return TRUE;
-    }
-    return FALSE;
-}
-
-VOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_SetValue(DWORD slot, LPVOID pData)
-{
-    void **pTlsData = CheckThreadState(slot);
-    if (pTlsData)  // Yes, CheckThreadState(slot, TRUE) can return NULL now.
-    {
-        pTlsData[slot] = pData;
-    }
-}
-
-VOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_ThreadDetaching()
-{
-    void **pTlsData = CheckThreadState(0, FALSE);
-    if (pTlsData)
-    {
-        for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
-        {
-            // If we have some data and a callback, issue it.
-            if (Callbacks[i] != 0 && pTlsData[i] != 0)
-                (*Callbacks[i])(pTlsData[i]);
-        }
-        ::HeapFree (GetProcessHeap(),0,pTlsData);
-
-    }
-}
-
 CRITSEC_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags)
 {
     CRITICAL_SECTION *cs = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
index 742b29d..326a3ee 100644 (file)
@@ -36,25 +36,6 @@ private:
     ULONG STDMETHODCALLTYPE Release();
 
     //***************************************************************************
-    // IExecutionEngine methods for TLS
-    //***************************************************************************
-
-    // Associate a callback for cleanup with a TLS slot
-    VOID  STDMETHODCALLTYPE TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback);
-    // Get the master TLS slot index
-    LPVOID* STDMETHODCALLTYPE TLS_GetDataBlock();
-
-    // Get the value at a slot
-    LPVOID STDMETHODCALLTYPE TLS_GetValue(DWORD slot);
-
-    // Get the value at a slot, return FALSE if TLS info block doesn't exist
-    BOOL STDMETHODCALLTYPE TLS_CheckValue(DWORD slot, LPVOID * pValue);
-    // Set the value at a slot
-    VOID STDMETHODCALLTYPE TLS_SetValue(DWORD slot, LPVOID pData);
-    // Free TLS memory block and make callback
-    VOID STDMETHODCALLTYPE TLS_ThreadDetaching();
-
-    //***************************************************************************
     // IExecutionEngine methods for locking
     //***************************************************************************
 
index 184e222..b4907e3 100644 (file)
@@ -391,66 +391,30 @@ VOID LogSpew(DWORD facility, DWORD level, const char *fmt, ... )
 {
     STATIC_CONTRACT_WRAPPER;
 
-#ifdef SELF_NO_HOST
-    if (TRUE)
-#else //!SELF_NO_HOST
-    if (CanThisThreadCallIntoHost())
-#endif //!SELF_NO_HOST
-    {
-        va_list     args;
-        va_start(args, fmt);
-        LogSpewValist (facility, level, fmt, args);
-        va_end(args);
-    }
-    else
-    {
-        // Cannot acquire the required lock, as this would call back
-        // into the host.  Eat the log message.
-    }
+    va_list     args;
+    va_start(args, fmt);
+    LogSpewValist (facility, level, fmt, args);
+    va_end(args);
 }
 
 VOID LogSpew2(DWORD facility2, DWORD level, const char *fmt, ... )
 {
     STATIC_CONTRACT_WRAPPER;
 
-#ifdef SELF_NO_HOST
-    if (TRUE)
-#else //!SELF_NO_HOST
-    if (CanThisThreadCallIntoHost())
-#endif //!SELF_NO_HOST
-    {
-        va_list     args;
-        va_start(args, fmt);
-        LogSpew2Valist(facility2, level, fmt, args);
-        va_end(args);
-    }
-    else
-    {
-        // Cannot acquire the required lock, as this would call back
-        // into the host.  Eat the log message.
-    }
+    va_list     args;
+    va_start(args, fmt);
+    LogSpew2Valist(facility2, level, fmt, args);
+    va_end(args);
 }
 
 VOID LogSpewAlways (const char *fmt, ... )
 {
     STATIC_CONTRACT_WRAPPER;
 
-#ifdef SELF_NO_HOST
-    if (TRUE)
-#else //!SELF_NO_HOST
-    if (CanThisThreadCallIntoHost())
-#endif //!SELF_NO_HOST
-    {
-        va_list     args;
-        va_start(args, fmt);
-        LogSpewValist (LF_ALWAYS, LL_ALWAYS, fmt, args);
-        va_end(args);
-    }
-    else
-    {
-        // Cannot acquire the required lock, as this would call back
-        // into the host.  Eat the log message.
-    }
+    va_list     args;
+    va_start(args, fmt);
+    LogSpewValist (LF_ALWAYS, LL_ALWAYS, fmt, args);
+    va_end(args);
 }
 
 #endif // LOGGING
index cd07b4c..4145ba8 100644 (file)
@@ -62,28 +62,18 @@ HRESULT SecurityUtil::GetACLOfPid(DWORD pid, PACL *ppACL)
     SidBuffer sidTargetProcessAppContainer;
 
     // Get sid for current process.
-    EX_TRY
+    if (SUCCEEDED(sidCurrentProcess.InitFromProcessNoThrow(GetCurrentProcessId())))
     {
-        sidCurrentProcess.InitFromProcess(GetCurrentProcessId()); // throw on error.
         pCurrentProcessSid = sidCurrentProcess.GetSid().RawSid();
         cSid++;
     }
-    EX_CATCH
-    {
-    }
-    EX_END_CATCH(RethrowTerminalExceptions);
 
     // Get sid for target process.
-    EX_TRY
+    if (SUCCEEDED(sidTargetProcess.InitFromProcessNoThrow(pid)))
     {
-        sidTargetProcess.InitFromProcess(pid); // throws on error.
         pTargetProcessSid = sidTargetProcess.GetSid().RawSid();
         cSid++;
     }
-    EX_CATCH
-    {
-    }
-    EX_END_CATCH(RethrowTerminalExceptions);
 
     //FISHY: what is the scenario where only one of the above calls succeeds?
     if (cSid == 0)
index 9c5d7a7..075f4cd 100644 (file)
@@ -19,6 +19,7 @@
 
  #if !defined(STRESS_LOG_READONLY)
 HANDLE StressLogChunk::s_LogChunkHeap = NULL;
+thread_local ThreadStressLog* StressLog::t_pCurrentThreadLog;
 #endif // !STRESS_LOG_READONLY
 
 /*********************************************************************************/
@@ -149,7 +150,6 @@ void StressLog::Initialize(unsigned facilities,  unsigned level, unsigned maxByt
         return;
     }
 
-    _ASSERTE (theLog.TLSslot == (unsigned int)TLS_OUT_OF_INDEXES);
     theLog.lock = ClrCreateCriticalSection(CrstStressLog,(CrstFlags)(CRST_UNSAFE_ANYMODE|CRST_DEBUGGER_THREAD));
     // StressLog::Terminate is going to free memory.
     if (maxBytesPerThread < STRESSLOG_CHUNK_SIZE)
@@ -167,7 +167,6 @@ void StressLog::Initialize(unsigned facilities,  unsigned level, unsigned maxByt
     theLog.facilitiesToLog = facilities | LF_ALWAYS;
     theLog.levelToLog = level;
     theLog.deadCount = 0;
-    theLog.TLSslot = TlsIdx_StressLog;
 
     theLog.tickFrequency = getTickFrequency();
 
@@ -202,36 +201,34 @@ void StressLog::Terminate(BOOL fProcessDetach) {
     STATIC_CONTRACT_NOTHROW;
     STATIC_CONTRACT_FORBID_FAULT;
 
-    if (theLog.TLSslot != (unsigned int)TLS_OUT_OF_INDEXES) {
-        theLog.facilitiesToLog = 0;
+    theLog.facilitiesToLog = 0;
 
-        StressLogLockHolder lockh(theLog.lock, FALSE);
-        if (!fProcessDetach) {
-            lockh.Acquire(); lockh.Release();       // The Enter() Leave() forces a memory barrier on weak memory model systems
-                                    // we want all the other threads to notice that facilitiesToLog is now zero
-
-                    // This is not strictly threadsafe, since there is no way of insuring when all the
-                    // threads are out of logMsg.  In practice, since they can no longer enter logMsg
-                    // and there are no blocking operations in logMsg, simply sleeping will insure
-                    // that everyone gets out.
-            ClrSleepEx(2, FALSE);
-            lockh.Acquire();
-        }
+    StressLogLockHolder lockh(theLog.lock, FALSE);
+    if (!fProcessDetach) {
+        lockh.Acquire(); lockh.Release();       // The Enter() Leave() forces a memory barrier on weak memory model systems
+                                // we want all the other threads to notice that facilitiesToLog is now zero
+
+                // This is not strictly threadsafe, since there is no way of insuring when all the
+                // threads are out of logMsg.  In practice, since they can no longer enter logMsg
+                // and there are no blocking operations in logMsg, simply sleeping will insure
+                // that everyone gets out.
+        ClrSleepEx(2, FALSE);
+        lockh.Acquire();
+    }
 
-        // Free the log memory
-        ThreadStressLog* ptr = theLog.logs;
-        theLog.logs = 0;
-        while(ptr != 0) {
-            ThreadStressLog* tmp = ptr;
-            ptr = ptr->next;
-            delete tmp;
-        }
+    // Free the log memory
+    ThreadStressLog* ptr = theLog.logs;
+    theLog.logs = 0;
+    while(ptr != 0) {
+        ThreadStressLog* tmp = ptr;
+        ptr = ptr->next;
+        delete tmp;
+    }
 
-        theLog.TLSslot = TLS_OUT_OF_INDEXES;
-        if (!fProcessDetach) {
-            lockh.Release();
-        }
+    if (!fProcessDetach) {
+        lockh.Release();
     }
+
 #if !defined (STRESS_LOG_READONLY)
     if (StressLogChunk::s_LogChunkHeap != NULL && StressLogChunk::s_LogChunkHeap != ClrGetProcessHeap ())
     {
@@ -241,7 +238,7 @@ void StressLog::Terminate(BOOL fProcessDetach) {
 }
 
 /*********************************************************************************/
-/* create a new thread stress log buffer associated with Thread local slot TLSslot, for the Stress log */
+/* create a new thread stress log buffer associated with Thread local slot, for the Stress log */
 
 ThreadStressLog* StressLog::CreateThreadStressLog() {
     CONTRACTL
@@ -254,7 +251,7 @@ ThreadStressLog* StressLog::CreateThreadStressLog() {
 
     static PVOID callerID = NULL;
 
-    ThreadStressLog* msgs = (ThreadStressLog*) ClrFlsGetValue(theLog.TLSslot);
+    ThreadStressLog* msgs = t_pCurrentThreadLog;
     if (msgs != NULL)
     {
         return msgs;
@@ -266,7 +263,7 @@ ThreadStressLog* StressLog::CreateThreadStressLog() {
     }
 
     //if we are not allowed to allocate stress log, we should not even try to take the lock
-    if (!StressLogChunk::s_LogChunkHeap || !CanThisThreadCallIntoHost() || IsInCantAllocStressLogRegion ())
+    if (!StressLogChunk::s_LogChunkHeap || IsInCantAllocStressLogRegion ())
     {
         return NULL;
     }
@@ -310,7 +307,7 @@ ThreadStressLog* StressLog::CreateThreadStressLog() {
         // ClrFlsSetValue can throw an OOM exception the first time its called on a thread for a given slot. We go
         // ahead and try to provoke that now, before we've altered the list of available stress logs, and bail if
         // we fail.
-        ClrFlsSetValue(theLog.TLSslot, NULL);
+        t_pCurrentThreadLog = NULL;
     }
 #pragma warning(suppress: 4101)
     PAL_CPP_CATCH_DERIVED(OutOfMemoryException, obj)
@@ -336,9 +333,6 @@ ThreadStressLog* StressLog::CreateThreadStressLogHelper() {
     }
     CONTRACTL_END;
 
-    _ASSERTE(theLog.TLSslot != (unsigned int)TLS_OUT_OF_INDEXES); // because facilitiesToLog is != 0
-
-
     BOOL skipInsert = FALSE;
     ThreadStressLog* msgs = NULL;
 
@@ -405,12 +399,7 @@ ThreadStressLog* StressLog::CreateThreadStressLogHelper() {
 
     msgs->Activate ();
 
-    // We know this isn't going to throw an exception now because the call to ClrFlsSetValue above succeeded for
-    // this thread.
-    {
-        CONTRACT_VIOLATION(ThrowsViolation);
-        ClrFlsSetValue(theLog.TLSslot, msgs);
-    }
+    t_pCurrentThreadLog = msgs;
 
     if (!skipInsert) {
 #ifdef _DEBUG
@@ -433,18 +422,21 @@ LEAVE:
 
 /*********************************************************************************/
 /* static */
-void StressLog::ThreadDetach(ThreadStressLog *msgs) {
+void StressLog::ThreadDetach() {
     STATIC_CONTRACT_NOTHROW;
     STATIC_CONTRACT_FORBID_FAULT;
     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
 
+    ThreadStressLog* msgs = t_pCurrentThreadLog;
+
 #ifndef DACCESS_COMPILE
     if (msgs == 0)
     {
         return;
     }
 
-    _ASSERTE(theLog.TLSslot != (unsigned int)TLS_OUT_OF_INDEXES); // because facilitiesToLog is != 0
+    t_pCurrentThreadLog = NULL;
+
     // We are deleting a fiber.  The thread is running a different fiber now.
     // We should write this message to the StressLog for deleted fiber.
     msgs->LogMsg (LF_STARTUP, 0, "******* DllMain THREAD_DETACH called Thread dying *******\n");
@@ -479,7 +471,7 @@ BOOL StressLog::AllowNewChunk (LONG numChunksInCurThread)
 
 BOOL StressLog::ReserveStressLogChunks (unsigned chunksToReserve)
 {
-    ThreadStressLog* msgs = (ThreadStressLog*) ClrFlsGetValue(theLog.TLSslot);
+    ThreadStressLog* msgs = t_pCurrentThreadLog;
 
     if (msgs == 0)
     {
@@ -646,7 +638,7 @@ void StressLog::LogMsg (unsigned level, unsigned facility, int cArgs, const char
 
     if(InlinedStressLogOn(facility, level))
     {
-        ThreadStressLog* msgs = (ThreadStressLog*) ClrFlsGetValue(theLog.TLSslot);
+        ThreadStressLog* msgs = t_pCurrentThreadLog;
 
         if (msgs == 0) {
             msgs = CreateThreadStressLog();
index 3f1926c..c09496d 100644 (file)
@@ -2935,8 +2935,6 @@ LPWSTR *SegmentCommandLine(LPCWSTR lpCmdLine, DWORD *pNumArgs)
     return argv;
 }
 
-Volatile<PVOID> ForbidCallsIntoHostOnThisThread::s_pvOwningFiber = NULL;
-
 //======================================================================
 // This function returns true, if it can determine that the instruction pointer
 // refers to a code address that belongs in the range of the given image.
@@ -3084,11 +3082,6 @@ BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO /*
 
 #endif // FEATURE_CORRUPTING_EXCEPTIONS
 
-void EnableTerminationOnHeapCorruption()
-{
-    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
-}
-
 namespace Clr
 {
 namespace Util
index 25feee8..0a23cc4 100644 (file)
@@ -1414,9 +1414,9 @@ void StubLinkerCPU::ThumbEmitGetThread(ThumbReg dest)
 
     ThumbEmitLoadRegIndirect(dest, dest, offsetof(TEB, ThreadLocalStoragePointer));
 
-    ThumbEmitLoadRegIndirect(dest, dest, sizeof(void *) * (g_TlsIndex & 0xFFFF));
+    ThumbEmitLoadRegIndirect(dest, dest, sizeof(void *) * _tls_index);
 
-    ThumbEmitLoadRegIndirect(dest, dest, (g_TlsIndex & 0x7FFF0000) >> 16);
+    ThumbEmitLoadRegIndirect(dest, dest, (int)Thread::GetOffsetOfThreadStatic(&gCurrentThreadInfo));
 
 #endif // TARGET_UNIX
 }
index 1a95656..e32fe31 100644 (file)
@@ -1850,12 +1850,10 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
         HINSTANCE hInst;
         DWORD dwReason;
         LPVOID lpReserved;
-        void **pTlsData;
     } param;
     param.hInst = hInst;
     param.dwReason = dwReason;
     param.lpReserved = lpReserved;
-    param.pTlsData = NULL;
 
     // Can't use PAL_TRY/EX_TRY here as they access the ClrDebugState which gets blown away as part of the
     // PROCESS_DETACH path. Must use special PAL_TRY_FOR_DLLMAIN, passing the reason were in the DllMain.
@@ -1917,17 +1915,6 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
                 // Don't destroy threads here if we're in shutdown (shutdown will
                 // clean up for us instead).
 
-                // Store the TLS data; we'll need it later and we might NULL the slot in DetachThread.
-                // This would be problematic because we can't depend on the FLS still existing.
-                pParam->pTlsData = CExecutionEngine::CheckThreadStateNoCreate(0
-#ifdef _DEBUG
-                 // When we get here, OS has destroyed FLS, so FlsGetValue returns NULL now.
-                 // We have validation code in CExecutionEngine::CheckThreadStateNoCreate to ensure that
-                 // our TLS and FLS data are consistent, but since FLS has been destroyed, we need
-                 // to silent the check there.  The extra arg for check build is for this purpose.
-                                                                                         , TRUE
-#endif
-                                                                                         );
                 Thread* thread = GetThread();
                 if (thread)
                 {
@@ -1961,7 +1948,7 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
 
     if (dwReason == DLL_THREAD_DETACH || dwReason == DLL_PROCESS_DETACH)
     {
-        CExecutionEngine::ThreadDetaching(param.pTlsData);
+        CExecutionEngine::ThreadDetaching();
     }
     return TRUE;
 }
index 859386c..bd926f6 100644 (file)
@@ -40,6 +40,9 @@ enum ShutdownCompleteAction
 // Force shutdown of the EE
 void ForceEEShutdown(ShutdownCompleteAction sca = SCA_ExitProcessWhenShutdownComplete);
 
+// Setup thread statics, including ClrDebugState and StressLog.
+void SetupTLSForThread(Thread* pThread);
+
 // We have an internal class that can be used to expose EE functionality to other CLR
 // DLLs, via the deliberately obscure IEE DLL exports from the shim and the EE
 // NOTE:  This class must not ever contain any instance variables.  The reason for
@@ -57,29 +60,9 @@ class CExecutionEngine : public IExecutionEngine, public IEEMemoryManager
 public:
 
     // Notification of a DLL_THREAD_DETACH or a Thread Terminate.
-    static void ThreadDetaching(void **pTlsData);
-
-    // Delete on TLS block
-    static void DeleteTLS(void **pTlsData);
-
-    static void **CheckThreadState(DWORD slot, BOOL force = TRUE);
-    static void **CheckThreadStateNoCreate(DWORD slot
-#ifdef _DEBUG
-                                           , BOOL fForDestruction = FALSE
-#endif // _DEBUG
-                                           );
-
-    // Setup FLS simulation block, including ClrDebugState and StressLog.
-    static void SetupTLSForThread(Thread *pThread);
+    static void ThreadDetaching();
 
-    static LPVOID* GetTlsData();
-    static BOOL SetTlsData (void** ppTlsInfo);
-
-    //***************************************************************************
-    // private implementation:
-    //***************************************************************************
 private:
-    static PTLS_CALLBACK_FUNCTION Callbacks[MAX_PREDEFINED_TLS_SLOT];
 
     //***************************************************************************
     // IUnknown methods
@@ -94,30 +77,6 @@ private:
     ULONG STDMETHODCALLTYPE Release();
 
     //***************************************************************************
-    // IExecutionEngine methods for TLS
-    //***************************************************************************
-
-    // Associate a callback for cleanup with a TLS slot
-    VOID  STDMETHODCALLTYPE TLS_AssociateCallback(
-            DWORD slot,
-            PTLS_CALLBACK_FUNCTION callback);
-
-    // Get the TLS block for fast Get/Set operations
-    LPVOID* STDMETHODCALLTYPE TLS_GetDataBlock();
-
-    // Get the value at a slot
-    LPVOID STDMETHODCALLTYPE TLS_GetValue(DWORD slot);
-
-    // Get the value at a slot, return FALSE if TLS info block doesn't exist
-    BOOL STDMETHODCALLTYPE TLS_CheckValue(DWORD slot, LPVOID * pValue);
-
-    // Set the value at a slot
-    VOID STDMETHODCALLTYPE TLS_SetValue(DWORD slot, LPVOID pData);
-
-    // Free TLS memory block and make callback
-    VOID STDMETHODCALLTYPE TLS_ThreadDetaching();
-
-    //***************************************************************************
     // IExecutionEngine methods for locking
     //***************************************************************************
 
index 4d56c1d..af833fc 100644 (file)
@@ -869,22 +869,6 @@ PTR_COR_ILMETHOD ILCodeVersion::GetIL() const
     return pIL;
 }
 
-PTR_COR_ILMETHOD ILCodeVersion::GetILNoThrow() const
-{
-    LIMITED_METHOD_DAC_CONTRACT;
-    PTR_COR_ILMETHOD ret;
-    EX_TRY
-    {
-        ret = GetIL();
-    }
-    EX_CATCH
-    {
-        ret = NULL;
-    }
-    EX_END_CATCH(RethrowTerminalExceptions);
-    return ret;
-}
-
 DWORD ILCodeVersion::GetJitFlags() const
 {
     LIMITED_METHOD_DAC_CONTRACT;
index 1cb3f2a..724d91a 100644 (file)
@@ -158,7 +158,6 @@ public:
     bool HasAnyOptimizedNativeCodeVersion(NativeCodeVersion tier0NativeCodeVersion) const;
 #endif
     PTR_COR_ILMETHOD GetIL() const;
-    PTR_COR_ILMETHOD GetILNoThrow() const;
     DWORD GetJitFlags() const;
     const InstrumentedILOffsetMapping* GetInstrumentedILMap() const;
 
index f60ac23..0679dd4 100644 (file)
@@ -186,7 +186,7 @@ typedef DPTR(OBJECTREF) PTR_OBJECTREF;
 typedef DPTR(PTR_OBJECTREF) PTR_PTR_OBJECTREF;
 
 EXTERN_C Thread* STDCALL GetThread();
-BOOL SetThread(Thread*);
+void SetThread(Thread*);
 
 // This is a mechanism by which macros can make the Thread pointer available to inner scopes
 // that is robust to code changes.  If the outer Thread no longer is available for some reason
index fb3eac7..51c8c7f 100644 (file)
@@ -300,42 +300,7 @@ ULONG WINAPI ThreadNative::KickOffThread(void* pass)
 
     _ASSERTE(pThread != NULL);
 
-    BOOL ok = TRUE;
-
-    {
-        EX_TRY
-        {
-            CExecutionEngine::CheckThreadState(0);
-        }
-        EX_CATCH
-        {
-            // OOM might be thrown from CheckThreadState, so it's important
-            // that we don't rethrow it; if we do then the process will die
-            // because there are no installed handlers at this point, so
-            // swallow the exception.  this will set the thread's state to
-            // FailStarted which will result in a ThreadStartException being
-            // thrown from the thread that attempted to start this one.
-            if (!GET_EXCEPTION()->IsTransient() && !SwallowUnhandledExceptions())
-                EX_RETHROW;
-        }
-        EX_END_CATCH(SwallowAllExceptions);
-        if (CExecutionEngine::CheckThreadStateNoCreate(0) == NULL)
-        {
-            // We can not
-            pThread->SetThreadState(Thread::TS_FailStarted);
-            pThread->DetachThread(FALSE);
-            // !!! Do not touch any field of Thread object.  The Thread object is subject to delete
-            // !!! after DetachThread call.
-            ok = FALSE;
-        }
-    }
-
-    if (ok)
-    {
-        ok = pThread->HasStarted();
-    }
-
-    if (ok)
+    if (pThread->HasStarted())
     {
         // Do not swallow the unhandled exception here
         //
index 5178b45..08519c9 100644 (file)
@@ -1181,8 +1181,6 @@ HRESULT CorHost2::GetCLRControl(ICLRControl** pCLRControl)
 static BYTE g_CEEInstance[sizeof(CExecutionEngine)];
 static Volatile<IExecutionEngine*> g_pCEE = NULL;
 
-PTLS_CALLBACK_FUNCTION CExecutionEngine::Callbacks[MAX_PREDEFINED_TLS_SLOT];
-
 extern "C" IExecutionEngine * __stdcall IEE()
 {
     LIMITED_METHOD_CONTRACT;
@@ -1250,140 +1248,10 @@ ULONG STDMETHODCALLTYPE CExecutionEngine::Release()
     return 1;
 }
 
-struct ClrTlsInfo
-{
-    void* data[MAX_PREDEFINED_TLS_SLOT];
-};
-
-#define DataToClrTlsInfo(a) ((ClrTlsInfo*)a)
-
-void** CExecutionEngine::GetTlsData()
-{
-    LIMITED_METHOD_CONTRACT;
-
-   return gCurrentThreadInfo.m_EETlsData;
-}
-
-BOOL CExecutionEngine::SetTlsData (void** ppTlsInfo)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    gCurrentThreadInfo.m_EETlsData = ppTlsInfo;
-    return TRUE;
-}
-
-//---------------------------------------------------------------------------------------
-//
-// Returns the current logical thread's data block (ClrTlsInfo::data).
-//
-// Arguments:
-//    slot - Index of the slot that is about to be requested
-//    force - If the data block does not exist yet, create it as a side-effect
-//
-// Return Value:
-//    NULL, if the data block did not exist yet for the current thread and force was FALSE.
-//    A pointer to the data block, otherwise.
-//
-// Notes:
-//    If the underlying OS does not support fiber mode, the data block is stored in TLS.
-//    If the underlying OS does support fiber mode, it is primarily stored in FLS,
-//    and cached in TLS so that we can use our generated optimized TLS accessors.
-//
-// TLS support for the other DLLs of the CLR operates quite differently in hosted
-// and unhosted scenarios.
-
-void **CExecutionEngine::CheckThreadState(DWORD slot, BOOL force)
-{
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_THROWS;
-    STATIC_CONTRACT_MODE_ANY;
-    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
-
-    //<TODO> @TODO: Decide on an exception strategy for all the DLLs of the CLR, and then
-    // enable all the exceptions out of this method.</TODO>
-
-    // Treat as a runtime assertion, since the invariant spans many DLLs.
-    _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
-//    if (slot >= MAX_PREDEFINED_TLS_SLOT)
-//        COMPlusThrow(kArgumentOutOfRangeException);
-
-    void** pTlsData = CExecutionEngine::GetTlsData();
-    BOOL fInTls = (pTlsData != NULL);
-
-    ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
-    if (pTlsInfo == 0 && force)
-    {
-#undef HeapAlloc
-#undef GetProcessHeap
-        // !!! Contract uses our TLS support.  Contract may be used before our host support is set up.
-        // !!! To better support contract, we call into OS for memory allocation.
-        pTlsInfo = (ClrTlsInfo*) ::HeapAlloc(GetProcessHeap(),0,sizeof(ClrTlsInfo));
-#define GetProcessHeap() Dont_Use_GetProcessHeap()
-#define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes)
-        if (pTlsInfo == NULL)
-        {
-            goto LError;
-        }
-        memset (pTlsInfo, 0, sizeof(ClrTlsInfo));
-    }
-
-    if (!fInTls && pTlsInfo)
-    {
-        if (!CExecutionEngine::SetTlsData(pTlsInfo->data))
-        {
-            goto LError;
-        }
-    }
-
-    return pTlsInfo?pTlsInfo->data:NULL;
-
-LError:
-    if (pTlsInfo)
-    {
-#undef HeapFree
-#undef GetProcessHeap
-        ::HeapFree(GetProcessHeap(), 0, pTlsInfo);
-#define GetProcessHeap() Dont_Use_GetProcessHeap()
-#define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
-    }
-    // If this is for the stack probe, and we failed to allocate memory for it, we won't
-    // put in a guard page.
-    if (slot == TlsIdx_ClrDebugState)
-        return NULL;
-
-    ThrowOutOfMemory();
-}
-
-
-void **CExecutionEngine::CheckThreadStateNoCreate(DWORD slot
-#ifdef _DEBUG
-                                                  , BOOL fForDestruction
-#endif // _DEBUG
-                                                  )
-{
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_MODE_ANY;
-
-    // !!! This function is called during Thread::SwitchIn and SwitchOut
-    // !!! It is extremely important that while executing this function, we will not
-    // !!! cause fiber switch.  This means we can not allocate memory, lock, etc...
-
-
-    // Treat as a runtime assertion, since the invariant spans many DLLs.
-    _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
-
-    void **pTlsData = CExecutionEngine::GetTlsData();
-
-    ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
-
-    return pTlsInfo?pTlsInfo->data:NULL;
-}
-
 // Note: Sampling profilers also use this function to initialize TLS for a unmanaged
 // sampling thread so that initialization can be done in advance to avoid deadlocks.
 // See ProfToEEInterfaceImpl::InitializeCurrentThread for more details.
-void CExecutionEngine::SetupTLSForThread(Thread *pThread)
+void SetupTLSForThread(Thread* pThread)
 {
     STATIC_CONTRACT_THROWS;
     STATIC_CONTRACT_GC_NOTRIGGER;
@@ -1395,35 +1263,27 @@ void CExecutionEngine::SetupTLSForThread(Thread *pThread)
         StressLog::CreateThreadStressLog();
     }
 #endif
-    void **pTlsData;
-    pTlsData = CheckThreadState(0);
 
-    PREFIX_ASSUME(pTlsData != NULL);
+    // Make sure ThreadType can be seen by SOS
+    ClrFlsSetThreadType((TlsThreadTypeFlag)0);
 
 #ifdef ENABLE_CONTRACTS
     // Profilers need the side effect of GetClrDebugState() to perform initialization
     // in advance to avoid deadlocks. Refer to ProfToEEInterfaceImpl::InitializeCurrentThread
-    ClrDebugState *pDebugState = ::GetClrDebugState();
+    ClrDebugStatepDebugState = ::GetClrDebugState();
 
     if (pThread)
         pThread->m_pClrDebugState = pDebugState;
 #endif
 }
 
-static void ThreadDetachingHelper(PTLS_CALLBACK_FUNCTION callback, void* pData)
-{
-    // Do not use contract.  We are freeing TLS blocks.
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-
-    callback(pData);
-}
+#ifdef ENABLE_CONTRACTS_IMPL
+// Fls callback to deallocate ClrDebugState when our FLS block goes away.
+void FreeClrDebugState(LPVOID pTlsData);
+#endif
 
-// Called here from a thread detach or from destruction of a Thread object.  In
-// the detach case, we get our info from TLS.  In the destruct case, it comes from
-// the object we are destructing.
-void CExecutionEngine::ThreadDetaching(void ** pTlsData)
+// Called here from a thread detach or from destruction of a Thread object. 
+void CExecutionEngine::ThreadDetaching()
 {
     // Can not cause memory allocation during thread detach, so no real contracts.
     STATIC_CONTRACT_NOTHROW;
@@ -1435,151 +1295,25 @@ void CExecutionEngine::ThreadDetaching(void ** pTlsData)
     // 2. When a fiber is destroyed, or OS calls FlsCallback after DLL_THREAD_DETACH process.
     // We will null the FLS and TLS entry if it matches the deleted one.
 
-    if (pTlsData)
-    {
-        DeleteTLS (pTlsData);
-    }
-}
-
-void CExecutionEngine::DeleteTLS(void ** pTlsData)
-{
-    // Can not cause memory allocation during thread detach, so no real contracts.
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_MODE_ANY;
-
-    if (CExecutionEngine::GetTlsData() == NULL)
-    {
-        // We have not allocated TlsData yet.
-        return;
-    }
-
-    PREFIX_ASSUME(pTlsData != NULL);
-
-    ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
-    BOOL fNeed;
-    do
-    {
-        fNeed = FALSE;
-        for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
-        {
-            if (i == TlsIdx_ClrDebugState ||
-                i == TlsIdx_StressLog)
-            {
-                // StressLog and DebugState may be needed during callback.
-                continue;
-            }
-            // If we have some data and a callback, issue it.
-            if (Callbacks[i] != 0 && pTlsInfo->data[i] != 0)
-            {
-                void* pData = pTlsInfo->data[i];
-                pTlsInfo->data[i] = 0;
-                ThreadDetachingHelper(Callbacks[i], pData);
-                fNeed = TRUE;
-            }
-        }
-    } while (fNeed);
-
-    if (pTlsInfo->data[TlsIdx_StressLog] != 0)
+    if (StressLog::t_pCurrentThreadLog != NULL)
     {
 #ifdef STRESS_LOG
-        StressLog::ThreadDetach((ThreadStressLog *)pTlsInfo->data[TlsIdx_StressLog]);
+        StressLog::ThreadDetach();
 #else
         _ASSERTE (!"should not have StressLog");
 #endif
     }
 
-    if (Callbacks[TlsIdx_ClrDebugState] != 0 && pTlsInfo->data[TlsIdx_ClrDebugState] != 0)
-    {
-        void* pData = pTlsInfo->data[TlsIdx_ClrDebugState];
-        pTlsInfo->data[TlsIdx_ClrDebugState] = 0;
-        ThreadDetachingHelper(Callbacks[TlsIdx_ClrDebugState], pData);
-    }
-
-    // NULL TLS and FLS entry so that we don't double free.
-    // We may get two callback here on thread death
-    // 1. From EEDllMain
-    // 2. From OS callback on FLS destruction
-    if (CExecutionEngine::GetTlsData() == pTlsData)
-    {
-        CExecutionEngine::SetTlsData(0);
-    }
-
-#undef HeapFree
-#undef GetProcessHeap
-    ::HeapFree (GetProcessHeap(),0,pTlsInfo);
-#define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
-#define GetProcessHeap() Dont_Use_GetProcessHeap()
-
-}
-
 #ifdef ENABLE_CONTRACTS_IMPL
-// Fls callback to deallocate ClrDebugState when our FLS block goes away.
-void FreeClrDebugState(LPVOID pTlsData);
-#endif
-
-VOID STDMETHODCALLTYPE CExecutionEngine::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
-{
-    WRAPPER_NO_CONTRACT;
-
-    CheckThreadState(slot);
-
-    // They can toggle between a callback and no callback.  But anything else looks like
-    // confusion on their part.
-    //
-    // (TlsIdx_ClrDebugState associates its callback from utilcode.lib - which can be replicated. But
-    // all the callbacks are equally good.)
-    _ASSERTE(slot == TlsIdx_ClrDebugState || Callbacks[slot] == 0 || Callbacks[slot] == callback || callback == 0);
-    if (slot == TlsIdx_ClrDebugState)
+    if (t_pClrDebugState != NULL)
     {
-#ifdef ENABLE_CONTRACTS_IMPL
-        // ClrDebugState is shared among many dlls.  Some dll, like perfcounter.dll, may be unloaded.
-        // We force the callback function to be in mscorwks.dll.
-        Callbacks[slot] = FreeClrDebugState;
-#else
-        _ASSERTE (!"should not get here");
-#endif
+        void* pData = t_pClrDebugState;
+        t_pClrDebugState = 0;
+        FreeClrDebugState(pData);
     }
-    else
-        Callbacks[slot] = callback;
+#endif // ENABLE_CONTRACTS_IMPL
 }
 
-LPVOID* STDMETHODCALLTYPE CExecutionEngine::TLS_GetDataBlock()
-{
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_THROWS;
-    STATIC_CONTRACT_MODE_ANY;
-    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
-
-    return CExecutionEngine::GetTlsData();
-}
-
-LPVOID STDMETHODCALLTYPE CExecutionEngine::TLS_GetValue(DWORD slot)
-{
-    WRAPPER_NO_CONTRACT;
-    return EETlsGetValue(slot);
-}
-
-BOOL STDMETHODCALLTYPE CExecutionEngine::TLS_CheckValue(DWORD slot, LPVOID * pValue)
-{
-    WRAPPER_NO_CONTRACT;
-    return EETlsCheckValue(slot, pValue);
-}
-
-VOID STDMETHODCALLTYPE CExecutionEngine::TLS_SetValue(DWORD slot, LPVOID pData)
-{
-    WRAPPER_NO_CONTRACT;
-    EETlsSetValue(slot,pData);
-}
-
-
-VOID STDMETHODCALLTYPE CExecutionEngine::TLS_ThreadDetaching()
-{
-    WRAPPER_NO_CONTRACT;
-    CExecutionEngine::ThreadDetaching(NULL);
-}
-
-
 CRITSEC_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags)
 {
     CONTRACTL
index ea08960..6bdf396 100644 (file)
@@ -113,6 +113,11 @@ HRESULT GetExceptionHResult(OBJECTREF throwable)
     return E_FAIL;
 }
 
+DWORD GetCurrentExceptionCode()
+{
+    return 0;
+}
+
 //---------------------------------------------------------------------------------------
 //
 // Dynamically unreachable implementation of profiler callbacks. Note that we can't just
index c08ee7f..3dbdfd1 100644 (file)
@@ -124,8 +124,7 @@ void CrstBase::ReleaseAndBlockForShutdownIfNotSpecialThread()
     }
     CONTRACTL_END;
 
-    if (
-        (((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & (ThreadType_Finalizer|ThreadType_DbgHelper|ThreadType_Shutdown|ThreadType_GC)) == 0)
+    if ((t_ThreadType & (ThreadType_Finalizer|ThreadType_DbgHelper|ThreadType_Shutdown|ThreadType_GC)) == 0)
     {
         // The process is shutting down. Release the lock and just block forever.
         this->Leave();
@@ -389,6 +388,9 @@ void CrstBase::Leave()
 
 
 #ifdef _DEBUG
+
+thread_local CrstBase* t_pOwnedCrstsChain;
+
 void CrstBase::PreEnter()
 {
     STATIC_CONTRACT_NOTHROW;
@@ -470,10 +472,10 @@ void CrstBase::PostEnter()
         _ASSERTE((m_next == NULL) && (m_prev == NULL));
 
         // Link this Crst into the Thread's chain of OwnedCrsts
-        CrstBase *pcrst = GetThreadsOwnedCrsts();
+        CrstBase *pcrst = t_pOwnedCrstsChain;
         if (pcrst == NULL)
         {
-            SetThreadsOwnedCrsts (this);
+            t_pOwnedCrstsChain = this;
         }
         else
         {
@@ -528,7 +530,7 @@ void CrstBase::PreLeave()
         if (m_prev)
             m_prev->m_next = m_next;
         else
-            SetThreadsOwnedCrsts(m_next);
+            t_pOwnedCrstsChain = m_next;
 
         if (m_next)
             m_next->m_prev = m_prev;
@@ -586,16 +588,6 @@ struct CrstDebugInfo
 const int crstDebugInfoCount = 4000;
 CrstDebugInfo crstDebugInfo[crstDebugInfoCount];
 
-CrstBase *CrstBase::GetThreadsOwnedCrsts()
-{
-    return (CrstBase*)ClrFlsGetValue(TlsIdx_OwnedCrstsChain);
-}
-void CrstBase::SetThreadsOwnedCrsts(CrstBase *pCrst)
-{
-    WRAPPER_NO_CONTRACT;
-    ClrFlsSetValue(TlsIdx_OwnedCrstsChain, (LPVOID) (pCrst));
-}
-
 void CrstBase::DebugInit(CrstType crstType, CrstFlags flags)
 {
     LIMITED_METHOD_CONTRACT;
@@ -655,7 +647,7 @@ void CrstBase::DebugDestroy()
             {
                 if (m_next)
                     m_next->m_prev = NULL; // workaround: break up the chain
-                SetThreadsOwnedCrsts(NULL);
+                t_pOwnedCrstsChain = NULL;
             }
         }
         else
@@ -753,7 +745,7 @@ BOOL CrstBase::IsSafeToTake()
 
     // See if the current thread already owns a lower or sibling lock.
     BOOL fSafe = TRUE;
-    for (CrstBase *pcrst = GetThreadsOwnedCrsts(); pcrst != NULL; pcrst = pcrst->m_next)
+    for (CrstBase *pcrst = t_pOwnedCrstsChain; pcrst != NULL; pcrst = pcrst->m_next)
     {
         fSafe =
             !pcrst->m_holderthreadid.IsCurrentThread()
index dd10beb..68c1f6e 100644 (file)
@@ -262,9 +262,6 @@ public:
 #endif
     }
 
-    CrstBase *GetThreadsOwnedCrsts();
-    void SetThreadsOwnedCrsts(CrstBase *pCrst);
-
     NOINLINE EEThreadId GetHolderThreadId()
     {
         LIMITED_METHOD_CONTRACT;
index 2d54b54..f35def0 100644 (file)
@@ -279,8 +279,9 @@ public:
     virtual bool SweepThreadsForDebug(bool forceSync) = 0;
 
    virtual void GetRuntimeOffsets(SIZE_T *pTLSIndex,
-                                  SIZE_T *pTLSIsSpecialIndex,
-                                  SIZE_T *pTLSCantStopIndex,
+                                  SIZE_T *pTLSEEThreadOffset,
+                                  SIZE_T *pTLSIsSpecialOffset,
+                                  SIZE_T *pTLSCantStopOffset,
                                   SIZE_T *pEEThreadStateOffset,
                                   SIZE_T *pEEThreadStateNCOffset,
                                   SIZE_T *pEEThreadPGCDisabledOffset,
@@ -290,7 +291,6 @@ public:
                                   DWORD  *pEEThreadSteppingStateMask,
                                   DWORD  *pEEMaxFrameValue,
                                   SIZE_T *pEEThreadDebuggerFilterContextOffset,
-                                  SIZE_T *pEEThreadCantStopMask,
                                   SIZE_T *pEEFrameNextOffset,
                                   DWORD  *pEEIsManagedExceptionStateMask) = 0;
 
index ab77b18..ae268d4 100644 (file)
@@ -1314,11 +1314,10 @@ void EEDbgInterfaceImpl::DisableTraceCall(Thread *thread)
     thread->DecrementTraceCallCount();
 }
 
-EXTERN_C UINT32 _tls_index;
-
 void EEDbgInterfaceImpl::GetRuntimeOffsets(SIZE_T *pTLSIndex,
-                                           SIZE_T *pTLSIsSpecialIndex,
-                                           SIZE_T *pTLSCantStopIndex,
+                                           SIZE_T *pTLSEEThreadOffset,
+                                           SIZE_T *pTLSIsSpecialOffset,
+                                           SIZE_T *pTLSCantStopOffset,
                                            SIZE_T *pEEThreadStateOffset,
                                            SIZE_T *pEEThreadStateNCOffset,
                                            SIZE_T *pEEThreadPGCDisabledOffset,
@@ -1328,34 +1327,22 @@ void EEDbgInterfaceImpl::GetRuntimeOffsets(SIZE_T *pTLSIndex,
                                            DWORD  *pEEThreadSteppingStateMask,
                                            DWORD  *pEEMaxFrameValue,
                                            SIZE_T *pEEThreadDebuggerFilterContextOffset,
-                                           SIZE_T *pEEThreadCantStopOffset,
                                            SIZE_T *pEEFrameNextOffset,
                                            DWORD  *pEEIsManagedExceptionStateMask)
 {
-    CONTRACTL
-    {
-        NOTHROW;
-        GC_NOTRIGGER;
-        PRECONDITION(CheckPointer(pTLSIndex));
-        PRECONDITION(CheckPointer(pTLSIsSpecialIndex));
-        PRECONDITION(CheckPointer(pEEThreadStateOffset));
-        PRECONDITION(CheckPointer(pEEThreadStateNCOffset));
-        PRECONDITION(CheckPointer(pEEThreadPGCDisabledOffset));
-        PRECONDITION(CheckPointer(pEEThreadPGCDisabledValue));
-        PRECONDITION(CheckPointer(pEEThreadFrameOffset));
-        PRECONDITION(CheckPointer(pEEThreadMaxNeededSize));
-        PRECONDITION(CheckPointer(pEEThreadSteppingStateMask));
-        PRECONDITION(CheckPointer(pEEMaxFrameValue));
-        PRECONDITION(CheckPointer(pEEThreadDebuggerFilterContextOffset));
-        PRECONDITION(CheckPointer(pEEThreadCantStopOffset));
-        PRECONDITION(CheckPointer(pEEFrameNextOffset));
-        PRECONDITION(CheckPointer(pEEIsManagedExceptionStateMask));
-    }
-    CONTRACTL_END;
+    LIMITED_METHOD_CONTRACT;
 
-    *pTLSIndex = g_TlsIndex;
-    *pTLSIsSpecialIndex = TlsIdx_ThreadType;
-    *pTLSCantStopIndex = TlsIdx_CantStopCount;
+#ifdef TARGET_WINDOWS
+    *pTLSIndex = _tls_index;
+    *pTLSEEThreadOffset = Thread::GetOffsetOfThreadStatic(&gCurrentThreadInfo.m_pThread);
+    *pTLSIsSpecialOffset = Thread::GetOffsetOfThreadStatic(&t_ThreadType);
+    *pTLSCantStopOffset = Thread::GetOffsetOfThreadStatic(&t_CantStopCount);
+#else
+    *pTLSIndex = (SIZE_T)-1;
+    *pTLSEEThreadOffset = (SIZE_T)-1;
+    *pTLSIsSpecialOffset = (SIZE_T)-1;
+    *pTLSCantStopOffset = (SIZE_T)-1;
+#endif
     *pEEThreadStateOffset = Thread::GetOffsetOfState();
     *pEEThreadStateNCOffset = Thread::GetOffsetOfStateNC();
     *pEEThreadPGCDisabledOffset = Thread::GetOffsetOfGCFlag();
@@ -1363,7 +1350,6 @@ void EEDbgInterfaceImpl::GetRuntimeOffsets(SIZE_T *pTLSIndex,
     *pEEThreadFrameOffset = Thread::GetOffsetOfCurrentFrame();
     *pEEThreadMaxNeededSize = sizeof(Thread);
     *pEEThreadDebuggerFilterContextOffset = Thread::GetOffsetOfDebuggerFilterContext();
-    *pEEThreadCantStopOffset = Thread::GetOffsetOfCantStop();
     *pEEThreadSteppingStateMask = Thread::TSNC_DebuggerIsStepping;
     *pEEMaxFrameValue = (DWORD)(size_t)FRAME_TOP; // <TODO> should this be size_t for 64bit?</TODO>
     *pEEFrameNextOffset = Frame::GetOffsetOfNextLink();
index 036aeb9..40f5894 100644 (file)
@@ -271,8 +271,9 @@ public:
     void DisableTraceCall(Thread *thread);
 
     void GetRuntimeOffsets(SIZE_T *pTLSIndex,
-                           SIZE_T *pTLSIsSpecialIndex,
-                           SIZE_T *pTLSCantStopIndex,
+                           SIZE_T *pTLSEEThreadOffset,
+                           SIZE_T *pTLSIsSpecialOffset,
+                           SIZE_T *pTLSCantStopOffset,
                            SIZE_T *pEEThreadStateOffset,
                            SIZE_T *pEEThreadStateNCOffset,
                            SIZE_T *pEEThreadPGCDisabledOffset,
@@ -282,7 +283,6 @@ public:
                            DWORD  *pEEThreadSteppingStateMask,
                            DWORD  *pEEMaxFrameValue,
                            SIZE_T *pEEThreadDebuggerFilterContextOffset,
-                           SIZE_T *pEEThreadCantStopOffset,
                            SIZE_T *pEEFrameNextOffset,
                            DWORD  *pEEIsManagedExceptionStateMask);
 
index 35a39f3..ecec224 100644 (file)
@@ -8184,6 +8184,33 @@ VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFra
     RaiseTheExceptionInternalOnly(orThrowable, FALSE);
 }
 
+thread_local DWORD t_dwCurrentExceptionCode;
+thread_local PEXCEPTION_RECORD t_pCurrentExceptionRecord;
+thread_local PCONTEXT t_pCurrentExceptionContext;
+
+void GetCurrentExceptionPointers(PEXCEPTION_POINTERS pExceptionInfo DEBUG_ARG(bool checkExceptionRecordLocation))
+{
+    WRAPPER_NO_CONTRACT;
+
+    pExceptionInfo->ContextRecord = t_pCurrentExceptionContext;
+    pExceptionInfo->ExceptionRecord = t_pCurrentExceptionRecord;
+
+#ifdef _DEBUG
+    if (pExceptionInfo->ExceptionRecord != NULL && checkExceptionRecordLocation)
+    {
+        _ASSERTE((PVOID)(pExceptionInfo->ExceptionRecord) > (PVOID)(&checkExceptionRecordLocation));
+    }
+#endif
+}
+
+DWORD GetCurrentExceptionCode()
+{
+    WRAPPER_NO_CONTRACT;
+    SUPPORTS_DAC_HOST_ONLY;
+
+    return t_dwCurrentExceptionCode;
+}
+
 void SaveCurrentExceptionInfo(PEXCEPTION_RECORD pRecord, PCONTEXT pContext)
 {
     CONTRACTL
@@ -8202,51 +8229,47 @@ void SaveCurrentExceptionInfo(PEXCEPTION_RECORD pRecord, PCONTEXT pContext)
         return;
     }
 
-    if (CExecutionEngine::CheckThreadStateNoCreate(TlsIdx_PEXCEPTION_RECORD))
+    BOOL fSave = TRUE;
+    if (pRecord->ExceptionCode != STATUS_STACK_OVERFLOW)
     {
-        BOOL fSave = TRUE;
-        if (pRecord->ExceptionCode != STATUS_STACK_OVERFLOW)
+        DWORD dwLastExceptionCode = t_dwCurrentExceptionCode;
+        if (dwLastExceptionCode == STATUS_STACK_OVERFLOW)
         {
-            DWORD dwLastExceptionCode = (DWORD)(SIZE_T) (ClrFlsGetValue(TlsIdx_EXCEPTION_CODE));
-            if (dwLastExceptionCode == STATUS_STACK_OVERFLOW)
-            {
-                PEXCEPTION_RECORD lastRecord =
-                    static_cast<PEXCEPTION_RECORD> (ClrFlsGetValue(TlsIdx_PEXCEPTION_RECORD));
+            PEXCEPTION_RECORD lastRecord = t_pCurrentExceptionRecord;
 
-                // We are trying to see if C++ is attempting a rethrow of a SO exception. If so,
-                // we want to prevent updating the exception details in the TLS. This is a workaround,
-                // as explained below.
-                if (pRecord->ExceptionCode == EXCEPTION_MSVC)
+            // We are trying to see if C++ is attempting a rethrow of a SO exception. If so,
+            // we want to prevent updating the exception details in the TLS. This is a workaround,
+            // as explained below.
+            if (pRecord->ExceptionCode == EXCEPTION_MSVC)
+            {
+                // This is a workaround.
+                // When C++ rethrows, C++ internally gets rid of the new exception record after
+                // unwinding stack, and present the original exception record to the thread.
+                // When we get VC's support to obtain exception record in try/catch, we will replace
+                // this code.
+                if (pRecord < lastRecord)
                 {
-                    // This is a workaround.
-                    // When C++ rethrows, C++ internally gets rid of the new exception record after
-                    // unwinding stack, and present the original exception record to the thread.
-                    // When we get VC's support to obtain exception record in try/catch, we will replace
-                    // this code.
-                    if (pRecord < lastRecord)
+                    // For the C++ rethrow workaround, ensure that the last exception record is still valid and as we expect it to be.
+                    //
+                    // Its possible that we are still below the address of last exception record
+                    // but since the execution stack could have changed, simply comparing its address
+                    // with the address of the current exception record may not be enough.
+                    //
+                    // Thus, ensure that its still valid and holds the exception code we expect it to
+                    // have (i.e. value in dwLastExceptionCode).
+                    if ((lastRecord != NULL) && (lastRecord->ExceptionCode == dwLastExceptionCode))
                     {
-                        // For the C++ rethrow workaround, ensure that the last exception record is still valid and as we expect it to be.
-                        //
-                        // Its possible that we are still below the address of last exception record
-                        // but since the execution stack could have changed, simply comparing its address
-                        // with the address of the current exception record may not be enough.
-                        //
-                        // Thus, ensure that its still valid and holds the exception code we expect it to
-                        // have (i.e. value in dwLastExceptionCode).
-                        if ((lastRecord != NULL) && (lastRecord->ExceptionCode == dwLastExceptionCode))
-                        {
-                            fSave = FALSE;
-                        }
+                        fSave = FALSE;
                     }
                 }
             }
         }
-        if (fSave)
-        {
-            ClrFlsSetValue(TlsIdx_EXCEPTION_CODE, (void*)(size_t)(pRecord->ExceptionCode));
-            ClrFlsSetValue(TlsIdx_PEXCEPTION_RECORD, pRecord);
-            ClrFlsSetValue(TlsIdx_PCONTEXT, pContext);
-        }
+    }
+    if (fSave)
+    {
+        t_dwCurrentExceptionCode = pRecord->ExceptionCode;
+        t_pCurrentExceptionRecord = pRecord;
+        t_pCurrentExceptionContext = pContext;
     }
 }
 
index 6abcc2c..78db938 100644 (file)
@@ -226,7 +226,7 @@ LPVOID EEHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes)
             && GetExecutionEngine ()
            // If we have not created StressLog ring buffer, we should not try to use it.
            // StressLog is going to do a memory allocation.  We may enter an endless loop.
-           && ClrFlsGetValue(TlsIdx_StressLog) != NULL )
+           && StressLog::t_pCurrentThreadLog != NULL )
         {
             STRESS_LOG_OOM_STACK(dwBytes);
         }
@@ -572,66 +572,6 @@ DEBUG_NOINLINE void EELeaveCriticalSection(CRITSEC_COOKIE cookie)
     pCrst->Leave();
 }
 
-LPVOID EETlsGetValue(DWORD slot)
-{
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_MODE_ANY;
-    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
-
-    //
-    // @todo: we don't want TlsGetValue to throw, but CheckThreadState throws right now. Either modify
-    // CheckThreadState to not throw, or catch any exception and just return NULL.
-    //
-    //CONTRACT_VIOLATION(ThrowsViolation);
-    SCAN_IGNORE_THROW;
-
-    void **pTlsData = CExecutionEngine::CheckThreadState(slot, FALSE);
-
-    if (pTlsData)
-        return pTlsData[slot];
-    else
-        return NULL;
-}
-
-BOOL EETlsCheckValue(DWORD slot, LPVOID * pValue)
-{
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_NOTHROW;
-    STATIC_CONTRACT_MODE_ANY;
-
-    //
-    // @todo: we don't want TlsGetValue to throw, but CheckThreadState throws right now. Either modify
-    // CheckThreadState to not throw, or catch any exception and just return NULL.
-    //
-    //CONTRACT_VIOLATION(ThrowsViolation);
-    SCAN_IGNORE_THROW;
-
-    void **pTlsData = CExecutionEngine::CheckThreadState(slot, FALSE);
-
-    if (pTlsData)
-    {
-        *pValue = pTlsData[slot];
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-VOID EETlsSetValue(DWORD slot, LPVOID pData)
-{
-    STATIC_CONTRACT_GC_NOTRIGGER;
-    STATIC_CONTRACT_THROWS;
-    STATIC_CONTRACT_MODE_ANY;
-
-    void **pTlsData = CExecutionEngine::CheckThreadState(slot);
-
-    if (pTlsData)  // Yes, CheckThreadState(slot, TRUE) can return NULL now.
-    {
-        pTlsData[slot] = pData;
-    }
-}
-
 BOOL EEAllocationDisallowed()
 {
     WRAPPER_NO_CONTRACT;
index 769d634..b4e6fd8 100644 (file)
@@ -53,12 +53,5 @@ void EELeaveCriticalSection(CRITSEC_COOKIE cookie);
 
 DWORD EESleepEx(DWORD dwMilliseconds, BOOL bAlertable);
 
-// TLS functions
-LPVOID EETlsGetValue(DWORD slot);
-BOOL EETlsCheckValue(DWORD slot, LPVOID * pValue);
-VOID EETlsSetValue(DWORD slot, LPVOID pData);
-
-
-
 #endif
 
index 3e9180c..eac75f6 100644 (file)
@@ -2445,9 +2445,9 @@ VOID StubLinkerCPU::X86EmitCurrentThreadFetch(X86Reg dstreg, unsigned preservedR
     EmitBytes(code, sizeof(code));
     Emit32(offsetof(TEB, ThreadLocalStoragePointer));
 
-    X86EmitIndexRegLoad(dstreg, dstreg, sizeof(void *) * (g_TlsIndex & 0xFFFF));
+    X86EmitIndexRegLoad(dstreg, dstreg, sizeof(void *) * _tls_index);
 
-    X86EmitIndexRegLoad(dstreg, dstreg, (g_TlsIndex & 0x7FFF0000) >> 16);
+    X86EmitIndexRegLoad(dstreg, dstreg, (int)Thread::GetOffsetOfThreadStatic(&gCurrentThreadInfo));
 
 #endif // TARGET_UNIX
 }
index 39e1e7d..ee5b6b5 100644 (file)
@@ -1338,7 +1338,7 @@ ReturnKind MethodDesc::GetReturnKind(INDEBUG(bool supportStringConstructors))
     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
     // Mark that we are performing a stackwalker like operation on the current thread.
     // This is necessary to allow the signature parsing functions to work without triggering any loads
-    ClrFlsValueSwitch threadStackWalking(TlsIdx_StackWalkerWalkingThread, GetThread());
+    StackWalkerWalkingThreadHolder threadStackWalking(GetThread());
 
 #ifdef TARGET_X86
     MetaSig msig(this);
index e8ce53d..cbdae62 100644 (file)
@@ -7741,7 +7741,7 @@ HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
 
     // Remember that we're walking the stack.  This holder will reinstate the original
     // value of the stackwalker flag (from the thread type mask) in its destructor.
-    ClrFlsValueSwitch _threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThreadToSnapshot);
+    StackWalkerWalkingThreadHolder threadStackWalking(pThreadToSnapshot);
 
     // This flag remembers if we reported a managed frame since the last unmanaged block
     // we reported. It's used to avoid reporting two unmanaged blocks in a row.
@@ -9870,18 +9870,9 @@ HRESULT ProfToEEInterfaceImpl::InitializeCurrentThread()
             LL_INFO10,
             "**PROF: InitializeCurrentThread.\n"));
 
-    HRESULT hr = S_OK;
-
-    EX_TRY
-    {
-        CExecutionEngine::SetupTLSForThread(GetThread());
-    }
-    EX_CATCH_HRESULT(hr);
+    SetupTLSForThread(GetThread());
 
-    if (FAILED(hr))
-        return hr;
-
-     return S_OK;
+    return S_OK;
 }
 
 struct InternalProfilerModuleEnum : public ProfilerModuleEnum
index d12211e..04a5db3 100644 (file)
@@ -898,14 +898,14 @@ StackWalkAction Thread::StackWalkFramesEx(
     {
         // SCOPE: Remember that we're walking the stack.
         //
-        // Normally, we'd use a holder (ClrFlsThreadTypeSwitch) to temporarily set this
+        // Normally, we'd use a StackWalkerWalkingThreadHolder to temporarily set this
         // flag in the thread state, but we can't in this function, since C++ destructors
         // are forbidden when this is called for exception handling (which causes
         // MakeStackwalkerCallback() not to return). Note that in exception handling
         // cases, we will have already cleared the stack walker thread state indicator inside
         // MakeStackwalkerCallback(), so we will be properly cleaned up.
 #if !defined(DACCESS_COMPILE)
-        PVOID pStackWalkThreadOrig = ClrFlsGetValue(TlsIdx_StackWalkerWalkingThread);
+        Thread* pStackWalkThreadOrig = t_pStackWalkerWalkingThread;
 #endif
         SET_THREAD_TYPE_STACKWALKER(this);
 
@@ -1141,13 +1141,6 @@ BOOL StackFrameIterator::Init(Thread *    pThread,
     _ASSERTE(pThread  != NULL);
     _ASSERTE(pRegDisp != NULL);
 
-#if !defined(DACCESS_COMPILE)
-    // When the LIGHTUNWIND flag is set, we use the stack walk cache.
-    // On x64, accesses to the stack walk cache are synchronized by
-    // a CrstStatic, which may need to call back into the host.
-    _ASSERTE(CanThisThreadCallIntoHost() || (flags & LIGHTUNWIND) == 0);
-#endif // DACCESS_COMPILE
-
 #ifdef FEATURE_EH_FUNCLETS
     _ASSERTE(!(flags & POPFRAMES));
     _ASSERTE(pRegDisp->pCurrentContext);
index 9c66cd9..877b9c5 100644 (file)
 #include "eventpipebuffermanager.h"
 #endif // FEATURE_PERFTRACING
 
+#if defined (_DEBUG_IMPL) || defined(_PREFAST_)
+thread_local int t_ForbidGCLoaderUseCount;
+#endif
+
 uint64_t Thread::dead_threads_non_alloc_bytes = 0;
 
 SPTR_IMPL(ThreadStore, ThreadStore, s_pThreadStore);
@@ -88,6 +92,20 @@ UINT64 Thread::s_monitorLockContentionCountOverflow = 0;
 
 CrstStatic g_DeadlockAwareCrst;
 
+//
+// A transient thread value that indicates this thread is currently walking its stack
+// or the stack of another thread. This value is useful to help short-circuit
+// some problematic checks in the loader, guarantee that types & assemblies
+// encountered during the walk must already be loaded, and provide information to control
+// assembly loading behavior during stack walks.
+//
+// This value is set around the main portions of the stack walk (as those portions may
+// enter the type & assembly loaders). This is also explicitly cleared while the
+// walking thread calls the stackwalker callback or needs to execute managed code, as
+// such calls may execute arbitrary code unrelated to the actual stack walking, and
+// may never return, in the case of exception stackwalk callbacks.
+//
+thread_local Thread* t_pStackWalkerWalkingThread;
 
 #if defined(_DEBUG)
 BOOL MatchThreadHandleToOsId ( HANDLE h, DWORD osId )
@@ -298,29 +316,20 @@ bool Thread::DetectHandleILStubsForDebugger()
 __thread ThreadLocalInfo gCurrentThreadInfo;
 #endif
 
-// index into TLS Array. Definition added by compiler
-EXTERN_C UINT32 _tls_index;
-
-#ifndef HOST_WINDOWS
-UINT32 _tls_index;
-#endif
-
 #ifndef DACCESS_COMPILE
 
-BOOL SetThread(Thread* t)
+void SetThread(Thread* t)
 {
     LIMITED_METHOD_CONTRACT
 
     gCurrentThreadInfo.m_pThread = t;
-    return TRUE;
 }
 
-BOOL SetAppDomain(AppDomain* ad)
+void SetAppDomain(AppDomain* ad)
 {
     LIMITED_METHOD_CONTRACT
 
     gCurrentThreadInfo.m_pAppDomain = ad;
-    return TRUE;
 }
 
 BOOL Thread::Alert ()
@@ -703,7 +712,7 @@ Thread* SetupThread(BOOL fInternal)
 
     Holder<Thread*,DoNothing<Thread*>,DeleteThread> threadHolder(pThread);
 
-    CExecutionEngine::SetupTLSForThread(pThread);
+    SetupTLSForThread(pThread);
 
     // A host can deny a thread entering runtime by returning a NULL IHostTask.
     // But we do want threads used by threadpool.
@@ -725,10 +734,8 @@ Thread* SetupThread(BOOL fInternal)
 
     ThreadStore::AddThread(pThread);
 
-    BOOL fOK = SetThread(pThread);
-    _ASSERTE (fOK);
-    fOK = SetAppDomain(pThread->GetDomain());
-    _ASSERTE (fOK);
+    SetThread(pThread);
+    SetAppDomain(pThread->GetDomain());
 
 #ifdef FEATURE_INTEROP_DEBUGGING
     // Ensure that debugger word slot is allocated
@@ -986,7 +993,11 @@ DWORD GetRuntimeId()
 {
     LIMITED_METHOD_CONTRACT;
 
+#ifdef HOST_WINDOWS
     return _tls_index;
+#else
+    return 0;
+#endif
 }
 
 //---------------------------------------------------------------------------
@@ -1051,6 +1062,16 @@ PCODE AdjustWriteBarrierIP(PCODE controlPc)
 
 extern "C" void *JIT_WriteBarrier_Loc;
 
+#ifndef TARGET_UNIX
+// g_TlsIndex is only used by the DAC. Disable optimizations around it to prevent it from getting optimized out.
+#pragma optimize("", off)
+static void SetIlsIndex(DWORD tlsIndex)
+{
+    g_TlsIndex = tlsIndex;
+}
+#pragma optimize("", on)
+#endif
+
 //---------------------------------------------------------------------------
 // One-time initialization. Called during Dll initialization. So
 // be careful what you do in here!
@@ -1104,17 +1125,13 @@ void InitThreadManager()
 #ifndef TARGET_UNIX
     _ASSERTE(GetThread() == NULL);
 
-    PTEB Teb = NtCurrentTeb();
-    BYTE** tlsArray = (BYTE**)Teb->ThreadLocalStoragePointer;
-    BYTE* tlsData = (BYTE*)tlsArray[_tls_index];
-
-    size_t offsetOfCurrentThreadInfo = (BYTE*)&gCurrentThreadInfo - tlsData;
+    size_t offsetOfCurrentThreadInfo = Thread::GetOffsetOfThreadStatic(&gCurrentThreadInfo);
 
     _ASSERTE(offsetOfCurrentThreadInfo < 0x8000);
     _ASSERTE(_tls_index < 0x10000);
 
     // Save gCurrentThreadInfo location for debugger
-    g_TlsIndex = (DWORD)(_tls_index + (offsetOfCurrentThreadInfo << 16) + 0x80000000);
+    SetIlsIndex((DWORD)(_tls_index + (offsetOfCurrentThreadInfo << 16) + 0x80000000));
 
     _ASSERTE(g_TrapReturningThreads == 0);
 #endif // !TARGET_UNIX
@@ -1125,8 +1142,6 @@ void InitThreadManager()
         COMPlusThrowWin32();
 #endif
 
-    __ClrFlsGetBlock = CExecutionEngine::GetTlsData;
-
     IfFailThrow(Thread::CLRSetThreadStackGuarantee(Thread::STSGuarantee_Force));
 
     ThreadStore::InitThreadStore();
@@ -1352,7 +1367,6 @@ Thread::Thread()
     m_ltoIsUnhandled = FALSE;
 
     m_debuggerFilterContext = NULL;
-    m_debuggerCantStop = 0;
     m_fInteropDebuggingHijacked = FALSE;
     m_profilerCallbackState = 0;
 #if defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA)
@@ -1750,7 +1764,8 @@ BOOL Thread::HasStarted(BOOL bRequiresTSL)
         //
         // Initialization must happen in the following order - hosts like SQL Server depend on this.
         //
-        CExecutionEngine::SetupTLSForThread(this);
+
+        SetupTLSForThread(this);
 
         fCanCleanupCOMState = TRUE;
         res = PrepareApartmentAndContext();
@@ -1761,15 +1776,8 @@ BOOL Thread::HasStarted(BOOL bRequiresTSL)
 
         InitThread(FALSE);
 
-        if (SetThread(this) == FALSE)
-        {
-            ThrowOutOfMemory();
-        }
-
-        if (SetAppDomain(m_pDomain) == FALSE)
-        {
-            ThrowOutOfMemory();
-        }
+        SetThread(this);
+        SetAppDomain(m_pDomain);
 
         ThreadStore::TransferStartedThread(this, bRequiresTSL);
 
@@ -1813,10 +1821,8 @@ FAILURE:
             {
                 // The thread pointer in TLS may not be set yet, if we had a failure before we set it.
                 // So we'll set it up here (we'll unset it a few lines down).
-                if (SetThread(this) != FALSE)
-                {
-                    CleanupCOMState();
-                }
+                SetThread(this);
+                CleanupCOMState();
             }
 #endif
             FastInterlockDecrement(&ThreadStore::s_pThreadStore->m_PendingThreadCount);
@@ -7130,34 +7136,6 @@ T_CONTEXT *Thread::GetFilterContext(void)
 
 #ifndef DACCESS_COMPILE
 
-// @todo - eventually complete remove the CantStop count on the thread and use
-// the one in the PreDef block. For now, we increment both our thread counter,
-// and the FLS counter. Eventually we can remove our thread counter and only use
-// the FLS counter.
-void Thread::SetDebugCantStop(bool fCantStop)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    if (fCantStop)
-    {
-        IncCantStopCount();
-        m_debuggerCantStop++;
-    }
-    else
-    {
-        DecCantStopCount();
-        m_debuggerCantStop--;
-    }
-}
-
-// @todo - remove this, we only read this from oop.
-bool Thread::GetDebugCantStop(void)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    return m_debuggerCantStop != 0;
-}
-
 void Thread::InitContext()
 {
     CONTRACTL {
index a830887..94ca1c8 100644 (file)
@@ -950,12 +950,12 @@ typedef DWORD (*AppropriateWaitFunc) (void *args, DWORD timeout, DWORD option);
 // of that physical thread.
 
 // FEATURE_MULTIREG_RETURN is set for platforms where a struct return value
-// [GcInfo v2 only]        can be returned in multiple registers
+//                         can be returned in multiple registers
 //                         ex: Windows/Unix ARM/ARM64, Unix-AMD64.
 //
 //
 // UNIX_AMD64_ABI is a specific kind of FEATURE_MULTIREG_RETURN
-// [GcInfo v1 and v2]       specified by SystemV ABI for AMD64
+//                         specified by SystemV ABI for AMD64
 //
 
 #ifdef FEATURE_HIJACK                                                    // Hijack function returning
@@ -1020,7 +1020,7 @@ class Thread
     friend class DacDbiInterfaceImpl;       // DacDbiInterfaceImpl::GetThreadHandle(HANDLE * phThread);
 #endif // DACCESS_COMPILE
     friend class ProfToEEInterfaceImpl;     // HRESULT ProfToEEInterfaceImpl::GetHandleFromThread(ThreadID threadId, HANDLE *phThread);
-    friend class CExecutionEngine;
+    friend void SetupTLSForThread(Thread* pThread);
     friend class UnC;
     friend class CheckAsmOffsets;
 
@@ -2121,6 +2121,11 @@ public:
 #endif // ENABLE_CONTRACTS_IMPL
 
     //---------------------------------------------------------------
+    // Calculate thread static offset
+    //---------------------------------------------------------------
+    static size_t GetOffsetOfThreadStatic(void* pThreadStatic);
+
+    //---------------------------------------------------------------
     // Expose key offsets and values for stub generation.
     //---------------------------------------------------------------
     static BYTE GetOffsetOfCurrentFrame()
@@ -2147,30 +2152,6 @@ public:
         return (BYTE)ofs;
     }
 
-    static void StaticDisablePreemptiveGC( Thread *pThread)
-    {
-        WRAPPER_NO_CONTRACT;
-        _ASSERTE(pThread != NULL);
-        pThread->DisablePreemptiveGC();
-    }
-
-    static void StaticEnablePreemptiveGC( Thread *pThread)
-    {
-        WRAPPER_NO_CONTRACT;
-        _ASSERTE(pThread != NULL);
-        pThread->EnablePreemptiveGC();
-    }
-
-
-    //---------------------------------------------------------------
-    // Expose offset of the app domain word for the interop and delegate callback
-    //---------------------------------------------------------------
-    static SIZE_T GetOffsetOfAppDomain()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return (SIZE_T)(offsetof(class Thread, m_pDomain));
-    }
-
     //---------------------------------------------------------------
     // Expose offset of the place for storing the filter context for the debugger.
     //---------------------------------------------------------------
@@ -2181,15 +2162,6 @@ public:
     }
 
     //---------------------------------------------------------------
-    // Expose offset of the debugger cant stop count for the debugger
-    //---------------------------------------------------------------
-    static SIZE_T GetOffsetOfCantStop()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return (SIZE_T)(offsetof(class Thread, m_debuggerCantStop));
-    }
-
-    //---------------------------------------------------------------
     // Expose offset of m_StateNC
     //---------------------------------------------------------------
     static SIZE_T GetOffsetOfStateNC()
@@ -3709,11 +3681,6 @@ private:
     // return addresses on the stack)
     //---------------------------------------------------------------
     Volatile<LONG> m_hijackLock;
-    //---------------------------------------------------------------
-    // m_debuggerCantStop holds a count of entries into "can't stop"
-    // areas that the Interop Debugging Services must know about.
-    //---------------------------------------------------------------
-    DWORD m_debuggerCantStop;
 
     //---------------------------------------------------------------
     // The current custom notification data object (or NULL if none
@@ -3977,9 +3944,6 @@ public:
         ResetThreadState(TS_GCSuspendPending);
     }
 
-    void SetDebugCantStop(bool fCantStop);
-    bool GetDebugCantStop(void);
-
     static LPVOID GetStaticFieldAddress(FieldDesc *pFD);
     TADDR GetStaticFieldAddrNoCreate(FieldDesc *pFD);
 
@@ -4585,7 +4549,7 @@ public:
 #endif // FEATURE_COMINTEROP
 
 private:
-    // This duplicates the ThreadType_GC bit stored in TLS (TlsIdx_ThreadType). It exists
+    // This duplicates the ThreadType_GC bit stored in TLS (t_ThreadType). It exists
     // so that any thread can query whether any other thread is a "GC Special" thread.
     // (In contrast, ::IsGCSpecialThread() only gives this info about the currently
     // executing thread.) The Profiling API uses this to determine whether it should
@@ -6126,6 +6090,9 @@ if (g_pConfig->GetGCStressLevel() && g_pConfig->FastGCStressLevel() > 1) {   \
 #endif  // _DEBUG
 
 #ifdef _DEBUG_IMPL
+
+extern thread_local int t_ForbidGCLoaderUseCount;
+
 // Holder for incrementing the ForbidGCLoaderUse counter.
 class GCForbidLoaderUseHolder
 {
@@ -6133,13 +6100,13 @@ class GCForbidLoaderUseHolder
     GCForbidLoaderUseHolder()
     {
         WRAPPER_NO_CONTRACT;
-        ClrFlsIncrementValue(TlsIdx_ForbidGCLoaderUseCount, 1);
+        t_ForbidGCLoaderUseCount++;
     }
 
     ~GCForbidLoaderUseHolder()
     {
         WRAPPER_NO_CONTRACT;
-        ClrFlsIncrementValue(TlsIdx_ForbidGCLoaderUseCount, -1);
+        t_ForbidGCLoaderUseCount--;
     }
 };
 
@@ -6204,12 +6171,8 @@ class GCForbidLoaderUseHolder
 #define FORBIDGC_LOADER_USE_ENABLED() true
 
 #else // DACCESS_COMPILE
-#if defined (_DEBUG_IMPL) || defined(_PREFAST_)
-#ifndef DACCESS_COMPILE
-#define FORBIDGC_LOADER_USE_ENABLED() (ClrFlsGetValue(TlsIdx_ForbidGCLoaderUseCount))
-#else
-#define FORBIDGC_LOADER_USE_ENABLED() TRUE
-#endif
+#ifdef _DEBUG_IMPL
+#define FORBIDGC_LOADER_USE_ENABLED() (t_ForbidGCLoaderUseCount)
 #else   // _DEBUG_IMPL
 
 // If you got an error about FORBIDGC_LOADER_USE_ENABLED being undefined, it's because you tried
@@ -6436,4 +6399,50 @@ PCODE AdjustWriteBarrierIP(PCODE controlPc);
 
 #endif // FEATURE_WRITEBARRIER_COPY
 
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+extern thread_local Thread* t_pStackWalkerWalkingThread;
+#define SET_THREAD_TYPE_STACKWALKER(pThread)    t_pStackWalkerWalkingThread = pThread
+#define CLEAR_THREAD_TYPE_STACKWALKER()         t_pStackWalkerWalkingThread = NULL
+#else
+#define SET_THREAD_TYPE_STACKWALKER(pThread)
+#define CLEAR_THREAD_TYPE_STACKWALKER()
+#endif
+
+inline BOOL IsStackWalkerThread()
+{
+    LIMITED_METHOD_CONTRACT;
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+    return t_pStackWalkerWalkingThread != NULL;
+#else
+    return FALSE;
+#endif
+}
+
+class StackWalkerWalkingThreadHolder
+{
+public:
+    StackWalkerWalkingThreadHolder(Thread* value)
+    {
+        LIMITED_METHOD_CONTRACT;
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+        m_PreviousValue = t_pStackWalkerWalkingThread;
+        t_pStackWalkerWalkingThread = value;
+#endif
+    }
+
+    ~StackWalkerWalkingThreadHolder()
+    {
+        LIMITED_METHOD_CONTRACT;
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+        t_pStackWalkerWalkingThread = m_PreviousValue;
+#endif
+    }
+
+private:
+    Thread* m_PreviousValue;
+};
+
 #endif //__threads_h__
index 530e439..6d69469 100644 (file)
 
 #ifndef DACCESS_COMPILE
 
+#ifdef HOST_WINDOWS
+EXTERN_C UINT32 _tls_index;
+#endif
+
 #ifdef _MSC_VER
 __declspec(selectany) __declspec(thread) ThreadLocalInfo gCurrentThreadInfo;
 #else
@@ -192,6 +196,19 @@ inline Thread::CurrentPrepareCodeConfigHolder::~CurrentPrepareCodeConfigHolder()
     config->SetNextInSameThread(nullptr);
 }
 
+#ifdef HOST_WINDOWS
+inline size_t Thread::GetOffsetOfThreadStatic(void* pThreadStatic)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    PTEB Teb = NtCurrentTeb();
+    BYTE** tlsArray = (BYTE**)Teb->ThreadLocalStoragePointer;
+    BYTE* tlsData = (BYTE*)tlsArray[_tls_index];
+
+    return (BYTE*)pThreadStatic - tlsData;
+}
+#endif
+
 #endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
 
 #endif
index ba4ced4..ec307e9 100644 (file)
@@ -526,18 +526,13 @@ static inline BOOL CheckSuspended(Thread *pThread)
     _ASSERTE(CheckPointer(pThread));
 
 #ifndef DISABLE_THREADSUSPEND
-    // Only perform this test if we're allowed to call back into the host.
-    // Thread::SuspendThread contains several potential calls into the host.
-    if (CanThisThreadCallIntoHost())
+    DWORD dwSuspendCount;
+    Thread::SuspendThreadResult str = pThread->SuspendThread(FALSE, &dwSuspendCount);
+    forceStackA = &dwSuspendCount;
+    if (str == Thread::STR_Success)
     {
-        DWORD dwSuspendCount;
-        Thread::SuspendThreadResult str = pThread->SuspendThread(FALSE, &dwSuspendCount);
-        forceStackA = &dwSuspendCount;
-        if (str == Thread::STR_Success)
-        {
-            pThread->ResumeThread();
-            return dwSuspendCount >= 1;
-        }
+        pThread->ResumeThread();
+        return dwSuspendCount >= 1;
     }
 #endif // !DISABLE_THREADSUSPEND
     return TRUE;
@@ -2255,7 +2250,7 @@ void ThreadSuspend::LockThreadStore(ThreadSuspend::SUSPEND_REASON reason)
         // we're doing managed/unmanaged debugging. Calling SetDebugCantStop(true) on the current thread helps us
         // remember that.
         if (pCurThread)
-            pCurThread->SetDebugCantStop(true);
+            IncCantStopCount();
 
         // This is used to avoid thread starvation if non-GC threads are competing for
         // the thread store lock when there is a real GC-thread waiting to get in.
@@ -2340,7 +2335,7 @@ void ThreadSuspend::UnlockThreadStore(BOOL bThreadDestroyed, ThreadSuspend::SUSP
 
         // We're out of the critical area for managed/unmanaged debugging.
         if (!bThreadDestroyed && pCurThread)
-            pCurThread->SetDebugCantStop(false);
+            DecCantStopCount();
     }
 #ifdef _DEBUG
     else
@@ -6652,7 +6647,7 @@ void HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext)
 
         // Mark that we are performing a stackwalker like operation on the current thread.
         // This is necessary to allow the signature parsing functions to work without triggering any loads.
-        ClrFlsValueSwitch threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThread);
+        StackWalkerWalkingThreadHolder threadStackWalking(pThread);
 
         // Hijack the return address to point to the appropriate routine based on the method's return type.
         void *pvHijackAddr = GetHijackAddr(pThread, &codeInfo);
index dd38578..3a05a9d 100644 (file)
 
 #ifndef DACCESS_COMPILE
 
+#ifdef CROSSGEN_COMPILE
+void ClrFlsSetThreadType(TlsThreadTypeFlag flag)
+{
+}
+
+void ClrFlsClearThreadType(TlsThreadTypeFlag flag)
+{
+}
+#else // CROSSGEN_COMPILE
+
+thread_local size_t t_ThreadType;
+
+void ClrFlsSetThreadType(TlsThreadTypeFlag flag)
+{
+    LIMITED_METHOD_CONTRACT;
+
+    t_ThreadType |= flag;
+
+    // The historic location of ThreadType slot kept for compatibility with SOS
+    // TODO: Introduce DAC API to make this hack unnecessary
+#if defined(_MSC_VER) && defined(HOST_X86)
+    // Workaround for https://developercommunity.visualstudio.com/content/problem/949233/tls-relative-fixup-overflow-tls-section-is-too-lar.html
+    gCurrentThreadInfo.m_EETlsData = (void**)(((size_t)&t_ThreadType ^ 1) - (4 * TlsIdx_ThreadType + 1));
+#else
+    gCurrentThreadInfo.m_EETlsData = (void**)&t_ThreadType - TlsIdx_ThreadType;
+#endif
+}
+
+void ClrFlsClearThreadType(TlsThreadTypeFlag flag)
+{
+    LIMITED_METHOD_CONTRACT;
+    t_ThreadType &= ~flag;
+}
+#endif // CROSSGEN_COMPILE
+
+thread_local size_t t_CantStopCount;
+
 // Helper function that encapsulates the parsing rules.
 //
 // Called first with *pdstout == NULL to figure out how many args there are
index 606180a..692b9d5 100644 (file)
@@ -652,39 +652,18 @@ FORCEINLINE void VoidFreeNativeLibrary(NATIVE_LIBRARY_HANDLE h)
 
 typedef Wrapper<NATIVE_LIBRARY_HANDLE, DoNothing<NATIVE_LIBRARY_HANDLE>, VoidFreeNativeLibrary, NULL> NativeLibraryHandleHolder;
 
-#ifndef TARGET_UNIX
-
-// A holder for memory blocks allocated by Windows.  This holder (and any OS APIs you call
-// that allocate objects on your behalf) should not be used when the CLR is memory-hosted.
-
-FORCEINLINE void VoidFreeWinAllocatedBlock(LPVOID pv)
-{
-    LIMITED_METHOD_CONTRACT;
-
-#pragma push_macro("GetProcessHeap")
-#pragma push_macro("HeapFree")
-#undef GetProcessHeap
-#undef HeapFree
-    // 0: no special flags
-    ::HeapFree(::GetProcessHeap(), 0, pv);
-#pragma pop_macro("HeapFree")
-#pragma pop_macro("GetProcessHeap")
-}
-
-typedef Wrapper<LPVOID, DoNothing<LPVOID>, VoidFreeWinAllocatedBlock, NULL> WinAllocatedBlockHolder;
-
-#endif // !TARGET_UNIX
+extern thread_local size_t t_CantStopCount;
 
 // For debugging, we can track arbitrary Can't-Stop regions.
 // In V1.0, this was on the Thread object, but we need to track this for threads w/o a Thread object.
 FORCEINLINE void IncCantStopCount()
 {
-    ClrFlsIncrementValue(TlsIdx_CantStopCount, 1);
+    t_CantStopCount++;
 }
 
 FORCEINLINE void DecCantStopCount()
 {
-    ClrFlsIncrementValue(TlsIdx_CantStopCount, -1);
+    t_CantStopCount--;
 }
 
 typedef StateHolder<IncCantStopCount, DecCantStopCount> CantStopHolder;
@@ -692,9 +671,9 @@ typedef StateHolder<IncCantStopCount, DecCantStopCount> CantStopHolder;
 #ifdef _DEBUG
 // For debug-only, this can be used w/ a holder to ensure that we're keeping our CS count balanced.
 // We should never use this w/ control flow.
-inline int GetCantStopCount()
+inline size_t GetCantStopCount()
 {
-    return (int) (size_t) ClrFlsGetValue(TlsIdx_CantStopCount);
+    return t_CantStopCount;
 }
 
 // At places where we know we're calling out to native code, we can assert that we're NOT in a CS region.
@@ -952,4 +931,3 @@ HRESULT GetFileVersion(LPCWSTR wszFilePath, ULARGE_INTEGER* pFileVersion);
 #endif // !TARGET_UNIX
 
 #endif /* _H_UTIL */
-