Cleanup current culture handling in the unmanaged runtime (#21706)
authorJan Kotas <jkotas@microsoft.com>
Thu, 3 Jan 2019 13:52:30 +0000 (03:52 -1000)
committerGitHub <noreply@github.com>
Thu, 3 Jan 2019 13:52:30 +0000 (03:52 -1000)
Large portion of the current culture handling in the unmanaged runtime inherited from desktop has been no-op. The nativeInitCultureAccessors QCall that it used to depend on desktop got (almost) never called in CoreCLR.

- Delete resetting of current culture on threadpool threads. It was needed in desktop because of a very tricky flow of current culture between appdomains. It is superseded by the flowing the current culture via AsyncLocal in CoreCLR.
- Comment out fetch of managed current culture for unmanaged resource lookup. It has number of problems that are not easy to fix. We are not localizing the unmanaged runtime currently anyway, so it is ok to just comment it out.
- Fix the rest to call CultureInfo directly without going through Thread.CurrentThread

15 files changed:
src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Unix.cs
src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs
src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs
src/System.Private.CoreLib/src/System/Threading/Thread.cs
src/vm/ceemain.cpp
src/vm/comsynchronizable.cpp
src/vm/comsynchronizable.h
src/vm/dispatchinfo.cpp
src/vm/dllimport.cpp
src/vm/ecalllist.h
src/vm/metasig.h
src/vm/mscorlib.h
src/vm/object.h
src/vm/threads.cpp
src/vm/threads.h

index aa8586a..0b897c8 100644 (file)
@@ -15,8 +15,7 @@ namespace System.Globalization
             string localeName;
             if (CultureData.GetDefaultLocaleName(out localeName))
             {
-                cultureInfo = GetCultureByName(localeName, true);
-                cultureInfo._isReadOnly = true;
+                cultureInfo = GetCultureByName(localeName);
             }
             else
             {
index 19dd63d..f662788 100644 (file)
@@ -40,11 +40,7 @@ namespace System.Globalization
                 }
             }
 
-            CultureInfo temp = GetCultureByName(strDefault, true);
-
-            temp._isReadOnly = true;
-
-            return temp;
+            return GetCultureByName(strDefault);
         }
 
         private static CultureInfo GetUserDefaultUICulture()
@@ -68,9 +64,7 @@ namespace System.Globalization
                         index++;
                     }
 
-                    CultureInfo temp = GetCultureByName(new string(languages, 0, index), true);
-                    temp._isReadOnly = true;
-                    return temp;
+                    return GetCultureByName(new string(languages, 0, index));
                 }
             }
 #endif
index 4247c75..f3f56dd 100644 (file)
@@ -113,19 +113,19 @@ namespace System.Globalization
         private static volatile CultureInfo s_DefaultThreadCurrentCulture;
 
         [ThreadStatic]
-        internal static CultureInfo s_currentThreadCulture;
+        private static CultureInfo s_currentThreadCulture;
         [ThreadStatic]
-        internal static CultureInfo s_currentThreadUICulture;
+        private static CultureInfo s_currentThreadUICulture;
 
-        internal static AsyncLocal<CultureInfo> s_asyncLocalCurrentCulture; 
-        internal static AsyncLocal<CultureInfo> s_asyncLocalCurrentUICulture;
+        private static AsyncLocal<CultureInfo> s_asyncLocalCurrentCulture;
+        private static AsyncLocal<CultureInfo> s_asyncLocalCurrentUICulture;
 
-        internal static void AsyncLocalSetCurrentCulture(AsyncLocalValueChangedArgs<CultureInfo> args)
+        private static void AsyncLocalSetCurrentCulture(AsyncLocalValueChangedArgs<CultureInfo> args)
         {
             s_currentThreadCulture = args.CurrentValue;
         }
 
-        internal static void AsyncLocalSetCurrentUICulture(AsyncLocalValueChangedArgs<CultureInfo> args)
+        private static void AsyncLocalSetCurrentUICulture(AsyncLocalValueChangedArgs<CultureInfo> args)
         {
             s_currentThreadUICulture = args.CurrentValue;
         }
@@ -269,15 +269,14 @@ namespace System.Globalization
         // We do this to try to return the system UI language and the default user languages
         // This method will fallback if this fails (like Invariant)
         //
-        // TODO: It would appear that this is only ever called with userOveride = true
-        // and this method only has one caller.  Can we fold it into the caller?
-        private static CultureInfo GetCultureByName(string name, bool userOverride)
+        private static CultureInfo GetCultureByName(string name)
         {
             CultureInfo ci = null;
             // Try to get our culture
             try
             {
-                ci = userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
+                ci = new CultureInfo(name);
+                ci._isReadOnly = true;
             }
             catch (ArgumentException)
             {
@@ -544,12 +543,6 @@ namespace System.Globalization
             }
         }
 
-        internal static void ResetThreadCulture()
-        {
-            s_currentThreadCulture = null;
-            s_currentThreadUICulture = null;
-        }
-
         internal static CultureInfo UserDefaultUICulture => s_userDefaultUICulture ?? InitializeUserDefaultUICulture();
 
         public static CultureInfo InstalledUICulture => s_userDefaultCulture ?? InitializeUserDefaultCulture();
index bfe85af..241b279 100644 (file)
@@ -369,95 +369,6 @@ namespace System.Threading
         private extern void StartupSetApartmentStateInternal();
 #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
 
