[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / clrhost_nodependencies.cpp
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 //
5
6 //
7
8 #include "stdafx.h"
9
10 #include "clrhost.h"
11 #include "utilcode.h"
12 #include "ex.h"
13 #include "hostimpl.h"
14 #include "clrnt.h"
15 #include "contract.h"
16
17 #if defined __llvm__
18 #  if defined(__has_feature) && __has_feature(address_sanitizer)
19 #    define HAS_ADDRESS_SANITIZER
20 #  endif
21 #endif
22
23 #ifdef _DEBUG_IMPL
24
25 //
26 // I'd very much like for this to go away. Its used to disable all THROWS contracts within whatever DLL this
27 // function is called from. That's obviously very, very bad, since there's no validation of those macros. But it
28 // can be difficult to remove this without actually fixing every violation at the same time.
29 //
30 // When this flag is finally removed, remove RealCLRThrowsExceptionWorker() too and put CONTRACT_THROWS() in place
31 // of it.
32 //
33 //
34 static BOOL dbg_fDisableThrowCheck = FALSE;
35
36 void DisableThrowCheck()
37 {
38     LIMITED_METHOD_CONTRACT;
39
40     dbg_fDisableThrowCheck = TRUE;
41 }
42
43 #ifdef HAS_ADDRESS_SANITIZER
44 // use the functionality from address santizier (which does not throw exceptions)
45 #else
46
47 #define CLRThrowsExceptionWorker() RealCLRThrowsExceptionWorker(__FUNCTION__, __FILE__, __LINE__)
48
49 static void RealCLRThrowsExceptionWorker(__in_z const char *szFunction,
50                                          __in_z const char *szFile,
51                                          int lineNum)
52 {
53     WRAPPER_NO_CONTRACT;
54
55     if (dbg_fDisableThrowCheck)
56     {
57         return;
58     }
59
60     CONTRACT_THROWSEX(szFunction, szFile, lineNum);
61 }
62
63 #endif // HAS_ADDRESS_SANITIZER
64 #endif //_DEBUG_IMPL
65
66 #if defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
67
68 // Fls callback to deallocate ClrDebugState when our FLS block goes away.
69 void FreeClrDebugState(LPVOID pTlsData)
70 {
71 #ifdef _DEBUG
72     ClrDebugState *pClrDebugState = (ClrDebugState*)pTlsData;
73
74     // Make sure the ClrDebugState was initialized by a compatible version of
75     // utilcode.lib. If it was initialized by an older version, we just let it leak.
76     if (pClrDebugState && (pClrDebugState->ViolationMask() & CanFreeMe) && !(pClrDebugState->ViolationMask() & BadDebugState))
77     {
78 #undef HeapFree
79 #undef GetProcessHeap
80         
81         // Since "!(pClrDebugState->m_violationmask & BadDebugState)", we know we have
82         // a valid m_pLockData
83         _ASSERTE(pClrDebugState->GetDbgStateLockData() != NULL);
84         ::HeapFree (GetProcessHeap(), 0, pClrDebugState->GetDbgStateLockData());
85
86         ::HeapFree (GetProcessHeap(), 0, pClrDebugState);
87 #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
88 #define GetProcessHeap() Dont_Use_GetProcessHeap()
89     }
90 #endif //_DEBUG
91 }
92
93 // This is a drastic shutoff toggle that forces all new threads to fail their CLRInitDebugState calls.
94 // We only invoke this if FLS can't allocate its master block, preventing us from tracking the shutoff
95 // on a per-thread basis.
96 BYTE* GetGlobalContractShutoffFlag()
97 {
98 #ifdef SELF_NO_HOST
99
100     static BYTE gGlobalContractShutoffFlag = 0;
101     return &gGlobalContractShutoffFlag;
102 #else //!SELF_NO_HOST
103     HINSTANCE hmod = GetCLRModule();
104     if (!hmod)
105     {
106         return NULL;
107     }
108     typedef BYTE*(__stdcall * PGETSHUTOFFADDRFUNC)();
109     PGETSHUTOFFADDRFUNC pGetContractShutoffFlagFunc = (PGETSHUTOFFADDRFUNC)GetProcAddress(hmod, "GetAddrOfContractShutoffFlag");
110     if (!pGetContractShutoffFlagFunc)
111     {
112         return NULL;
113     }
114     return pGetContractShutoffFlagFunc();
115 #endif //!SELF_NO_HOST
116 }
117
118 static BOOL AreContractsShutoff()
119 {
120     BYTE *pShutoff = GetGlobalContractShutoffFlag();
121     if (!pShutoff)
122     {
123         return FALSE;
124     }
125     else
126     {
127         return 0 != *pShutoff;
128     }
129 }
130
131 static VOID ShutoffContracts()
132 {
133     BYTE *pShutoff = GetGlobalContractShutoffFlag();
134     if (pShutoff)
135     {
136         *pShutoff = 1;
137     }
138 }
139
140 //=============================================================================================
141 // Used to initialize the per-thread ClrDebugState. This is called once per thread (with
142 // possible exceptions for OOM scenarios.)
143 //
144 // No matter what, this function will not return NULL. If it can't do its job because of OOM reasons,
145 // it will return a pointer to &gBadClrDebugState which effectively disables contracts for
146 // this thread.
147 //=============================================================================================
148 ClrDebugState *CLRInitDebugState()
149 {
150     // workaround!
151     //
152     // The existing Fls apis didn't provide the support we need and adding support cleanly is
153     // messy because of the brittleness of IExecutionEngine.
154     //
155     // To understand this function, you need to know that the Fls routines have special semantics
156     // for the TlsIdx_ClrDebugState slot:
157     //
158     //  - FlsSetValue will never throw. If it fails due to OOM on creation of the slot storage,
159     //    it will silently bail. Thus, we must do a confirming FlsGetValue before we can conclude
160     //    that the SetValue succeeded.
161     //
162     //  - FlsAssociateCallback will not complain about multiple sets of the callback.
163     //
164     //  - The mscorwks implemention of FlsAssociateCallback will ignore the passed in value
165     //    and use the version of FreeClrDebugState compiled into mscorwks. This is needed to
166     //    avoid dangling pointer races on shutdown.
167
168
169     // This is our global "bad" debug state that thread use when they OOM on CLRInitDebugState.
170     // We really only need to initialize it once but initializing each time is convenient
171     // and has low perf impact.
172     static ClrDebugState gBadClrDebugState;
173     gBadClrDebugState.ViolationMaskSet( AllViolation );
174     gBadClrDebugState.SetOkToThrow();
175
176     ClrDebugState *pNewClrDebugState = NULL;
177     ClrDebugState *pClrDebugState    = NULL;
178     DbgStateLockData    *pNewLockData      = NULL;
179
180     // We call this first partly to force a CheckThreadState. We've hopefully chased out all the
181     // recursive contract calls inside here but if we haven't, it's best to get them out of the way
182     // early.
183     ClrFlsAssociateCallback(TlsIdx_ClrDebugState, FreeClrDebugState);
184
185
186     if (AreContractsShutoff())
187     {
188         pNewClrDebugState = NULL;
189     }
190     else
191     {
192         // Yuck. We cannot call the hosted allocator for ClrDebugState (it is impossible to maintain a guarantee
193         // that none of code paths, many of them called conditionally, don't themselves trigger a ClrDebugState creation.)
194         // We have to call the OS directly for this.
195 #undef HeapAlloc
196 #undef GetProcessHeap
197         pNewClrDebugState = (ClrDebugState*)::HeapAlloc(GetProcessHeap(), 0, sizeof(ClrDebugState));
198         if (pNewClrDebugState != NULL)
199         {
200             // Only allocate a DbgStateLockData if its owning ClrDebugState was successfully allocated
201             pNewLockData  = (DbgStateLockData *)::HeapAlloc(GetProcessHeap(), 0, sizeof(DbgStateLockData));
202         }
203 #define GetProcessHeap() Dont_Use_GetProcessHeap()
204 #define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes)
205
206         if ((pNewClrDebugState != NULL) && (pNewLockData != NULL))
207         {
208             // Both allocations succeeded, so initialize the structures, and have
209             // pNewClrDebugState point to pNewLockData.  If either of the allocations
210             // failed, we'll use gBadClrDebugState for this thread, and free whichever of
211             // pNewClrDebugState or pNewLockData actually did get allocated (if either did).
212             // (See code in this function below, outside this block.)
213
214             pNewClrDebugState->SetStartingValues();
215             pNewClrDebugState->ViolationMaskSet( CanFreeMe );
216             _ASSERTE(!(pNewClrDebugState->ViolationMask() & BadDebugState));
217
218             pNewLockData->SetStartingValues();
219             pNewClrDebugState->SetDbgStateLockData(pNewLockData);
220         }
221     }
222
223
224     // This is getting really diseased. All the one-time host init stuff inside the ClrFlsStuff could actually
225     // have caused mscorwks contracts to be executed since the last time we actually checked to see if the ClrDebugState
226     // needed creating.
227     //
228     // So we must make one last check to see if the ClrDebugState still needs creating.
229     //
230     ClrDebugState *pTmp = (ClrDebugState*)(ClrFlsGetValue(TlsIdx_ClrDebugState));
231     if (pTmp != NULL)
232     {
233         // Recursive call set up ClrDebugState for us
234         pClrDebugState = pTmp;
235     }
236     else if ((pNewClrDebugState != NULL) && (pNewLockData != NULL))
237     {
238         // Normal case: our new ClrDebugState will be the one we just allocated.
239         // Note that we require BOTH the ClrDebugState and the DbgStateLockData
240         // structures to have been successfully allocated for contracts to be
241         // enabled for this thread.
242         _ASSERTE(!(pNewClrDebugState->ViolationMask() & BadDebugState));
243         _ASSERTE(pNewClrDebugState->GetDbgStateLockData() == pNewLockData);
244         pClrDebugState = pNewClrDebugState;
245     }
246     else
247     {
248         // OOM case: HeapAlloc of newClrDebugState failed.
249         pClrDebugState = &gBadClrDebugState;
250     }
251
252     _ASSERTE(pClrDebugState != NULL);
253
254
255     ClrFlsSetValue(TlsIdx_ClrDebugState, (LPVOID)pClrDebugState);
256
257     // For the ClrDebugState index, ClrFlsSetValue does *not* throw on OOM.
258     // Instead, it silently throws away the value. So we must now do a confirming
259     // FlsGet to learn if our Set succeeded.
260     if (ClrFlsGetValue(TlsIdx_ClrDebugState) == NULL)
261     {
262         // Our FlsSet didn't work. That means it couldn't allocate the master FLS block for our thread.
263         // Now we're a bad state because not only can't we succeed, we can't record that we didn't succeed.
264         // And it's invalid to return a BadClrDebugState here only to return a good debug state later.
265         //
266         // So we now take the drastic step of forcing all future ClrInitDebugState calls to return the OOM state.
267         ShutoffContracts();
268         pClrDebugState = &gBadClrDebugState;
269
270         // Try once more time to set the FLS (if it doesn't work, the next call will keep cycling through here
271         // until it does succeed.)
272         ClrFlsSetValue(TlsIdx_ClrDebugState, &gBadClrDebugState);
273     }
274
275
276 #if defined(_DEBUG)
277     // The ClrDebugState we allocated above made it into FLS iff
278     //      the DbgStateLockData we allocated above made it into
279     //      the FLS's ClrDebugState::m_pLockData
280     // These debug-only checks enforce this invariant
281
282     if (pClrDebugState != NULL)
283     {
284         // If we're here, then typically pClrDebugState is what's in FLS.  However,
285         // it's possible that pClrDebugState is gBadClrDebugState, and FLS is NULL
286         // (if the last ClrFlsSetValue() failed).  Either way, our checks below
287         // are valid ones to make.
288
289         if (pClrDebugState == pNewClrDebugState)
290         {
291             // ClrDebugState we allocated above made it into FLS, so DbgStateLockData
292             // must be there, too
293             _ASSERTE(pNewLockData != NULL);
294             _ASSERTE(pClrDebugState->GetDbgStateLockData() == pNewLockData);
295         }
296         else
297         {
298             // ClrDebugState we allocated above did NOT make it into FLS,
299             // so the DbgStateLockData we allocated must not be there, either
300             _ASSERTE(pClrDebugState->GetDbgStateLockData() == NULL || pClrDebugState->GetDbgStateLockData() != pNewLockData);
301         }
302     }
303
304     // One more invariant:  Because of ordering & conditions around the HeapAllocs above,
305     // we'll never have a DbgStateLockData without a ClrDebugState
306     _ASSERTE((pNewLockData == NULL) || (pNewClrDebugState != NULL));
307
308 #endif //_DEBUG
309
310 #undef HeapFree
311 #undef GetProcessHeap
312     if (pNewClrDebugState != NULL && pClrDebugState != pNewClrDebugState)
313     {
314         // We allocated a ClrDebugState which didn't make it into FLS, so free it.
315         ::HeapFree (GetProcessHeap(), 0, pNewClrDebugState);
316         if (pNewLockData != NULL)
317         {
318             // We also allocated a DbgStateLockData that didn't make it into FLS, so
319             // free it, too.  (Remember, we asserted above that we can only have
320             // this unused DbgStateLockData if we had an unused ClrDebugState
321             // as well (which we just freed).)
322             ::HeapFree (GetProcessHeap(), 0, pNewLockData);
323         }
324     }
325 #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
326 #define GetProcessHeap() Dont_Use_GetProcessHeap()
327
328     // Not necessary as TLS slots are born NULL and potentially problematic for OOM cases as we can't
329     // take an exception here.
330     //ClrFlsSetValue(TlsIdx_OwnedCrstsChain, NULL);
331
332     return pClrDebugState;
333 } // CLRInitDebugState
334
335 #endif //defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
336
337 const NoThrow nothrow = { 0 };
338
339 #ifdef HAS_ADDRESS_SANITIZER
340 // use standard heap functions for address santizier
341 #else
342
343 void * __cdecl
344 operator new(size_t n)
345 {
346 #ifdef _DEBUG_IMPL
347     CLRThrowsExceptionWorker();
348 #endif
349
350     STATIC_CONTRACT_THROWS;
351     STATIC_CONTRACT_GC_NOTRIGGER;
352     STATIC_CONTRACT_FAULT;
353     STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
354
355     void * result = ClrAllocInProcessHeap(0, S_SIZE_T(n));
356     if (result == NULL) {
357         ThrowOutOfMemory();
358     }
359     TRASH_LASTERROR;
360     return result;
361 }
362
363 void * __cdecl
364 operator new[](size_t n)
365 {
366 #ifdef _DEBUG_IMPL
367     CLRThrowsExceptionWorker();
368 #endif
369
370     STATIC_CONTRACT_THROWS;
371     STATIC_CONTRACT_GC_NOTRIGGER;
372     STATIC_CONTRACT_FAULT;
373     STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
374
375     void * result = ClrAllocInProcessHeap(0, S_SIZE_T(n));
376     if (result == NULL) {
377         ThrowOutOfMemory();
378     }
379     TRASH_LASTERROR;
380     return result;
381 };
382
383 #endif // HAS_ADDRESS_SANITIZER
384
385 void * __cdecl operator new(size_t n, const NoThrow&) NOEXCEPT
386 {
387 #ifdef HAS_ADDRESS_SANITIZER
388     // use standard heap functions for address santizier (which doesn't provide for NoThrow)
389         void * result = operator new(n);
390 #else
391     STATIC_CONTRACT_NOTHROW;
392     STATIC_CONTRACT_GC_NOTRIGGER;
393     STATIC_CONTRACT_FAULT;
394     STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
395
396     INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
397
398     void * result = ClrAllocInProcessHeap(0, S_SIZE_T(n));
399 #endif // HAS_ADDRESS_SANITIZER
400         TRASH_LASTERROR;
401     return result;
402 }
403
404 void * __cdecl operator new[](size_t n, const NoThrow&) NOEXCEPT
405 {
406 #ifdef HAS_ADDRESS_SANITIZER
407     // use standard heap functions for address santizier (which doesn't provide for NoThrow)
408         void * result = operator new[](n);
409 #else
410     STATIC_CONTRACT_NOTHROW;
411     STATIC_CONTRACT_GC_NOTRIGGER;
412     STATIC_CONTRACT_FAULT;
413     STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
414
415     INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
416
417     void * result = ClrAllocInProcessHeap(0, S_SIZE_T(n));
418 #endif // HAS_ADDRESS_SANITIZER
419         TRASH_LASTERROR;
420     return result;
421 }
422
423 #ifdef HAS_ADDRESS_SANITIZER
424 // use standard heap functions for address santizier
425 #else
426 void __cdecl
427 operator delete(void *p) NOEXCEPT
428 {
429     STATIC_CONTRACT_NOTHROW;
430     STATIC_CONTRACT_GC_NOTRIGGER;
431     STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
432
433     if (p != NULL)
434         ClrFreeInProcessHeap(0, p);
435     TRASH_LASTERROR;
436 }
437
438 void __cdecl
439 operator delete[](void *p) NOEXCEPT
440 {
441     STATIC_CONTRACT_NOTHROW;
442     STATIC_CONTRACT_GC_NOTRIGGER;
443     STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
444
445     if (p != NULL)
446         ClrFreeInProcessHeap(0, p);
447     TRASH_LASTERROR;
448 }
449
450 #endif // HAS_ADDRESS_SANITIZER
451
452
453 /* ------------------------------------------------------------------------ *
454  * New operator overloading for the executable heap
455  * ------------------------------------------------------------------------ */
456
457 #ifndef FEATURE_PAL 
458  
459 const CExecutable executable = { 0 };
460
461 void * __cdecl operator new(size_t n, const CExecutable&)
462 {
463 #if defined(_DEBUG_IMPL)
464     CLRThrowsExceptionWorker();
465 #endif
466
467     STATIC_CONTRACT_THROWS;
468     STATIC_CONTRACT_GC_NOTRIGGER;
469     STATIC_CONTRACT_FAULT;
470
471     HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
472     if (hExecutableHeap == NULL) {
473         ThrowOutOfMemory();
474     }
475
476     void * result = ClrHeapAlloc(hExecutableHeap, 0, S_SIZE_T(n));
477     if (result == NULL) {
478         ThrowOutOfMemory();
479     }
480     TRASH_LASTERROR;
481     return result;
482 }
483
484 void * __cdecl operator new[](size_t n, const CExecutable&)
485 {
486 #if defined(_DEBUG_IMPL)
487     CLRThrowsExceptionWorker();
488 #endif
489
490     STATIC_CONTRACT_THROWS;
491     STATIC_CONTRACT_GC_NOTRIGGER;
492     STATIC_CONTRACT_FAULT;
493
494     HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
495     if (hExecutableHeap == NULL) {
496         ThrowOutOfMemory();
497     }
498
499     void * result = ClrHeapAlloc(hExecutableHeap, 0, S_SIZE_T(n));
500     if (result == NULL) {
501         ThrowOutOfMemory();
502     }
503     TRASH_LASTERROR;
504     return result;
505 }
506
507 void * __cdecl operator new(size_t n, const CExecutable&, const NoThrow&)
508 {    
509     STATIC_CONTRACT_NOTHROW;
510     STATIC_CONTRACT_GC_NOTRIGGER;
511     STATIC_CONTRACT_FAULT;
512
513     INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
514
515     HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
516     if (hExecutableHeap == NULL)
517         return NULL;
518
519     void * result = ClrHeapAlloc(hExecutableHeap, 0, S_SIZE_T(n));
520     TRASH_LASTERROR;
521     return result;
522 }
523
524 void * __cdecl operator new[](size_t n, const CExecutable&, const NoThrow&)
525 {
526     STATIC_CONTRACT_NOTHROW;
527     STATIC_CONTRACT_GC_NOTRIGGER;
528     STATIC_CONTRACT_FAULT;
529
530     INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
531
532     HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
533     if (hExecutableHeap == NULL)
534         return NULL;
535
536     void * result = ClrHeapAlloc(hExecutableHeap, 0, S_SIZE_T(n));
537     TRASH_LASTERROR;
538     return result;
539 }
540
541 #endif // FEATURE_PAL 
542
543 #ifdef _DEBUG
544
545 // This is a DEBUG routing to verify that a memory region complies with executable requirements
546 BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length)
547 {
548 #if defined(CROSSGEN_COMPILE) || defined(FEATURE_PAL)
549     // No NX support on PAL or for crossgen compilations.
550     return TRUE;
551 #else // !(CROSSGEN_COMPILE || FEATURE_PAL) 
552     BYTE *regionStart = (BYTE*) ALIGN_DOWN((BYTE*)lpMem, GetOsPageSize());
553     BYTE *regionEnd = (BYTE*) ALIGN_UP((BYTE*)lpMem+length, GetOsPageSize());
554     _ASSERTE(length > 0);
555     _ASSERTE(regionStart < regionEnd);
556
557     while(regionStart < regionEnd)
558     {
559         MEMORY_BASIC_INFORMATION mbi;
560
561         SIZE_T cbBytes = ClrVirtualQuery(regionStart, &mbi, sizeof(mbi));
562         _ASSERTE(cbBytes);
563
564         // The pages must have EXECUTE set
565         if(!(mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)))
566             return FALSE;
567
568         _ASSERTE((BYTE*)mbi.BaseAddress + mbi.RegionSize > regionStart);
569         regionStart = (BYTE*)mbi.BaseAddress + mbi.RegionSize;
570     }
571
572     return TRUE;
573 #endif // CROSSGEN_COMPILE || FEATURE_PAL
574 }
575
576 #endif //_DEBUG
577
578
579
580
581 // Access various ExecutionEngine support services, like a logical TLS that abstracts
582 // fiber vs. thread issues.  We obtain it from a DLL export via the shim.
583
584 typedef IExecutionEngine * (__stdcall * IEE_FPTR) ();
585
586 //
587 // Access various ExecutionEngine support services, like a logical TLS that abstracts
588 // fiber vs. thread issues.
589 // From an IExecutionEngine is possible to get other services via QueryInterfaces such
590 // as memory management
591 //
592 IExecutionEngine *g_pExecutionEngine = NULL;
593
594 #ifdef SELF_NO_HOST
595 BYTE g_ExecutionEngineInstance[sizeof(UtilExecutionEngine)];
596 #endif
597
598
599 IExecutionEngine *GetExecutionEngine()
600 {
601     STATIC_CONTRACT_NOTHROW;
602     STATIC_CONTRACT_GC_NOTRIGGER;
603     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
604     SUPPORTS_DAC_HOST_ONLY;
605        
606     if (g_pExecutionEngine == NULL)
607     {
608         IExecutionEngine* pExecutionEngine;
609 #ifdef SELF_NO_HOST
610         // Create a local copy on the stack and then copy it over to the static instance.
611         // This avoids race conditions caused by multiple initializations of vtable in the constructor
612         UtilExecutionEngine local;
613         memcpy((void*)&g_ExecutionEngineInstance, (void*)&local, sizeof(UtilExecutionEngine));
614         pExecutionEngine = (IExecutionEngine*)(UtilExecutionEngine*)&g_ExecutionEngineInstance;
615 #else
616         // statically linked.
617         VALIDATECORECLRCALLBACKS();
618         pExecutionEngine = g_CoreClrCallbacks.m_pfnIEE();
619 #endif  // SELF_NO_HOST
620
621         //We use an explicit memory barrier here so that the reference g_pExecutionEngine is valid when
622         //it is used, This ia a requirement on platforms with weak memory model . We cannot use VolatileStore  
623         //because they are the same as normal assignment for DAC builds [see code:VOLATILE]
624
625         MemoryBarrier();
626         g_pExecutionEngine = pExecutionEngine;
627     }
628
629     // It's a bug to ask for the ExecutionEngine interface in scenarios where the
630     // ExecutionEngine cannot be loaded.
631     _ASSERTE(g_pExecutionEngine);
632     return g_pExecutionEngine;
633 } // GetExecutionEngine
634
635 IEEMemoryManager * GetEEMemoryManager()
636 {
637     STATIC_CONTRACT_GC_NOTRIGGER;
638     STATIC_CONTRACT_NOTHROW;
639     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
640     SUPPORTS_DAC_HOST_ONLY;
641
642     static IEEMemoryManager *pEEMemoryManager = NULL;
643     if (NULL == pEEMemoryManager) {
644         IExecutionEngine *pExecutionEngine = GetExecutionEngine();
645         _ASSERTE(pExecutionEngine);
646
647         // It is dangerous to pass a global pointer to QueryInterface.  The pointer may be set
648         // to NULL in the call.  Imagine that thread 1 calls QI, and get a pointer.  But before thread 1
649         // returns the pointer to caller, thread 2 calls QI and the pointer is set to NULL.
650         IEEMemoryManager *pEEMM;
651         pExecutionEngine->QueryInterface(IID_IEEMemoryManager, (void**)&pEEMM);
652         pEEMemoryManager = pEEMM;
653     }
654     // It's a bug to ask for the MemoryManager interface in scenarios where it cannot be loaded.
655     _ASSERTE(pEEMemoryManager);
656     return pEEMemoryManager;
657 }
658
659 // should return some error code or exception
660 void SetExecutionEngine(IExecutionEngine *pExecutionEngine)
661 {
662     STATIC_CONTRACT_NOTHROW;
663     STATIC_CONTRACT_GC_NOTRIGGER;
664
665     _ASSERTE(pExecutionEngine && !g_pExecutionEngine);
666     if (!g_pExecutionEngine) {
667         g_pExecutionEngine = pExecutionEngine;
668         g_pExecutionEngine->AddRef();
669     }
670 }
671
672 void ClrFlsAssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
673 {
674     WRAPPER_NO_CONTRACT;
675
676     GetExecutionEngine()->TLS_AssociateCallback(slot, callback);
677 }
678
679 LPVOID *ClrFlsGetBlockGeneric()
680 {
681     WRAPPER_NO_CONTRACT;
682
683     return (LPVOID *) GetExecutionEngine()->TLS_GetDataBlock();
684 }
685
686 CLRFLSGETBLOCK __ClrFlsGetBlock = ClrFlsGetBlockGeneric;
687
688 CRITSEC_COOKIE ClrCreateCriticalSection(CrstType crstType, CrstFlags flags)
689 {
690     WRAPPER_NO_CONTRACT;
691
692     return GetExecutionEngine()->CreateLock(NULL, (LPCSTR)crstType, flags);
693 }
694
695 HRESULT ClrDeleteCriticalSection(CRITSEC_COOKIE cookie)
696 {
697     WRAPPER_NO_CONTRACT;
698     GetExecutionEngine()->DestroyLock(cookie);
699     return S_OK;
700 }
701
702 void ClrEnterCriticalSection(CRITSEC_COOKIE cookie)
703 {
704     WRAPPER_NO_CONTRACT;
705
706     return GetExecutionEngine()->AcquireLock(cookie);
707 }
708
709 void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie)
710 {
711     WRAPPER_NO_CONTRACT;
712
713     return GetExecutionEngine()->ReleaseLock(cookie);
714 }
715
716 EVENT_COOKIE ClrCreateAutoEvent(BOOL bInitialState)
717 {
718     WRAPPER_NO_CONTRACT;
719
720     return GetExecutionEngine()->CreateAutoEvent(bInitialState);
721 }
722
723 EVENT_COOKIE ClrCreateManualEvent(BOOL bInitialState)
724 {
725     WRAPPER_NO_CONTRACT;
726
727     return GetExecutionEngine()->CreateManualEvent(bInitialState);
728 }
729
730 void ClrCloseEvent(EVENT_COOKIE event)
731 {
732     WRAPPER_NO_CONTRACT;
733
734     GetExecutionEngine()->CloseEvent(event);
735 }
736
737 BOOL ClrSetEvent(EVENT_COOKIE event)
738 {
739     WRAPPER_NO_CONTRACT;
740
741     return GetExecutionEngine()->ClrSetEvent(event);
742 }
743
744 BOOL ClrResetEvent(EVENT_COOKIE event)
745 {
746     WRAPPER_NO_CONTRACT;
747
748     return GetExecutionEngine()->ClrResetEvent(event);
749 }
750
751 DWORD ClrWaitEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable)
752 {
753     WRAPPER_NO_CONTRACT;
754
755     return GetExecutionEngine()->WaitForEvent(event, dwMilliseconds, bAlertable);
756 }
757
758 SEMAPHORE_COOKIE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax)
759 {
760     WRAPPER_NO_CONTRACT;
761
762     return GetExecutionEngine()->ClrCreateSemaphore(dwInitial, dwMax);
763 }
764
765 void ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore)
766 {
767     WRAPPER_NO_CONTRACT;
768
769     GetExecutionEngine()->ClrCloseSemaphore(semaphore);
770 }
771
772 BOOL ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount)
773 {
774     WRAPPER_NO_CONTRACT;
775
776     return GetExecutionEngine()->ClrReleaseSemaphore(semaphore, lReleaseCount, lpPreviousCount);
777 }
778
779 DWORD ClrWaitSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable)
780 {
781     WRAPPER_NO_CONTRACT;
782
783     return GetExecutionEngine()->ClrWaitForSemaphore(semaphore, dwMilliseconds, bAlertable);
784 }
785
786 MUTEX_COOKIE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
787                             BOOL bInitialOwner,
788                             LPCTSTR lpName)
789 {
790     WRAPPER_NO_CONTRACT;
791
792     return GetExecutionEngine()->ClrCreateMutex(lpMutexAttributes, bInitialOwner, lpName);
793 }
794
795 void ClrCloseMutex(MUTEX_COOKIE mutex)
796 {
797     WRAPPER_NO_CONTRACT;
798
799     GetExecutionEngine()->ClrCloseMutex(mutex);
800 }
801
802 BOOL ClrReleaseMutex(MUTEX_COOKIE mutex)
803 {
804     WRAPPER_NO_CONTRACT;
805
806     return GetExecutionEngine()->ClrReleaseMutex(mutex);
807 }
808
809 DWORD ClrWaitForMutex(MUTEX_COOKIE mutex, DWORD dwMilliseconds, BOOL bAlertable)
810 {
811     WRAPPER_NO_CONTRACT;
812
813     return GetExecutionEngine()->ClrWaitForMutex(mutex, dwMilliseconds, bAlertable);
814 }
815
816 DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable)
817 {
818     WRAPPER_NO_CONTRACT;
819
820     return GetExecutionEngine()->ClrSleepEx(dwMilliseconds, bAlertable);
821 }
822
823 LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
824 {
825     WRAPPER_NO_CONTRACT;
826
827     LPVOID result =  GetEEMemoryManager()->ClrVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
828     LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualAlloc  (0x%p, 0x%06x, 0x%06x, 0x%02x) = 0x%p\n", lpAddress, dwSize, flAllocationType, flProtect, result));
829
830     return result;
831 }
832
833 BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
834 {
835     WRAPPER_NO_CONTRACT;
836
837     LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualFree   (0x%p, 0x%06x, 0x%04x)\n", lpAddress, dwSize, dwFreeType));
838     BOOL result = GetEEMemoryManager()->ClrVirtualFree(lpAddress, dwSize, dwFreeType);
839
840     return result;
841 }
842
843 SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength)
844 {
845     WRAPPER_NO_CONTRACT;
846
847     LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualQuery  (0x%p)\n", lpAddress));
848     return GetEEMemoryManager()->ClrVirtualQuery(lpAddress, lpBuffer, dwLength);
849 }
850
851 BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
852 {
853     WRAPPER_NO_CONTRACT;
854
855     LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualProtect(0x%p, 0x%06x, 0x%02x)\n", lpAddress, dwSize, flNewProtect));
856     return GetEEMemoryManager()->ClrVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
857 }
858
859 HANDLE ClrGetProcessHeap()
860 {
861     WRAPPER_NO_CONTRACT;
862
863     return GetEEMemoryManager()->ClrGetProcessHeap();
864 }
865
866 HANDLE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize)
867 {
868     WRAPPER_NO_CONTRACT;
869
870     return GetEEMemoryManager()->ClrHeapCreate(flOptions, dwInitialSize, dwMaximumSize);
871 }
872
873 BOOL ClrHeapDestroy(HANDLE hHeap)
874 {
875     WRAPPER_NO_CONTRACT;
876
877     return GetEEMemoryManager()->ClrHeapDestroy(hHeap);
878 }
879
880 LPVOID ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, S_SIZE_T dwBytes)
881 {
882     WRAPPER_NO_CONTRACT;
883
884     if(dwBytes.IsOverflow()) return NULL;
885
886     LPVOID result = GetEEMemoryManager()->ClrHeapAlloc(hHeap, dwFlags, dwBytes.Value());
887
888     return result;
889 }
890
891 BOOL ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
892 {
893     WRAPPER_NO_CONTRACT;
894
895     BOOL result = GetEEMemoryManager()->ClrHeapFree(hHeap, dwFlags, lpMem);
896
897     return result;
898 }
899
900 BOOL ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
901 {
902     WRAPPER_NO_CONTRACT;
903
904     return GetEEMemoryManager()->ClrHeapValidate(hHeap, dwFlags, lpMem);
905 }
906
907 HANDLE ClrGetProcessExecutableHeap()
908 {
909     WRAPPER_NO_CONTRACT;
910
911     return GetEEMemoryManager()->ClrGetProcessExecutableHeap();
912 }
913
914 void GetLastThrownObjectExceptionFromThread(void **ppvException)
915 {
916     WRAPPER_NO_CONTRACT;
917
918     GetExecutionEngine()->GetLastThrownObjectExceptionFromThread(ppvException);
919 }