1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ===========================================================================
6 // ===========================================================================
11 // The CLR code base uses a hyperlink feature of the HyperAddin plugin for Visual Studio. If you don't see
12 // 'HyperAddin' in your Visual Studio menu bar you don't have this support. To get it type
14 // \\clrmain\tools\installCLRAddins
16 // After installing HyperAddin, your first run of VS should be as an administrator so HyperAddin can update
17 // some registry information.
19 // At this point the code: prefixes become hyperlinks in Visual Studio and life is good. See
20 // http://mswikis/clr/dev/Pages/CLR%20Team%20Commenting.aspx for more information
22 // There is a bug associated with Visual Studio where it does not recognise the hyperlink if there is a ::
23 // preceeding it on the same line. Since C++ uses :: as a namespace separator, this can often mean that the
24 // second hyperlink on a line does not work. To work around this it is better to use '.' instead of :: as
25 // the namespace separators in code: hyperlinks.
28 // #TableOfContents The .NET Runtime Table of contents
30 // This comment is mean to be a nexus that allows you to jump quickly to various interesting parts of the
33 // You can refer to product studio bugs using urls like the following
34 // * http://bugcheck/bugs/DevDivBugs/2320.asp
35 // * http://bugcheck/bugs/VSWhidbey/601210.asp
37 // Dev10 Bugs can be added with URLs like the following (for Dev10 bug 671409)
38 // * http://tkbgitvstfat01:8090/wi.aspx?id=671409
40 //*************************************************************************************************
42 // * Introduction to the runtime file:../../Documentation/botr/botr-faq.md
44 // #MajorDataStructures. The major data structures associated with the runtime are
45 // * code:Thread (see file:threads.h#ThreadClass) - the additional thread state the runtime needs.
46 // * code:AppDomain - The managed version of a process
47 // * code:Assembly - The unit of deployment and versioning (may be several DLLs but often is only one).
48 // * code:Module - represents a Module (DLL or EXE).
49 // * code:MethodTable - represents the 'hot' part of a type (needed during normal execution)
50 // * code:EEClass - represents the 'cold' part of a type (used during compilation, interop, ...)
51 // * code:MethodDesc - represents a Method
52 // * code:FieldDesc - represents a Field.
53 // * code:Object - represents a object on the GC heap allocated with code:Alloc
55 // * ECMA specifications
56 // * Partition I Concepts
57 // http://download.microsoft.com/download/D/C/1/DC1B219F-3B11-4A05-9DA3-2D0F98B20917/Partition%20I%20Architecture.doc
58 // * Partition II Meta Data
59 // http://download.microsoft.com/download/D/C/1/DC1B219F-3B11-4A05-9DA3-2D0F98B20917/Partition%20II%20Metadata.doc
61 // http://download.microsoft.com/download/D/C/1/DC1B219F-3B11-4A05-9DA3-2D0F98B20917/Partition%20III%20CIL.doc
63 // * Serge Liden (worked on the CLR and owned ILASM / ILDASM for a long time wrote a good book on IL
64 // * Expert .NET 2.0 IL Assembler http://www.amazon.com/Expert-NET-2-0-IL-Assembler/dp/1590596463
66 // * This is also a pretty nice overview of what the CLR is at
67 // http://msdn2.microsoft.com/en-us/netframework/aa497266.aspx
69 // * code:EEStartup - This routine must be called before any interesting runtime services are used. It is
70 // invoked as part of mscorwks's DllMain logic.
71 // * code:#EEShutDown - Code called before we shut down the EE.
73 // * file:..\inc\corhdr.h#ManagedHeader - From a data structure point of view, this is the entry point into
74 // the runtime. This is how all other data in the EXE are found.
76 // * code:ICorJitCompiler#EEToJitInterface - This is the interface from the the EE to the Just in time (JIT)
77 // compiler. The interface to the JIT is relatively simple (compileMethod), however the EE provides a
78 // rich set of callbacks so the JIT can get all the information it needs. See also
79 // file:../../Documentation/botr/ryujit-overview.md for general information on the JIT.
81 // * code:VirtualCallStubManager - This is the main class that implements interface dispatch
83 // * Precode - Every method needs entry point for other code to call even if that native code does not
84 // actually exist yet. To support this methods can have code:Precode that is an entry point that exists
85 // and will call the JIT compiler if the code does not yet exist.
87 // * NGEN - NGen stands for Native code GENeration and it is the runtime way of precompiling IL and IL
88 // Meta-data into native code and runtime data structures. At compilation time the most
89 // fundamental data structures is the code:ZapNode which represents something that needs to go into the
92 // * What is cooperative / preemtive mode ? file:threads.h#CooperativeMode and
93 // file:threads.h#SuspendingTheRuntime and file:../../Documentation/botr/threading.md
94 // * Garbage collection - file:gc.cpp#Overview and file:../../Documentation/botr/garbage-collection.md
95 // * code:AppDomain - The managed version of a process.
96 // * Calling Into the runtime (FCALLs QCalls) file:../../Documentation/botr/mscorlib.md
97 // * Exceptions - file:../../Documentation/botr/exceptions.md. The most important routine to start
98 // with is code:COMPlusFrameHandler which is the routine that we hook up to get called when an unmanaged
100 // * Assembly Loading file:../../Documentation/botr/type-loader.md
101 // * Profiling file:../../Documentation/botr/profiling.md and file:../../Documentation/botr/profilability.md
102 // * FCALLS QCALLS (calling into the runtime from managed code)
103 // file:../../Documentation/botr/mscorlib.md
104 // * Event Tracing for Windows
105 // * file:../inc/eventtrace.h#EventTracing -
106 // * This is the main file dealing with event tracing in CLR
107 // * The implementation of this class is available in file:eventtrace.cpp
108 // * file:../inc/eventtrace.h#CEtwTracer - This is the main class dealing with event tracing in CLR.
109 // Follow the link for more information on how this feature has been implemented
110 // * http://mswikis/clr/dev/Pages/CLR%20ETW%20Events%20Wiki.aspx - Follow the link for more information on how to
111 // use this instrumentation feature.
113 // ----------------------------------------------------------------------------------------------------
114 // Features in the runtime that have been given hyperlinks
116 // * code:Nullable#NullableFeature - the Nullable<T> type has special runtime semantics associated with
117 // boxing this describes this feature.
124 #include "clsload.hpp"
129 #include "dllimport.h"
131 #include "eeconfig.h"
132 #include "stublink.h"
133 #include "method.hpp"
137 #include "stackwalk.h"
138 #include "gcheaputilities.h"
139 #include "interoputil.h"
140 #include "fieldmarshaler.h"
141 #include "dbginterface.h"
142 #include "eedbginterfaceimpl.h"
143 #include "debugdebugger.h"
144 #include "cordbpriv.h"
145 #include "comdelegate.h"
146 #include "appdomain.hpp"
147 #include "eventtrace.h"
150 #include "olevariant.h"
151 #include "comcallablewrapper.h"
152 #include "apithreadstress.h"
154 #include "../dlls/mscorrc/resource.h"
156 #include "shimload.h"
157 #include "comthreadpool.h"
158 #include "posterror.h"
159 #include "virtualcallstub.h"
160 #include "strongnameinternal.h"
161 #include "syncclean.hpp"
162 #include "typeparse.h"
163 #include "debuginfostore.h"
164 #include "eemessagebox.h"
165 #include "finalizerthread.h"
166 #include "threadsuspend.h"
167 #include "disassembler.h"
171 #include "dwreport.h"
172 #endif // !FEATURE_PAL
174 #include "stringarraylist.h"
175 #include "stubhelpers.h"
177 #ifdef FEATURE_STACK_SAMPLING
178 #include "stacksampler.h"
186 #ifdef FEATURE_COMINTEROP
187 #include "runtimecallablewrapper.h"
188 #include "notifyexternals.h"
189 #include "mngstdinterfaces.h"
190 #include "rcwwalker.h"
191 #endif // FEATURE_COMINTEROP
193 #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
194 #include "olecontexthelpers.h"
195 #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
197 #ifdef PROFILING_SUPPORTED
198 #include "proftoeeinterfaceimpl.h"
199 #include "profilinghelper.h"
200 #endif // PROFILING_SUPPORTED
202 #ifdef FEATURE_COMINTEROP
203 #include "synchronizationcontextnative.h" // For SynchronizationContextNative::Cleanup
206 #ifdef FEATURE_INTERPRETER
207 #include "interpreter.h"
208 #endif // FEATURE_INTERPRETER
210 #include "../binder/inc/coreclrbindercommon.h"
213 #ifdef FEATURE_PERFMAP
217 #include "diagnosticserver.h"
218 #include "eventpipe.h"
221 // Included for referencing __security_cookie
223 #endif // !FEATURE_PAL
225 #ifdef FEATURE_GDBJIT
227 #endif // FEATURE_GDBJIT
229 #ifndef CROSSGEN_COMPILE
230 static int GetThreadUICultureId(__out LocaleIDValue* pLocale); // TODO: This shouldn't use the LCID. We should rely on name instead
232 static HRESULT GetThreadUICultureNames(__inout StringArrayList* pCultureNames);
233 #endif // !CROSSGEN_COMPILE
235 HRESULT EEStartup(COINITIEE fFlags);
238 #ifndef CROSSGEN_COMPILE
239 static void InitializeGarbageCollector();
241 #ifdef DEBUGGING_SUPPORTED
242 static void InitializeDebugger(void);
243 static void TerminateDebugger(void);
244 extern "C" HRESULT __cdecl CorDBGetInterface(DebugInterface** rcInterface);
245 #endif // DEBUGGING_SUPPORTED
246 #endif // !CROSSGEN_COMPILE
251 // Remember how the last startup of EE went.
252 HRESULT g_EEStartupStatus = S_OK;
254 // Flag indicating if the EE has been started. This is set prior to initializing the default AppDomain, and so does not indicate that
255 // the EE is fully able to execute arbitrary managed code. To ensure the EE is fully started, call EnsureEEStarted rather than just
256 // checking this flag.
257 Volatile<BOOL> g_fEEStarted = FALSE;
259 // Flag indicating if the EE was started up by COM.
260 extern BOOL g_fEEComActivatedStartup;
262 // flag indicating that EE was not started up by IJW, Hosted, COM or my managed exe.
263 extern BOOL g_fEEOtherStartup;
265 // The OS thread ID of the thread currently performing EE startup, or 0 if there is no such thread.
266 DWORD g_dwStartupThreadId = 0;
268 // Event to synchronize EE shutdown.
269 static CLREvent * g_pEEShutDownEvent;
271 static DangerousNonHostedSpinLock g_EEStartupLock;
273 HRESULT InitializeEE(COINITIEE flags)
276 #ifdef FEATURE_EVENT_TRACE
277 if(!g_fEEComActivatedStartup)
278 g_fEEOtherStartup = TRUE;
279 #endif // FEATURE_EVENT_TRACE
280 return EnsureEEStarted(flags);
283 // ---------------------------------------------------------------------------
284 // %%Function: EnsureEEStarted()
286 // Description: Ensure the CLR is started.
287 // ---------------------------------------------------------------------------
288 HRESULT EnsureEEStarted(COINITIEE flags)
304 // On non x86 platforms, when we load mscorlib.dll during EEStartup, we will
305 // re-enter _CorDllMain with a DLL_PROCESS_ATTACH for mscorlib.dll. We are
306 // far enough in startup that this is allowed, however we don't want to
307 // re-start the startup code so we need to check to see if startup has
308 // been initiated or completed before we call EEStartup.
310 // We do however want to make sure other threads block until the EE is started,
311 // which we will do further down.
314 BEGIN_ENTRYPOINT_NOTHROW;
316 #if defined(FEATURE_APPX) && !defined(CROSSGEN_COMPILE)
317 STARTUP_FLAGS startupFlags = CorHost2::GetStartupFlags();
318 // On CoreCLR, the host is in charge of determining whether the process is AppX or not.
319 AppX::SetIsAppXProcess(!!(startupFlags & STARTUP_APPX_APP_MODEL));
323 // The sooner we do this, the sooner we avoid probing registry entries.
324 // (Perf Optimization for VSWhidbey:113373.)
325 REGUTIL::InitOptionalConfigCache();
332 DangerousNonHostedSpinLockHolder lockHolder(&g_EEStartupLock);
334 // Now that we've acquired the lock, check again to make sure we aren't in
335 // the process of starting the CLR or that it hasn't already been fully started.
336 // At this point, if startup has been inited we don't have anything more to do.
337 // And if EEStartup already failed before, we don't do it again.
338 if (!g_fEEStarted && !g_fEEInit && SUCCEEDED (g_EEStartupStatus))
340 g_dwStartupThreadId = GetCurrentThreadId();
343 bStarted=g_fEEStarted;
344 hr = g_EEStartupStatus;
346 g_dwStartupThreadId = 0;
350 hr = g_EEStartupStatus;
351 if (SUCCEEDED(g_EEStartupStatus))
358 END_ENTRYPOINT_NOTHROW;
363 // g_fEEStarted is TRUE, but startup may not be complete since we initialize the default AppDomain
364 // *after* setting that flag. g_fEEStarted is set inside of g_EEStartupLock, and that lock is
365 // not released until the EE is really started - so we can quickly check whether the EE is definitely
366 // started by checking if that lock is currently held. If it is not, then we know the other thread
367 // (that is actually doing the startup) has finished startup. If it is currently held, then we
368 // need to wait for the other thread to release it, which we do by simply acquiring the lock ourselves.
370 // We do not want to do this blocking if we are the thread currently performing EE startup. So we check
373 // Note that the call to IsHeld here is an "acquire" barrier, as is acquiring the lock. And the release of
374 // the lock by the other thread is a "release" barrier, due to the volatile semantics in the lock's
375 // implementation. This assures us that once we observe the lock having been released, we are guaranteed
376 // to observe a fully-initialized EE.
378 // A note about thread affinity here: we're using the OS thread ID of the current thread without
379 // asking the host to pin us to this thread, as we did above. We can get away with this, because we are
380 // only interested in a particular thread ID (that of the "startup" thread) and *that* particular thread
381 // is already affinitized by the code above. So if we get that particular OS thread ID, we know for sure
382 // we are really the startup thread.
384 if (g_EEStartupLock.IsHeld() && g_dwStartupThreadId != GetCurrentThreadId())
386 DangerousNonHostedSpinLockHolder lockHolder(&g_EEStartupLock);
389 hr = g_EEStartupStatus;
390 if (SUCCEEDED(g_EEStartupStatus))
400 #ifndef CROSSGEN_COMPILE
403 // This is our Ctrl-C, Ctrl-Break, etc. handler.
404 static BOOL WINAPI DbgCtrlCHandler(DWORD dwCtrlType)
408 #if defined(DEBUGGING_SUPPORTED)
409 // Note that if a managed-debugger is attached, it's actually attached with the native
410 // debugging pipeline and it will get a control-c notifications via native debug events.
411 // However, if we let the native debugging pipeline handle the event and send the notification
412 // to the debugger, then we break pre-V4 behaviour because we intercept handlers registered
413 // in-process. See Dev10 Bug 846455 for more information.
414 if (CORDebuggerAttached() &&
415 (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT))
417 return g_pDebugInterface->SendCtrlCToDebugger(dwCtrlType);
420 #endif // DEBUGGING_SUPPORTED
422 if (dwCtrlType == CTRL_CLOSE_EVENT)
424 // Initiate shutdown so the ProcessExit handlers run
425 ForceEEShutdown(SCA_ReturnWhenShutdownComplete);
428 g_fInControlC = true; // only for weakening assertions in checked build.
429 return FALSE; // keep looking for a real handler.
434 // A host can specify that it only wants one version of hosting interface to be used.
435 BOOL g_singleVersionHosting;
439 void InitializeStartupFlags()
447 STARTUP_FLAGS flags = CorHost2::GetStartupFlags();
450 if (flags & STARTUP_CONCURRENT_GC)
456 g_heap_type = ((flags & STARTUP_SERVER_GC) && GetCurrentProcessCpuCount() > 1) ? GC_HEAP_SVR : GC_HEAP_WKS;
457 g_IGCHoardVM = (flags & STARTUP_HOARD_GC_VM) == 0 ? 0 : 1;
459 #endif // CROSSGEN_COMPILE
462 // BBSweepStartFunction is the first function to execute in the BBT sweeper thread.
463 // It calls WatchForSweepEvent where we wait until a sweep occurs.
464 DWORD __stdcall BBSweepStartFunction(LPVOID lpArgs)
474 class CLRBBSweepCallback : public ICLRBBSweepCallback
476 virtual HRESULT WriteProfileData()
478 BEGIN_ENTRYPOINT_NOTHROW
480 Module::WriteAllModuleProfileData(false);
481 END_ENTRYPOINT_NOTHROW;
488 g_BBSweep.WatchForSweepEvents(&clrCallback);
493 EX_END_CATCH(RethrowTerminalExceptions)
499 //-----------------------------------------------------------------------------
511 GSCookie * pGSCookiePtr = GetProcessGSCookiePtr();
514 // On Unix, the GS cookie is stored in a read only data segment
515 DWORD newProtection = PAGE_READWRITE;
517 DWORD newProtection = PAGE_EXECUTE_READWRITE;
518 #endif // !FEATURE_PAL
521 if(!ClrVirtualProtect((LPVOID)pGSCookiePtr, sizeof(GSCookie), newProtection, &oldProtection))
527 // PAL layer is unable to extract old protection for regions that were not allocated using VirtualAlloc
528 oldProtection = PAGE_READONLY;
529 #endif // FEATURE_PAL
532 // The GSCookie cannot be in a writeable page
533 assert(((oldProtection & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|
534 PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOMBINE)) == 0));
536 // Forces VC cookie to be initialized.
537 void * pf = &__security_check_cookie;
540 GSCookie val = (GSCookie)(__security_cookie ^ GetTickCount());
541 #else // !FEATURE_PAL
542 // REVIEW: Need something better for PAL...
543 GSCookie val = (GSCookie)GetTickCount();
544 #endif // !FEATURE_PAL
547 // In _DEBUG, always use the same value to make it easier to search for the cookie
548 val = (GSCookie) WIN64_ONLY(0x9ABCDEF012345678) NOT_WIN64(0x12345678);
551 // To test if it is initialized. Also for ICorMethodInfo::getGSCookie()
556 if(!ClrVirtualProtect((LPVOID)pGSCookiePtr, sizeof(GSCookie), oldProtection, &oldProtection))
562 Volatile<BOOL> g_bIsGarbageCollectorFullyInitialized = FALSE;
564 void SetGarbageCollectorFullyInitialized()
566 LIMITED_METHOD_CONTRACT;
568 g_bIsGarbageCollectorFullyInitialized = TRUE;
571 // Tells whether the garbage collector is fully initialized
572 // Stronger than IsGCHeapInitialized
573 BOOL IsGarbageCollectorFullyInitialized()
575 LIMITED_METHOD_CONTRACT;
577 return g_bIsGarbageCollectorFullyInitialized;
580 // ---------------------------------------------------------------------------
581 // %%Function: EEStartupHelper
584 // fFlags - Initialization flags for the engine. See the
585 // EEStartupFlags enumerator for valid values.
591 // Reserved to initialize the EE runtime engine explicitly.
592 // ---------------------------------------------------------------------------
594 #ifndef IfFailGotoLog
595 #define IfFailGotoLog(EXPR, LABEL) \
599 STRESS_LOG2(LF_STARTUP, LL_ALWAYS, "%s failed with code %x", #EXPR, hr);\
603 STRESS_LOG1(LF_STARTUP, LL_ALWAYS, "%s completed", #EXPR);\
608 #define IfFailGoLog(EXPR) IfFailGotoLog(EXPR, ErrExit)
612 #ifndef CROSSGEN_COMPILE
614 void EESocketCleanupHelper()
622 // Close the debugger transport socket first
623 if (g_pDebugInterface != NULL)
625 g_pDebugInterface->CleanupTransportSocket();
628 // Close the diagnostic server socket.
629 #ifdef FEATURE_PERFTRACING
630 DiagnosticServer::Shutdown();
631 #endif // FEATURE_PERFTRACING
633 #endif // FEATURE_PAL
634 #endif // CROSSGEN_COMPILE
636 void EEStartupHelper(COINITIEE fFlags)
645 #ifdef ENABLE_CONTRACTS_IMPL
647 extern void ContractRegressionCheck();
648 ContractRegressionCheck();
653 static ConfigDWORD breakOnEELoad;
658 #ifndef CROSSGEN_COMPILE
661 ::SetConsoleCtrlHandler(DbgCtrlCHandler, TRUE/*add*/);
664 #endif // CROSSGEN_COMPILE
666 // SString initialization
667 // This needs to be done before config because config uses SString::Empty()
670 IfFailGo(EEConfig::Setup());
672 #ifndef CROSSGEN_COMPILE
673 // Initialize Numa and CPU group information
674 // Need to do this as early as possible. Used by creating object handle
675 // table inside Ref_Initialization() before GC is initialized.
676 NumaNodeInfo::InitNumaNodeInfo();
678 CPUGroupInfo::EnsureInitialized();
679 #endif // !FEATURE_PAL
681 // Initialize global configuration settings based on startup flags
682 // This needs to be done before the EE has started
683 InitializeStartupFlags();
685 MethodDescBackpatchInfoTracker::StaticInitialize();
688 STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "Returned successfully from InitThreadManager");
690 #ifdef FEATURE_PERFTRACING
691 // Initialize the event pipe.
692 EventPipe::Initialize();
694 #endif // FEATURE_PERFTRACING
697 PAL_SetShutdownCallback(EESocketCleanupHelper);
698 #endif // FEATURE_PAL
700 #ifdef FEATURE_GDBJIT
702 NotifyGdb::Initialize();
703 #endif // FEATURE_GDBJIT
705 #ifdef FEATURE_EVENT_TRACE
706 // Initialize event tracing early so we can trace CLR startup time events.
707 InitializeEventTracing();
709 // Fire the EE startup ETW event
710 ETWFireEvent(EEStartupStart_V1);
711 #endif // FEATURE_EVENT_TRACE
717 #endif // CROSSGEN_COMPILE
721 if (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLog, g_pConfig->StressLog ()) != 0) {
722 unsigned facilities = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogFacility, LF_ALL);
723 unsigned level = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_LogLevel, LL_INFO1000);
724 unsigned bytesPerThread = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLogSize, STRESSLOG_CHUNK_SIZE * 4);
725 unsigned totalBytes = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_TotalStressLogSize, STRESSLOG_CHUNK_SIZE * 1024);
726 StressLog::Initialize(facilities, level, bytesPerThread, totalBytes, GetModuleInst());
727 g_pStressLog = &StressLog::theLog;
735 #ifdef ENABLE_PERF_LOG
736 PerfLog::PerfLogInitialize();
737 #endif //ENABLE_PERF_LOG
739 #ifdef FEATURE_PERFMAP
740 PerfMap::Initialize();
743 STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "===================EEStartup Starting===================");
745 #ifndef CROSSGEN_COMPILE
747 IfFailGoLog(EnsureRtlFunctions());
748 #endif // !FEATURE_PAL
753 // Initialize the general Assembly Binder infrastructure
754 IfFailGoLog(CCoreCLRBinderHelper::Init());
756 if (g_pConfig != NULL)
758 IfFailGoLog(g_pConfig->sync());
761 // Fire the runtime information ETW event
762 ETW::InfoLog::RuntimeInformation(ETW::InfoLog::InfoStructs::Normal);
764 if (breakOnEELoad.val(CLRConfig::UNSUPPORTED_BreakOnEELoad) == 1)
767 _ASSERTE(!"Start loading EE!");
773 #ifdef ENABLE_STARTUP_DELAY
774 PREFIX_ASSUME(NULL != g_pConfig);
775 if (g_pConfig->StartupDelayMS())
777 ClrSleepEx(g_pConfig->StartupDelayMS(), FALSE);
782 if ((g_pConfig->GetGCStressLevel() & (EEConfig::GCSTRESS_INSTR_JIT | EEConfig::GCSTRESS_INSTR_NGEN)) != 0)
784 Disassembler::StaticInitialize();
785 if (!Disassembler::IsAvailable())
787 fprintf(stderr, "External disassembler is not available.\n");
791 #endif // USE_DISASSEMBLER
793 // Monitors, Crsts, and SimpleRWLocks all use the same spin heuristics
794 // Cache the (potentially user-overridden) values now so they are accessible from asm routines
795 InitializeSpinConstants();
797 #ifndef CROSSGEN_COMPILE
799 // Cross-process named objects are not supported in PAL
800 // (see CorUnix::InternalCreateEvent - src/pal/src/synchobj/event.cpp.272)
801 #if !defined(FEATURE_PAL)
802 // Initialize the sweeper thread.
803 if (g_pConfig->GetZapBBInstr() != NULL)
806 HANDLE hBBSweepThread = ::CreateThread(NULL,
808 (LPTHREAD_START_ROUTINE) BBSweepStartFunction,
812 _ASSERTE(hBBSweepThread);
813 g_BBSweep.SetBBSweepThreadHandle(hBBSweepThread);
815 #endif // FEATURE_PAL
817 #ifdef FEATURE_INTERPRETER
818 Interpreter::Initialize();
819 #endif // FEATURE_INTERPRETER
821 StubManager::InitializeStubManagers();
825 // Record mscorwks geometry
826 PEDecoder pe(g_pMSCorEE);
828 g_runtimeLoadedBaseAddress = (SIZE_T)pe.GetBase();
829 g_runtimeVirtualSize = (SIZE_T)pe.GetVirtualSize();
830 InitCodeAllocHint(g_runtimeLoadedBaseAddress, g_runtimeVirtualSize, GetRandomInt(64));
832 #endif // !FEATURE_PAL
834 #endif // CROSSGEN_COMPILE
836 // Set up the cor handle map. This map is used to load assemblies in
837 // memory instead of using the normal system load
840 AccessCheckOptions::Startup();
842 MscorlibBinder::Startup();
845 StubLinkerCPU::Init();
847 #ifndef CROSSGEN_COMPILE
849 InitializeGarbageCollector();
851 // Initialize remoting
853 if (!GCHandleUtilities::GetGCHandleManager()->Initialize())
855 IfFailGo(E_OUTOFMEMORY);
858 g_pEEShutDownEvent = new CLREvent();
859 g_pEEShutDownEvent->CreateManualEvent(FALSE);
861 VirtualCallStubManager::InitStatic();
863 GCInterface::m_MemoryPressureLock.Init(CrstGCMemoryPressure);
865 #endif // CROSSGEN_COMPILE
867 // Setup the domains. Threads are started in a default domain.
869 // Static initialization
870 PEAssembly::Attach();
871 BaseDomain::Attach();
872 SystemDomain::Attach();
874 // Start up the EE intializing all the global variables
879 ExecutionManager::Init();
883 #ifndef CROSSGEN_COMPILE
886 if (!RegisterOutOfProcessWatsonCallbacks())
890 #endif // !FEATURE_PAL
892 #ifdef DEBUGGING_SUPPORTED
895 // Initialize the debugging services. This must be done before any
896 // EE thread objects are created, and before any classes or
897 // modules are loaded.
898 InitializeDebugger(); // throws on error
900 #endif // DEBUGGING_SUPPORTED
902 #ifdef PROFILING_SUPPORTED
903 // Initialize the profiling services.
904 hr = ProfilingAPIUtility::InitializeProfiling();
906 _ASSERTE(SUCCEEDED(hr));
908 #endif // PROFILING_SUPPORTED
910 InitializeExceptionHandling();
913 // Install our global exception filter
915 if (!InstallUnhandledExceptionFilter())
923 #ifdef DEBUGGING_SUPPORTED
924 // Notify debugger once the first thread is created to finish initialization.
925 if (g_pDebugInterface != NULL)
927 g_pDebugInterface->StartupPhase2(GetThread());
931 InitPreStubManager();
933 #ifdef FEATURE_COMINTEROP
934 InitializeComInterop();
935 #endif // FEATURE_COMINTEROP
939 // Before setting up the execution manager initialize the first part
940 // of the JIT helpers.
944 SyncBlockCache::Attach();
946 // Set up the sync block
947 SyncBlockCache::Start();
949 StackwalkCache::Init();
951 // This isn't done as part of InitializeGarbageCollector() above because it
952 // requires write barriers to have been set up on x86, which happens as part
953 // of InitJITHelpers1.
954 hr = g_pGCHeap->Initialize();
957 // This isn't done as part of InitializeGarbageCollector() above because thread
958 // creation requires AppDomains to have been set up.
959 FinalizerThread::FinalizerThreadCreate();
961 // Now we really have fully initialized the garbage collector
962 SetGarbageCollectorFullyInitialized();
964 #ifdef DEBUGGING_SUPPORTED
965 // Make a call to publish the DefaultDomain for the debugger
966 // This should be done before assemblies/modules are loaded into it (i.e. SystemDomain::Init)
967 // and after its OK to switch GC modes and syncronize for sending events to the debugger.
968 // @dbgtodo synchronization: this can probably be simplified in V3
969 LOG((LF_CORDB | LF_SYNC | LF_STARTUP, LL_INFO1000, "EEStartup: adding default domain 0x%x\n",
970 SystemDomain::System()->DefaultDomain()));
971 SystemDomain::System()->PublishAppDomainAndInformDebugger(SystemDomain::System()->DefaultDomain());
974 #endif // CROSSGEN_COMPILE
976 SystemDomain::System()->Init();
978 #ifdef PROFILING_SUPPORTED
979 // <TODO>This is to compensate for the DefaultDomain workaround contained in
980 // SystemDomain::Attach in which the first user domain is created before profiling
981 // services can be initialized. Profiling services cannot be moved to before the
982 // workaround because it needs SetupThread to be called.</TODO>
984 SystemDomain::NotifyProfilerStartup();
985 #endif // PROFILING_SUPPORTED
989 SystemDomain::System()->DefaultDomain()->LoadSystemAssemblies();
991 SystemDomain::System()->DefaultDomain()->SetupSharedStatics();
994 APIThreadStress::SetThreadStressCount(g_pConfig->GetAPIThreadStressCount());
996 #ifdef FEATURE_STACK_SAMPLING
997 StackSampler::Init();
1000 #ifndef CROSSGEN_COMPILE
1001 if (!NingenEnabled())
1003 // Perform any once-only SafeHandle initialization.
1007 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1008 // retrieve configured max size for the mini-metadata buffer (defaults to 64KB)
1009 g_MiniMetaDataBuffMaxSize = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MiniMdBufferCapacity);
1010 // align up to GetOsPageSize(), with a maximum of 1 MB
1011 g_MiniMetaDataBuffMaxSize = (DWORD) min(ALIGN_UP(g_MiniMetaDataBuffMaxSize, GetOsPageSize()), 1024 * 1024);
1012 // allocate the buffer. this is never touched while the process is running, so it doesn't
1013 // contribute to the process' working set. it is needed only as a "shadow" for a mini-metadata
1014 // buffer that will be set up and reported / updated in the Watson process (the
1015 // DacStreamsManager class coordinates this)
1016 g_MiniMetaDataBuffAddress = (TADDR) ClrVirtualAlloc(NULL,
1017 g_MiniMetaDataBuffMaxSize, MEM_COMMIT, PAGE_READWRITE);
1018 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1020 #endif // CROSSGEN_COMPILE
1022 g_fEEStarted = TRUE;
1023 #ifndef CROSSGEN_COMPILE
1024 #ifdef FEATURE_PERFTRACING
1025 DiagnosticServer::Initialize();
1028 g_EEStartupStatus = S_OK;
1030 STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "===================EEStartup Completed===================");
1032 #ifndef CROSSGEN_COMPILE
1036 //if g_fEEStarted was false when we loaded the System Module, we did not run ExpandAll on it. In
1037 //this case, make sure we run ExpandAll here. The rationale is that if we Jit before g_fEEStarted
1038 //is true, we can't initialize Com, so we can't jit anything that uses Com types. Also, it's
1039 //probably not safe to Jit while g_fEEStarted is false.
1041 //Also, if you run this it's possible we'll call CoInitialize, which defaults to MTA. This might
1042 //mess up an application that uses STA. However, this mode is only supported for certain limited
1043 //jit testing scenarios, so it can live with the limitation.
1044 if (g_pConfig->ExpandModulesOnLoad())
1046 SystemDomain::SystemModule()->ExpandAll();
1049 // Perform mscorlib consistency check if requested
1050 g_Mscorlib.CheckExtended();
1058 #endif // !CROSSGEN_COMPILE
1064 #ifdef CROSSGEN_COMPILE
1065 // for minimal impact we won't update hr for regular builds
1066 hr = GET_EXCEPTION()->GetHR();
1067 _ASSERTE(FAILED(hr));
1068 StackSString exceptionMessage;
1069 GET_EXCEPTION()->GetMessage(exceptionMessage);
1070 fprintf(stderr, "%S\n", exceptionMessage.GetUnicode());
1071 #endif // CROSSGEN_COMPILE
1073 EX_END_CATCH(RethrowTerminalExceptionsWithInitCheck)
1075 if (!g_fEEStarted) {
1082 g_EEStartupStatus = hr;
1085 if (breakOnEELoad.val(CLRConfig::UNSUPPORTED_BreakOnEELoad) == 2)
1088 _ASSERTE(!"Done loading EE!");
1096 LONG FilterStartupException(PEXCEPTION_POINTERS p, PVOID pv)
1103 PRECONDITION(CheckPointer(p));
1104 PRECONDITION(CheckPointer(pv));
1107 g_EEStartupStatus = (HRESULT)p->ExceptionRecord->ExceptionInformation[0];
1109 // Make sure we got a failure code in this case
1110 if (!FAILED(g_EEStartupStatus))
1111 g_EEStartupStatus = E_FAIL;
1113 // Initializations has failed so reset the g_fEEInit flag.
1116 if (p->ExceptionRecord->ExceptionCode == BOOTUP_EXCEPTION_COMPLUS)
1118 // Don't ever handle the exception in a checked build
1120 return EXCEPTION_EXECUTE_HANDLER;
1124 return EXCEPTION_CONTINUE_SEARCH;
1127 // EEStartup is responsible for all the one time intialization of the runtime. Some of the highlights of
1128 // what it does include
1129 // * Creates the default and shared, appdomains.
1130 // * Loads mscorlib.dll and loads up the fundamental types (System.Object ...)
1132 // see code:EEStartup#TableOfContents for more on the runtime in general.
1133 // see code:#EEShutdown for a analagous routine run during shutdown.
1135 HRESULT EEStartup(COINITIEE fFlags)
1137 // Cannot use normal contracts here because of the PAL_TRY.
1138 STATIC_CONTRACT_NOTHROW;
1140 _ASSERTE(!g_fEEStarted && !g_fEEInit && SUCCEEDED (g_EEStartupStatus));
1142 PAL_TRY(COINITIEE *, pfFlags, &fFlags)
1144 #ifndef CROSSGEN_COMPILE
1145 InitializeClrNotifications();
1147 InitializeJITNotificationTable();
1148 DacGlobals::Initialize();
1150 #endif // CROSSGEN_COMPILE
1152 EEStartupHelper(*pfFlags);
1154 PAL_EXCEPT_FILTER (FilterStartupException)
1156 // The filter should have set g_EEStartupStatus to a failure HRESULT.
1157 _ASSERTE(FAILED(g_EEStartupStatus));
1161 return g_EEStartupStatus;
1165 #ifndef CROSSGEN_COMPILE
1167 #ifdef FEATURE_COMINTEROP
1169 void InnerCoEEShutDownCOM()
1178 static LONG AlreadyDone = -1;
1180 if (g_fEEStarted != TRUE)
1183 if (FastInterlockIncrement(&AlreadyDone) != 0)
1186 g_fShutDownCOM = true;
1188 // Release IJupiterGCMgr *
1189 RCWWalker::OnEEShutdown();
1191 // Release all of the RCWs in all contexts in all caches.
1192 ReleaseRCWsInCaches(NULL);
1195 // Cleanup cached factory pointer in SynchronizationContextNative
1196 SynchronizationContextNative::Cleanup();
1200 #endif // FEATURE_COMINTEROP
1202 // ---------------------------------------------------------------------------
1203 // %%Function: ForceEEShutdown()
1205 // Description: Force the EE to shutdown now.
1207 // Note: returns when sca is SCA_ReturnWhenShutdownComplete.
1208 // ---------------------------------------------------------------------------
1209 void ForceEEShutdown(ShutdownCompleteAction sca)
1211 WRAPPER_NO_CONTRACT;
1213 // Don't bother to take the lock for this case.
1215 STRESS_LOG0(LF_STARTUP, INFO3, "EEShutdown invoked from ForceEEShutdown");
1216 EEPolicy::HandleExitProcess(sca);
1219 static bool WaitForEndOfShutdown_OneIteration()
1227 // We are shutting down. GC triggers does not have any effect now.
1228 CONTRACT_VIOLATION(GCViolation);
1230 // If someone calls EEShutDown while holding OS loader lock, the thread we created for shutdown
1231 // won't start running. This is a deadlock we can not fix. Instead, we timeout and continue the
1233 DWORD timeout = GetEEPolicy()->GetTimeout(OPR_ProcessExit);
1235 ULONGLONG endTime = CLRGetTickCount64() + timeout;
1240 ULONGLONG curTime = CLRGetTickCount64();
1241 if (curTime > endTime)
1247 #ifdef PROFILING_SUPPORTED
1248 if (CORProfilerPresent())
1250 // A profiler is loaded, so just wait without timeout. This allows
1251 // profilers to complete potentially lengthy post processing, without the
1252 // CLR killing them off first. The Office team's server memory profiler,
1253 // for example, does a lot of post-processing that can exceed the 80
1254 // second imit we normally impose here. The risk of waiting without
1255 // timeout is that, if there really is a deadlock, shutdown will hang.
1256 // Since that will only happen if a profiler is loaded, that is a
1257 // reasonable compromise
1261 #endif //PROFILING_SUPPORTED
1263 timeout = static_cast<DWORD>(endTime - curTime);
1265 DWORD status = g_pEEShutDownEvent->Wait(timeout,TRUE);
1266 if (status == WAIT_OBJECT_0 || status == WAIT_TIMEOUT)
1279 EX_END_CATCH(SwallowAllExceptions);
1283 void WaitForEndOfShutdown()
1291 // We are shutting down. GC triggers does not have any effect now.
1292 CONTRACT_VIOLATION(GCViolation);
1294 Thread *pThread = GetThread();
1295 // After a thread is blocked in WaitForEndOfShutdown, the thread should not enter runtime again,
1296 // and block at WaitForEndOfShutdown again.
1299 _ASSERTE(!pThread->HasThreadStateNC(Thread::TSNC_BlockedForShutdown));
1300 pThread->SetThreadStateNC(Thread::TSNC_BlockedForShutdown);
1303 while (!WaitForEndOfShutdown_OneIteration());
1306 // ---------------------------------------------------------------------------
1307 // Function: EEShutDownHelper(BOOL fIsDllUnloading)
1309 // The real meat of shut down happens here. See code:#EEShutDown for details, including
1310 // what fIsDllUnloading means.
1312 void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
1321 // Used later for a callback.
1324 if (fIsDllUnloading)
1326 // The process is detaching, so set the global state.
1327 // This is used to get around FreeLibrary problems.
1328 g_fProcessDetach = true;
1330 ETW::EnumerationLog::ProcessShutdown();
1333 #ifdef FEATURE_PERFTRACING
1334 if (!fIsDllUnloading)
1336 EventPipe::Shutdown();
1337 DiagnosticServer::Shutdown();
1339 #endif // FEATURE_PERFTRACING
1341 #if defined(FEATURE_COMINTEROP)
1342 // Get the current thread.
1343 Thread * pThisThread = GetThread();
1346 if (IsDbgHelperSpecialThread())
1348 // Our debugger helper thread does not allow Thread object to be set up.
1349 // We should not run shutdown code on debugger helper thread.
1350 _ASSERTE(fIsDllUnloading);
1355 // stop API thread stress
1356 APIThreadStress::SetThreadStressCount(0);
1359 STRESS_LOG1(LF_STARTUP, LL_INFO10, "EEShutDown entered unloading = %d", fIsDllUnloading);
1363 _ASSERTE(!"An assert was hit before EE Shutting down");
1365 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnEEShutdown))
1366 _ASSERTE(!"Shutting down EE!");
1369 #ifdef DEBUGGING_SUPPORTED
1370 // This is a nasty, terrible, horrible thing. If we're being
1371 // called from our DLL main, then the odds are good that our DLL
1372 // main has been called as the result of some person calling
1373 // ExitProcess. That rips the debugger helper thread away very
1374 // ungracefully. This check is an attempt to recognize that case
1375 // and avoid the impending hang when attempting to get the helper
1376 // thread to do things for us.
1377 if ((g_pDebugInterface != NULL) && g_fProcessDetach)
1378 g_pDebugInterface->EarlyHelperThreadDeath();
1379 #endif // DEBUGGING_SUPPORTED
1383 ClrFlsSetThreadType(ThreadType_Shutdown);
1385 if (fIsDllUnloading && g_fEEShutDown)
1387 // I'm in the final shutdown and the first part has already been run.
1391 // Indicate the EE is the shut down phase.
1392 g_fEEShutDown |= ShutDown_Start;
1394 // Terminate the BBSweep thread
1395 g_BBSweep.ShutdownBBSweepThread();
1397 if (!g_fProcessDetach && !g_fFastExitProcess)
1399 g_fEEShutDown |= ShutDown_Finalize1;
1401 // Wait for the finalizer thread to deliver process exit event
1403 FinalizerThread::RaiseShutdownEvents();
1406 // Ok. Let's stop the EE.
1407 if (!g_fProcessDetach)
1409 // Convert key locks into "shutdown" mode. A lock in shutdown mode means:
1410 // - Only the finalizer/helper/shutdown threads will be able to take the the lock.
1411 // - Any other thread that tries takes it will just get redirected to an endless WaitForEndOfShutdown().
1413 // The only managed code that should run after this point is the finalizers for shutdown.
1414 // We convert locks needed for running + debugging such finalizers. Since such locks may need to be
1415 // juggled between multiple threads (finalizer/helper/shutdown), no single thread can take the
1416 // lock and not give it up.
1418 // Each lock needs its own shutdown flag (they can't all be converted at once).
1419 // To avoid deadlocks, we need to convert locks in order of crst level (biggest first).
1421 // Notify the debugger that we're going into shutdown to convert debugger-lock to shutdown.
1422 if (g_pDebugInterface != NULL)
1424 g_pDebugInterface->LockDebuggerForShutdown();
1427 // This call will convert the ThreadStoreLock into "shutdown" mode, just like the debugger lock above.
1428 g_fEEShutDown |= ShutDown_Finalize2;
1431 #ifdef FEATURE_EVENT_TRACE
1432 // Flush managed object allocation logging data.
1433 // We do this after finalization is complete and returning threads have been trapped, so that
1434 // no there will be no more managed allocations and no more GCs which will manipulate the
1435 // allocation sampling data structures.
1436 ETW::TypeSystemLog::FlushObjectAllocationEvents();
1437 #endif // FEATURE_EVENT_TRACE
1439 #ifdef FEATURE_PERFMAP
1440 // Flush and close the perf map file.
1445 // If we're doing basic block profiling, we need to write the log files to disk.
1446 static BOOL fIBCLoggingDone = FALSE;
1447 if (!fIBCLoggingDone)
1449 if (g_IBCLogger.InstrEnabled())
1451 Thread * pThread = GetThread();
1452 ThreadLocalIBCInfo* pInfo = pThread->GetIBCInfo();
1454 // Acquire the Crst lock before creating the IBCLoggingDisabler object.
1455 // Only one thread at a time can be processing an IBC logging event.
1456 CrstHolder lock(IBCLogger::GetSync());
1458 IBCLoggingDisabler disableLogging( pInfo ); // runs IBCLoggingDisabler::DisableLogging
1460 CONTRACT_VIOLATION(GCViolation);
1461 Module::WriteAllModuleProfileData(true);
1464 fIBCLoggingDone = TRUE;
1468 ceeInf.JitProcessShutdownWork(); // Do anything JIT-related that needs to happen at shutdown.
1470 #ifdef FEATURE_INTERPRETER
1471 // This will check a flag and do nothing if not enabled.
1472 Interpreter::PrintPostMortemData();
1473 #endif // FEATURE_INTERPRETER
1475 #ifdef PROFILING_SUPPORTED
1476 // If profiling is enabled, then notify of shutdown first so that the
1477 // profiler can make any last calls it needs to. Do this only if we
1478 // are not detaching
1480 // NOTE: We haven't stopped other threads at this point and nothing is stopping
1481 // callbacks from coming into the profiler even after Shutdown() has been called.
1482 // See https://github.com/dotnet/coreclr/issues/22176 for an example of how that
1485 // To prevent issues when profilers are attached we intentionally skip freeing the
1486 // profiler here. Since there is no guarantee that the profiler won't be accessed after
1487 // we free it (e.g. through callbacks or ELT hooks), we can't safely free the profiler.
1488 if (CORProfilerPresent())
1490 // Don't call back in to the profiler if we are being torn down, it might be unloaded
1491 if (!fIsDllUnloading)
1493 BEGIN_PIN_PROFILER(CORProfilerPresent());
1495 g_profControlBlock.pProfInterface->Shutdown();
1499 g_fEEShutDown |= ShutDown_Profiler;
1501 #endif // PROFILING_SUPPORTED
1505 g_fEEShutDown |= ShutDown_SyncBlock;
1508 // From here on out we might call stuff that violates mode requirements, but we ignore these
1509 // because we are shutting down.
1510 CONTRACT_VIOLATION(ModeViolation);
1512 #ifdef FEATURE_COMINTEROP
1513 // We need to call CoUninitialize in part one to ensure orderly shutdown of COM dlls.
1514 if (!g_fFastExitProcess)
1516 if (pThisThread!= NULL)
1518 pThisThread->CoUninitialize();
1521 #endif // FEATURE_COMINTEROP
1524 // This is the end of Part 1.
1527 // If process shutdown is in progress and Crst locks to be used in shutdown phase 2
1528 // are already in use, then skip phase 2. This will happen only when those locks
1529 // are orphaned. In Vista, the penalty for attempting to enter such locks is
1530 // instant process termination.
1531 if (g_fProcessDetach)
1533 // The assert below is a bit too aggresive and has generally brought cases that have been race conditions
1534 // and not easily reproed to validate a bug. A typical race scenario is when there are two threads,
1535 // T1 and T2, with T2 having taken a lock (e.g. SystemDomain lock), the OS terminates
1536 // T2 for some reason. Later, when we enter the shutdown thread, we would assert on such
1537 // a lock leak, but there is not much we can do since the OS wont notify us prior to thread
1538 // termination. And this is not even a user bug.
1540 // Converting it to a STRESS LOG to reduce noise, yet keep things in radar if they need
1541 // to be investigated.
1542 //_ASSERTE_MSG(g_ShutdownCrstUsageCount == 0, "Some locks to be taken during shutdown may already be orphaned!");
1543 if (g_ShutdownCrstUsageCount > 0)
1545 STRESS_LOG0(LF_STARTUP, LL_INFO10, "Some locks to be taken during shutdown may already be orphaned!");
1551 CONTRACT_VIOLATION(ModeViolation);
1553 // On the new plan, we only do the tear-down under the protection of the loader
1554 // lock -- after the OS has stopped all other threads.
1555 if (fIsDllUnloading && (g_fEEShutDown & ShutDown_Phase2) == 0)
1557 g_fEEShutDown |= ShutDown_Phase2;
1559 // Shutdown finalizer before we suspend all background threads. Otherwise we
1560 // never get to finalize anything. Obviously.
1564 _ASSERTE(!"An assert was hit After Finalizer run");
1567 // No longer process exceptions
1568 g_fNoExceptions = true;
1571 // Remove our global exception filter. If it was NULL before, we want it to be null now.
1573 UninstallUnhandledExceptionFilter();
1575 // <TODO>@TODO: This does things which shouldn't occur in part 2. Namely,
1576 // calling managed dll main callbacks (AppDomain::SignalProcessDetach), and
1577 // RemoveAppDomainFromIPC.
1579 // (If we move those things to earlier, this can be called only if fShouldWeCleanup.)</TODO>
1580 if (!g_fFastExitProcess)
1582 SystemDomain::DetachBegin();
1586 #ifdef DEBUGGING_SUPPORTED
1587 // Terminate the debugging services.
1588 TerminateDebugger();
1589 #endif // DEBUGGING_SUPPORTED
1591 StubManager::TerminateStubManagers();
1593 #ifdef FEATURE_INTERPRETER
1594 Interpreter::Terminate();
1595 #endif // FEATURE_INTERPRETER
1597 //@TODO: find the right place for this
1598 VirtualCallStubManager::UninitStatic();
1600 #ifdef ENABLE_PERF_LOG
1601 PerfLog::PerfLogDone();
1602 #endif //ENABLE_PERF_LOG
1604 // Unregister our vectored exception and continue handlers from the OS.
1605 // This will ensure that if any other DLL unload (after ours) has an exception,
1606 // we wont attempt to process that exception (which could lead to various
1607 // issues including AV in the runtime).
1609 // This should be done:
1611 // 1) As the last action during the shutdown so that any unexpected AVs
1612 // in the runtime during shutdown do result in FailFast in VEH.
1614 // 2) Only when the runtime is processing DLL_PROCESS_DETACH.
1615 CLRRemoveVectoredHandlers();
1617 #if USE_DISASSEMBLER
1618 Disassembler::StaticClose();
1619 #endif // USE_DISASSEMBLER
1623 _ASSERTE(!"EE Shutting down after an assert");
1628 extern unsigned FcallTimeHist[11];
1630 LOG((LF_STUBS, LL_INFO10, "FcallHist %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
1631 FcallTimeHist[0], FcallTimeHist[1], FcallTimeHist[2], FcallTimeHist[3],
1632 FcallTimeHist[4], FcallTimeHist[5], FcallTimeHist[6], FcallTimeHist[7],
1633 FcallTimeHist[8], FcallTimeHist[9], FcallTimeHist[10]));
1635 WriteJitHelperCountToSTRESSLOG();
1637 STRESS_LOG0(LF_STARTUP, LL_INFO10, "EEShutdown shutting down logging");
1639 #if 0 // Dont clean up the stress log, so that even at process exit we have a log (after all the process is going away
1640 if (!g_fFastExitProcess)
1641 StressLog::Terminate(TRUE);
1655 EX_END_CATCH(SwallowAllExceptions);
1657 ClrFlsClearThreadType(ThreadType_Shutdown);
1658 if (!g_fProcessDetach)
1660 g_pEEShutDownEvent->Set();
1665 #ifdef FEATURE_COMINTEROP
1667 BOOL IsThreadInSTA()
1677 // If ole32.dll is not loaded
1678 if (WszGetModuleHandle(W("ole32.dll")) == NULL)
1684 // To be conservative, check if finalizer thread is around
1687 Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
1688 if (!pFinalizerThread || pFinalizerThread->Join(0, FALSE) != WAIT_TIMEOUT)
1696 EX_END_CATCH(SwallowAllExceptions);
1706 hr = GetCurrentThreadTypeNT5(&type);
1709 fInSTA = (type == THDTYPE_PROCESSMESSAGES) ? TRUE : FALSE;
1711 // If we get back THDTYPE_PROCESSMESSAGES, we are guaranteed to
1712 // be an STA thread. If not, we are an MTA thread, however
1713 // we can't know if the thread has been explicitly set to MTA
1714 // (via a call to CoInitializeEx) or if it has been implicitly
1715 // made MTA (if it hasn't been CoInitializeEx'd but CoInitialize
1716 // has already been called on some other thread in the process.
1720 // CoInitialize hasn't been called in the process yet so assume the current thread
1731 // Function: EEShutDown(BOOL fIsDllUnloading)
1734 // BOOL fIsDllUnloading:
1735 // * TRUE => Called from CLR's DllMain (DLL_PROCESS_DETACH). Not safe point for
1737 // * FALSE => Called some other way (e.g., end of the CLR's main). Safe to do
1742 // All ee shutdown stuff should be done here. EEShutDown is generally called in one
1744 // * 1. From code:EEPolicy::HandleExitProcess (via HandleExitProcessHelper), with
1745 // fIsDllUnloading == FALSE. This code path is typically invoked by the CLR's
1746 // main just falling through to the end. Full cleanup can be performed when
1747 // EEShutDown is called this way.
1748 // * 2. From CLR's DllMain (DLL_PROCESS_DETACH), with fIsDllUnloading == TRUE. When
1749 // called this way, much cleanup code is unsafe to run, and is thus skipped.
1751 // Actual shut down logic is factored out to EEShutDownHelper which may be called
1752 // directly by EEShutDown, or indirectly on another thread (see code:#STAShutDown).
1754 // In order that callees may also know the value of fIsDllUnloading, EEShutDownHelper
1755 // sets g_fProcessDetach = fIsDllUnloading, and g_fProcessDetach may then be retrieved
1756 // via code:IsAtProcessExit.
1758 // NOTE 1: Actually, g_fProcessDetach is set to TRUE if fIsDllUnloading is TRUE. But
1759 // g_fProcessDetach doesn't appear to be explicitly set to FALSE. (Apparently
1760 // g_fProcessDetach is implicitly initialized to FALSE as clr.dll is loaded.)
1762 // NOTE 2: EEDllMain(DLL_PROCESS_DETACH) already sets g_fProcessDetach to TRUE, so it
1763 // appears EEShutDownHelper doesn't have to.
1765 void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading)
1771 PRECONDITION(g_fEEStarted);
1774 // If we have not started runtime successfully, it is not safe to call EEShutDown.
1775 if (!g_fEEStarted || g_fFastExitProcess == 2)
1780 // We only do the first part of the shutdown once.
1781 static LONG OnlyOne = -1;
1783 if (!fIsDllUnloading)
1785 if (FastInterlockIncrement(&OnlyOne) != 0)
1787 // I'm in a regular shutdown -- but another thread got here first.
1788 // It's a race if I return from here -- I'll call ExitProcess next, and
1789 // rip things down while the first thread is half-way through a
1790 // nice cleanup. Rather than do that, I should just wait until the
1791 // first thread calls ExitProcess(). I'll die a nice death when that
1793 GCX_PREEMP_NO_DTOR();
1794 WaitForEndOfShutdown();
1798 #ifdef FEATURE_MULTICOREJIT
1799 if (!AppX::IsAppXProcess()) // When running as Appx, make the delayed timer driven writing be the only option
1801 MulticoreJitManager::StopProfileAll();
1809 EEShutDownHelper(fIsDllUnloading);
1813 EEShutDownHelper(fIsDllUnloading);
1817 // ---------------------------------------------------------------------------
1818 // %%Function: IsRuntimeActive()
1826 // Description: Indicates if the runtime is active or not. "Active" implies
1827 // that the runtime has started and is in a position to run
1829 // ---------------------------------------------------------------------------
1830 BOOL IsRuntimeActive()
1832 return (g_fEEStarted);
1835 //*****************************************************************************
1836 BOOL ExecuteDLL_ReturnOrThrow(HRESULT hr, BOOL fFromThunk)
1839 if (fFromThunk) THROWS; else NOTHROW;
1840 WRAPPER(GC_TRIGGERS);
1844 // If we have a failure result, and we're called from a thunk,
1845 // then we need to throw an exception to communicate the error.
1846 if (FAILED(hr) && fFromThunk)
1850 return SUCCEEDED(hr);
1854 // Initialize the Garbage Collector
1857 void InitializeGarbageCollector()
1867 // Build the special Free Object used by the Generational GC
1868 _ASSERT(g_pFreeObjectMethodTable == NULL);
1869 g_pFreeObjectMethodTable = (MethodTable *) new BYTE[sizeof(MethodTable)];
1870 ZeroMemory(g_pFreeObjectMethodTable, sizeof(MethodTable));
1872 // As the flags in the method table indicate there are no pointers
1873 // in the object, there is no gc descriptor, and thus no need to adjust
1874 // the pointer to skip the gc descriptor.
1876 g_pFreeObjectMethodTable->SetBaseSize(ARRAYBASE_BASESIZE);
1877 g_pFreeObjectMethodTable->SetComponentSize(1);
1879 hr = GCHeapUtilities::LoadAndInitialize();
1885 // Apparently the Windows linker removes global variables if they are never
1886 // read from, which is a problem for g_gcDacGlobals since it's expected that
1887 // only the DAC will read from it. This forces the linker to include
1889 volatile void* _dummy = g_gcDacGlobals;
1892 /*****************************************************************************/
1893 /* This is here only so that if we get an exception we stop before we catch it */
1894 LONG DllMainFilter(PEXCEPTION_POINTERS p, PVOID pv)
1896 LIMITED_METHOD_CONTRACT;
1897 _ASSERTE(!"Exception happened in mscorwks!DllMain!");
1898 return EXCEPTION_EXECUTE_HANDLER;
1901 //*****************************************************************************
1902 // This is the part of the old-style DllMain that initializes the
1903 // stuff that the EE team works on. It's called from the real DllMain
1904 // up in MSCOREE land. Separating the DllMain tasks is simply for
1905 // convenience due to the dual build trees.
1906 //*****************************************************************************
1907 BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
1908 HINSTANCE hInst, // Instance handle of the loaded module.
1909 DWORD dwReason, // Reason for loading.
1910 LPVOID lpReserved) // Unused.
1912 STATIC_CONTRACT_NOTHROW;
1913 STATIC_CONTRACT_GC_TRIGGERS;
1916 // BEGIN_EXTERNAL_ENTRYPOINT(&hr);
1917 // EE isn't spun up enough to use this macro
1926 param.hInst = hInst;
1927 param.dwReason = dwReason;
1928 param.lpReserved = lpReserved;
1929 param.pTlsData = NULL;
1931 // Can't use PAL_TRY/EX_TRY here as they access the ClrDebugState which gets blown away as part of the
1932 // PROCESS_DETACH path. Must use special PAL_TRY_FOR_DLLMAIN, passing the reason were in the DllMain.
1933 PAL_TRY_FOR_DLLMAIN(Param *, pParam, ¶m, pParam->dwReason)
1936 switch (pParam->dwReason)
1938 case DLL_PROCESS_ATTACH:
1940 // We cache the SystemInfo for anyone to use throughout the
1942 GetSystemInfo(&g_SystemInfo);
1944 // Remember module instance
1945 g_pMSCorEE = pParam->hInst;
1948 // Set callbacks so that LoadStringRC knows which language our
1949 // threads are in so that it can return the proper localized string.
1950 // TODO: This shouldn't rely on the LCID (id), but only the name
1951 SetResourceCultureCallbacks(GetThreadUICultureNames,
1952 GetThreadUICultureId);
1959 case DLL_PROCESS_DETACH:
1961 // lpReserved is NULL if we're here because someone called FreeLibrary
1962 // and non-null if we're here because the process is exiting.
1963 // Since nobody should ever be calling FreeLibrary on mscorwks.dll, lpReserved
1964 // should always be non NULL.
1965 _ASSERTE(pParam->lpReserved || !g_fEEStarted);
1966 g_fProcessDetach = TRUE;
1970 if (GCHeapUtilities::IsGCInProgress())
1972 g_fEEShutDown |= ShutDown_Phase2;
1976 LOG((LF_STARTUP, INFO3, "EEShutDown invoked from EEDllMain"));
1977 EEShutDown(TRUE); // shut down EE if it was started up
1981 CLRRemoveVectoredHandlers();
1986 case DLL_THREAD_DETACH:
1988 // Don't destroy threads here if we're in shutdown (shutdown will
1989 // clean up for us instead).
1991 // Store the TLS data; we'll need it later and we might NULL the slot in DetachThread.
1992 // This would be problematic because we can't depend on the FLS still existing.
1993 pParam->pTlsData = CExecutionEngine::CheckThreadStateNoCreate(0
1995 // When we get here, OS has destroyed FLS, so FlsGetValue returns NULL now.
1996 // We have validation code in CExecutionEngine::CheckThreadStateNoCreate to ensure that
1997 // our TLS and FLS data are consistent, but since FLS has been destroyed, we need
1998 // to silent the check there. The extra arg for check build is for this purpose.
2002 Thread* thread = GetThread();
2005 #ifdef FEATURE_COMINTEROP
2006 // reset the CoInitialize state
2007 // so we don't call CoUninitialize during thread detach
2008 thread->ResetCoInitialized();
2009 #endif // FEATURE_COMINTEROP
2010 // For case where thread calls ExitThread directly, we need to reset the
2011 // frame pointer. Otherwise stackwalk would AV. We need to do it in cooperative mode.
2012 // We need to set m_GCOnTransitionsOK so this thread won't trigger GC when toggle GC mode
2013 if (thread->m_pFrame != FRAME_TOP)
2016 thread->m_GCOnTransitionsOK = FALSE;
2019 thread->m_pFrame = FRAME_TOP;
2020 GCX_COOP_NO_DTOR_END();
2022 thread->DetachThread(TRUE);
2028 PAL_EXCEPT_FILTER(DllMainFilter)
2033 if (dwReason == DLL_THREAD_DETACH || dwReason == DLL_PROCESS_DETACH)
2035 CExecutionEngine::ThreadDetaching(param.pTlsData);
2040 #ifdef DEBUGGING_SUPPORTED
2042 // InitializeDebugger initialized the Runtime-side COM+ Debugging Services
2044 static void InitializeDebugger(void)
2054 // Ensure that if we throw, we'll call TerminateDebugger to cleanup.
2055 // This makes our Init more atomic by avoiding partially-init states.
2056 class EnsureCleanup {
2061 fNeedCleanup = TRUE;
2064 void SuppressCleanup()
2066 fNeedCleanup = FALSE;
2071 STATIC_CONTRACT_NOTHROW;
2072 STATIC_CONTRACT_GC_NOTRIGGER;
2073 STATIC_CONTRACT_MODE_ANY;
2077 TerminateDebugger();
2084 LOG((LF_CORDB, LL_INFO10, "Initializing left-side debugging services.\n"));
2086 FARPROC gi = (FARPROC) &CorDBGetInterface;
2088 // Init the interface the EE provides to the debugger,
2089 // ask the debugger for its interface, and if all goes
2090 // well call Startup on the debugger.
2091 EEDbgInterfaceImpl::Init();
2092 _ASSERTE(g_pEEDbgInterfaceImpl != NULL); // throws on OOM
2094 // This allocates the Debugger object.
2095 typedef HRESULT __cdecl CORDBGETINTERFACE(DebugInterface**);
2096 hr = ((CORDBGETINTERFACE*)gi)(&g_pDebugInterface);
2099 g_pDebugInterface->SetEEInterface(g_pEEDbgInterfaceImpl);
2102 hr = g_pDebugInterface->Startup(); // throw on error
2103 _ASSERTE(SUCCEEDED(hr));
2106 // If the debug pack is not installed, Startup will return S_FALSE
2107 // and we should cleanup and proceed without debugging support.
2116 LOG((LF_CORDB, LL_INFO10, "Left-side debugging services setup.\n"));
2118 hCleanup.SuppressCleanup();
2125 // TerminateDebugger shuts down the Runtime-side COM+ Debugging Services
2126 // InitializeDebugger will call this if it fails.
2127 // This may be called even if the debugger is partially initialized.
2128 // This can be called multiple times.
2130 static void TerminateDebugger(void)
2140 LOG((LF_CORDB, LL_INFO10, "Shutting down left-side debugger services.\n"));
2142 // If initialized failed really early, then we didn't even get the Debugger object.
2143 if (g_pDebugInterface != NULL)
2145 // Notify the out-of-process debugger that shutdown of the in-process debugging support has begun. This is only
2146 // really used in interop debugging scenarios.
2147 g_pDebugInterface->ShutdownBegun();
2149 // This will kill the helper thread, delete the Debugger object, and free all resources.
2150 g_pDebugInterface->StopDebugger();
2153 g_CORDebuggerControlFlags = DBCF_NORMAL_OPERATION;
2157 #endif // DEBUGGING_SUPPORTED
2159 #ifndef LOCALE_SPARENT
2160 #define LOCALE_SPARENT 0x0000006d
2163 // ---------------------------------------------------------------------------
2164 // Impl for UtilLoadStringRC Callback: In VM, we let the thread decide culture
2165 // copy culture name into szBuffer and return length
2166 // ---------------------------------------------------------------------------
2167 extern BOOL g_fFatalErrorOccuredOnGCThread;
2168 static HRESULT GetThreadUICultureNames(__inout StringArrayList* pCultureNames)
2175 PRECONDITION(CheckPointer(pCultureNames));
2183 InlineSString<LOCALE_NAME_MAX_LENGTH> sCulture;
2184 InlineSString<LOCALE_NAME_MAX_LENGTH> sParentCulture;
2186 #if 0 // Enable and test if/once the unmanaged runtime is localized
2187 Thread * pThread = GetThread();
2189 // When fatal errors have occured our invariants around GC modes may be broken and attempting to transition to co-op may hang
2190 // 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
2191 // getting localized with a non-default thread-specific culture.
2192 // A canonical stack trace that gets here is a fatal error in the GC that comes through:
2193 // coreclr.dll!GetThreadUICultureNames
2194 // coreclr.dll!CCompRC::LoadLibraryHelper
2195 // coreclr.dll!CCompRC::LoadLibrary
2196 // coreclr.dll!CCompRC::GetLibrary
2197 // coreclr.dll!CCompRC::LoadString
2198 // coreclr.dll!CCompRC::LoadString
2199 // coreclr.dll!SString::LoadResourceAndReturnHR
2200 // coreclr.dll!SString::LoadResourceAndReturnHR
2201 // coreclr.dll!SString::LoadResource
2202 // coreclr.dll!EventReporter::EventReporter
2203 // coreclr.dll!EEPolicy::LogFatalError
2204 // coreclr.dll!EEPolicy::HandleFatalError
2205 if (pThread != NULL && !g_fFatalErrorOccuredOnGCThread) {
2207 // Switch to cooperative mode, since we'll be looking at managed objects
2208 // and we don't want them moving on us.
2211 CULTUREINFOBASEREF pCurrentCulture = (CULTUREINFOBASEREF)Thread::GetCulture(TRUE);
2213 if (pCurrentCulture != NULL)
2215 STRINGREF cultureName = pCurrentCulture->GetName();
2217 if (cultureName != NULL)
2219 sCulture.Set(cultureName->GetBuffer(),cultureName->GetStringLength());
2222 CULTUREINFOBASEREF pParentCulture = pCurrentCulture->GetParent();
2224 if (pParentCulture != NULL)
2226 STRINGREF parentCultureName = pParentCulture->GetName();
2228 if (parentCultureName != NULL)
2230 sParentCulture.Set(parentCultureName->GetBuffer(),parentCultureName->GetStringLength());
2238 // If the lazily-initialized cultureinfo structures aren't initialized yet, we'll
2239 // need to do the lookup the hard way.
2240 if (sCulture.IsEmpty() || sParentCulture.IsEmpty())
2243 int tmp; tmp = GetThreadUICultureId(&id); // TODO: We should use the name instead
2244 _ASSERTE(tmp!=0 && id != UICULTUREID_DONTCARE);
2245 SIZE_T cchParentCultureName=LOCALE_NAME_MAX_LENGTH;
2249 if (!::GetLocaleInfoEx((LPCWSTR)sCulture, LOCALE_SPARENT, sParentCulture.OpenUnicodeBuffer(static_cast<COUNT_T>(cchParentCultureName)),static_cast<int>(cchParentCultureName)))
2251 hr = HRESULT_FROM_GetLastError();
2253 sParentCulture.CloseBuffer();
2254 #else // !FEATURE_PAL
2255 sParentCulture = sCulture;
2256 #endif // !FEATURE_PAL
2258 // (LPCWSTR) to restrict the size to null terminated size
2259 pCultureNames->AppendIfNotThere((LPCWSTR)sCulture);
2260 // Disabling for Dev10 for consistency with managed resource lookup (see AppCompat bug notes in ResourceFallbackManager.cs)
2261 // Also, this is in the wrong order - put after the parent culture chain.
2262 //AddThreadPreferredUILanguages(pCultureNames);
2263 pCultureNames->AppendIfNotThere((LPCWSTR)sParentCulture);
2264 pCultureNames->Append(SString::Empty());
2270 EX_END_CATCH(SwallowAllExceptions);
2275 // The exit code for the process is communicated in one of two ways. If the
2276 // entrypoint returns an 'int' we take that. Otherwise we take a latched
2277 // process exit code. This can be modified by the app via System.SetExitCode().
2278 static INT32 LatchedExitCode;
2280 void SetLatchedExitCode (INT32 code)
2290 STRESS_LOG1(LF_SYNC, LL_INFO10, "SetLatchedExitCode = %d\n", code);
2291 LatchedExitCode = code;
2294 INT32 GetLatchedExitCode (void)
2296 LIMITED_METHOD_CONTRACT;
2297 return LatchedExitCode;
2300 // ---------------------------------------------------------------------------
2301 // Impl for UtilLoadStringRC Callback: In VM, we let the thread decide culture
2302 // Return an int uniquely describing which language this thread is using for ui.
2303 // ---------------------------------------------------------------------------
2304 static int GetThreadUICultureId(__out LocaleIDValue* pLocale)
2312 _ASSERTE(sizeof(LocaleIDValue)/sizeof(WCHAR) >= LOCALE_NAME_MAX_LENGTH);
2316 Thread * pThread = GetThread();
2318 #if 0 // Enable and test if/once the unmanaged runtime is localized
2319 // When fatal errors have occured our invariants around GC modes may be broken and attempting to transition to co-op may hang
2320 // 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
2321 // getting localized with a non-default thread-specific culture.
2322 // A canonical stack trace that gets here is a fatal error in the GC that comes through:
2323 // coreclr.dll!GetThreadUICultureNames
2324 // coreclr.dll!CCompRC::LoadLibraryHelper
2325 // coreclr.dll!CCompRC::LoadLibrary
2326 // coreclr.dll!CCompRC::GetLibrary
2327 // coreclr.dll!CCompRC::LoadString
2328 // coreclr.dll!CCompRC::LoadString
2329 // coreclr.dll!SString::LoadResourceAndReturnHR
2330 // coreclr.dll!SString::LoadResourceAndReturnHR
2331 // coreclr.dll!SString::LoadResource
2332 // coreclr.dll!EventReporter::EventReporter
2333 // coreclr.dll!EEPolicy::LogFatalError
2334 // coreclr.dll!EEPolicy::HandleFatalError
2335 if (pThread != NULL && !g_fFatalErrorOccuredOnGCThread)
2338 // Switch to cooperative mode, since we'll be looking at managed objects
2339 // and we don't want them moving on us.
2342 CULTUREINFOBASEREF pCurrentCulture = (CULTUREINFOBASEREF)Thread::GetCulture(TRUE);
2344 if (pCurrentCulture != NULL)
2346 STRINGREF currentCultureName = pCurrentCulture->GetName();
2348 if (currentCultureName != NULL)
2350 int cchCurrentCultureNameResult = currentCultureName->GetStringLength();
2351 if (cchCurrentCultureNameResult < LOCALE_NAME_MAX_LENGTH)
2353 memcpy(*pLocale, currentCultureName->GetBuffer(), cchCurrentCultureNameResult*sizeof(WCHAR));
2354 (*pLocale)[cchCurrentCultureNameResult]='\0';
2355 Result=cchCurrentCultureNameResult;
2364 // This thread isn't set up to use a non-default culture. Let's grab the default
2365 // one and return that.
2367 Result = ::GetUserDefaultLocaleName(*pLocale, LOCALE_NAME_MAX_LENGTH);
2369 _ASSERTE(Result != 0);
2370 #else // !FEATURE_PAL
2371 static const WCHAR enUS[] = W("en-US");
2372 memcpy(*pLocale, enUS, sizeof(enUS));
2373 Result = sizeof(enUS);
2374 #endif // !FEATURE_PAL
2379 #ifdef ENABLE_CONTRACTS_IMPL
2381 // Returns TRUE if any contract violation suppressions are in effect.
2382 BOOL AreAnyViolationBitsOn()
2391 UINT_PTR violationMask = GetClrDebugState()->ViolationMask();
2392 violationMask &= ~((UINT_PTR)CanFreeMe); //CanFreeMe is a borrowed bit and has nothing to do with violations
2393 if (violationMask & ((UINT_PTR)BadDebugState))
2398 return violationMask != 0;
2402 // This function is intentionally invoked inside a big CONTRACT_VIOLATION that turns on every violation
2403 // bit on the map. The dynamic contract at the beginning *should* turn off those violation bits.
2404 // The body of this function tests to see that it did exactly that. This is to prevent the VSWhidbey B#564831 fiasco
2405 // from ever recurring.
2406 void ContractRegressionCheckInner()
2408 // DO NOT TURN THIS CONTRACT INTO A STATIC CONTRACT!!! The very purpose of this function
2409 // is to ensure that dynamic contracts disable outstanding contract violation bits.
2410 // This code only runs once at process startup so it's not going pooch the checked build perf.
2416 LOADS_TYPE(CLASS_LOAD_BEGIN);
2421 if (AreAnyViolationBitsOn())
2423 // If we got here, the contract above FAILED to turn off one or more violation bits. This is a
2424 // huge diagnostics hole and must be fixed immediately.
2425 _ASSERTE(!("WARNING: mscorwks has detected an internal error that may indicate contracts are"
2426 " being silently disabled across the runtime. Do not ignore this assert!"));
2430 // This function executes once per process to ensure our CONTRACT_VIOLATION() mechanism
2431 // is properly scope-limited by nested contracts.
2432 void ContractRegressionCheck()
2443 // DO NOT "FIX" THIS CONTRACT_VIOLATION!!!
2444 // The existence of this CONTRACT_VIOLATION is not a bug. This is debug-only code specifically written
2445 // to test the CONTRACT_VIOLATION mechanism itself. This is needed to prevent a regression of
2446 // B#564831 (which left a huge swath of contracts silently disabled for over six months)
2447 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation
2450 | LoadsTypeViolation
2451 | TakesLockViolation
2452 , ReasonContractInfrastructure
2456 ContractRegressionCheckInner();
2460 if (AreAnyViolationBitsOn())
2462 // If we got here, the CONTRACT_VIOLATION() holder left one or more violation bits turned ON
2463 // after we left its scope. This is a huge diagnostic hole and must be fixed immediately.
2464 _ASSERTE(!("WARNING: mscorwks has detected an internal error that may indicate contracts are"
2465 " being silently disabled across the runtime. Do not ignore this assert!"));
2470 #endif // ENABLE_CONTRACTS_IMPL
2472 #endif // CROSSGEN_COMPILE