-        // #threadCultureInfo
-        //
-        // Background:
-        // In the desktop runtime, we allow a thread's cultures to travel with the thread
-        // across AppDomain boundaries. Furthermore we update the native thread with the
-        // culture of the managed thread. Because of security concerns and potential SxS
-        // effects, in Silverlight we are making the changes listed below. 
-        // 
-        // Silverlight Changes:
-        // - thread instance member cultures (CurrentCulture and CurrentUICulture) 
-        //   confined within AppDomains
-        // - changes to these properties don't affect the underlying native thread
-        // 
-        // Implementation notes:
-        // In Silverlight, culture members thread static (per Thread, per AppDomain). 
-        //
-        // Quirks:
-        // An interesting side-effect of isolating cultures within an AppDomain is that we
-        // now need to special case resource lookup for mscorlib, which transitions to the 
-        // default domain to lookup resources. See Environment.cs for more details.
-        // 
-
-        // As the culture can be customized object then we cannot hold any 
-        // reference to it before we check if it is safe because the app domain 
-        // owning this customized culture may get unloaded while executing this 
-        // code. To achieve that we have to do the check using nativeGetSafeCulture 
-        // as the thread cannot get interrupted during the FCALL. 
-        // If the culture is safe (not customized or created in current app domain) 
-        // then the FCALL will return a reference to that culture otherwise the 
-        // FCALL will return failure. In case of failure we'll return the default culture.
-        // If the app domain owning a customized culture that is set to the thread and this
-        // app domain get unloaded there is a code to clean up the culture from the thread
-        // using the code in AppDomain::ReleaseDomainStores.
-
-        public CultureInfo CurrentUICulture
-        {
-            get
-            {
-                return CultureInfo.CurrentUICulture;
-            }
-
-            set
-            {
-                // If you add more pre-conditions to this method, check to see if you also need to 
-                // add them to CultureInfo.DefaultThreadCurrentUICulture.set.
-
-                if (CultureInfo.s_currentThreadUICulture == null && CultureInfo.s_currentThreadCulture == null)
-                    nativeInitCultureAccessors();
-
-                CultureInfo.CurrentUICulture = value;
-            }
-        }
-
-        // This returns the exposed context for a given context ID.
-
-        // As the culture can be customized object then we cannot hold any 
-        // reference to it before we check if it is safe because the app domain 
-        // owning this customized culture may get unloaded while executing this 
-        // code. To achieve that we have to do the check using nativeGetSafeCulture 
-        // as the thread cannot get interrupted during the FCALL. 
-        // If the culture is safe (not customized or created in current app domain) 
-        // then the FCALL will return a reference to that culture otherwise the 
-        // FCALL will return failure. In case of failure we'll return the default culture.
-        // If the app domain owning a customized culture that is set to the thread and this
-        // app domain get unloaded there is a code to clean up the culture from the thread
-        // using the code in AppDomain::ReleaseDomainStores.
-
-        public CultureInfo CurrentCulture
-        {
-            get
-            {
-                return CultureInfo.CurrentCulture;
-            }
-
-            set
-            {
-                // If you add more pre-conditions to this method, check to see if you also need to 
-                // add them to CultureInfo.DefaultThreadCurrentCulture.set.
-
-                if (CultureInfo.s_currentThreadUICulture == null && CultureInfo.s_currentThreadCulture == null)
-                    nativeInitCultureAccessors();
-                
-                CultureInfo.CurrentCulture = value;
-            }
-        }
-
-        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
-        private static extern void nativeInitCultureAccessors();
-
         /*
          *  This returns a unique id to identify an appdomain.
          */
index 468a1da..159c91b 100644 (file)
@@ -2688,7 +2688,7 @@ static HRESULT GetThreadUICultureNames(__inout StringArrayList* pCultureNames)
         InlineSString<LOCALE_NAME_MAX_LENGTH> sCulture;
         InlineSString<LOCALE_NAME_MAX_LENGTH> sParentCulture;
 
-
+#if 0 // Enable and test if/once the unmanaged runtime is localized
         Thread * pThread = GetThread();
 
         // When fatal errors have occured our invariants around GC modes may be broken and attempting to transition to co-op may hang
@@ -2713,36 +2713,33 @@ static HRESULT GetThreadUICultureNames(__inout StringArrayList* pCultureNames)
             // and we don't want them moving on us.
             GCX_COOP();
 
-            THREADBASEREF pThreadBase = (THREADBASEREF)pThread->GetExposedObjectRaw();
+            CULTUREINFOBASEREF pCurrentCulture = (CULTUREINFOBASEREF)Thread::GetCulture(TRUE);
 
-            if (pThreadBase != NULL)
+            if (pCurrentCulture != NULL)
             {
-                CULTUREINFOBASEREF pCurrentCulture = pThreadBase->GetCurrentUICulture();
+                STRINGREF cultureName = pCurrentCulture->GetName();
 
-                if (pCurrentCulture != NULL)
+                if (cultureName != NULL)
                 {
-                    STRINGREF cultureName = pCurrentCulture->GetName();
+                    sCulture.Set(cultureName->GetBuffer(),cultureName->GetStringLength());
+                }
 
-                    if (cultureName != NULL)
-                    {
-                        sCulture.Set(cultureName->GetBuffer(),cultureName->GetStringLength());
-                    }
+                CULTUREINFOBASEREF pParentCulture = pCurrentCulture->GetParent();
 
-                    CULTUREINFOBASEREF pParentCulture = pCurrentCulture->GetParent();
+                if (pParentCulture != NULL)
+                {
+                    STRINGREF parentCultureName = pParentCulture->GetName();
 
-                    if (pParentCulture != NULL)
+                    if (parentCultureName != NULL)
                     {
-                        STRINGREF parentCultureName = pParentCulture->GetName();
-
-                        if (parentCultureName != NULL)
-                        {
-                            sParentCulture.Set(parentCultureName->GetBuffer(),parentCultureName->GetStringLength());
-                        }
-
+                        sParentCulture.Set(parentCultureName->GetBuffer(),parentCultureName->GetStringLength());
                     }
+
                 }
             }
         }
+#endif
+
         // If the lazily-initialized cultureinfo structures aren't initialized yet, we'll
         // need to do the lookup the hard way.
         if (sCulture.IsEmpty() || sParentCulture.IsEmpty())
@@ -2837,6 +2834,7 @@ static int GetThreadUICultureId(__out LocaleIDValue* pLocale)
 
     Thread * pThread = GetThread();
 
+#if 0 // Enable and test if/once the unmanaged runtime is localized
     // When fatal errors have occured our invariants around GC modes may be broken and attempting to transition to co-op may hang
     // indefinately. We want to ensure a clean exit so rather than take the risk of hang we take a risk of the error resource not
     // getting localized with a non-default thread-specific culture.
@@ -2859,21 +2857,18 @@ static int GetThreadUICultureId(__out LocaleIDValue* pLocale)
         // and we don't want them moving on us.
         GCX_COOP();
 
-        THREADBASEREF pThreadBase = (THREADBASEREF)pThread->GetExposedObjectRaw();
-        if (pThreadBase != NULL)
-        {
-            CULTUREINFOBASEREF pCurrentCulture = pThreadBase->GetCurrentUICulture();
+        CULTUREINFOBASEREF pCurrentCulture = (CULTUREINFOBASEREF)Thread::GetCulture(TRUE);
 
-            if (pCurrentCulture != NULL)
-            {
-                STRINGREF cultureName = pCurrentCulture->GetName();
-                _ASSERT(cultureName != NULL);
+        if (pCurrentCulture != NULL)
+        {
+            STRINGREF cultureName = pCurrentCulture->GetName();
+            _ASSERT(cultureName != NULL);
 
-                if ((Result = ::LocaleNameToLCID(cultureName->GetBuffer(), 0)) == 0)
-                    Result = (int)UICULTUREID_DONTCARE;
-            }
+            if ((Result = ::LocaleNameToLCID(cultureName->GetBuffer(), 0)) == 0)
+                Result = (int)UICULTUREID_DONTCARE;
         }
     }
+#endif
 
     if (Result == (int)UICULTUREID_DONTCARE)
     {
@@ -2912,6 +2907,7 @@ static int GetThreadUICultureId(__out LocaleIDValue* pLocale)
 
     Thread * pThread = GetThread();
 
+#if 0 // Enable and test if/once the unmanaged runtime is localized
     // When fatal errors have occured our invariants around GC modes may be broken and attempting to transition to co-op may hang
     // indefinately. We want to ensure a clean exit so rather than take the risk of hang we take a risk of the error resource not
     // getting localized with a non-default thread-specific culture.
@@ -2935,29 +2931,25 @@ static int GetThreadUICultureId(__out LocaleIDValue* pLocale)
         // and we don't want them moving on us.
         GCX_COOP();
 
-        THREADBASEREF pThreadBase = (THREADBASEREF)pThread->GetExposedObjectRaw();
-        if (pThreadBase != NULL)
+        CULTUREINFOBASEREF pCurrentCulture = (CULTUREINFOBASEREF)Thread::GetCulture(TRUE);
+
+        if (pCurrentCulture != NULL)
         {
-            CULTUREINFOBASEREF pCurrentCulture = pThreadBase->GetCurrentUICulture();
+            STRINGREF currentCultureName = pCurrentCulture->GetName();
 
-            if (pCurrentCulture != NULL)
+            if (currentCultureName != NULL)
             {
-                STRINGREF currentCultureName = pCurrentCulture->GetName();
-
-                if (currentCultureName != NULL)
+                int cchCurrentCultureNameResult = currentCultureName->GetStringLength();
+                if (cchCurrentCultureNameResult < LOCALE_NAME_MAX_LENGTH)
                 {
-                    int cchCurrentCultureNameResult = currentCultureName->GetStringLength();
-                    if (cchCurrentCultureNameResult < LOCALE_NAME_MAX_LENGTH)
-                    {
-                        memcpy(*pLocale, currentCultureName->GetBuffer(), cchCurrentCultureNameResult*sizeof(WCHAR));
-                        (*pLocale)[cchCurrentCultureNameResult]='\0';
-                        Result=cchCurrentCultureNameResult;
-                    }
+                    memcpy(*pLocale, currentCultureName->GetBuffer(), cchCurrentCultureNameResult*sizeof(WCHAR));
+                    (*pLocale)[cchCurrentCultureNameResult]='\0';
+                    Result=cchCurrentCultureNameResult;
                 }
-
             }
         }
     }
+#endif
     if (Result == 0)
     {
 #ifndef FEATURE_PAL
index e99837c..16cc49f 100644 (file)
@@ -1313,123 +1313,6 @@ void ThreadBaseObject::InitExisting()
 
 }
 
-OBJECTREF ThreadBaseObject::GetManagedThreadCulture(BOOL bUICulture)
-{
-    CONTRACTL {
-        GC_NOTRIGGER;
-        NOTHROW;
-        MODE_COOPERATIVE;
-    }
-    CONTRACTL_END;
-
-    // This is the case when we're building mscorlib and haven't yet created
-    // the system assembly.
-    if (SystemDomain::System()->SystemAssembly()==NULL || g_fForbidEnterEE) {
-        return NULL;
-    }
-
-    OBJECTREF *pCurrentCulture = NULL;
-    Thread    *pThread = GetInternal();
-    FieldDesc *pFD = NULL;
-
-    if (bUICulture)
-    {
-        pFD = pThread->managedThreadCurrentUICulture;
-    }
-    else
-    {
-        pFD = pThread->managedThreadCurrentCulture;
-    }
-
-    if (pFD != NULL)
-    {
-        pCurrentCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD);
-        if (pCurrentCulture)
-        {
-            return *pCurrentCulture;
-        }
-    }
-
-    return NULL;
-}
-
-CULTUREINFOBASEREF ThreadBaseObject::GetCurrentUserCulture()
-{
-    WRAPPER_NO_CONTRACT;
-
-    return (CULTUREINFOBASEREF)GetManagedThreadCulture(false);
-}
-
-CULTUREINFOBASEREF ThreadBaseObject::GetCurrentUICulture()
-{
-    WRAPPER_NO_CONTRACT;
-
-    return (CULTUREINFOBASEREF)GetManagedThreadCulture(true);
-}
-
-// If the thread pool thread switched appdomains and the culture was set, the culture won't be
-// reset for the second appdomain. It's impossible to do general cleanup of thread pool threads
-// because we don't have the right extensible infrastructure for it. For example, if the second
-// appdomain was in a different CLR you won't be able to reset the culture without introducing 
-// new cross-CLR communication mechanism. However, note that this isn't a user scenario in 
-// CoreCLR anyway.
-void ThreadBaseObject::ResetCurrentUserCulture()
-{
-    WRAPPER_NO_CONTRACT;
-    ResetManagedThreadCulture(false);
-}
-
-void ThreadBaseObject::ResetCurrentUICulture()
-{
-    WRAPPER_NO_CONTRACT;
-    ResetManagedThreadCulture(true);
-}
-
-void ThreadBaseObject::ResetManagedThreadCulture(BOOL bUICulture)
-{
-    CONTRACTL
-    {
-        GC_NOTRIGGER;
-        NOTHROW;
-        MODE_COOPERATIVE;
-        SO_TOLERANT;
-    }
-    CONTRACTL_END;
-
-    // This is the case when we're building mscorlib and haven't yet created
-    // the system assembly.
-    if (SystemDomain::System()->SystemAssembly()==NULL || g_fForbidEnterEE) {
-        return;
-    }
-    
-    Thread    *pThread = GetInternal();
-    FieldDesc *pFD = NULL;
-
-    if (bUICulture)
-    {
-        pFD = pThread->managedThreadCurrentUICulture;
-    }
-    else
-    {
-        pFD = pThread->managedThreadCurrentCulture;
-    }
-
-    if (pFD != NULL)
-    {
-        OBJECTREF *pCulture = NULL;
-        BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(COMPlusThrowSO());
-        pCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD);
-        if (pCulture) 
-        {
-            SetObjectReferenceUnchecked(pCulture, NULL);
-        }
-        END_SO_INTOLERANT_CODE;
-
-    }
-}
-
-
-
 FCIMPL1(void, ThreadNative::Finalize, ThreadBaseObject* pThisUNSAFE)
 {
     FCALL_CONTRACT;
@@ -1464,30 +1347,6 @@ FCIMPL1(void, ThreadNative::DisableComObjectEagerCleanup, ThreadBaseObject* pThi
 FCIMPLEND
 #endif //FEATURE_COMINTEROP
 
-//
-// nativeGetSafeCulture is used when the culture get requested from the thread object. 
-// we have to check the culture in the FCALL because in FCALL the thread cannot be 
-// interrupted and unload other app domian.
-// the concern here is if the thread hold a subclassed culture object and somebody 
-// requested it from other app domain then we shouldn't hold any reference to that 
-// culture object any time because the app domain created this culture may get 
-// unloaded and this culture will survive although the type metadata will be unloaded 
-// and GC will crash first time accessing this object after the app domain unload.
-//
-
-void QCALLTYPE ThreadNative::nativeInitCultureAccessors()
-{
-    QCALL_CONTRACT;
-
-    BEGIN_QCALL;
-
-    Thread* pThread = GetThread();
-    pThread->InitCultureAccessors();
-
-    END_QCALL;
-}
-
-
 void QCALLTYPE ThreadNative::InformThreadNameChange(QCall::ThreadHandle thread, LPCWSTR name, INT32 len)
 {
     QCALL_CONTRACT;
index a770fba..afe6fd7 100644 (file)
@@ -84,7 +84,6 @@ public:
     static FCDECL3(INT32,   SetApartmentState, ThreadBaseObject* pThisUNSAFE, INT32 iState, CLR_BOOL fireMDAOnMismatch);
     static FCDECL1(void,    StartupSetApartmentState, ThreadBaseObject* pThis);
 #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
-    static void QCALLTYPE nativeInitCultureAccessors();
 
     static
     void QCALLTYPE InformThreadNameChange(QCall::ThreadHandle thread, LPCWSTR name, INT32 len);
index 1b4fbb4..78007b2 100644 (file)
@@ -1564,8 +1564,8 @@ void DispatchInfo::InvokeMemberWorker(DispatchMemberInfo*   pDispMemberInfo,
         {
             // If the method is culture aware, then set the specified culture on the thread.
             GetCultureInfoForLCID(lcid, &pObjs->CultureInfo);
-            pObjs->OldCultureInfo = pThread->GetCulture(FALSE);
-            pThread->SetCultureId(lcid, FALSE);
+            pObjs->OldCultureInfo = Thread::GetCulture(FALSE);
+            Thread::SetCulture(&pObjs->CultureInfo, FALSE);
         }
 
         // If the method has custom marshalers then we will need to call
@@ -1979,7 +1979,6 @@ HRESULT DispatchInfo::InvokeMember(SimpleComCallWrapper *pSimpleWrap, DISPID id,
     DISPID *pSrcArgNames = NULL;
     VARIANT *pSrcArgs = NULL;
     ULONG_PTR ulActCtxCookie = 0;
-    Thread *pThread = GetThread();
 
     //
     // Validate the arguments.
@@ -2292,7 +2291,7 @@ HRESULT DispatchInfo::InvokeMember(SimpleComCallWrapper *pSimpleWrap, DISPID id,
 
         // If the culture was changed then restore it to the old culture.
         if (Objs.OldCultureInfo != NULL)
-            pThread->SetCulture(&Objs.OldCultureInfo, FALSE);
+            Thread::SetCulture(&Objs.OldCultureInfo, FALSE);
     }
     GCPROTECT_END();
     GCPROTECT_END();
index 9dda48f..2ce100b 100644 (file)
@@ -468,16 +468,8 @@ public:
                 argIdx--;
             }
 
-            LocalDesc locDescThread(MscorlibBinder::GetClass(CLASS__THREAD));
-            DWORD dwThreadLocalNum = pcs->NewLocal(locDescThread);
-
-            // call Thread.get_CurrentThread()
-            pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
-            pcs->EmitDUP();
-            pcs->EmitSTLOC(dwThreadLocalNum);
-
-            // call current_thread.get_CurrentCulture()
-            pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
+            // call CultureInfo.get_CurrentCulture()
+            pcs->EmitCALL(METHOD__CULTURE_INFO__GET_CURRENT_CULTURE, 0, 1);
 
             // save the current culture
             LocalDesc locDescCulture(MscorlibBinder::GetClass(CLASS__CULTURE_INFO));
@@ -486,23 +478,20 @@ public:
             pcs->EmitSTLOC(dwCultureLocalNum);
 
             // set a new one based on the LCID passed from unmanaged
-            pcs->EmitLDLOC(dwThreadLocalNum);
             pcs->EmitLDARG(argIdx);
 
             // call CultureInfo..ctor(lcid)
-            // call current_thread.set_CurrentCulture(culture)
+            // call CultureInfo.set_CurrentCulture(culture)
             pcs->EmitNEWOBJ(METHOD__CULTURE_INFO__INT_CTOR, 1);
-            pcs->EmitCALL(METHOD__THREAD__SET_CULTURE, 2, 0);
+            pcs->EmitCALL(METHOD__CULTURE_INFO__SET_CURRENT_CULTURE, 1, 0);
 
             // and restore the current one after the call
             m_slIL.SetCleanupNeeded();
             ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
 
-            // call current_thread.set_CurrentCulture(original_culture)
-            pcsCleanup->EmitLDLOC(dwThreadLocalNum);
+            // call CultureInfo.set_CurrentCulture(original_culture)
             pcsCleanup->EmitLDLOC(dwCultureLocalNum);
-            pcsCleanup->EmitCALL(METHOD__THREAD__SET_CULTURE, 1, 1);
-
+            pcsCleanup->EmitCALL(METHOD__CULTURE_INFO__SET_CURRENT_CULTURE, 1, 0);
         }
         else
         {
@@ -514,10 +503,8 @@ public:
             }
             else
             {
-                // call Thread.get_CurrentThread()
-                // call current_thread.get_CurrentCulture()
-                pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
-                pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
+                // call CultureInfo.get_CurrentCulture()
+                pcs->EmitCALL(METHOD__CULTURE_INFO__GET_CURRENT_CULTURE, 0, 1);
 
                 //call CultureInfo.get_LCID(this)
                 pcs->EmitCALL(METHOD__CULTURE_INFO__GET_ID, 1, 1);
index 145c949..0217052 100644 (file)
@@ -673,7 +673,6 @@ FCFuncEnd()
 FCFuncStart(gThreadFuncs)
     FCDynamic("InternalGetCurrentThread", CORINFO_INTRINSIC_Illegal, ECall::InternalGetCurrentThread)
     FCFuncElement("StartInternal", ThreadNative::Start)
-    QCFuncElement("nativeInitCultureAccessors", ThreadNative::nativeInitCultureAccessors)
 #undef Sleep
     FCFuncElement("SleepInternal", ThreadNative::Sleep)
 #define Sleep(a) Dont_Use_Sleep(a)
index e701cf3..154c915 100644 (file)
@@ -395,8 +395,6 @@ DEFINE_METASIG_T(IM(RetCultureInfo, _, C(CULTURE_INFO)))
 DEFINE_METASIG_T(IM(RetCausalityTraceLevel, _, g(CAUSALITY_TRACE_LEVEL)))
 #endif // FEATURE_COMINTEROP
 
-DEFINE_METASIG_T(SM(RetThread, _, C(THREAD)))
-
 DEFINE_METASIG(IM(Bool_RetIntPtr, F, I))
 DEFINE_METASIG_T(IM(Bool_RetMethodInfo, F, C(METHOD_INFO)))
 DEFINE_METASIG(SM(Bool_RetStr, F, s))
@@ -424,7 +422,8 @@ DEFINE_METASIG(IM(Obj_Int_RetIntPtr, j i, I))
 
 DEFINE_METASIG(IM(Char_Char_RetStr, u u, s))
 DEFINE_METASIG(IM(Char_Int_RetVoid, u i, v))
-DEFINE_METASIG_T(IM(CultureInfo_RetVoid, C(CULTURE_INFO), v))
+DEFINE_METASIG_T(SM(RetCultureInfo, _, C(CULTURE_INFO)))
+DEFINE_METASIG_T(SM(CultureInfo_RetVoid, C(CULTURE_INFO), v))
 DEFINE_METASIG(IM(Dbl_RetVoid, d, v))
 DEFINE_METASIG(IM(Flt_RetVoid, f, v))
 DEFINE_METASIG(IM(Int_RetInt, i, i))
index 5d81162..62205d3 100644 (file)
     DEFINE_METHOD(classId, SET_ ## id, set_ ## stringName, IM_## gSign ## _RetVoid)
 #endif
 
+#ifndef DEFINE_STATIC_SET_PROPERTY
+#define DEFINE_STATIC_SET_PROPERTY(classId, id, stringName, gSign) \
+    DEFINE_STATIC_PROPERTY(classId, id, stringName, gSign) \
+    DEFINE_METHOD(classId, SET_ ## id, set_ ## stringName, SM_## gSign ## _RetVoid)
+#endif
+
 //
 // DEFINE_CLASS_U and DEFINE_FIELD_U are debug-only checks to verify that the managed and unmanaged layouts are in sync
 //
@@ -261,9 +267,10 @@ DEFINE_PROPERTY(CULTURE_INFO,       NAME,                   Name,
 DEFINE_METHOD(CULTURE_INFO,         INT_CTOR,               .ctor,                      IM_Int_RetVoid)
 DEFINE_PROPERTY(CULTURE_INFO,       ID,                     LCID,                       Int)
 #endif
-DEFINE_PROPERTY(CULTURE_INFO,       PARENT,                 Parent,                     CultureInfo)
 DEFINE_FIELD(CULTURE_INFO,          CULTURE,                s_currentThreadCulture)
 DEFINE_FIELD(CULTURE_INFO,          UI_CULTURE,             s_currentThreadUICulture)
+DEFINE_STATIC_SET_PROPERTY(CULTURE_INFO, CURRENT_CULTURE,      CurrentCulture,     CultureInfo)
+DEFINE_STATIC_SET_PROPERTY(CULTURE_INFO, CURRENT_UI_CULTURE,   CurrentUICulture,   CultureInfo)
 
 DEFINE_CLASS(CURRENCY,              System,                 Currency)
 DEFINE_METHOD(CURRENCY,             DECIMAL_CTOR,           .ctor,                      IM_Dec_RetVoid)
@@ -823,9 +830,6 @@ DEFINE_FIELD_U(m_ThreadStartArg,           ThreadBaseObject,   m_ThreadStartArg)
 DEFINE_FIELD_U(DONT_USE_InternalThread,    ThreadBaseObject,   m_InternalThread)
 DEFINE_FIELD_U(m_Priority,                 ThreadBaseObject,   m_Priority)
 DEFINE_CLASS(THREAD,                Threading,              Thread)
-DEFINE_SET_PROPERTY(THREAD,         CULTURE,                CurrentCulture,             CultureInfo)
-DEFINE_SET_PROPERTY(THREAD,         UI_CULTURE,             CurrentUICulture,           CultureInfo)
-DEFINE_STATIC_PROPERTY(THREAD,      CURRENT_THREAD,         CurrentThread,              Thread)
 DEFINE_METHOD(THREAD,               INTERNAL_GET_CURRENT_THREAD,             InternalGetCurrentThread,                    SM_RetIntPtr)
 
 DEFINE_CLASS(PARAMETERIZEDTHREADSTART,     Threading,                 ParameterizedThreadStart)
index 671d57e..dd943ee 100644 (file)
@@ -1506,15 +1506,6 @@ public:
     OBJECTREF GetDelegate()                   { LIMITED_METHOD_CONTRACT; return m_Delegate; }
     void      SetDelegate(OBJECTREF delegate);
 
-    CULTUREINFOBASEREF GetCurrentUserCulture();
-    CULTUREINFOBASEREF GetCurrentUICulture();
-    OBJECTREF GetManagedThreadCulture(BOOL bUICulture);
-    void ResetManagedThreadCulture(BOOL bUICulture);
-    void ResetCurrentUserCulture();
-    void ResetCurrentUICulture();
-
-
-
     OBJECTREF GetSynchronizationContext()
     {
         LIMITED_METHOD_CONTRACT;
@@ -1526,13 +1517,6 @@ public:
     // existing physical thread is later exposed.
     void      InitExisting();
 
-    void ResetCulture()
-    {
-        LIMITED_METHOD_CONTRACT;
-        ResetCurrentUserCulture();
-        ResetCurrentUICulture();
-    }
-
     void ResetName()
     {
         LIMITED_METHOD_CONTRACT;
index 8ec986d..fa31676 100644 (file)
@@ -1644,9 +1644,6 @@ Thread::Thread()
     contextHolder.SuppressRelease();
     savedRedirectContextHolder.SuppressRelease();
 
-    managedThreadCurrentCulture = NULL;
-    managedThreadCurrentUICulture = NULL;
-
 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
     m_ullProcessorUsageBaseline = 0;
 #endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
@@ -8610,92 +8607,6 @@ void Thread::DeleteThreadStaticData(ModuleIndex index)
     m_ThreadLocalBlock.FreeTLM(index.m_dwIndex, FALSE /* isThreadShuttingDown */);
 }
 
-void Thread::InitCultureAccessors()
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-    }
-    CONTRACTL_END;
-
-    OBJECTREF *pCurrentCulture = NULL;
-    Thread *pThread = GetThread();
-
-    GCX_COOP();
-
-    if (managedThreadCurrentCulture == NULL) {
-        managedThreadCurrentCulture = MscorlibBinder::GetField(FIELD__CULTURE_INFO__CULTURE);
-        pCurrentCulture = (OBJECTREF*)pThread->GetStaticFieldAddress(managedThreadCurrentCulture);
-    }
-
-    if (managedThreadCurrentUICulture == NULL) {
-        managedThreadCurrentUICulture = MscorlibBinder::GetField(FIELD__CULTURE_INFO__UI_CULTURE);
-        pCurrentCulture = (OBJECTREF*)pThread->GetStaticFieldAddress(managedThreadCurrentUICulture);
-    }
-}
-
-
-ARG_SLOT Thread::CallPropertyGet(BinderMethodID id, OBJECTREF pObject)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
-    }
-    CONTRACTL_END;
-
-    if (!pObject) {
-        return 0;
-    }
-
-    ARG_SLOT retVal;
-
-    GCPROTECT_BEGIN(pObject);
-    MethodDescCallSite propGet(id, &pObject);
-
-    // Set up the Stack.
-    ARG_SLOT pNewArgs = ObjToArgSlot(pObject);
-
-    // Make the actual call.
-    retVal = propGet.Call_RetArgSlot(&pNewArgs);
-    GCPROTECT_END();
-
-    return retVal;
-}
-
-ARG_SLOT Thread::CallPropertySet(BinderMethodID id, OBJECTREF pObject, OBJECTREF pValue)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
-    }
-    CONTRACTL_END;
-
-    if (!pObject) {
-        return 0;
-    }
-
-    ARG_SLOT retVal;
-
-    GCPROTECT_BEGIN(pObject);
-    GCPROTECT_BEGIN(pValue);
-    MethodDescCallSite propSet(id, &pObject);
-
-    // Set up the Stack.
-    ARG_SLOT pNewArgs[] = {
-        ObjToArgSlot(pObject),
-        ObjToArgSlot(pValue)
-    };
-
-    // Make the actual call.
-    retVal = propSet.Call_RetArgSlot(pNewArgs);
-    GCPROTECT_END();
-    GCPROTECT_END();
-
-    return retVal;
-}
-
 OBJECTREF Thread::GetCulture(BOOL bUICulture)
 {
     CONTRACTL {
@@ -8707,253 +8618,32 @@ OBJECTREF Thread::GetCulture(BOOL bUICulture)
 
     FieldDesc *         pFD;
 
-    _ASSERTE(PreemptiveGCDisabled());
-
     // This is the case when we're building mscorlib and haven't yet created
     // the system assembly.
     if (SystemDomain::System()->SystemAssembly()==NULL || g_fForbidEnterEE) {
         return NULL;
     }
 
-    // Get the actual thread culture.
-    OBJECTREF pCurThreadObject = GetExposedObject();
-    _ASSERTE(pCurThreadObject!=NULL);
-
-    THREADBASEREF pThreadBase = (THREADBASEREF)(pCurThreadObject);
-    OBJECTREF pCurrentCulture = bUICulture ? pThreadBase->GetCurrentUICulture() : pThreadBase->GetCurrentUserCulture();
-
-    if (pCurrentCulture==NULL) {
-        GCPROTECT_BEGIN(pThreadBase);
-        if (bUICulture) {
-            // Call the Getter for the CurrentUICulture.  This will cause it to populate the field.
-            ARG_SLOT retVal = CallPropertyGet(METHOD__THREAD__GET_UI_CULTURE,
-                                           (OBJECTREF)pThreadBase);
-            pCurrentCulture = ArgSlotToObj(retVal);
-        } else {
-            //This is  faster than calling the property, because this is what the call does anyway.
-            pFD = MscorlibBinder::GetField(FIELD__CULTURE_INFO__CURRENT_CULTURE);
-            _ASSERTE(pFD);
+    OBJECTREF pCurrentCulture;
+    if (bUICulture) {
+        // Call the Getter for the CurrentUICulture.  This will cause it to populate the field.
+        MethodDescCallSite propGet(METHOD__CULTURE_INFO__GET_CURRENT_UI_CULTURE);
+        ARG_SLOT retVal = propGet.Call_RetArgSlot(NULL);
+        pCurrentCulture = ArgSlotToObj(retVal);
+    } else {
+        //This is  faster than calling the property, because this is what the call does anyway.
+        pFD = MscorlibBinder::GetField(FIELD__CULTURE_INFO__CURRENT_CULTURE);
+        _ASSERTE(pFD);
 
-            pFD->CheckRunClassInitThrowing();
+        pFD->CheckRunClassInitThrowing();
 
-            pCurrentCulture = pFD->GetStaticOBJECTREF();
-            _ASSERTE(pCurrentCulture!=NULL);
-        }
-        GCPROTECT_END();
+        pCurrentCulture = pFD->GetStaticOBJECTREF();
+        _ASSERTE(pCurrentCulture!=NULL);
     }
 
     return pCurrentCulture;
 }
 
-
-
-// copy culture name into szBuffer and return length
-int Thread::GetParentCultureName(__out_ecount(length) LPWSTR szBuffer, int length, BOOL bUICulture)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    // This is the case when we're building mscorlib and haven't yet created
-    // the system assembly.
-    if (SystemDomain::System()->SystemAssembly()==NULL) {
-        const WCHAR *tempName = W("en");
-        INT32 tempLength = (INT32)wcslen(tempName);
-        _ASSERTE(length>=tempLength);
-        memcpy(szBuffer, tempName, tempLength*sizeof(WCHAR));
-        return tempLength;
-    }
-
-    ARG_SLOT Result = 0;
-    INT32 retVal=0;
-    WCHAR *buffer=NULL;
-    INT32 bufferLength=0;
-    STRINGREF cultureName = NULL;
-
-    GCX_COOP();
-
-    struct _gc {
-        OBJECTREF pCurrentCulture;
-        OBJECTREF pParentCulture;
-    } gc;
-    ZeroMemory(&gc, sizeof(gc));
-    GCPROTECT_BEGIN(gc);
-
-    gc.pCurrentCulture = GetCulture(bUICulture);
-    if (gc.pCurrentCulture != NULL) {
-        Result = CallPropertyGet(METHOD__CULTURE_INFO__GET_PARENT, gc.pCurrentCulture);
-    }
-
-    if (Result) {
-        gc.pParentCulture = (OBJECTREF)(ArgSlotToObj(Result));
-        if (gc.pParentCulture != NULL)
-        {
-            Result = 0;
-            Result = CallPropertyGet(METHOD__CULTURE_INFO__GET_NAME, gc.pParentCulture);
-        }
-    }
-
-    GCPROTECT_END();
-
-    if (Result==0) {
-        return 0;
-    }
-
-
-    // Extract the data out of the String.
-    cultureName = (STRINGREF)(ArgSlotToObj(Result));
-    cultureName->RefInterpretGetStringValuesDangerousForGC((WCHAR**)&buffer, &bufferLength);
-
-    if (bufferLength<length) {
-        memcpy(szBuffer, buffer, bufferLength * sizeof (WCHAR));
-        szBuffer[bufferLength]=0;
-        retVal = bufferLength;
-    }
-
-    return retVal;
-}
-
-
-
-
-// copy culture name into szBuffer and return length
-int Thread::GetCultureName(__out_ecount(length) LPWSTR szBuffer, int length, BOOL bUICulture)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    // This is the case when we're building mscorlib and haven't yet created
-    // the system assembly.
-    if (SystemDomain::System()->SystemAssembly()==NULL || g_fForbidEnterEE) {
-        const WCHAR *tempName = W("en-US");
-        INT32 tempLength = (INT32)wcslen(tempName);
-        _ASSERTE(length>=tempLength);
-        memcpy(szBuffer, tempName, tempLength*sizeof(WCHAR));
-        return tempLength;
-    }
-
-    ARG_SLOT Result = 0;
-    INT32 retVal=0;
-    WCHAR *buffer=NULL;
-    INT32 bufferLength=0;
-    STRINGREF cultureName = NULL;
-
-    GCX_COOP ();
-
-    OBJECTREF pCurrentCulture = NULL;
-    GCPROTECT_BEGIN(pCurrentCulture)
-    {
-        pCurrentCulture = GetCulture(bUICulture);
-        if (pCurrentCulture != NULL)
-            Result = CallPropertyGet(METHOD__CULTURE_INFO__GET_NAME, pCurrentCulture);
-    }
-    GCPROTECT_END();
-
-    if (Result==0) {
-        return 0;
-    }
-
-    // Extract the data out of the String.
-    cultureName = (STRINGREF)(ArgSlotToObj(Result));
-    cultureName->RefInterpretGetStringValuesDangerousForGC((WCHAR**)&buffer, &bufferLength);
-
-    if (bufferLength<length) {
-        memcpy(szBuffer, buffer, bufferLength * sizeof (WCHAR));
-        szBuffer[bufferLength]=0;
-        retVal = bufferLength;
-    }
-
-    return retVal;
-}
-
-LCID GetThreadCultureIdNoThrow(Thread *pThread, BOOL bUICulture)
-{
-    CONTRACTL
-    {
-        NOTHROW;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    LCID Result = LCID(-1);
-
-    EX_TRY
-    {
-        Result = pThread->GetCultureId(bUICulture);
-    }
-    EX_CATCH
-    {
-    }
-    EX_END_CATCH (SwallowAllExceptions);
-
-    return (INT32)Result;
-}
-
-// Return a language identifier.
-LCID Thread::GetCultureId(BOOL bUICulture)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    // This is the case when we're building mscorlib and haven't yet created
-    // the system assembly.
-    if (SystemDomain::System()->SystemAssembly()==NULL || g_fForbidEnterEE) {
-        return (LCID) -1;
-    }
-
-    LCID Result = (LCID) -1;
-
-#ifdef FEATURE_USE_LCID
-    GCX_COOP();
-
-    OBJECTREF pCurrentCulture = NULL;
-    GCPROTECT_BEGIN(pCurrentCulture)
-    {
-        pCurrentCulture = GetCulture(bUICulture);
-        if (pCurrentCulture != NULL)
-            Result = (LCID)CallPropertyGet(METHOD__CULTURE_INFO__GET_ID, pCurrentCulture);
-    }
-    GCPROTECT_END();
-#endif
-
-    return Result;
-}
-
-void Thread::SetCultureId(LCID lcid, BOOL bUICulture)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    GCX_COOP();
-
-    OBJECTREF CultureObj = NULL;
-    GCPROTECT_BEGIN(CultureObj)
-    {
-        // Convert the LCID into a CultureInfo.
-        GetCultureInfoForLCID(lcid, &CultureObj);
-
-        // Set the newly created culture as the thread's culture.
-        SetCulture(&CultureObj, bUICulture);
-    }
-    GCPROTECT_END();
-}
-
 void Thread::SetCulture(OBJECTREF *CultureObj, BOOL bUICulture)
 {
     CONTRACTL {
@@ -8963,16 +8653,17 @@ void Thread::SetCulture(OBJECTREF *CultureObj, BOOL bUICulture)
     }
     CONTRACTL_END;
 
-    // Retrieve the exposed thread object.
-    OBJECTREF pCurThreadObject = GetExposedObject();
-    _ASSERTE(pCurThreadObject!=NULL);
+    MethodDescCallSite propSet(bUICulture
+        ? METHOD__CULTURE_INFO__SET_CURRENT_UI_CULTURE
+        : METHOD__CULTURE_INFO__SET_CURRENT_CULTURE);
 
-    // Set the culture property on the thread.
-    THREADBASEREF pThreadBase = (THREADBASEREF)(pCurThreadObject);
-    CallPropertySet(bUICulture
-                    ? METHOD__THREAD__SET_UI_CULTURE
-                    : METHOD__THREAD__SET_CULTURE,
-                    (OBJECTREF)pThreadBase, *CultureObj);
+    // Set up the Stack.
+    ARG_SLOT pNewArgs[] = {
+        ObjToArgSlot(*CultureObj)
+    };
+
+    // Make the actual call.
+    propSet.Call_RetArgSlot(pNewArgs);
 }
 
 void Thread::SetHasPromotedBytes ()
@@ -9073,7 +8764,6 @@ INT32 Thread::ResetManagedThreadObjectInCoopMode(INT32 nPriority)
     THREADBASEREF pObject = (THREADBASEREF)ObjectFromHandle(m_ExposedObject);
     if (pObject != NULL)
     {
-        pObject->ResetCulture();
         pObject->ResetName();
         nPriority = pObject->GetPriority();
     }
index 0c282d8..dbbb00b 100644 (file)
@@ -3361,24 +3361,11 @@ public:
         return m_TraceCallCount;
     }
 
-    // Functions to get culture information for thread.
-    int GetParentCultureName(__out_ecount(length) LPWSTR szBuffer, int length, BOOL bUICulture);
-    int GetCultureName(__out_ecount(length) LPWSTR szBuffer, int length, BOOL bUICulture);
-    LCID GetCultureId(BOOL bUICulture);
-    OBJECTREF GetCulture(BOOL bUICulture);
-
-    // Release user cultures that can't survive appdomain unload
-
-    // Functions to set the culture on the thread.
-    void SetCultureId(LCID lcid, BOOL bUICulture);
-    void SetCulture(OBJECTREF *CultureObj, BOOL bUICulture);
+    // Functions to get/set culture information for current thread.
+    static OBJECTREF GetCulture(BOOL bUICulture);
+    static void SetCulture(OBJECTREF *CultureObj, BOOL bUICulture);
 
 private:
-
-    // Used by the culture accesors.
-    ARG_SLOT CallPropertyGet(BinderMethodID id, OBJECTREF pObject);
-    ARG_SLOT CallPropertySet(BinderMethodID id, OBJECTREF pObject, OBJECTREF pValue);
-
 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
     // Used in suspension code to redirect a thread at a HandledJITCase
     BOOL RedirectThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt);
@@ -4209,20 +4196,16 @@ public:
         return m_pLoadingFile;
     }
 
- private:
-
+private:
     static void LoadingFileRelease(Thread *pThread)
     {
         WRAPPER_NO_CONTRACT;
         pThread->ClearLoadingFile();
     }
 
- public:
-
+public:
      typedef Holder<Thread *, DoNothing, Thread::LoadingFileRelease> LoadingFileHolder;
-    void InitCultureAccessors();
-    FieldDesc *managedThreadCurrentCulture;
-    FieldDesc *managedThreadCurrentUICulture;
+
 private:
     // Don't allow a thread to be asynchronously stopped or interrupted (e.g. because
     // it is performing a <clinit>)
@@ -5125,9 +5108,6 @@ public:
 
 // End of class Thread
 
-
-LCID GetThreadCultureIdNoThrow(Thread *pThread, BOOL bUICulture);
-
 typedef Thread::ForbidSuspendThreadHolder ForbidSuspendThreadHolder;
 typedef Thread::ThreadPreventAsyncHolder ThreadPreventAsyncHolder;
 typedef Thread::ThreadPreventAbortHolder ThreadPreventAbortHolder;
@@ -6668,62 +6648,6 @@ inline void NO_FORBIDGC_LOADER_USE_ThrowSO()
 // general corruption.
 BOOL HasIllegalReentrancy();
 
-
-// This class can be used to "schedule" a culture setting,
-//  kicking in when leaving scope or during exception unwinding.
-//  Note: during destruction, this can throw.  You have been warned.
-class ReturnCultureHolder
-{
-public:
-    ReturnCultureHolder(Thread* pThread, OBJECTREF* culture, BOOL bUICulture)
-    {
-        CONTRACTL
-        {
-            WRAPPER(NOTHROW);
-            WRAPPER(GC_NOTRIGGER);
-            MODE_COOPERATIVE;
-            PRECONDITION(CheckPointer(pThread));
-        }
-        CONTRACTL_END;
-
-        m_pThread = pThread;
-        m_culture = culture;
-        m_bUICulture = bUICulture;
-        m_acquired = TRUE;
-    }
-
-    FORCEINLINE void SuppressRelease()
-    {
-        m_acquired = FALSE;
-    }
-
-    ~ReturnCultureHolder()
-    {
-        CONTRACTL
-        {
-            WRAPPER(THROWS);
-            WRAPPER(GC_TRIGGERS);
-            MODE_COOPERATIVE;
-        }
-        CONTRACTL_END;
-
-        if (m_acquired)
-            m_pThread->SetCulture(m_culture, m_bUICulture);
-    }
-
-private:
-    ReturnCultureHolder()
-    {
-        LIMITED_METHOD_CONTRACT;
-    }
-
-    Thread* m_pThread;
-    OBJECTREF* m_culture;
-    BOOL m_bUICulture;
-    BOOL m_acquired;
-};
-
-
 //
 // _pThread:        (Thread*)       current Thread
 // _pCurrDomain:    (AppDomain*)    current AppDomain